In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

CFA-AS4

前回よりも色々と進化。引数が増えたり動きが増えたり。Tweener様様です。

画面クリックで再描画可能.
Get Adobe Flash player
by Hiroki_lzh 27 Jan 2011
package {
    
    import caurina.transitions.Tweener;
    import caurina.transitions.properties.ColorShortcuts;
    import caurina.transitions.properties.FilterShortcuts;
    
    import flash.display.*;
    import flash.display.DisplayObjectContainer;
    import flash.display.SimpleButton;
    import flash.display.Stage;
    import flash.events.ErrorEvent;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFieldType;
    import flash.text.TextFormat;
    
    public class Main extends Sprite{
        public function Main(){
            //ココにCFAの記述方法で書きこむ。最初の描画分。
            var cfdg :String =<><![CDATA[

startshape ellipse
background {hue -120 sat 1 b -0.4}
timer{d 0}  
rule ellipse 5 {
CIRCLE {act 3}
CIRCLE {s 0.93 0.99 r -10 b 2 act 5}
ellipse {s 0.90 0.97 r -10 }
}
 
]]></>;
            
            FilterShortcuts.init();
            ColorShortcuts.init();
            start( cfdg );
            
        }


        private function start( cfdg :String ) :void {//ASイベントリスナー、CFAを書き始める
            var art :ContextFreeArt = new ContextFreeArt( cfdg,465,465 );
            var txt:TextField = createTextField(cfdg, 10, 0);
    
            addChildAt(art,0);    // ContextFreeArt描画フィールドの描画
            addChild(txt); // テキストフィールドの描画

            var btn:CustomSimpleButton= new CustomSimpleButton();
            var count:Number = 0;
            addChild(btn);
            btn.addEventListener(MouseEvent.CLICK, function (e:MouseEvent):void{
                   if (count == 0) {
                    count = 1;
                    Tweener.addTween(txt,{ x:0,y:-465,time :2,transition:"easeOutQuad"});
                } else if (count == 1) {
                    count = 0;
                    Tweener.addTween(txt,{ x:0,y:0,time :2,transition:"easeOutQuad"});
                }
            });

            stage.addEventListener(MouseEvent.CLICK,CLICK);
                                
            function CLICK(e:MouseEvent):void {
                removeChild(art);
                art = new ContextFreeArt(txt.text,465,465 );
                addChildAt(art,0);
            }
        
        }
        
        private function createTextField(text:String, size:int, color:int):TextField
        {//書き込みスペースの設定
            var txt:TextField = new TextField();
            txt.defaultTextFormat = new TextFormat("_typeWriter", size, color, true);
            txt.type = TextFieldType.INPUT;
            txt.text = text;
            txt.x = 0;
            txt.height = 465;
            txt.width =150;
            txt.autoSize =TextFieldAutoSize.NONE;
            txt.multiline = true;
            txt.wordWrap = true;
            txt.border = true;
            txt.borderColor = 0xED1A3D;
            txt.background = true;    
            txt.backgroundColor = 0xA6E1ED;
            
            return txt;
        }
        
        

    }
}

function log(...args) :void {}


import flash.display.Sprite;
/*

CFA-ASのレンダリング

*/
class ContextFreeArt extends Sprite {
    private var renderer :Renderer;
    public function ContextFreeArt( cfdg_text :String, width :Number = 640, height :Number = 480 ) {
        var t :Tokenizer = new Tokenizer;
        var tokens :Array = t.tokenize( cfdg_text );
        var c :Compiler = new Compiler;
        var compiled :Object = c.compile( tokens );
        
        logger("compiled: ",compiled);
        
        renderer = new Renderer( width, height );
        renderer.clearQueue();
        renderer.render( compiled, this );
    }
    
    public function tick() :void {
        renderer.tick();
    }
    
    private function logger(... args) :void {
        if ( 1 ) {
            return; 
        }
        log.apply(null, (new Array("[ContextFreeArt]", this)).concat(args));
    }
}

import flash.utils.getDefinitionByName;

/*

CFAとしてのコンパイラ
startshape,rule,backgroundを作る

*/

class Compiler{
    private const keywords :Array = [ "startshape", "rule", "background" ];
    public var compiled :Object = {};
    public var state :IState;
    private var curKey :String;
    private var curValues :Array;
    private var obj :Object;
    public function Compiler(){
    }
    public function compile( tokens :Array ) :Object {
        state = new General;
        while ( tokens.length > 0 ) {
            var token :String = tokens.shift();
            var nextState :Array = state.eat( token, this );
            if ( nextState ) {
                next( nextState );
            }
        }
        return compiled;
    }
    
