In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

forked from: メタボールとシェーディング

terumat:http://termat.sakura.ne.jp/

 メタボールとシェーディングの練習

 初期状態    :メタボールを乱数で生成
 クリック1回目 :コンター線を表示
 クリック2回目 :三角メッシュを表示(濃度が高い箇所)
 クリック3回目 :三角メッシュを表示(全体:鳥瞰)
クリック4回目 :フラットシェーディング
クリック5回目 :初期状態に戻る(メタボールを新たに生成)
/**
 * Copyright Indyaner2 ( http://wonderfl.net/user/Indyaner2 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/8uK7
 */

// forked from termat's メタボールとシェーディング
/*
  terumat:http://termat.sakura.ne.jp/

 メタボールとシェーディングの練習

 初期状態    :メタボールを乱数で生成
 クリック1回目 :コンター線を表示
 クリック2回目 :三角メッシュを表示(濃度が高い箇所)
 クリック3回目 :三角メッシュを表示(全体:鳥瞰)
 クリック4回目 :フラットシェーディング
 クリック5回目 :初期状態に戻る(メタボールを新たに生成)
*/
package
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;

    [SWF(width = "481", height = "481", backgroundColor = "0x000000", fps = "30")] 
    public class Practice42 extends Sprite{
        private var bitmap:BitmapData;
        private var balls:Vector.<Metaball>;
        private var colors:Vector.<Array>;
        private var canvas:MovieClip;
        private var numOfBall:int = 16;
        private var tri:Triangles;
        
        public function Practice42() {
            canvas = new MovieClip();
            addChild(canvas);
            bitmap = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);
            canvas.addChild(new Bitmap(bitmap));
            tri = new Triangles();
            addChild(tri);
            balls = new Vector.<Metaball>();
            colors = createColors();
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
            for (var i:int = 0; i < numOfBall; i++) {
                addMetaball(Math.random()*stage.width, Math.random()*stage.height);
            }
            draw();
            tri.init(bitmap);
            tri.draw();
        }
        
        private function createColors():Vector.<Array>{
            var ret:Vector.<Array> = new Vector.<Array>();
            var r:int, g:int, b:int;
            for (var i:int=0;i<256;i++){
                r = g = b = 0;
                if (i >= 0) b = Math.min(255, 4 * i * 2);
                if (i >= 2) g = Math.min(255, 4 * (i / 4));
                if (i >= 4) r = Math.min(255, 4 * (i / 8));
                ret[i]=[r,g,b];
            }
            return ret;
        }
        
        private function draw():void {
            bitmap.fillRect(bitmap.rect, 0x000000);
            for each(var p:Metaball in balls) {
                p.draw(bitmap);    
            }
        }
        
        private function addMetaball(x:int, y:int):void {
            var r:int = 64 + Math.random() * 128;
            var m:Metaball = new Metaball(colors,r);
            m.x = x;    m.y = y;
            m.init();
            balls.push(m);
        }
        
        private function onDown(e:MouseEvent):void {
            var p:int = tri.draw();
            if (p == 0) {
                while (balls.length > 0) balls.pop();
                for (var i:int = 0; i < numOfBall; i++) {
                    addMetaball(Math.random()*stage.width, Math.random()*stage.height);
                }
                draw();
                tri.init(bitmap);
            }
        }
    }
}
import flash.display.BitmapData;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.geom.Point;
class Metaball {
    public var x:int, y:int;
    public var colors:Vector.<Array> ;
    private var pixels:Vector.<Pixel>;
    public var RADIUS:int;
    private var NUM_PIXELS:int;
        
    public function Metaball(c:Vector.<Array>, r:int) {
        RADIUS = r;
        NUM_PIXELS=(2 * RADIUS) * (2 * RADIUS);
        pixels = new Vector.<Pixel>();
        for (var i:int = 0; i < NUM_PIXELS; i++) pixels[i] = new Pixel();
        colors=c;
    }

    public function init():void {
        var n:int;
        var c:int = 0;
        for (var i:int = -RADIUS; i < RADIUS; i++) {
            for (var j:int = -RADIUS; j < RADIUS; j++) {
                var z:Number = RADIUS * RADIUS - i * i - j * j;
                if (z < 0) {
                    n = 0;
                }else{
                    z = Math.sqrt(z);
                    var t:Number = z / RADIUS;
                    n = (255 * (t * t * t * t));
                    n = Math.max(0, Math.min(n, 255));
                }
                pixels[c].dx = i;
                pixels[c].dy = j;
                pixels[c].n = n;
                c++;
            }
        }
    }
    
    public function draw(bitmap:BitmapData):void {
        for (var i:int = 0; i < NUM_PIXELS; i++) {
            var sx:int = x + pixels[i].dx;
            if (sx < 0 || sx > bitmap.width-1)continue;
            var sy:int = y + pixels[i].dy;
            if (sy < 0 || sy > bitmap.height-1)continue;
            var p:Array = getRgb(bitmap.getPixel(sx, sy));
            for (var j:int = 0; j < 3; j++) {
                p[j] += colors[pixels[i].n][j];
                if (p[j] > 255)p[j] = 255;
            }
            bitmap.setPixel(sx, sy, get16(p[0], p[1], p[2]));
        }
    }
    
