関数ツリーによる合成の見える化
/**
* 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;
}
}
}