    private function next( state_and_args :Array ) :void {
        var className :String = state_and_args.shift();
        className = className.substr(0,1).toUpperCase() + className.substr(1);
        switch( className ) {
            case "Startshape":
                state = new Startshape;
                break;
            case "General":
                state = new General;
                break;
            case "Background":
                state = new Background;
                break;
            case "Rule":
                state = new Rule;
                break;
            case "RuleWeight":
                state = new RuleWeight( state_and_args );
                break;
            case "RuleDraw":
                state = new RuleDraw( state_and_args );
                break;
            case "ShapeAdjustment":
                state = new ShapeAdjustment( state_and_args );
                break;
            case "Timer":
                state = new Timerchenge;
                break;
            default:
                throw('クラス名が不明です: '+className);
        }
    }
    
    private function logger(... args) :void {
        if ( 1 ) { 
            return; 
        }
        log.apply(null, (new Array("[compiler]", this)).concat(args));
    }
}

/*

CFAとしてのトークンの処理
{}とか
*/
class Tokenizer{
    private var input :String;
    private const stopChars :Array = [" ", "{", "}", "\n", "\r", "\t"];//改行、タブ、{}の処理
    
    public function Tokenizer() {
    }
    // TODO: String comments
    // TODO: Handle ordered arguments (i.e., square brakets)
    // TODO: Handle the | operator
    public function tokenize( _input :String ) :Array {
        input = _input;
        
        input = input.replace( /([{}])/g, " $1");  
        var tokens :Array = new Array;  
        var head :Object = { lastPos: 0 };
        while( 1 ) {
            head = tokenizeNext( head.lastPos );  
            if ( head == null ) { break; }  
            if ( head.token ) {
                tokens.push( head.token );
            }  
        }
        logger("[tokenize]tokens: ",tokens);  
        return tokens;
    }
    
    private function tokenizeNext( pos :Number ) :Object {
        var stops :Array = new Array;
        
        var len :int = stopChars.length;
        for ( var i:int=0; i<len; i++ ) {
            var stopChar :String = stopChars[ i ];
            var foundPos :int    = input.indexOf( stopChar, pos );
            if ( foundPos != -1 ) {
                stops.push( foundPos + 1 );
            }
        }
        
        if ( stops.length == 0 ) { return null; }
        
        var stopPos :Number = Math.min.apply( null, stops );
        
        var token :String   = input.substr(pos, stopPos-pos);
        
        token = token.replace( /[ \n\r\t]/, "" );
        
        return { token: token, lastPos: stopPos }
    }
    
    private function logger(... args) :void {
        if ( 1 ) {
            return; 
        }
        log.apply(null, (new Array("[Tokenizer]", this)).concat(args));
    }
}

import flash.display.DisplayObjectContainer;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Graphics;
import flash.events.TimerEvent;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.Timer;
import flash.geom.Transform;
import flash.events.MouseEvent;
import caurina.transitions.Tweener

/*

レンダリング(背景や中央配置)

*/
class Renderer extends Sprite{
    private var widths  :Number = 640;
    private var heights :Number = 480;
    private var globalScale :Number = 300;    
    private var centeringScale  :Number = 1;
    private var centeringMatrix :Matrix = new Matrix;
    private var queue :Array;
    private var compiled :Object;
    private var container :Sprite;
    private var background :Sprite;
    private var sprite :Sprite;
    private var isRendering :Boolean = false;
    private var maxThreads :int = 1000;
    private var tickTimer :Timer;
    private var globalMatrix :Matrix;
    
    public function Renderer( _width :Number = 0, _height :Number = 0 ){
        if ( _width  ) { widths  = _width;  }
        if ( _height ) { heights = _height; }
        
        logger("w: "+widths+" h: "+heights);
    }
    
    public function render( _compiled :Object, _container :DisplayObjectContainer ) :void {
        var render_time:Number = 500;
        compiled   = _compiled;
        background = new Sprite;
        _container.addChild( background );
        sprite = new Sprite;
        _container.addChild( sprite );
        
        if ( ! queue ) { queue = new Array; }
        
        globalMatrix = new Matrix;
    
        drawBackground();
        timetempo()
        draw();
        //描画時間変更
        tickTimer = new Timer( render_time );
        tickTimer.addEventListener( TimerEvent.TIMER, tick );
        tickTimer.start();
        
        function timetempo() :void {//背景の設定
            if ( compiled.timerchenge ) {
                var timeAdj :Adjustment = compiled.timerchenge;
                var timerTime :Time = new Time;
                timerTime.d = timeAdj.d; // { d:0 };
                render_time = render_time * timerTime.d;
            }
        }
    }
    
