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