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: adobe challenge 1 (Webcam on Cloth)

"Use Flash Player 10 drawing API,
*  specifically drawTriangles.
*  My favorite part of the new capabilities
*  is the ability to specify
*  UVT texture mapping data."
*                     by Justin Everett-Church
*  
* This code is a example of drawTriangle.

Elastic Rectangle を改造して布っぽいものにしてみました。
* http://wonderfl.net/code/e040d9da0f2a2bb74095a325a5a0dd9cdab7c5cb
* "a" でアンカー、"j" でジョイントの表示・非表示切り替えはそのまま
* perlinNoise による模様の代わりに WebCamera の映像を変形させます。
/**
 * Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/xGHS
 */

// forked from checkmate's adobe challenge 1
/**
 * 
 * "Use Flash Player 10 drawing API,
 *  specifically drawTriangles.
 *  My favorite part of the new capabilities
 *  is the ability to specify
 *  UVT texture mapping data."
 *                     by Justin Everett-Church
 *  
 * This code is a example of drawTriangle.
 */

/** 
 * Elastic Rectangle を改造して布っぽいものにしてみました。
 * http://wonderfl.net/code/e040d9da0f2a2bb74095a325a5a0dd9cdab7c5cb
 * "a" でアンカー、"j" でジョイントの表示・非表示切り替えはそのまま
 * perlinNoise による模様の代わりに WebCamera の映像を変形させます。 
 */