    public function tick( e :TimerEvent = null ) :void {
        
        if ( queue.length > 0 ) {
            isRendering = true;
            
            var concurrent :int = Math.min( queue.length - 1, maxThreads );
            
            for ( var i :int=0; i <= concurrent; i++ ) {
                var args :Array = queue.shift();
                drawRule.apply( null, args );
            }
            center();
        }
    }
    
    private function center() :void {
        
        var rect :Rectangle = sprite.getRect( cfa_sp );
        
        // 描画画像のリサイズ
        centeringScale    = Math.min( widths / rect.width, heights / rect.height ) *0.8;
        centeringMatrix.a = centeringMatrix.d = centeringScale;
        
        // センタリング
        centeringMatrix.tx         = widths/2 - (rect.left + rect.right ) / 2 * centeringScale;
        centeringMatrix.ty         = heights*2/5 - (rect.top  + rect.bottom) / 2 * centeringScale;
        sprite.transform.matrix = centeringMatrix;
    }
    
    private function draw() :void {
        var ruleName :String = compiled.startshape;
        var foregroundColor :Color = new Color;
        
        drawRule( ruleName, new Matrix, foregroundColor );
    }
    /*
    
    レンダリング停止条件
    
    */
    private function drawRule( ruleName :String, mtx :Matrix, color :Color, priority :Number = 0 ) :void {
        if( Math.abs( mtx.a ) * globalScale * centeringScale < 1.0 && Math.abs( mtx.b ) * globalScale * centeringScale < 1.0 ){
            return;
        }
        
        var shape :Object = chooseShape( ruleName );
        drawShape( shape, mtx, color, priority );
    }
    
    
    private function chooseShape( ruleName :String ) :Object {
        var choices :Array = compiled[ ruleName ];
        if ( ! choices ) { throw("ruleが見つかりません: "+ruleName); }
        
        var sum :Number = 0;
        for( var i :int=0; i<choices.length; i++) {
            sum += choices[i].weight;
        }
        
        var shape :Object;
        var r :Number = Math.random() * sum;
        sum = 0;
        for( i=0; i <= choices.length-1; i++) {
            sum += choices[i].weight;
            if( r <= sum ){
                shape = choices[i];
                break;
            }
        }
        if ( ! shape ) { throw("図形名が間違っており、rule: "+ruleName+" が無効です"); }
        
        return shape;
    }
    
    //////////////////
    private var cfa_sp:Sprite = new Sprite();
    /////////////////
    
    
    private function drawShape( shape :Object, mtx :Matrix, color :Color, priority :Number = 0 ) :void {
        var len :int = shape.draw.length;
        for ( var i :int = 0; i < len; i++ ) {
            var adj :Adjustment = shape.draw[ i ];
            
            cfa_sp = new Sprite();
            sprite.addChild(cfa_sp);
            
            var localTransform :Matrix = mtx.clone();
            localTransform             = adjustTransform( adj, localTransform , cfa_sp );
            var localColor :Color      = adjustColor( adj, color );
            
            var localMatrix :Matrix = globalMatrix.clone();
            globalMatrix.concat( localTransform );
            
            switch( adj.name ){
                case "CIRCLE":
                    drawCIRCLE( globalMatrix, localColor ,cfa_sp);
                    break;
           
                case "SQUARE":
                    drawSQUARE( localTransform, localColor , cfa_sp);
                    break;
                
                case "TRIANGLE":
                    drawTRIANGLE( localTransform, localColor , cfa_sp);
                    break;
                
                case "SEQ":
                    drawSEQ( localTransform, localColor , cfa_sp);
                    break;
                
                default:
                    var args :Array = [ adj.name, localTransform, localColor ];
                    
                    if( priority == 1 ){ queue.unshift( args ); }
                    else{ queue.push( args ); }
                    break;
            }
            
            globalMatrix = localMatrix;
            
        }
        
    }
    
