forked from: ベクターレンダリング

by jmbyh521 forked from ベクターレンダリング (diff: 2)
♥0 | Line 554 | Modified 2015-09-18 15:03:05 | MIT License
play

ActionScript3 source code

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

<?xml version="1.0" encoding="utf-8"?>
<!-- forked from Hakuhin's ベクターレンダリング --><mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="init();"><mx:Script><![CDATA[public function init():void{
// -------------------------------------------------
//
// ベクターレンダリング
//
// ベクターデータをラスタに1ドットずつレンダリングします。
// アンチエイリアス付きです。
//
// -------------------------------------------------



// -------------------------------------------------
// インポート
// -------------------------------------------------
import mx.core.*;
import mx.containers.*;
import mx.controls.*;
import mx.events.*;



// -------------------------------------------------
// Flash 設定
// -------------------------------------------------

// フレームレート
stage.frameRate = 60;

// 100% 表示
stage.scaleMode = StageScaleMode.NO_SCALE;

// 左上
stage.align = StageAlign.TOP_LEFT;
stage.align = "TL";



// -------------------------------------------------
// Flex 設定
// -------------------------------------------------

// パディングなし
setStyle("paddingTop",0);
setStyle("paddingBottom",0);
setStyle("paddingLeft",0);
setStyle("paddingRight",0);

// 背景透過
setStyle("backgroundAlpha",0);

// 左上
setStyle("horizontalAlign","left");
setStyle("verticalAlign","top");

// キャンバス作成
var canvas:Canvas = new Canvas();
addChild(canvas);



// -------------------------------------------------
// Flash オブジェクト作成
// -------------------------------------------------
var bmp_data:BitmapData;
var bmp:Bitmap = new Bitmap();
stage.addChildAt(bmp,0);
bmp.x = 5;
bmp.y = 5;

// ビュー行列
var view:Matrix = new Matrix(1,0,0,1,0,0);

// ユラユラ行列
var mtx:Object = StrollMatrixCreate();

// 星作成
var star:Object = PrimitiveCreateStar();

// 星の座標をユラユラ化
PrimitiveSetStroll(star,stage);

stage.addEventListener(Event.ENTER_FRAME,EnterFrameFunc);
function EnterFrameFunc(e:Event):void{
    // ラスタクリア
    bmp_data.fillRect(bmp_data.rect,0xFFFDFDFD);

    // フィルカラー
    star.fill_color = fill_color.selectedColor;

    // アンチエイリアスカラー
    star.anti_color = anti_color.selectedColor;

    // ユラユラ行列実行
    StrollMatrixExecute(mtx);
    
    // ビューポイント補正
    var m:Matrix = StrollMatrixGetMatrix(mtx).clone();
    m.concat(view);

    // プリミティブの姿勢変更
    PrimitiveTransform(star,bmp_data,m);

    // プリミティブをビットマップに描画
    PrimitiveDraw(star,bmp_data,m);
    if(check_anti_h.selected)    PrimitiveDrawAntialiasH(star,bmp_data,m);
    if(check_anti_v.selected)    PrimitiveDrawAntialiasV(star,bmp_data,m);
};


// -------------------------------------------------
// Flex コンポーネント作成
// -------------------------------------------------
var text : Text;

// 下側メニュー
var result:Canvas = new Canvas();
result.x = 0;
result.y = 300;
canvas.addChild(result);

// アンチエイリアス
var text_camera_l:Text = new Text();
text_camera_l.text = "アンチエイリアス設定:";
text_camera_l.x = 10;
text_camera_l.y = 5;
text_camera_l.width = 140;
text_camera_l.height = 22;
result.addChild(text_camera_l);


// 水平方向
var check_anti_h:CheckBox = new CheckBox();
check_anti_h.label = "水平";
check_anti_h.x = 130;
check_anti_h.y = 5;
check_anti_h.width = 100;
check_anti_h.height = 22;
check_anti_h.selected = true;
result.addChild(check_anti_h);

// 垂直方向
var check_anti_v:CheckBox = new CheckBox();
check_anti_v.label = "垂直";
check_anti_v.x = 130;
check_anti_v.y = 30;
check_anti_v.width = 100;
check_anti_v.height = 22;
check_anti_v.selected = true;
result.addChild(check_anti_v);