package {
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.GraphicsBitmapFill;
    import flash.display.GraphicsEndFill;
    import flash.display.GraphicsPath;
    import flash.display.GraphicsSolidFill;
    import flash.display.GraphicsTrianglePath;
    import flash.display.GraphicsStroke;
    import flash.display.IGraphicsData;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.media.Camera;
    import flash.media.Video;
    
    [SWF(width="600", height="600", backgroundColor="0x000000", frameRate="60")]

    public class drawTriangleTest extends Sprite{
    
        // セグメント数関連
        private const SEGMENT_W:uint = 7;
        private const SEGMENT_H:uint = 5;
        
        // イメージの BitmapData
        private var imageBitmapData:BitmapData;
        
        // セグメント化クラス
        private var segmentation:Segmentation;
        
        // コンテナ
        private var anchorContainer:Sprite;
        private var jointContainer:Sprite;
        private var imageContainer:Sprite;

        // 格納 Vector
        private var anchorVector:Vector.<Anchor>;
        private var jointVector:Vector.<Joint>;
        
        // ジョイント生成用
        private var anchorPairVector:Vector.<int>;
        
        // イメージ表示用 GraphicsData
        private var imageGraphicsData:Vector.<IGraphicsData>;
        private var trianglePath:GraphicsTrianglePath;

        // ジョイント表示用 GraphicsData
        private var jointGraphicsData:Vector.<IGraphicsData>;
        private var jointPath:GraphicsPath;
        
        private var draggingAnchor:Anchor;
        private var anchorVisible:Boolean = false;
        private var jointVisible:Boolean  = false;

        private var camera:Camera;
        private var video:Video;
        private const CAMERA_WIDTH:uint  = 180;
        private const CAMERA_HEIGHT:uint = 280;

        public function drawTriangleTest() {
            Wonderfl.capture_delay(10);
            
            // カメラ
            camera = Camera.getCamera();
            if (camera != null) {
                setup();
            } else {
                throw new Error("カメラがありません。");
            }
        }
        
        private function setup():void {
            // camera のセットアップ
            camera.setMode(CAMERA_WIDTH, CAMERA_HEIGHT, 60);
            
            // video のセットアップ
            video = new Video(CAMERA_WIDTH, CAMERA_HEIGHT);
            video.attachCamera(camera);
            imageBitmapData = new BitmapData(CAMERA_WIDTH, CAMERA_HEIGHT);
            imageBitmapData.draw(video);
            
            next();
        }
        
        private function next():void {
            // セグメント化クラスのインスタンス生成
            segmentation = new Segmentation(SEGMENT_W, SEGMENT_H);
            
            // 各コンテナの生成
            initStage();

            // GraphicsTrianglePath 用 Vector の生成
            var verticies:Vector.<Number> = new Vector.<Number>();		// vertics の生成
            var indicies:Vector.<int>   = segmentation.getIndicies();	// inducides の生成
            var uvDatas:Vector.<Number> = segmentation.getUvDatas();	// uvDatas の生成
            
            // imageGraphicsData の生成
            imageGraphicsData = new Vector.<IGraphicsData>(3);
            imageGraphicsData.push(new GraphicsBitmapFill(imageBitmapData));
            imageGraphicsData.push(trianglePath = new GraphicsTrianglePath(verticies, indicies, uvDatas));
            imageGraphicsData.push(new GraphicsEndFill());
            
            // アンカーの生成(↑で作った uvDatas を使う)
            createAnchor(uvDatas);

            // アンカーのペアリング
            anchorPairVector = segmentation.getVertexPair();
            
            // ジョイントの生成
            createJoint();

            // 固定アンカーの設定
            var anchor:Anchor = anchorVector[0];
            anchor.isFix = true;
            anchor.x = 20;
            anchor = anchorVector[SEGMENT_W];
            anchor.isFix = true;
            anchor.x = stage.stageWidth - 20;
            
            // ジョイント表示用 graphicsData の生成
            // 線の状態
            var stroke:GraphicsStroke = new GraphicsStroke(0);
            stroke.fill = new GraphicsSolidFill(0xFF0000, 0.5);
            // パス
            var commands:Vector.<int> = segmentation.getPathCommands(anchorPairVector);			// コマンド
            var data:Vector.<Number> = segmentation.getPathData(anchorVector, anchorPairVector);// データ
            jointPath = new GraphicsPath(commands, data);
            // GraphicsData
            jointGraphicsData = new Vector.<IGraphicsData>(2);
            jointGraphicsData.push(stroke);
            jointGraphicsData.push(jointPath);
            
            // イベントハンドラ
            anchorContainer.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            anchorContainer.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            addEventListener(Event.ENTER_FRAME, enterFrameHandlerandler);
        }

        
        // 各コンテナの生成
        private function initStage():void {
            imageContainer  = new Sprite();
            jointContainer  = new Sprite();
            anchorContainer = new Sprite();
            addChild(imageContainer);
            addChild(jointContainer);
            addChild(anchorContainer);
        }
        
        // アンカーの生成
        private function createAnchor(uvData:Vector.<Number>):void {
            Anchor.left   = 0;
            Anchor.right  = stage.stageWidth;
            Anchor.top    = 0;
            Anchor.bottom = stage.stageHeight;

            var n:uint = uvData.length / 2;
            anchorVector = new Vector.<Anchor>(n);
            var imageWidth:uint  = imageBitmapData.width;
            var imageHeight:uint = imageBitmapData.height;
            var offsetX:Number = (stage.stageWidth  - imageWidth)  / 2;
            var offsetY:Number = 20;//(stage.stageHeight - imageHeight) / 2;
            for (var i:uint = 0; i < n; i++) {
                var anchor:Anchor = new Anchor(15, 0xFFFFFF);
                anchor.x = imageWidth  * uvData[i * 2]     + offsetX;
                anchor.y = imageHeight * uvData[i * 2 + 1] + offsetY;
                anchorContainer.addChild(anchor);
                anchorVector[i] = anchor;
            }
        }
        
        // ジョイントの生成
        private function createJoint():void {
            var n:uint = anchorPairVector.length / 2;
            jointVector = new Vector.<Joint>(n);
            for (var i:uint = 0; i < n; i++) {
                var a:uint = anchorPairVector[i * 2];
                var b:uint = anchorPairVector[i * 2 + 1];
                var joint:Joint = new Joint(anchorVector[a], anchorVector[b]);
                jointVector[i] = joint;
            }
        }
        
        // キーボードイベント
        private function keyDownHandler(event:KeyboardEvent):void {
            if (event.charCode == 97) {		// "a" キーでアンカー表示
                anchorVisible = !anchorVisible;
                for each (var anchor:Anchor in anchorVector) {
                    anchor.isVisible = anchorVisible;
                }
            }
            if (event.charCode == 106) {	// "j" キーでジョイント表示
                jointVisible = !jointVisible;
                if (!jointVisible) {
                    jointContainer.graphics.clear();
                }
            }
        }
        // マウスイベント
        private function mouseDownHandler(event:MouseEvent):void {
            draggingAnchor = Anchor(event.target);
            draggingAnchor.mouseDown(true);
        }
        private function mouseUpHandler(event:MouseEvent):void {
            if (draggingAnchor != null) {
                draggingAnchor.mouseDown(false);
            }
        }
        // フレームイベント
        private function enterFrameHandlerandler(event:Event):void {
            for each (var joint:Joint in jointVector) {
                joint.update();
            }
            for each (var anchor:Anchor in anchorVector) {
                anchor.update();
            }
            
            // カメラ映像更新
            imageBitmapData.draw(video);
            
            // イメージの表示
            // vertics の更新
            trianglePath.vertices = segmentation.getVerticies(anchorVector);
            // 描画
            imageContainer.graphics.clear();
            imageContainer.graphics.drawGraphicsData(imageGraphicsData);
            
            // ジョイントの表示
            if (jointVisible) {
                // data の更新
                jointPath.data = segmentation.getPathData(anchorVector, anchorPairVector);
                // 描画
                jointContainer.graphics.clear();
                jointContainer.graphics.drawGraphicsData(jointGraphicsData);
            }
        }
    }
}