    private const halfScale :Number = globalScale * 0.5;
    private const _P:Number = 0.7071067811865476;    //Math.cos( Math.PI / 4 )
    private const _T:Number = 0.41421356237309503;   //Math.tan( Math.PI / 8 )
    private function drawCIRCLE( mx :Matrix, color :Color, s:Sprite ) :void {//円の設定
        //var g :Graphics = container.graphics;
        var g :Graphics = cfa_sp.graphics;
        
        g.beginFill.apply( null, colorToRgba(color) );
        
        moveTo(  g, mx, + halfScale, 0 );
        curveTo( g, mx, + halfScale     , + halfScale * _T, + halfScale * _P, + halfScale * _P );
        curveTo( g, mx, + halfScale * _T, + halfScale     , 0               , + halfScale );
        curveTo( g, mx, - halfScale * _T, + halfScale     , - halfScale * _P, + halfScale * _P );
        curveTo( g, mx, - halfScale     , + halfScale * _T, - halfScale     , 0 );
        curveTo( g, mx, - halfScale     , - halfScale * _T, - halfScale * _P, - halfScale * _P );
        curveTo( g, mx, - halfScale * _T, - halfScale     , 0               , - halfScale );
        curveTo( g, mx, + halfScale * _T, - halfScale     , + halfScale * _P, - halfScale * _P );
        curveTo( g, mx, + halfScale     , - halfScale * _T, + halfScale     , 0 );
        g.endFill();
    }
    
    
    private function drawSQUARE( mx :Matrix, color :Color , s:Sprite) :void {//正方形の設定
        //var g :Graphics = container.graphics;
        var g :Graphics = cfa_sp.graphics;
        g.beginFill.apply( null, colorToRgba(color) );
        
        moveTo( g, mx, - halfScale, - halfScale );
        lineTo( g, mx, + halfScale, - halfScale );
        lineTo( g, mx, + halfScale, + halfScale );
        lineTo( g, mx, - halfScale, + halfScale );
        lineTo( g, mx, - halfScale, - halfScale );
        
        g.endFill();
    }
    
    private const triangley :Number = Math.sqrt(3) * globalScale / 6;
    private function drawTRIANGLE( mx :Matrix, color :Color , s:Sprite) :void {//三角形の描画
        //var g :Graphics = container.graphics;
        var g :Graphics = cfa_sp.graphics;
        g.beginFill.apply( null, colorToRgba(color) );
        
        moveTo( g, mx, - halfScale, triangley );
        lineTo( g, mx, + halfScale, triangley );
        lineTo( g, mx, 0,          -triangley * 2 );
        lineTo( g, mx, - halfScale, triangley );
        
        g.endFill();
    }
    
    
    //どんな形にするか試行錯誤中
    private function drawSEQ( mx :Matrix, color :Color , s:Sprite) :void {//円の設定
        //var g :Graphics = container.graphics;
        var g :Graphics = cfa_sp.graphics;
        
        g.beginFill.apply( null, colorToRgba(color) );
        
        moveTo( g, mx, - halfScale, triangley );
        lineTo( g, mx, + halfScale, triangley );
        lineTo( g, mx, 0,          -triangley * 2 );
        lineTo( g, mx, - halfScale, triangley );
        moveTo( g, mx, + halfScale, -triangley );
        lineTo( g, mx, - halfScale, -triangley );
        lineTo( g, mx, 0,          triangley * 2 );
        lineTo( g, mx, + halfScale, -triangley );
        
        g.endFill();
    }
    
    
    //描画位置で書くためのmoveTo,lineTo,curveToの定義
    private function moveTo( g :Graphics, mx :Matrix, x :Number, y :Number ) :void {
        g.moveTo( x * mx.a + y * mx.c + mx.tx,
            x * mx.b + y * mx.d + mx.ty );
    }
    
    private function lineTo( g :Graphics, mx :Matrix, x :Number, y :Number ) :void {
        g.lineTo( x * mx.a + y * mx.c + mx.tx,
            x * mx.b + y * mx.d + mx.ty );
    }
    
    private function curveTo( g :Graphics, mx :Matrix, cx:Number, cy:Number, x:Number, y:Number ):void{
        g.curveTo( cx * mx.a + cy * mx.c + mx.tx,
            cx * mx.b + cy * mx.d + mx.ty,
            x * mx.a + y * mx.c + mx.tx,
            x * mx.b + y * mx.d + mx.ty );
    }
    
    
    
