forked from: ベクターレンダリング
forked from ベクターレンダリング (diff: 2)
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>