// フィルカラー
var text_fill_color:Text = new Text();
text_fill_color.text = "フィルカラー:";
text_fill_color.x = 250;
text_fill_color.y = 5;
text_fill_color.width = 130;
text_fill_color.height = 22;
text_fill_color.setStyle("textAlign","right");
result.addChild(text_fill_color);

var fill_color : ColorPicker = new ColorPicker();
fill_color.x = 380;
fill_color.y = 5;
fill_color.showTextField=true;
fill_color.selectedColor=0x66FF20;
result.addChild(fill_color);


// アンチエイリアスカラー
var text_anti_color:Text = new Text();
text_anti_color.text = "アンチエイリアスカラー:";
text_anti_color.x = 250;
text_anti_color.y = 30;
text_anti_color.width = 130;
text_anti_color.height = 22;
text_anti_color.setStyle("textAlign","right");
result.addChild(text_anti_color);

var anti_color : ColorPicker = new ColorPicker();
anti_color.x = 380;
anti_color.y = 30;
anti_color.showTextField=true;
anti_color.selectedColor=0x66FF20;
result.addChild(anti_color);

// ラスタスケール
var text_raster_scale:Text = new Text();
text_raster_scale.text = "ラスタスケール:";
text_raster_scale.x = 10;
text_raster_scale.y = 75;
text_raster_scale.width = 100;
text_raster_scale.height = 22;
result.addChild(text_raster_scale);

var raster_slider:HSlider = new HSlider();
raster_slider.x = 100;
raster_slider.y = 70;
raster_slider.width = 350;
raster_slider.height = 22;
raster_slider.labels = ["等倍(1.0)","16倍"];
raster_slider.minimum = 1.0;
raster_slider.maximum = 16.0;
raster_slider.tickInterval = 1.0;
raster_slider.value = 8.0;
result.addChild(raster_slider);
raster_slider.addEventListener(SliderEvent.CHANGE,RasterUpdate);
raster_slider.addEventListener(SliderEvent.THUMB_DRAG,RasterUpdate);




// -------------------------------------------------
// リサイズ時にフィット
// -------------------------------------------------
stage.addEventListener(Event.RESIZE,ResizeFunc);
function ResizeFunc(e:Event):void{
    var w:uint = stage.stageWidth;
    var h:uint = stage.stageHeight;

    // 下側メニュー
    result.y = h - 110;

    // スライダー
    raster_slider.width = w - 100 - 10;
    
    // ラスタ更新
    RasterUpdate(null);
}
ResizeFunc(null);



// -------------------------------------------------
// ラスタ再構築
// -------------------------------------------------
function RasterUpdate(e:Event):void{
    var w:uint = stage.stageWidth;
    var h:uint = stage.stageHeight;

    // ビットマップ作成
    var scale:Number = raster_slider.value;
    bmp_data = new BitmapData(
        Math.ceil((w -  10) / scale),
        Math.ceil((h - 120) / scale),
        true,
        0xFFFFFFFF);
    bmp.bitmapData = bmp_data;
    bmp.scaleX = (w -  10) / bmp_data.width;
    bmp.scaleY = (h - 120) / bmp_data.height;
    
    // ビュー行列更新
    view.identity();
    view.scale(bmp_data.width/2,bmp_data.height/2);
    view.translate(bmp_data.width/2,bmp_data.height/2);

    // 描画更新
    EnterFrameFunc(null);
}






// プリミティブ作成 星型(-1.0~1.0標準)
function PrimitiveCreateStar():Object{
    // プリミティブ
    var pos:Vector.<Point> = new Vector.<Point>();
    var idx:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>();
    
    // 頂点
    var i:uint;
    var num:uint = 7;
    var radius:Array = new Array(0.9,0.4);
    for(i=0;i<num * 2;i++){
        
        var radian:Number = i / (num * 2) * 360 * (Math.PI / 180);
        pos.push(
                 new Point(
                    Math.cos(radian) * radius[i % 2],
                    Math.sin(radian) * radius[i % 2]
                )
        );
    }
    
    // インデックス
    for(i=0;i<num*2;i++){
        idx[i] = Vector.<uint>([i,i+1]);
        idx[i][1] %= num * 2;
    }
    
    return {pos:pos,idx:idx,fill_color:0xFF000000,anti_color:0xFF000000};
}