    private function drawBackground() :void {//背景の設定
        if ( compiled.background ) {
            var colorAdj :Adjustment = compiled.background;
            var backgroundColor :Color = new Color;
            backgroundColor.b = 1; // { h:0, s:0, b:1, a:1 };
            var color :Color = adjustColor( colorAdj, backgroundColor );
            var color_alpha :Array = colorToRgba( color );
            
            logger("[drawBackground]color: ",color, backgroundColor,color_alpha);
            
            var bg :Shape = new Shape;
            bg.graphics.beginFill( color_alpha[0], color_alpha[1] );
            bg.graphics.drawRect( 0, 0, widths, heights );
            background.addChild( bg );
        }
    }
    

    // order: rotate scale,flip,skew,k
    private function adjustTransform( adjs :Adjustment, base :Matrix ,art:Sprite) :Matrix {
        var mtx :Matrix = new Matrix;
        
        //flip
        if ( adjs.flipDefined ){
            var flip :Number = adjs.flip;
            var vX :Number   = Math.cos( -2*Math.PI * flip / 360);
            var vY :Number   = Math.sin( -2*Math.PI * flip / 360);
            var norm :Number = 1/(vX*vX + vY*vY);
            //var flip :Matrix = new Matrix((vX*vX-vY*vY)/norm, 2*vX*vY/norm, 2*vX*vY/norm, (vY*vY-vX*vX)/norm, 0, 0);
            mtx.a = (vX*vX-vY*vY)/norm;
            mtx.b = 2*vX*vY/norm;
            mtx.c = 2*vX*vY/norm;
            mtx.d = (vY*vY-vX*vX)/norm;
        }
        
        //skew
        if ( adjs.skewDefined ){ 
            var skewX :Number = adjs.skewX;
            var skewY :Number = adjs.skewY;
            mtx.b = skewY * Math.PI/180;
            mtx.c = skewX * Math.PI/180;
        }
        
        // Scaling
        var sizeX :Number = adjs.sizeX;
        var sizeY :Number = adjs.sizeY;
        if ( sizeX || sizeY ) {
            mtx.scale( sizeX, sizeY );
        }
        
        // Rotation
        var r :Number = adjs.rotate;
        if ( r != 0 ) {
            mtx.rotate( - Math.PI * r / 180 );
        }
        // Tranalsation
        var x :Number =  adjs.x;
        var y :Number = -adjs.y;
        var point :Point = new Point( x * globalScale, y * globalScale );
        if ( x != 0 || y != 0 ) {
            mtx.translate( point.x, point.y );            
        }
                
    
        //Tweener動作コマンド
        // act 前後に動かす
        var act :Number = adjs.act;
        //mv
        var mvx :Number =  adjs.mvx;
        var mvy :Number = -adjs.mvy;
        var MV: Point = new Point(mvx*globalScale,mvy*globalScale);
        // ch 色の変化
        // ca 透明度の変化
        var ch :Number = adjs.ch;
        var ca :Number = adjs.ca;
        // l 影を付ける
        var sdw :Number = adjs.sdw;    
        //remove Tween
        var stp :Number = adjs.stp;
        var d :Number = adjs.d;

        if ( ch != 0 || ca != 0){
            Tweener.addTween(art,{ x:0, y:0, scaleX:1,scaleY:1,_hue: ch ,_color_alphaMultiplier: ca ,time :20 ,delay:d, transition:"liner"});  //色相・透明度変化
        }
        if ( sdw != 0 ){
            Tweener.addTween(art,{ x:0, y:0, scaleX:1,scaleY:1,_DropShadow_angle:sdw,  _DropShadow_distance: 10 , _DropShadow_blurX: 10, _DropShadow_blurY:10, _DropShadow_alpha: 0.5,time :5 , transition:"liner"});
        }
        if ( mvx!=0 || mvy!=0 ){
            Tweener.addTween(art,{ x:MV.x , y:MV.y ,scaleX:1,scaleY:1,time : 5 ,delay:d,transition:"liner"});
        }
        if (act !=0){
            Tweener.addTween(art,{ x:MV.x , y:MV.y , scaleX:1, scaleY:1 ,time : act ,delay:d, transition:"easeOutElastic",onComplete:action1,onCompleteParams:[art]});
        }
        if (stp != 0){//クリックで停止
            art.addEventListener(MouseEvent.CLICK,Stopmotion);
            art.buttonMode = true;
        }
        if (adjs.spnDefined){//回転
            var spn1 :Number = adjs.spnDeg;
            var spn2 :Number = adjs.spnTime;
            Tweener.addTween(art,{ rotation:0,time: spn2 ,delay:d,transition:"liner",onComplete:Rotate1,onCompleteParams:[art]});
        }

        
        function action1(art:Sprite):void{
            Tweener.addTween(art,{ x:base.tx , y:base.ty , scaleX:0, scaleY:0 ,time :act , transition:"easeOutElastic",onComplete:action2,onCompleteParams:[art]})
        }
        function action2(art:Sprite):void{
            Tweener.addTween(art,{ x:MV.x , y:MV.y, scaleX:1, scaleY:1 ,time :act , transition:"easeOutElastic",onComplete:action1,onCompleteParams:[art]})
        }
        function Rotate1(art:Sprite):void{//Tweener停止
            Tweener.addTween(art,{rotation:-spn1,time: spn2 ,transition:"liner",onComplete:Rotate2,onCompleteParams:[art]});
        }
        function Rotate2(art:Sprite):void{//Tweener停止
            Tweener.addTween(art,{rotation:0,time: spn2 ,transition:"liner",onComplete:Rotate1,onCompleteParams:[art]});
        }
        
        function Stopmotion(evt:MouseEvent):void{//Tweener停止
             Tweener.removeTweens(evt.target);
         }

        mtx.concat( base );
        
        
        return mtx;
    }
    
    
    private function colorToRgba( color :Color ) :Array {
        return hsl2rgb( color.h, color.s, color.b, color.a );
    }
    
