forked from: 関数ツリーによる合成の見える化

by bradsedito forked from 関数ツリーによる合成の見える化 (diff: 2)
♥0 | Line 103 | Modified 2010-12-01 07:35:49 | MIT License
play

ActionScript3 source code

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

// forked from AtuyL's 関数ツリーによる合成の見える化
package{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Rectangle;
    import flash.utils.ByteArray;
    public class BlendPattern extends Sprite{
        
        //AtuyL: あーもうtwitter上じゃうまく伝わらんw
        //paq89: @AtuyL 是非、wonderflで
        //clockmaker: @AtuyL 伝わった気がしなくもないですが、ぜひwonderflへ!
        
        //というわけで、関数ツリーによる合成の見える化について説明するだけのwonderflへようこそ(´・ω・`)
        //クリックで再合成するけど、連打対応とかしてないから連打すると死ぬよ!マジで!
        
        [SWF(width=450,height=450,backgroundColor=0x000000, frameRate=100)]
        private const stageRect:Rectangle = new Rectangle(0,0,450,450);
        public function BlendPattern() {
            initialize();
            stage.addEventListener(MouseEvent.CLICK,initialize);
        }
        
        private function initialize(event:Event = null):void{
            while(numChildren) removeChildAt(0);//画面表示をリセット
            
            var byte1:ByteArray = createRandomCircle();//blend用ByteArray 1つ目
            var byte2:ByteArray = createRandomCircle();//blend用ByteArray 2つ目
            var byte3:ByteArray = createRandomCircle();//blend用ByteArray 3つ目
            var byte4:ByteArray = createRandomCircle();//blend用ByteArray 4つ目
            var byte5:ByteArray = createRandomCircle();//blend用ByteArray 5つ目
            var byte6:ByteArray = createRandomCircle();//blend用ByteArray 6つ目
            var byte7:ByteArray = createRandomCircle();//blend用ByteArray 7つ目
            
            //!!! 以下の関数ツリーで合成を定義 !!!
            //対応済は add,multiply,screen のみ。
            var result:ByteArray = multiply(
                multiply(
                    byte1,
                    screen(
                        byte2,
                        byte3
                    )
                ),
                add(
                    multiply(
                        byte4,
                        byte5
                    ),
                    multiply(
                        byte6,
                        byte7
                    )
                )
            );
                        //説明!
                        //合成を関数化して引数と戻り値を一致させ、
                        //ツリーで表記できるようにするとブレンドが見やすくなるよ!
                        //ってだけ(´・ω・`)つまんなくてごめんね。
                        //応用してXMLやJSONとかで合成パターンを定義できるようにしたりすると便利。
            
                        
            //合成内容を画面に表示
            var resultBmpd:BitmapData = new BitmapData(stageRect.width,stageRect.height);
            resultBmpd.setPixels(stageRect,result);
            addChild(new Bitmap(resultBmpd));
        }
        
                //randomをmin~maxの範囲へ線形補完するやつ。Mathにあってもいいと思うんだけどなぁ
        private function lerp(val:Number,min:Number,max:Number):Number{
            return min + val * (max - min);
        }
        
        //ランダムな色・半径の円をBitmap化してByteArrayで返す
        private function createRandomCircle():ByteArray{
            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:ByteArray = bmpd.getPixels(stageRect);
            result.position = 0;
            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{
            return Math.min(src0 + src1,255);
        }
        private function add(src0:ByteArray,src1:ByteArray):ByteArray{
            return blend(_add,src0,src1);
        };
        
        //乗算
        private function _multiply(src0:uint,src1:uint):uint{
            return src0 * src1 / 255;
        }
        private function multiply(src0:ByteArray,src1:ByteArray):ByteArray{
            return blend(_multiply,src0,src1);
        };
        
        //スクリーン
        private function _screen(src0:uint,src1:uint):uint{
            return (src0 + src1) - (src0 * src1) / 255;
        }
        private function screen(src0:ByteArray,src1:ByteArray):ByteArray{
            return blend(_screen,src0,src1);
        };
        
        //uint合成をByteArray単位で行わせる関数
        private function blend(math:Function,src0:ByteArray,src1:ByteArray):ByteArray{
            var bytes:ByteArray = new ByteArray();
            
            src0.position = 0;
            src1.position = 0;
            
            var i:uint,length:uint = Math.min(src0.length,src1.length);
            while(i < length){
                bytes[i] = 0xFF; i++;
                bytes[i] = math(src0[i],src1[i++]);
                bytes[i] = math(src0[i],src1[i++]);
                bytes[i] = math(src0[i],src1[i++]);
            }
            
            bytes.position = 0;
            return bytes;
        }
    }
}