// プリミティブユラユラ化
function PrimitiveSetStroll(obj:Object,display:DisplayObject):void{
    // プリミティブ
    var pos:Vector.<Point> = obj.pos;
    
    var i:uint;
    var num:uint = pos.length;
    for(i=0;i<num;i++){
        PosSetStroll(pos[i],display);
    }

    // 座標をユラユラ化
    function PosSetStroll(pos:Point,display:DisplayObject):void{
        var base:Point = pos.clone();    // 基点
        var spd:Point = new Point(0,0);    // 速度
        display.addEventListener(Event.ENTER_FRAME,function(e:Event):void{
            
            // 速度を適当に加算
            spd.x += (Math.random() * 2 - 1) * 0.001;
            spd.y += (Math.random() * 2 - 1) * 0.001;
            
            // 減速
            spd.normalize(spd.length * 0.9);
            
            // 座標に加算
            pos.x += spd.x;
            pos.y += spd.y;
            
            // 基点から離れすぎたら速度を補正
            var v:Point = base.subtract(pos);
            if(v.length > 0.5){
                v.normalize(0.0001);
                spd = spd.add(v);
            }
        });
    }
}



// プリミティブ姿勢変更
function PrimitiveTransform(obj:Object,bmp:BitmapData,m:Matrix):void{

    var i:uint;
    var j:uint;
    
    var idx:Vector.<Vector.<uint>> = obj.idx;

    // 頂点を行列で変換
    var p:Vector.<Point> = new Vector.<Point>();
    var num:uint = obj.pos.length;
    for(i=0;i<num;i++){
        p[i] = m.transformPoint(obj.pos[i]);
    }
    
    // 描画矩形範囲抽出
    var t:Number = bmp.height;
    var b:Number = 0;
    var l:Number = bmp.width;
    var r:Number = 0;
    for(i=0;i<num;i++){
        if(t > p[i].y)    t = p[i].y;
        if(b < p[i].y)    b = p[i].y;
        if(l > p[i].x)    l = p[i].x;
        if(r < p[i].x)    r = p[i].x;
    }
    
    // 整数化
    t = int(t);
    l = int(l);
    b = Math.ceil(b);
    r = Math.ceil(r);
    
    // ビットマップ範囲外チェック
    if(t < 0)    t = 0;
    if(l < 0)    l = 0;
    if(b > bmp.height)    b = bmp.height;
    if(r > bmp.width)    r = bmp.width;
    
    obj.vtx = p;
    obj.rect = new Rectangle(l,t,r-l,b-t);
}