    // hue, saturation, brightness, alpha
    // hue:色彩 [0,360] default 0
    // saturation:明度 [0,1] default 0
    // brightness:濃度 [0,1] default 1
    // alpha:透明度 [0,1] default 1
    private function hsl2rgb(h :Number, s :Number, l :Number, a :Number) :Array {
        
        if (h == 360){ h = 0;}
        
        //
        // based on C code from http://astronomy.swin.edu.au/~pbourke/colour/hsl/
        //
        
        while (h < 0){ h += 360; }
        while (h > 360){ h -= 360; }
        var r :Number, g :Number, b :Number;
        if (h < 120){
            r = (120 - h) / 60;
            g = h / 60;
            b = 0;
        }else if (h < 240){
            r = 0;
            g = (240 - h) / 60;
            b = (h - 120) / 60;
        }else{
            r = (h - 240) / 60;
            g = 0;
            b = (360 - h) / 60;
        }
        
        r = Math.min(r, 1);
        g = Math.min(g, 1);
        b = Math.min(b, 1);
        
        r = 2 * s * r + (1 - s);
        g = 2 * s * g + (1 - s);
        b = 2 * s * b + (1 - s);
        
        if (l < 0.5){
            r = l * r;
            g = l * g;
            b = l * b;
        }else{
            r = (1 - l) * r + 2 * l - 1;
            g = (1 - l) * g + 2 * l - 1;
            b = (1 - l) * b + 2 * l - 1;
        }
        
        r = Math.ceil(r * 255);
        g = Math.ceil(g * 255);
        b = Math.ceil(b * 255);
        return [ (r * 256*256 + g * 256 + b), a ];
    }
    /*
    
    色彩設定RGB→HSVA 
    
    */ 
    private function adjustColor( adjs :Adjustment, color :Color ) :Color {
        // See http://www.contextfreeart.org/mediawiki/index.php/Shape_adjustments
        var newColor :Color = new Color;
        newColor.h = color.h;
        newColor.s = color.s;
        newColor.b = color.b;
        newColor.a = color.a;
        
        // Add num to the drawing hue value, modulo 360 
        newColor.h += adjs.hue;
        newColor.h %= 360;
        
        // If adj<0 then change the drawing [blah] adj% toward 0.
        // If adj>0 then change the drawing [blah] adj% toward 1. 
        if ( adjs.saturation != 0 ) {
            if( adjs.saturation > 0 ){
                newColor.s += adjs.saturation * (1-color.s);
            } else {
                newColor.s += adjs.saturation * color.s;
            }
        }
        if ( adjs.brightness != 0 ) {
            if( adjs.brightness > 0 ){
                newColor.b += adjs.brightness * (1/2-color.b);
            } else {
                newColor.b += adjs.brightness * color.b;
            }
        }
        if ( adjs.alpha != 0 ) {
            if( adjs.alpha > 0 ){
                newColor.a += adjs.alpha * (-1-color.a);
            } else {
                newColor.a += adjs.alpha * color.a;
            }
        }
        
        return newColor;
    }
    