import flash.display.GraphicsPathCommand;

class Segmentation {
    private var segW:uint;		// セグメント数(幅)
    private var segH:uint;		// セグメント数(高)
    private var numOfVertex:uint;	// 頂点数
    private var pairVector:Vector.<int>;
    
    // コンストラクタ
    public function Segmentation(segW:uint, segH:uint) {
        this.segW = segW;
        this.segH = segH;
        numOfVertex = (segW + 1) * (segH + 1);
    }
    
    // ---- drawTriangle 用 -----
    // verticies の生成(updata のたびに呼ばれる)
    public function getVerticies(anchorVector:Vector.<Anchor>):Vector.<Number> {
        var n:uint = numOfVertex;
        var verticies:Vector.<Number> = new Vector.<Number>(n * 2);
        for (var i:int = 0; i < n; i++) {
            verticies[i * 2]     = anchorVector[i].x;
            verticies[i * 2 + 1] = anchorVector[i].y;
        }
        return verticies;
    }
    // indicies の生成(最初に一度だけ呼ばれる)
    public function getIndicies():Vector.<int> {
        var sW:uint = segW;
        var sH:uint = segH;
        var indicies:Vector.<int> = new Vector.<int>(sW * sH * 6);
        var cnt:uint = 0;
        for (var i:uint = 0; i < sH; i++) {
            for (var j:uint = 0; j < sW; j++) {
                var leftTop:uint  = i * (sW + 1) + j;
                var rightTop:uint = i * (sW + 1) + j + 1;
                var leftBottom:uint  = (i + 1) * (sW + 1) + j;
                var rightBottom:uint = (i + 1) * (sW + 1) + j + 1;
                indicies[cnt]     = leftTop;
                indicies[cnt + 1] = rightTop;
                indicies[cnt + 2] = leftBottom;
                indicies[cnt + 3] = rightTop;
                indicies[cnt + 4] = rightBottom;
                indicies[cnt + 5] = leftBottom;
                cnt += 6;
            }
        }
        return indicies;
    }
    // uvDatas の生成(最初に一度だけ呼ばれる)
    public function getUvDatas():Vector.<Number> {
        var sW:uint = segW;
        var sH:uint = segH;
        var uvDatas:Vector.<Number> = new Vector.<Number>(numOfVertex * 2);
        var cnt:uint = 0;
        for (var i:uint = 0; i < sH + 1; i++) {
            for (var j:uint = 0; j < sW + 1; j++) {
                uvDatas[cnt++] = j / sW;
                uvDatas[cnt++] = i / sH;
            }
        }
        return uvDatas;
    }

    
    // ----- ジョイント用 -----
    // パスの commands の生成(最初に一度だけ呼ばれる)
    public function getPathCommands(pair:Vector.<int>):Vector.<int> {
        var n:uint = pair.length;
        var commands:Vector.<int> = new Vector.<int>(n);
        n /= 2;
        for (var i:uint = 0; i < n; i++) {
            commands[i * 2]     = GraphicsPathCommand.MOVE_TO;
            commands[i * 2 + 1] = GraphicsPathCommand.LINE_TO;
        }
        return commands;
    }
    // パスの data の生成(updata のたびに呼ばれる)
    public function getPathData(anchors:Vector.<Anchor>, pair:Vector.<int>):Vector.<Number> {
        var n:uint = pair.length;
        var data:Vector.<Number> = new Vector.<Number>(n * 2);
        for (var i:uint = 0; i < n; i++) {
            var anchor:Anchor = anchors[pair[i]];
            data[i * 2]     = anchor.x;
            data[i * 2 + 1] = anchor.y;
        }
        return data;
    }

    
    // ----- 頂点のペアリング -----
    public function getVertexPair():Vector.<int> {
        var sW:uint = segW;
        var sH:uint = segH;
        pairVector = new Vector.<int>();

        // 横
        for (var i:uint = 0; i < sH + 1; i++) {
            for (var j:uint = 0; j < sW; j++) {
                var a:uint = i * (sW + 1) + j;
                var b:uint = i * (sW + 1) + j + 1;
                pairVector.push(a, b);
            }
        }
        // 縦
        for (i = 0; i < sH; i++) {
            for (j = 0; j < sW+1; j++) {
                a =  i      * (sW + 1) + j;
                b = (i + 1) * (sW + 1) + j;
                pairVector.push(a, b);
            }
        }
        
        // 斜め(左上から右下)
        for (i = 0; i < sH; i++) {
            for (j = 0; j < sW; j++) {
                a = i * (sW + 1) + j;
                b = (i + 1) * (sW + 1) + j + 1;
                pairVector.push(a, b);
            }
        }
        // 斜め(右上から左下)
        for (i = 0; i < sH; i++) {
            for (j = 0; j < sW; j++) {
                a =  i      * (sW + 1) + j + 1;
                b = (i + 1) * (sW + 1) + j;
                pairVector.push(a, b);
            }
        }
        
        if (sW % 2 == 0) {
            // 横斜め(左上から右下)
            for (i = 0; i < sH; i++) {
                for (j = 0; j < sW - 1; j += 2) {
                    a = i * (sW + 1) + j;
                    b = (i + 1) * (sW + 1) + j + 2;
                    pairVector.push(a, b);
                }
            }
            // 横斜め(右上から左下)
            for (i = 0; i < sH; i++) {
                for (j = 0; j < sW; j+=2) {
                    a =  i      * (sW + 1) + j + 2;
                    b = (i + 1) * (sW + 1) + j;
                    pairVector.push(a, b);
                }
            }
        }
        if (sH % 2 == 0) {
            // 縦斜め(左上から右下)
            for (i = 0; i < sH; i += 2) {
                for (j = 0; j < sW; j++) {
                    a = i * (sW + 1) + j;
                    b = (i + 2) * (sW + 1) + j + 1;
                    pairVector.push(a, b);
                }
            }
            // 縦斜め(右上から左下)
            for (i = 0; i < sH; i+=2) {
                for (j = 0; j < sW; j++) {
                    a =  i      * (sW + 1) + j + 1;
                    b = (i + 2) * (sW + 1) + j;
                    pairVector.push(a, b);
                }
            }
        }
        return pairVector;
    }
}


