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

関数ツリーによる合成の見える化 Vector版

/**
 * Copyright clockmaker ( http://wonderfl.net/user/clockmaker )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/lwhd
 */

// forked from AtuyL's 関数ツリーによる合成の見える化
package{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.utils.*;
    import com.bit101.components.Label;
    
    public class Main extends Sprite{
        
        //AtuyL: あーもうtwitter上じゃうまく伝わらんw
        //paq89: @AtuyL 是非、wonderflで
        //clockmaker: @AtuyL 伝わった気がしなくもないですが、ぜひwonderflへ!
        
        //というわけで、関数ツリーによる合成の見える化について説明するだけのwonderflへようこそ(´・ω・`)
        //クリックで再合成するけど、連打対応とかしてないから連打すると死ぬよ!マジで!
        
        // -----------------------
        // [folk 1] by clockmaker
        // ByteArray で作られてたので Vector に移植
        // 高速化なるか
        // 参考記事: http://aquioux.blog48.fc2.com/blog-entry-467.html
        
        [SWF(width=450,height=450,backGroundColor=0xCCCCCC, frameRate=30)]
        private const stageRect:Rectangle = new Rectangle(0, 0, 450, 450);
        private var label:Label;
        public function Main() {
            initialize();
            stage.addEventListener(MouseEvent.CLICK,initialize);
        }
        
        private function initialize(event:Event = null):void {
            while (numChildren) removeChildAt(0);//画面表示をリセット
            
            var startTime:Number = getTimer();// 計測スタート
            
            var obj1:Vector.<uint> = createRandomCircle();//blend用Vector.<uint> 1つ目
            var obj2:Vector.<uint> = createRandomCircle();//blend用Vector.<uint> 2つ目
            var obj3:Vector.<uint> = createRandomCircle();//blend用Vector.<uint> 3つ目
            var obj4:Vector.<uint> = createRandomCircle();//blend用Vector.<uint> 4つ目
            var obj5:Vector.<uint> = createRandomCircle();//blend用Vector.<uint> 5つ目
            var obj6:Vector.<uint> = createRandomCircle();//blend用Vector.<uint> 6つ目
            var obj7:Vector.<uint> = createRandomCircle();//blend用Vector.<uint> 7つ目
            
            //!!! 以下の関数ツリーで合成を定義 !!!
            //対応済は add,multiply,screen のみ。
            
            var result:Vector.<uint> = multiply(
                multiply(
                    obj1,
                    screen(
                        obj2,
                        obj3
                    )
                ),
                add(
                    multiply(
                        obj4,
                        obj5
                    ),
                    multiply(
                        obj6,
                        obj7
                    )
                )
            );
            
            //説明!
            //合成を関数化して引数と戻り値を一致させ、
            //ツリーで表記できるようにするとブレンドが見やすくなるよ!
            //ってだけ(´・ω・`)つまんなくてごめんね。
            //応用してXMLやJSONとかで合成パターンを定義できるようにしたりすると便利。
                        
            //合成内容を画面に表示
            var resultBmpd:BitmapData = new BitmapData(stageRect.width,stageRect.height);
            var cnt:int = 0;
            for (var i:int = 0; i < resultBmpd.width; i++) {
                for (var j:int = 0; j < resultBmpd.height; j++) {
                    resultBmpd.setPixel32(i, j, result[cnt]);
                    cnt++;
                }
            }
            
            addChild(new Bitmap(resultBmpd));
            var endTime:Number = getTimer();
            
            // 計測終了
            label = new Label(this, 5, 5, "Calc Time : " + (endTime - startTime) / 1000 + "sec");
        }
        
        //randomをmin~maxの範囲へ線形補完するやつ。Mathにあってもいいと思うんだけどなぁ
        private function lerp(val:Number,min:Number,max:Number):Number{
            return min + val * (max - min);
        }
        
        //ランダムな色・半径の円をBitmap化してByteArrayで返す
        private function createRandomCircle():Vector.<uint>{
            var circle:Sprite = new Sprite();
            circle.graphics.beginFill(randomcolor(),1);
            circle.graphics.drawCircle(lerp(Math.random(),0.25,0.75) * 450,lerp(Math.random(),0.25,0.75) * 450,lerp(Math.random(),0.2,0.5) * 450);
            circle.graphics.endFill();
            var bmpd:BitmapData = new BitmapData(stageRect.width,stageRect.height);
            bmpd.draw(circle);
            
            var result:Vector.<uint> = new Vector.<uint>(bmpd.width * bmpd.height, true);
            var cnt:int = 0;
            for (var i:int = 0; i < bmpd.width; i++) {
                for (var j:int = 0; j < bmpd.height; j++) {
                    result[cnt++] = bmpd.getPixel32(i, j);
                }
            }
            return result;
        }
        
        //ランダムカラー生成
        private function randomcolor():uint{
            var rgb:uint = 0;
            rgb += Math.random() * 0xFF << 16;
            rgb += Math.random() * 0xFF << 8;
            rgb += Math.random() * 0xFF << 0;
            return rgb;
        }
        
        
        //加法
        private function _add(src0:uint, src1:uint):uint {
            // 色分解
            var a1:uint = ( src0 >> 24 ) & 0xff
            var r1:uint = ( src0 & 0xff0000 ) >> 16;
            var g1:uint = ( src0 & 0xff00 ) >> 8;
            var b1:uint = ( src0 & 0xff );
            
            var a2:uint = ( src1 >> 24 ) & 0xff
            var r2:uint = ( src1 & 0xff0000 ) >> 16;
            var g2:uint = ( src1 & 0xff00 ) >> 8;
            var b2:uint = ( src1 & 0xff );
            
            // Math.min使ってるあたりは遅い気がする
            var a:uint = Math.min(a1 + a2, 255);
            var r:uint = Math.min(r1 + r2, 255);
            var g:uint = Math.min(g1 + g2, 255);
            var b:uint = Math.min(b1 + b2, 255);
            
            var argb:uint = 0;
            argb += a << 24;
            argb += r << 16;
            argb += g << 8;
            argb += b << 0;
            
            return argb;
        }
        private function add(src0:Vector.<uint>, src1:Vector.<uint>):Vector.<uint> {
            return blend(_add, src0, src1);
        };
        
        //乗算
        private function _multiply(src0:uint, src1:uint):uint {
            // 色分解
            var a1:uint = ( src0 >> 24 ) & 0xff
            var r1:uint = ( src0 & 0xff0000 ) >> 16;
            var g1:uint = ( src0 & 0xff00 ) >> 8;
            var b1:uint = ( src0 & 0xff );
            
            var a2:uint = ( src1 >> 24 ) & 0xff
            var r2:uint = ( src1 & 0xff0000 ) >> 16;
            var g2:uint = ( src1 & 0xff00 ) >> 8;
            var b2:uint = ( src1 & 0xff );
            
            var a:uint = (a1 * a2) / 255;
            var r:uint = (r1 * r2) / 255;
            var g:uint = (g1 * g2) / 255;
            var b:uint = (b1 * b2) / 255;
            
            var argb:uint = 0;
            argb += a << 24;
            argb += r << 16;
            argb += g << 8;
            argb += b << 0;
            
            return argb;
        }
        
        private function multiply(src0:Vector.<uint>, src1:Vector.<uint>):Vector.<uint> {
            return blend(_multiply, src0, src1);
        };
        
        //スクリーン
        private function _screen(src0:uint, src1:uint):uint {
            // 色分解
            var a1:uint = ( src0 >> 24 ) & 0xff
            var r1:uint = ( src0 & 0xff0000 ) >> 16;
            var g1:uint = ( src0 & 0xff00 ) >> 8;
            var b1:uint = ( src0 & 0xff );
            
            var a2:uint = ( src1 >> 24 ) & 0xff
            var r2:uint = ( src1 & 0xff0000 ) >> 16;
            var g2:uint = ( src1 & 0xff00 ) >> 8;
            var b2:uint = ( src1 & 0xff );
            
            var a:uint = (a1 + a2) - (a1 * a2) / 255;
            var r:uint = (r1 + r2) - (r1 * r2) / 255;
            var g:uint = (g1 + g2) - (g1 * g2) / 255;
            var b:uint = (b1 + b2) - (b1 * b2) / 255;
            
            var argb:uint = 0;
            argb += a << 24;
            argb += r << 16;
            argb += g << 8;
            argb += b << 0;
            
            return argb;
        }
        private function screen(src0:Vector.<uint>, src1:Vector.<uint>):Vector.<uint> {
            return blend(_screen, src0, src1);
        };
        
        //uint合成をByteArray単位で行わせる関数
        private function blend(math:Function, src0:Vector.<uint>, src1:Vector.<uint>):Vector.<uint> {
            var bytes:Vector.<uint> = new Vector.<uint>(450 * 450, true);
            var i:uint, length:uint = Math.min(src0.length, src1.length);
            while(i < length) bytes[i] = math(src0[i], src1[i++]);
            return bytes;
        }
    }
}