    public function clearQueue() :void {
        queue = new Array;
    }
    
    private function logger(... args) :void {
        if ( 1 ) {
            return; 
        }
        log.apply(null, (new Array("[Renderer]", this)).concat(args));
    }
}

class Color {
    public var h :Number = 0;
    public var s :Number = 0;
    public var b :Number = 0;
    public var a :Number = 1;
    
    public function Color(){
    }
}

class Time {
    public var d :Number = 1;

    public function Time(){
    }
}




/*

ルール指定

*/
class Adjustment{
    public var name :String;
    public var flipDefined :Boolean = false;
    public var flip :Number;
    public var sizeX :Number = 1;
    public var sizeY :Number = 1;
    public var rotate :Number = 0;
    public var x :Number = 0;
    public var y :Number = 0;
    public var hue :Number = 0;
    public var saturation :Number = 0;
    public var brightness :Number = 0;
    public var alpha :Number = 0;
    public var skewDefined :Boolean = false;    
    public var skewX :Number = 0;
    public var skewY :Number = 0;
    public var act:Number = 0;
    public var sdw:Number =0;
    public var ch :Number = 0;
    public var ca :Number = 1;    
    public var mvx :Number = 0;
    public var mvy :Number = 0;
    public var stp :Number = 10;
    public var spnDefined :Boolean = false;
    public var spnDeg:Number = 0;
    public var spnTime:Number =0;
    public var d :Number = 0;
    public function fill( obj :Object ) :void {
        for( var key :String in obj ){
            switch( key ) {
                case "f":
                case "flip":
                    flipDefined = true;
                    flip = obj[key];
                    break;
                case "s":
                case "size":
                    var size :* = obj[key];
                    if ( typeof(size) == "number" ) { size = [size,size]; }
                    sizeX = size[0];
                    sizeY = size[1];
                    break;
                case "r":
                    rotate     = obj[key];
                    break;                
                case "h":
                    hue        = obj[key];
                    break;
                case "sat":
                    saturation = obj[key];
                    break;
                case "b":
                    brightness = obj[key];
                    break;
                case "a"://透明度
                    alpha      = obj[key];
                    break;
                case "skew"://skew=歪める
                    skewDefined =true;
                    var skew :*      = obj[key];
                    if ( typeof(skew) == "number" ) { skew = [skew,skew]; }
                    skewX = skew[0];
                    skewY = skew[1];
                    break;
                case "act"://消えては出るTween
                    act      = obj[key];
                    break;
                case "sdw"://影を付けるTween
                    sdw       = obj[key];
                    break;
                case "ch"://hue値を変化させるTween
                    ch       = obj[key];
                    break;
                case "ca"://alpha値を変化させるTween
                    ca       = obj[key];
                    break;
                case "mvx"://x方向に動かすTween
                    mvx       = obj[key];
                    break;
                case "mvy"://y方向に動かすTween
                    mvy       = obj[key];
                    break;
                case "stp"://RemoveするTween
                    stp       = obj[key];
                    break;
                case "spn"://回転するTween
                    spnDefined =true;
                    var spn :*      = obj[key];
                    if ( typeof(spn) == "number" ) { spn = [spn,spn]; }
                    spnDeg = spn[0];
                    spnTime = spn[1];
                    break;
                case "d"://timetempo用
                    d= obj[key];
                    break;
                case "rotate":
                case "x":
                case "y":
                case "hue":
                case "saturation":
                case "brightness":
                case "alpha":
                    this[key] = obj[key];
                    break;
                default:
                    throw("引数が正しくありません: "+key);
            }
        }
        
    }
    
}
//}


/*

ルール設定部分
(startshapeやbgなど)
(IStateに依存)

*/

class Rule implements IState {
    
    public function Rule(){
        
    }
    public function eat( token :String, compiler :Compiler ) :Array {
        var ruleName :String = token;
        
        if ( ! compiler.compiled[ ruleName ] ) {
            compiler.compiled[ ruleName ] = [];
        }
        return [ "ruleWeight", ruleName ];
    }
}




class RuleDraw implements IState {
    private var weight :Number = 1;
    private var ruleName :String;
    
    public function RuleDraw( args :Array ) {
        ruleName = args[0];
    }
    public function eat( token :String, compiler :Compiler ) :Array {
        if( token == "}" ){
            return [ "general" ];
        }
        
        return [ "shapeAdjustment", token, ruleName ];
    }
}