import flash.display.Sprite;

class Anchor extends Sprite {
    // 物理的数値
    static public var gravity:Number  = 0.47;	// 重力
    static public var friction:Number = 0.92;	// 空気抵抗
    static public var floorFriction:Number = 1;	// 床面抵抗
    static public var bounce:Number = 1;		// 跳ね返り

    // 壁面値
    static public var left:Number;
    static public var right:Number;
    static public var top:Number;
    static public var bottom:Number;
    
    // 固定フラグ
    private var _isFix:Boolean = false;
    public function set isFix(value:Boolean):void {
        this.isVisible = _isFix = value;
        circleDraw(true);
    }
    
    private var _isVisible:Boolean = false;
    public function set isVisible(value:Boolean):void {
        if(!_isFix){
            _isVisible = value;
            circleDraw(_isVisible);
        }
    }
    
    // 計算用変数
    // 速度
    private var vx:Number = 0;
    private var vy:Number = 0;
    // 前フレームの座標値
    private var prevX:Number = 0;
    private var prevY:Number = 0;
    // 剛性反映用の値
    private var sx:Number = 0;
    private var sy:Number = 0;

    // ドラッグ判定
    private var isMouseDown:Boolean = false;
    
    private var radius:Number;
    private var color:uint;
    
    private const LIMIT:Number = 10.0;