// プリミティブ描画
function PrimitiveDraw(obj:Object,bmp:BitmapData,m:Matrix):void{

    var i:uint;
    var j:uint;
    
    var idx:Vector.<Vector.<uint>> = obj.idx;
    var p:Vector.<Point> = obj.vtx;
    
    // 描画矩形範囲抽出
    var t:Number = obj.rect.y;
    var b:Number = obj.rect.y + obj.rect.height;
    var l:Number = obj.rect.x;
    var r:Number = obj.rect.x + obj.rect.width;
    
    var x:int = l;
    var y:int;
    var dx:Number = r - l + 1.0;
    
    // ロック
    bmp.lock();

    // 1行ずつ走査
    for(y=t;y<b;y++){

        // 双方向リスト構築
        var count:Number = 0;
        var list:Object;
        var prev:Object;
        var next:Object;
        var pref:Object = new Object();
        var post:Object = new Object();
        pref.pref = post;
        pref.post = post;
        post.pref = pref;
        post.post = pref;

        var py:Number = y + 0.5;

        // 水平ラインと線との交差チェック
        for(i=0;i<idx.length;i++){
            
            // 交差判定
            var nx:Number = -(p[idx[i][1]].y - p[idx[i][0]].y);
            var ny:Number =  (p[idx[i][1]].x - p[idx[i][0]].x);
            
            if(ny == 0.0)    continue;
            
            // 交点
            var px:Number = x - 0.5;
            var d:Number = -(nx * px + ny * py -(p[idx[i][0]].x * nx + p[idx[i][0]].y * ny)) / (nx * dx);
            px = px + dx * d;
        
            // 線分の交差か調べる
            if(p[idx[i][0]].x < p[idx[i][1]].x){
                if(px < p[idx[i][0]].x || p[idx[i][1]].x < px)    continue;
            }else{
                if(px < p[idx[i][1]].x || p[idx[i][0]].x < px)    continue;
            }

            // 格納位置を検索(ソート)
            list = pref.post;
            while(true){
                if(list == post)    break;
                if(list.pos > px){
                    break;
                }
                
                list = list.post;
            }
    
            // リストに挿入
            prev = list.pref;
            next = list;
            list = new Object();
            
            list.pref = prev;
            list.post = next;
            prev.post = list;
            next.pref = list;
            list.pos = px;
            list.decimal = px - Math.floor(px);
            list.front = (nx > 0) ? true : false;
            count ++;
        }
            
        // 開始地点
        pref.front = false;

        
        // 反転検索
        list = pref;
        while(true){
            next = list.post;
            if(next == post)    break;
            
            // 次のデータと裏表が一致するなら逆転
            if(next.front == list.front){
                next.front = (next.front) ? false:true;
            }
    
            list = next;
        }
        
        list = pref.post;
        var front:Boolean = pref.front;
        var front_next:Boolean = front;
        
        for(x=l;x<r;x++){                
            var decimal:Number = 1.0;            
            while(true){
                if(list == post)    break;
                
                if(list.pos < x + 1.0){
                    
                    // アンチエイリアス成分
                    if(list.front)    decimal *= (1.0 - list.decimal);
                    else            decimal *= (      list.decimal);
                    
                    front = true;
                    front_next = list.front;
                    list = list.post;
                    
                    continue;
                }
                break;
            }

            
            // ビットマップに書き込む
            if(front){        
                var color:uint;
                if(decimal >= 1.0){
                    color = obj.fill_color;
                    bmp.setPixel(x,y,color);
                }
            }
            
            front = front_next;
            
        }
        
    }


    // アンロック
    bmp.unlock();
}