class Startshape implements IState {    
    public function Startshape() {
        
    }
    public function eat( token :String, compiler :Compiler ) :Array {
        compiler.compiled[ "startshape" ] = token;
        return [ "general" ];
    }
}


class AbstractArgument implements IState {
    protected var curKey :String = null;
    protected var curValues :Array = [];
    protected var obj :Object = {};
    protected var compiler :Compiler;
    
    public function AbstractArgument(){
        
    }
    public function eat( token :String, _compiler :Compiler ) :Array {
        compiler = _compiler;
        
        switch ( token ) {
            case "}":
                flushKey();
                return onDone( obj );
            case "{":
                return null;
        }
        
        // If it's a keyword name...
        if( token.match(/[a-z_]+/i) ) {
            flushKey();
            curKey = token;
            curValues = [];
        }
            // Otherwise it's a value (and hence a number)
        else {
            curValues.push( parseFloat(token) );
        }
        
        return null;
    }
    
    protected function onDone( obj :Object ) :Array { return null; } // abstract
    
    protected function flushKey() :void {
        if ( curKey ) {
            if ( curValues.length == 1 ) {
                obj[ curKey ] = curValues[0];
            }
            else {
                obj[ curKey ] = curValues;
            }
        }
    }
    
}



class Background extends AbstractArgument {
    
    public function Background() {
    }
    
    override protected function onDone( obj :Object ) :Array {
        var adj :Adjustment = new Adjustment;
        adj.fill( obj );
        compiler.compiled[ "background" ] = adj;
        compiler = null;
        return [ "general" ];
    }
}

class Timerchenge extends AbstractArgument {
    
    public function Timerchenge() {
    }
    
    override protected function onDone( obj :Object ) :Array {
        var adj :Adjustment = new Adjustment;
        adj.fill( obj );
        compiler.compiled[ "timerchenge" ] = adj;
        compiler = null;
        return [ "general" ];
    }
}

class ShapeAdjustment extends AbstractArgument {
    private var name :String;
    private var ruleName :String;
    
    public function ShapeAdjustment( args :Array ) {
        name     = args[0];
        ruleName = args[1];
    }
    
    override protected function onDone( obj :Object ) :Array {
        var shape :Adjustment = new Adjustment();
        shape.name = name;
        shape.fill( obj );
        var last :int = compiler.compiled[ ruleName ].length - 1;
        compiler.compiled[ ruleName ][ last ].draw.push( shape )
        
        compiler = null;
        return [ "ruleDraw", ruleName ];
    }
}


/*
IStateインターフェース
トークンの読み込み用のもの
*/
interface IState {
    function eat( token :String, compiler :Compiler ) :Array;
}


/*
確率変動
*/
class RuleWeight implements IState {
    private var weight :Number = 1;
    private var ruleName :String;
    
    public function RuleWeight( args :Array ) {
        ruleName = args[0];
    }
    public function eat( token :String, compiler :Compiler ) :Array {
        if ( token != "{" ) {
            weight = parseFloat( token );
            return null;
        }
        else {
            compiler.compiled[ ruleName ].push({ weight: weight, draw: [] });
            return [ "ruleDraw", ruleName ];
        }
    }
}

class General implements IState {
    public function General(){
    }
    public function eat( token :String, compiler :Compiler ) :Array {
        return [ token ];
    }
}

import flash.display.DisplayObject;
import flash.display.Shape;
import flash.display.SimpleButton;

class CustomSimpleButton extends SimpleButton {
    private var upColor:uint   = 0xFFCC00;
    private var overColor:uint = 0xCCFF00;
    private var downColor:uint = 0x00CCFF;
    private var size:uint      = 20;
    
    public function CustomSimpleButton(width:Number=640,height:Number=480) {
        downState      = new ButtonDisplayState(downColor, size);
        overState      = new ButtonDisplayState(overColor, size);
        upState        = new ButtonDisplayState(upColor, size);
        hitTestState   = new ButtonDisplayState(upColor, size * 2);
        hitTestState.x = -(size / 4);
        hitTestState.y = hitTestState.x;
        useHandCursor  = true;
    }
}

class ButtonDisplayState extends Shape {
    private var bgColor:uint;
    private var size:uint;
    
    public function ButtonDisplayState(bgColor:uint, size:uint) {
        this.bgColor = bgColor;
        this.size    = size;
        draw();
    }
    
    private function draw():void {
        graphics.beginFill(bgColor);
        graphics.drawRect(0, 0, size, size);
        graphics.endFill();
    }
}