    private function get16(rr:int,gg:int,bb:int):uint {
        return (rr << 16) + (gg << 8) + bb;
    }
    
    private function getRgb(c:uint):Array {
        return [(c & 0xff0000) >> 16, (c & 0xff00) >> 8, (c & 0xff)];
    }
}

class Pixel {
    public var dx:int;
    public var dy:int;
    public var n:int;
}

class Triangles extends MovieClip{
    private var node:Vector.<Array>;
    private var bitmap:BitmapData;
    private var step:int = 5;
    private var elem:Vector.<Array>;
    public var limit:int = 80;
    private var mode:int = 0;
    private const THETA:Number=-90,PHI:Number=5;
    private const XZERO:Number=-480,YZERO:Number=-520;
    private const SIZE:Number=480;
    private const SINT:Number=Math.sin(THETA/180*Math.PI);
    private const SINP:Number=Math.sin(PHI/180*Math.PI);
    private const COST:Number=Math.cos(THETA/180*Math.PI);
    private const COSP:Number=Math.cos(PHI/180*Math.PI);
    
    public function init(b:BitmapData):void {
        bitmap = b;
        node = new Vector.<Array>();
        for (var i:int = 0; i <= bitmap.width; i = i + step) {
            for (var j:int = 0; j <= bitmap.height; j = j + step) {
                var c:uint = bitmap.getPixel(i, j);
                var gv:int = (c & 0xff0000) >> 16;
                node.push([i, j, gv]);
            }
        }
        createElem();
    }
    
    private function createElem():void {
        var mx:int = bitmap.width / step+1;
        var my:int = bitmap.height / step+1;
        elem = new Vector.<Array>();
        for (var i:int = 0; i < mx; i++) {
            for (var j:int = 0; j < my; j++) {
                if (i < mx - 1 && j < my - 1) {
                    elem.push([i * my + j, (i + 1) * my + j + 1, (i + 1) * my + j]);
                    elem.push([i * my + j, i * my + j + 1, (i + 1) * my + j + 1]);
                }
            }
        }
    }

    public function draw():int {
        if (mode % 5 == 0) {
            graphics.clear();
        }else if (mode % 5 == 1) {
            drawContour()
        }else if (mode % 5 == 2) {
            drawTriangles();
        }else if (mode % 5 == 3) {
            drawTriangles2()
        }else if (mode % 5 == 4) {
            shade()
        }
        return mode++%5;
    }
    
    private function drawTriangles():void {
        graphics.clear();
        var vertex:Vector.<Number> = new Vector.<Number>();
        for (var i:int = 0; i < elem.length; i++) {
            var p:Array = elem[i];
            if ((node[p[0]][2] < limit) || (node[p[1]][2] < limit) || (node[p[2]][2] < limit)) continue;
            for (var j:int = 0; j < p.length; j++) {
                vertex.push(node[p[j]][0]); vertex.push(node[p[j]][1]);
            }
        }
        graphics.lineStyle(1, 0xff6666);
        graphics.drawTriangles(vertex);
    }
    
    private function drawTriangles2():void {
        graphics.clear();
        graphics.lineStyle(1, 0xff6666);
        for (var i:int = 0; i < elem.length; i++) {
            var p:Array = elem[i];
            var p0:Point = trand2D(node[p[0]][0], node[p[0]][1], node[p[0]][2]);
            var p1:Point = trand2D(node[p[1]][0], node[p[1]][1], node[p[1]][2]);
            var p2:Point = trand2D(node[p[2]][0], node[p[2]][1], node[p[2]][2]);
            graphics.moveTo(p0.x, p0.y);
            graphics.lineTo(p1.x, p1.y);
            graphics.lineTo(p2.x, p2.y);
            graphics.lineTo(p0.x, p0.y);
        }
    }
    
    private function trand2D(xx:Number, yy:Number, zz:Number):Point {
        var p:Point = new Point();
        p.x = XZERO + ( -SINT * (xx + SIZE) + COST * (yy + SIZE) + 0.5);
        p.y = YZERO + ( -COST * COSP * (xx + SIZE) - SINT * COSP * (yy + SIZE) + SINP * (zz + SIZE) + 0.5);
        return p;
   }
   
    private function drawContour():void {
        graphics.clear();
        graphics.lineStyle(1, 0xff6666);
        var tp:int = (Math.floor(limit/ 10.0) * 10.0) as int;
        for (var i:int = tp; i < 255; i = i + 20) {
            createContour(i);
        }
    }
    
