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

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

Get Adobe Flash player
by AtuyL 07 Sep 2009
/**
 * Copyright AtuyL ( http://wonderfl.net/user/AtuyL )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/3Xcp
 */

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=0xCCCCCC, frameRate=30)]
		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;
		}
	}
}