    public function Anchor(radius:Number = 10.0, color:uint = 0x0000FF):void {
        this.radius = radius;
        this.color  = color;
        circleDraw(_isVisible);
        buttonMode = true;
    }
    
    // 円描画
    private function circleDraw(flg:Boolean):void {
        var a:Number = flg ? 0.25 : 0.0;
        graphics.clear();
        graphics.beginFill(color, a);
        graphics.drawCircle(0, 0, radius);
        graphics.endFill();
    }

    // このアンカーがマウスドラッグ中か否か
    public function mouseDown(flg:Boolean):void {
        isMouseDown = flg;
        (isMouseDown) ? startDrag() : stopDrag();
    }
    // アクセル
    public function accelalete(valX:Number, valY:Number):void {
        vx = valX;
        vy = valY;
    }
    // ジョイントの剛性値を反映
    public function setStiffness(valX:Number, valY:Number):void {
        sx += valX;
        sy += valY;
    }

    public function update():void {
        if (isMouseDown) {	// ドラッグしている場合
            // 壁処理
            if (x < left) { x = left; }		// 左側面
            if (x > right) { x = right; }	// 右側面
            if (y < top) { y = top; }		// 天井
            if (y > bottom) { y = bottom; }	// 床
            // 計算
            var tmpX:Number = x;
            var tmpY:Number = y;
            vx = x - prevX;
            vy = y - prevY;
            prevX = tmpX;
            prevY = tmpY;
        } else {			// ドラッグしていない場合
            if(!_isFix){
                // 壁処理
                if (x < left) {
                    x = left;
                    vx *= floorFriction;
                    vx *= bounce;
                } else if (x > right) {
                    x = right;
                    vx *= floorFriction;
                    vx *= bounce;
                }
                if (y < top) {
                    y = top;
                    vy *= floorFriction;
                    vy *= bounce;
                } else if (y > bottom) {
                    y = bottom;
                    vy *= floorFriction;
                    vy *= bounce;
                }
                // 計算
                vx = Math.max( -LIMIT, Math.min(LIMIT, vx));
                vy = Math.max( -LIMIT, Math.min(LIMIT, vy));
                vx += sx;
                vy += sy;
                vx *= friction;
                vy *= friction;
                vy += gravity;
                x += vx;
                y += vy;
            }

            // 剛性値の初期化
            sx = 0;
            sy = 0;
        }
    }
}


class Joint {
    // 物理的数値
    static public var stiffness:Number = 0.025;// 剛性値

    // 両端のアンカー
    private var a:Anchor;	// 片端のアンカー
    private var b:Anchor;	// もう片端のアンカー

    // アンカー間の値
    private var defaultDistance:Number = 0;	// アンカー間の距離(既定値)
    private var distanceXY:Number;			// アンカー間の距離(実際の値)
    private var distanceX:Number;	// distanceXY を求めるための X座標値
    private var distanceY:Number;	// distanceXY を求めるための Y座標値

    public function Joint(a:Anchor, b:Anchor):void {
        this.a = a;
        this.b = b;
        getAnchorData();
        defaultDistance = distanceXY;
    }

    // ジョイントの剛性計算をおこない、対象アンカーに反映させる
    public function update():void {
        getAnchorData();
        var s:Number  = stiffness * (distanceXY - defaultDistance);
        var sx:Number = s * distanceX / distanceXY;
        var sy:Number = s * distanceY / distanceXY;
        a.setStiffness(-sx, -sy);
        b.setStiffness( sx,  sy);
    }

    // アンカー間の値を更新
    private function getAnchorData():void {
        var x:Number = a.x - b.x;
        var y:Number = a.y - b.y;
        distanceXY = Math.sqrt(x * x + y * y);
        distanceX = x;
        distanceY = y;
    }
}