2Dメタボール(マーチングキューブ法)
2Dメタボール
//
// 2Dメタボール
//
package {
import flash.display.Sprite;
import flash.events.*;
[SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="60")]
public class FlashTest extends Sprite {
public function FlashTest() {
Main = this;
initialize();
stage.addEventListener(Event.ENTER_FRAME,update);
}
}
}
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.geom.*;
var SCREEN_W:Number = 465, SCREEN_H:Number = 465;
var Main:Sprite;
var Text:TextField
var BmpData: BitmapData;
var Bmp: Bitmap;
var WIDTH:int = 128;
var Scale:Number = 7.5 * 0.5;
var BITMAP_W:int = WIDTH;
var BITMAP_H:int = WIDTH;
var Threshold:int = 0.0;
var PointAry:Vector.<EdgePoint> = new Vector.<EdgePoint>;
var BallAry:Vector.<Ball> = new Vector.<Ball>;
function initialize():void{
Text = new TextField();
Text.text = "test";
Text.autoSize = "left";
Main.addChild(Text);
BmpData = new BitmapData(BITMAP_W, BITMAP_H, false, 0x000000);
Bmp = new Bitmap(BmpData);
Bmp.scaleX = 0.5;
Bmp.scaleY = 0.5;
Main.addChild(Bmp);
for( var y:int=0; y<WIDTH; y++ ){
for( var x:int=0; x<WIDTH; x++ ){
var idx:int = x + y * WIDTH;
PointAry[idx] = new EdgePoint(x, y);
PointAry[idx].Value = -1.25 + 1/4.0 * Math.sqrt( (x-3.5) * (x-3.5) + (y-4.5) * (y-4.5) );
}
}
for( var i:int=0; i<35; i++){
BallAry.push( new Ball( 0, 0, Math.random()*0.75, Math.random()*0.75, 3+Math.random()*25 ) );
}
}
function update(e :Event):void{
graphicClear();
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
g.beginFill( 0x0000, 1 );
g.drawRect( 0, 0, WIDTH, WIDTH );
g.endFill();
BmpData.draw(shape);
for each ( var ball:Ball in BallAry ) ball.update();
for each ( var pnt:EdgePoint in PointAry ) {
var col:int = BmpData.getPixel( pnt.x, pnt.y );
pnt.Value = (col&0xff) / 127.0 - 0.5;
//pnt.draw();
}
for( var y:int=0; y<WIDTH-1; y++ ){
for( var x:int=0; x<WIDTH-1; x++ ){
var idx0:int = x + y * WIDTH;
var idx1:int = (x+1) + y * WIDTH;
var idx2:int = x + (y+1) * WIDTH;
var idx3:int = (x+1) + (y+1) * WIDTH;
test( PointAry[idx0], PointAry[idx1], PointAry[idx2], PointAry[idx3] );
}
}
}
function test( p0:EdgePoint, p1:EdgePoint, p2:EdgePoint, p3:EdgePoint ):void{
var type:int = 0;
if( p0.Value > Threshold ) type += 1;
if( p1.Value > Threshold ) type += 2;
if( p2.Value > Threshold ) type += 4;
if( p3.Value > Threshold ) type += 8;
switch( type ){
case 0: break;
case 1: drawType0( p0, p1, p2 ); break;
case 2: drawType0( p1, p3, p0 ); break;
case 3: drawType1( p0, p1, p2, p3 ); break;
case 4: drawType0( p2, p3, p0 ); break;
case 5: drawType1( p0, p2, p1, p3 ); break;
case 6: drawType0( p0, p1, p2 ); drawType0( p1, p3, p0 ); break;
case 7: drawType2( p3, p1, p2 ); break;
case 8: drawType0( p3, p1, p2 ); break;
case 9: drawType0( p0, p1, p2 ); drawType0( p3, p1, p2 ); break;
case 10: drawType1( p1, p3, p0, p2 ); break;
case 11: drawType2( p2, p0, p3 ); break;
case 12: drawType1( p2, p3, p0, p1 ); break;
case 13: drawType2( p1, p0, p3 ); break;
case 14: drawType2( p0, p1, p2 ); break;
case 15: break;
}
}
class Ball{
public var X:Number, Y:Number;
public var Sx:Number, Sy:Number;
public var R:Number;
public function Ball( x:Number, y:Number, sx:Number, sy:Number, r:Number ){
X = x;
Y = y;
Sx = sx;
Sy = sy;
R = r;
}
public function update():void{
X += Sx;
Y += Sy;
if( X < 0 ) Sx *= -1;
if( Y < 0 ) Sy *= -1;
if( X > WIDTH ) Sx *= -1;
if( Y > WIDTH ) Sy *= -1;
drawGradientCircleBmp( BmpData, X, Y, R, 0x606060, 0x000000 );
}
}
class EdgePoint{
public var x:Number, y:Number;
public var Value:Number;
public function EdgePoint( rx:Number, ry:Number ){
x = rx;
y = ry;
}
public function draw():void{
drawPoint( x, y, 0x000000 );
}
}
function drawType0( p0:EdgePoint, p1:EdgePoint, p2:EdgePoint ):void{
var pv0:Point = new Point, pv1:Point = new Point;
var vec0:Point = new Point, vec1:Point = new Point;
var ratio0:Number = p0.Value / (p0.Value - p1.Value);
var ratio1:Number = p0.Value / (p0.Value - p2.Value);
vec0.x = p1.x - p0.x;
vec0.y = p1.y - p0.y;
vec1.x = p2.x - p0.x;
vec1.y = p2.y - p0.y;
pv0.x = p0.x + vec0.x * ratio0;
pv0.y = p0.y + vec0.y * ratio0;
pv1.x = p0.x + vec1.x * ratio1;
pv1.y = p0.y + vec1.y * ratio1;
drawLine( pv0.x, pv0.y, pv1.x, pv1.y, 1, 0xff0000 );
}
function drawType1( p0:EdgePoint, p1:EdgePoint, p2:EdgePoint, p3:EdgePoint ):void{
var pv0:Point = new Point, pv1:Point = new Point;
var vec0:Point = new Point, vec1:Point = new Point;
var ratio0:Number = p0.Value / (p0.Value - p2.Value);
var ratio1:Number = p1.Value / (p1.Value - p3.Value);
vec0.x = p2.x - p0.x;
vec0.y = p2.y - p0.y;
vec1.x = p3.x - p1.x;
vec1.y = p3.y - p1.y;
pv0.x = p0.x + vec0.x * ratio0;
pv0.y = p0.y + vec0.y * ratio0;
pv1.x = p1.x + vec1.x * ratio1;
pv1.y = p1.y + vec1.y * ratio1;
drawLine( pv0.x, pv0.y, pv1.x, pv1.y, 1, 0xff0000 );
}
function drawType2( p3:EdgePoint, p1:EdgePoint, p2:EdgePoint ):void{
var pv0:Point = new Point, pv1:Point = new Point;
var vec0:Point = new Point, vec1:Point = new Point;
var ratio0:Number = p3.Value / (p3.Value - p1.Value);
var ratio1:Number = p3.Value / (p3.Value - p2.Value);
vec0.x = p1.x - p3.x;
vec0.y = p1.y - p3.y;
vec1.x = p2.x - p3.x;
vec1.y = p2.y - p3.y;
pv0.x = p3.x + vec0.x * ratio0;
pv0.y = p3.y + vec0.y * ratio0;
pv1.x = p3.x + vec1.x * ratio1;
pv1.y = p3.y + vec1.y * ratio1;
drawLine( pv0.x, pv0.y, pv1.x, pv1.y, 1, 0xff0000 );
}
function graphicClear():void{
Main.graphics.clear();
}
function drawLine( sx:Number, sy:Number, ex:Number, ey:Number, size:Number, col:int ):void{
Main.graphics.lineStyle(size,col);
Main.graphics.moveTo( Scale*sx, Scale*sy );
Main.graphics.lineTo( Scale*ex, Scale*ey);
}
function drawCircle( x:Number, y:Number, size:Number, col:int ):void{
Main.graphics.lineStyle(1.0,0x000000);
Main.graphics.beginFill( col, 1 );
Main.graphics.drawCircle( Scale*x, Scale*y, Scale*size );
Main.graphics.endFill();
}
function drawPoint( x:Number, y:Number, col:int ):void{
Main.graphics.lineStyle(1.0,0x000000);
Main.graphics.beginFill( col, 1 );
Main.graphics.drawRect( Scale*x, Scale*y, 1, 1 );
Main.graphics.endFill();
}
function drawGradientCircleBmp( bmpData:BitmapData, x0:Number, y0:Number, r:Number, col0:int, col1:int ):void{
var matrix:Matrix = new Matrix();
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
var mtx:Matrix;
matrix.createGradientBox( 1, 1, 0, -0.5, -0.5 );
var vx0:Number = r;
var vy0:Number = 0;
var vx1:Number = 0;
var vy1:Number = r;
var cx:Number = x0;
var cy:Number = y0;
matrix.concat( new Matrix( vx0*2, vy0*2, vx1*2, vy1*2, cx, cy ) );
g.clear();
g.beginGradientFill(GradientType.RADIAL, [col0,col1], [1,1], [0,255], matrix);
g.drawCircle(cx, cy, r );
g.endFill();
bmpData.draw(shape, null, null, BlendMode.ADD);
}