// プリミティブアンチエイリアス水平方向描画
function PrimitiveDrawAntialiasH(obj:Object,bmp:BitmapData,m:Matrix):void{

    var i:uint;
    var j:uint;
    
    var idx:Vector.<Vector.<uint>> = obj.idx;
    var p:Vector.<Point> = obj.vtx;
    
    // 描画矩形範囲抽出
    var t:Number = obj.rect.y;
    var b:Number = obj.rect.y + obj.rect.height;
    var l:Number = obj.rect.x;
    var r:Number = obj.rect.x + obj.rect.width;
    
    var x:int = l;
    var y:int;
    var dx:Number = r - l + 1.0;
    
    // ロック
    bmp.lock();

    // 1行ずつ走査
    for(y=t;y<b;y++){

        // 双方向リスト構築
        var count:Number = 0;
        var list:Object;
        var prev:Object;
        var next:Object;
        var pref:Object = new Object();
        var post:Object = new Object();
        pref.pref = post;
        pref.post = post;
        post.pref = pref;
        post.post = pref;

        var py:Number = y + 0.5;

        // 水平ラインと線との交差チェック
        for(i=0;i<idx.length;i++){
            
            // 交差判定
            var nx:Number = -(p[idx[i][1]].y - p[idx[i][0]].y);
            var ny:Number =  (p[idx[i][1]].x - p[idx[i][0]].x);
            
            if(ny == 0.0)    continue;
            
            // 交点
            var px:Number = x - 0.5;
            var d:Number = -(nx * px + ny * py -(p[idx[i][0]].x * nx + p[idx[i][0]].y * ny)) / (nx * dx);
            px = px + dx * d;
        
            // 線分の交差か調べる
            if(p[idx[i][0]].x < p[idx[i][1]].x){
                if(px < p[idx[i][0]].x || p[idx[i][1]].x < px)    continue;
            }else{
                if(px < p[idx[i][1]].x || p[idx[i][0]].x < px)    continue;
            }

            // 格納位置を検索(ソート)
            list = pref.post;
            while(true){
                if(list == post)    break;
                if(list.pos > px){
                    break;
                }
                
                list = list.post;
            }
    
            // リストに挿入
            prev = list.pref;
            next = list;
            list = new Object();
            
            list.pref = prev;
            list.post = next;
            prev.post = list;
            next.pref = list;
            list.pos = px;
            list.decimal = px - Math.floor(px);
            list.front = (nx > 0) ? true : false;
            count ++;
        }
            
        // 開始地点
        pref.front = false;

        
        // 反転検索
        list = pref;
        while(true){
            next = list.post;
            if(next == post)    break;
            
            // 次のデータと裏表が一致するなら逆転
            if(next.front == list.front){
                next.front = (next.front) ? false:true;
            }
    
            list = next;
        }
        
        list = pref.post;
        var front:Boolean = pref.front;
        var front_next:Boolean = front;
        
        for(x=l;x<r;x++){                
            var decimal:Number = 1.0;            
            while(true){
                if(list == post)    break;
                
                if(list.pos < x + 1.0){
                    
                    // アンチエイリアス成分
                    if(list.front)    decimal *= (1.0 - list.decimal);
                    else            decimal *= (      list.decimal);
                    
                    front = true;
                    front_next = list.front;
                    list = list.post;
                    
                    continue;
                }
                break;
            }

            
            // ビットマップに書き込む
            if(front){        
                var color:uint;
                if(decimal >= 1.0){
                }else{

                    // アルファブレンディング
                    color = bmp.getPixel32(x,y);
                    var a0:uint = (color >>> 24) & 0xFF;
                    var r0:uint = (color >>> 16) & 0xFF;
                    var g0:uint = (color >>>  8) & 0xFF;
                    var b0:uint = (color >>>  0) & 0xFF;
                    color = obj.anti_color;
                    var r1:uint = (color >>> 16) & 0xFF;
                    var g1:uint = (color >>>  8) & 0xFF;
                    var b1:uint = (color >>>  0) & 0xFF;
                    r0 = r0 * (1.0 - decimal) + r1 * decimal;
                    g0 = g0 * (1.0 - decimal) + g1 * decimal;
                    b0 = b0 * (1.0 - decimal) + b1 * decimal;
                    color = (a0 << 24) | (r0 << 16) | (g0 << 8) | (b0 << 0);
                    bmp.setPixel(x,y,color);
                }
                
            }
            
            front = front_next;
            
        }
        
    }


    // アンロック
    bmp.unlock();
}