    private function createContour(val:int):void {
        for (var i:int = 0; i < elem.length; i++) {
            var d:Array = new Array(node[elem[i][0]], node[elem[i][1]], node[elem[i][2]]);
            var p:Array = sort(new Array(0, 1, 2), d);
            if (val >= p[0][2]) {
                if (val > p[2][2]) {
                    continue;
                }else {
                    var a:Array;
                    var b:Array;
                    if(val>=p[1][2]){
                        a = getPoint(p[0], p[2], val);
                        b = getPoint(p[1], p[2], val);
                        if (a == null || b == null) continue;
                        graphics.moveTo(a[0], a[1]);
                        graphics.lineTo(b[0], b[1]);
                    }else{
                        a = getPoint(p[0], p[2], val);
                        b = getPoint(p[0], p[1], val);
                        if (a == null || b == null) continue;
                        graphics.moveTo(a[0], a[1]);
                        graphics.lineTo(b[0], b[1]);
                    }
                }
            }
        }    
    }

    private function sort(it:Array,d:Array):Array{
        for (var i:int = 1; i < it.length; i++) {
            if (d[it[i]][2] < d[it[i - 1]][2]) {
                var t:int=it[i-1];
                it[i-1]=it[i];
                it[i]=t;
                return sort(it,d);
            }
        }
        return new Array(d[it[0]],d[it[1]],d[it[2]]);
    }
    
    private function getPoint(small:Array,large:Array,val:Number):Array{
        if (small[2] == large[2]) return null;
        var rr:Number=(val-small[2])/(large[2]-small[2]);
        var x:Number=small[0];
        var z:Number=small[1];        
        var xx:Number=(large[0]-x)*rr+x;
        var zz:Number=(large[1]-z)*rr+z;
        var l10:Number=Math.sqrt(Math.pow(xx-x, 2.0)+Math.pow(zz-z, 2.0));
        var l11:Number=Math.sqrt(Math.pow(xx-large.x, 2.0)+Math.pow(zz-large.z, 2.0));
        var ret:Array;
        if (l10 == 0.0) {
            ret = small;
        }else if (l10 == 1.0) {
            ret = large;
        }else{
            ret = [xx, zz, val];
        }
        return ret;
    }
    
    private var eye:Array = [0.1, 0.1, 1.0];
    private var light:Array = [0.1, 0.1, 1.0, 1.0, 1.0, 1.0];
    private var amb:Array = [0.6, 0.6, 0.6];
    private var spec:Array = [1.0, 1.0, 1.0];
    private var diff:Array = [0.4, 0.4, 0.4];
    private var pow:Number = 3.0;
    public function shade():void {
        graphics.clear();
        normalize(light);
        normalize(eye);
        for (var i:int = 0; i < elem.length; i++) {
            var v0:Array = [node[elem[i][1]][0]-node[elem[i][0]][0],node[elem[i][1]][1]-node[elem[i][0]][1],node[elem[i][1]][2]-node[elem[i][0]][2]];
            var v1:Array = [node[elem[i][2]][0]-node[elem[i][0]][0],node[elem[i][2]][1]-node[elem[i][0]][1],node[elem[i][2]][2]-node[elem[i][0]][2]];
            var normal:Array = cross(v1, v0);
            normalize(normal);
            var dotP:Number = dot(normal, light);
            var r0:Number = 2.0 * dotP * normal[0] - light[3];
            var r1:Number = 2.0 * dotP * normal[1] - light[4];
            var r2:Number = 2.0 * dotP * normal[2] - light[5];
            var re:Array = [r0, r1, r2];
            var dotE:Number = dot(re, eye);
            var r:int = Math.min(255,255.0 * (amb[0] + diff[0] * (Math.max(0, dot(normal, light))) + spec[0] * Math.max(0, Math.pow(dotE, pow))));
            var g:int = Math.min(255,255.0 * (amb[1] + diff[1] * (Math.max(0, dot(normal, light))) + spec[1] * Math.max(0, Math.pow(dotE, pow))));
            var b:int = Math.min(255,255.0 * (amb[2] + diff[2] * (Math.max(0, dot(normal, light))) + spec[2] * Math.max(0, Math.pow(dotE, pow))));
            var col:uint = (r << 16) + (g << 8) + b;
            var vertex:Vector.<Number> = new Vector.<Number>();
            vertex.push(node[elem[i][0]][0]); vertex.push(node[elem[i][0]][1]);
            vertex.push(node[elem[i][1]][0]); vertex.push(node[elem[i][1]][1]);
            vertex.push(node[elem[i][2]][0]); vertex.push(node[elem[i][2]][1]);
            graphics.beginFill(col);
            graphics.drawTriangles(vertex);
            graphics.endFill();
        }
    }
    
    private function normalize(vec:Array):void {
        var t:Number = vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2];
        if (t != 0 && t != 1) t = (1.0 / Math.sqrt(t));
        vec[0] = vec[0] * t;
        vec[1] = vec[1] * t;
        vec[2] = vec[2] * t;
    }
    
    private function dot(a:Array,b:Array):Number{
        return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
    }
    
    private function cross(a:Array,b:Array):Array{
        var x:Number = a[1] * b[2] - a[2] * b[1];
        var y:Number = a[2] * b[0] - a[0] * b[2];
        var z:Number = a[0] * b[1] - a[1] * b[0];
        return [x, y, z];
    }
}