// プリミティブアンチエイリアス垂直方向描画
function PrimitiveDrawAntialiasV(obj:Object,bmp:BitmapData,m:Matrix):void{

    var i:uint;
    var j:uint;
    
    var idx:Vector.<Vector.<uint>> = obj.idx;
    var p:Vector.<Point> = obj.vtx;
    
    // 描画矩形範囲抽出
    var t:Number = obj.rect.y;
    var b:Number = obj.rect.y + obj.rect.height;
    var l:Number = obj.rect.x;
    var r:Number = obj.rect.x + obj.rect.width;
    
    var x:int;
    var y:int = t;
    var dy:Number = b - t + 1.0;
    
    // ロック
    bmp.lock();

    // 1行ずつ走査
    for(x=l;x<r;x++){

        // 双方向リスト構築
        var count:Number = 0;
        var list:Object;
        var prev:Object;
        var next:Object;
        var pref:Object = new Object();
        var post:Object = new Object();
        pref.pref = post;
        pref.post = post;
        post.pref = pref;
        post.post = pref;

        var px:Number = x + 0.5;

        // 水平ラインと線との交差チェック
        for(i=0;i<idx.length;i++){
            
            // 交差判定
            var nx:Number = -(p[idx[i][1]].y - p[idx[i][0]].y);
            var ny:Number =  (p[idx[i][1]].x - p[idx[i][0]].x);
            
            if(nx == 0.0)    continue;
            
            // 交点
            var py:Number = y - 0.5;
            var d:Number = -(nx * px + ny * py -(p[idx[i][0]].x * nx + p[idx[i][0]].y * ny)) / (ny * dy);
            py = py + dy * d;
        
            // 線分の交差か調べる
            if(p[idx[i][0]].y < p[idx[i][1]].y){
                if(py < p[idx[i][0]].y || p[idx[i][1]].y < py)    continue;
            }else{
                if(py < p[idx[i][1]].y || p[idx[i][0]].y < py)    continue;
            }

            // 格納位置を検索(ソート)
            list = pref.post;
            while(true){
                if(list == post)    break;
                if(list.pos > py){
                    break;
                }
                
                list = list.post;
            }
    
            // リストに挿入
            prev = list.pref;
            next = list;
            list = new Object();
            
            list.pref = prev;
            list.post = next;
            prev.post = list;
            next.pref = list;
            list.pos = py;
            list.decimal = py - Math.floor(py);
            list.front = (ny > 0) ? true : false;
            count ++;
        }
            
        // 開始地点
        pref.front = false;

        
        // 反転検索
        list = pref;
        while(true){
            next = list.post;
            if(next == post)    break;
            
            // 次のデータと裏表が一致するなら逆転
            if(next.front == list.front){
                next.front = (next.front) ? false:true;
            }
    
            list = next;
        }
        
        list = pref.post;
        var front:Boolean = pref.front;
        var front_next:Boolean = front;
        
        for(y=t;y<b;y++){                
            var decimal:Number = 1.0;            
            while(true){
                if(list == post)    break;
                
                if(list.pos < y + 1.0){
                    
                    // アンチエイリアス成分
                    if(list.front)    decimal *= (1.0 - list.decimal);
                    else            decimal *= (      list.decimal);
                    
                    front = true;
                    front_next = list.front;
                    list = list.post;
                    
                    continue;
                }
                break;
            }

            
            // ビットマップに書き込む
            if(front){        
                var color:uint;
                if(decimal >= 1.0){
                }else{

                    // アルファブレンディング
                    color = bmp.getPixel32(x,y);
                    var a0:uint = (color >>> 24) & 0xFF;
                    var r0:uint = (color >>> 16) & 0xFF;
                    var g0:uint = (color >>>  8) & 0xFF;
                    var b0:uint = (color >>>  0) & 0xFF;
                    color = obj.anti_color;
                    var r1:uint = (color >>> 16) & 0xFF;
                    var g1:uint = (color >>>  8) & 0xFF;
                    var b1:uint = (color >>>  0) & 0xFF;
                    r0 = r0 * (1.0 - decimal) + r1 * decimal;
                    g0 = g0 * (1.0 - decimal) + g1 * decimal;
                    b0 = b0 * (1.0 - decimal) + b1 * decimal;
                    color = (a0 << 24) | (r0 << 16) | (g0 << 8) | (b0 << 0);
                    bmp.setPixel(x,y,color);
                }
                
            }
            
            front = front_next;
            
        }
        
    }


    // アンロック
    bmp.unlock();
}



// ユラユラ行列作成
function StrollMatrixCreate():Object{
    return {
        mtx:new Matrix(1,0,0,1,0,0),
        rotate_pos_x:0,
        rotate_pos_y:90,
        scale_pos_x:1.0,
        scale_pos_y:1.0
    }
}


// ユラユラ行列実行
function StrollMatrixExecute(obj:Object):void{
    
    obj.rotate_pos_x -= 0.1;
    obj.rotate_pos_y += 0.3;
    obj.mtx.identity();
    obj.mtx.a = Math.cos(obj.rotate_pos_x * Math.PI / 180) * obj.scale_pos_x;
    obj.mtx.b = Math.sin(obj.rotate_pos_x * Math.PI / 180) * obj.scale_pos_x;
    obj.mtx.c = Math.cos(obj.rotate_pos_y * Math.PI / 180) * obj.scale_pos_y;
    obj.mtx.d = Math.sin(obj.rotate_pos_y * Math.PI / 180) * obj.scale_pos_y;
}
               
// ユラユラ行列から行列を取得
function StrollMatrixGetMatrix(obj:Object):Matrix{
    return obj.mtx;
}




}]]></mx:Script></mx:Application>