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

Stage3D 3D Webcam Video

Get Adobe Flash player
by devon_o 21 Sep 2012
/**
 * Copyright devon_o ( http://wonderfl.net/user/devon_o )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/ctT7
 */

package  {
    
    /**
     * 3D Webcam video using Stage3D
     * 
     * great inspiration and some source code from this joint: http://blog.bongiovi.tw/?p=265
     * @author Devon O.
     */
    
    import com.adobe.utils.AGALMiniAssembler;
    import com.bit101.components.HUISlider;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.display3D.Context3D;
    import flash.display3D.Context3DBlendFactor;
    import flash.display3D.Context3DProgramType;
    import flash.display3D.Context3DVertexBufferFormat;
    import flash.display3D.IndexBuffer3D;
    import flash.display3D.Program3D;
    import flash.display3D.VertexBuffer3D;
    import flash.events.Event;
    import flash.geom.Matrix;
    import flash.geom.Matrix3D;
    import flash.geom.Vector3D;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.text.AntiAliasType;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;
    import flash.utils.ByteArray;
    
    [SWF(width='465', height='465', backgroundColor='#000000', frameRate='60')]
    public class Main extends Sprite {
        
        private static const INDEX:Vector.<uint> = Vector.<uint>([0, 1, 2, 0, 2, 3]);
        private static const PIXEL_SIZE:int = 4;
        
        private var mVideoData:BitmapData;
        private var mVBuffer:VertexBuffer3D;
        private var mIBuffer:IndexBuffer3D;
        private var mProgram:Program3D;
        private var mNumVerts:int;
        private var mNumRows:int;
        private var mNumCols:int;
        private var mSliderSize:HUISlider;
        private var mSliderDepth:HUISlider;
        private var mContext:Context3D;
        private var mVerticies:Vector.<Number>;
        
        private var mAppWidth:int;
        private var mAppHeight:int;
        
        private var mWebCam:Camera;
        private var mVideo:Video;
        
        public function Main() {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(event:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            initStage();
        }
        
        private function initStage():void
        {
            mAppWidth = stage.stageWidth;
            mAppHeight = stage.stageHeight;
            
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            
            stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onContext);
            stage.stage3Ds[0].requestContext3D();
            
            stage.addEventListener(Event.RESIZE, onStageResize);
        }
        
        private function onStageResize(event:Event):void{
            if (!mContext) return;
                
            mAppWidth = stage.stageWidth;
            mAppHeight = stage.stageHeight;
            mContext.configureBackBuffer(mAppWidth, mAppHeight, 4, true);
        }
        
        protected function onContext(event:Event):void{
            stage.stage3Ds[0].removeEventListener(Event.CONTEXT3D_CREATE, onContext);
            
            mContext = stage.stage3Ds[0].context3D;
            mContext.configureBackBuffer(mAppWidth, mAppHeight, 4, true);
            
            initApp();
        }
        
        private function initApp():void {
            if (!initCam())
            {
                exit();
                return;
            }
            
            initBuffers();
            initShader();
            initUI();
            
            start();
        }
        
        private function initUI():void
        {
            mSliderSize = new HUISlider(this, 10, 5, "Size");
            mSliderSize.value = 40;
            mSliderDepth = new HUISlider(this, 10, 25, "Depth");
            mSliderDepth.maximum = 2.5;
            mSliderDepth.minimum = -2.5;
            mSliderDepth.tick = .1;
        }
        
        private function exit():void
        {
            var tf:TextField = new TextField();
            tf.selectable = false;
            tf.mouseEnabled = false;
            tf.mouseWheelEnabled = false;
            tf.autoSize = TextFieldAutoSize.LEFT;
            tf.defaultTextFormat = new TextFormat("_sans", 12, 0xFFFFFF);
            tf.antiAliasType = AntiAliasType.ADVANCED;
            tf.text = "No Web Cam detected.";
            tf.x = (mAppWidth - tf.width) >> 1;
            tf.y = (mAppHeight - tf.height) >> 1;
            addChild(tf);
        }
        
        private function initCam():Boolean
        {
            var camIndex:int = 0;
            for ( var i:int = 0 ; i < Camera.names.length ; i++ ) {
                if ( Camera.names[ i ] == "USB Video Class Video" ) {
                    camIndex = i;
                    break;
                }
            }
            mWebCam = Camera.getCamera(String(camIndex));
            
            if (!mWebCam) return false;
            
            mVideo = new Video();
            mVideo.attachCamera(mWebCam);
            
            mVideoMat = new Matrix( -1, 0, 0, 1, mVideo.width, 0)
            mVideoData = new BitmapData(mVideo.width, mVideo.height, false, 0x000000);
            mVideoData.draw(mVideo);
            
            return true;
        }
        
        public function start():void{
            addEventListener(Event.ENTER_FRAME, onFrame);
        }
        
        private function initBuffers():void {
            var i:int, j:int, k:int;
            var idx:int = 0;
            
            mNumRows = mVideoData.width / PIXEL_SIZE;
            mNumCols = mVideoData.height / PIXEL_SIZE;

            var pixelCount:int = mNumRows * mNumCols;
            mNumVerts = pixelCount * 4;
            
            var numInds:int = pixelCount * 6;
            
            mVBuffer = mContext.createVertexBuffer(mNumVerts, 7);
            mContext.setVertexBufferAt(0, mVBuffer, 0, Context3DVertexBufferFormat.FLOAT_4);
            mContext.setVertexBufferAt(1, mVBuffer, 4, Context3DVertexBufferFormat.FLOAT_3);
            mVerticies = new Vector.<Number>(mNumVerts * 7, true);
            
            var dat:Vector.<Number>;
            
            dat = Vector.<Number>([-1, -1, 0, 1]);
            mContext.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 10, dat, 1);
            
            dat = Vector.<Number>([1, -1, 0, 1]);
            mContext.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 11, dat, 1);
            
            dat = Vector.<Number>([1, 1, 0, 1]);
            mContext.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 12, dat, 1);
            
            dat = Vector.<Number>([-1, 1, 0, 1]);
            mContext.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 13, dat, 1);
            
            var indicies:Vector.<uint> = new Vector.<uint>(numInds, true);
            idx = 0;
            i = 0;
            while (i < pixelCount) 
            {
                j = 0;
                while (j < INDEX.length) 
                {
                    indicies[idx++] = (INDEX[j] + (i * PIXEL_SIZE));

                    j++;
                }
                i++;
            }
            
            mIBuffer = mContext.createIndexBuffer(numInds);
            mIBuffer.uploadFromVector(indicies, 0, numInds);
        }
        
        private function getColorObj(color:uint):Object
        {
            return { r:color >> 16, g:color >> 8 & 0xFF, b:color & 0xFF };
        }
        
        private function initShader():void {
            var assembler:AGALMiniAssembler = new AGALMiniAssembler();
            
            var agal:String = "";
            agal += "mov vt0, vc[va0.w]\n";
            agal += "mul vt0, vt0, vc9\n";
            agal += "div vt2, va1, vc7\n";
            agal += "mul vt3, vt2, vt2\n";
            agal += "add vt3.x, vt3.x, vt3.y\n";
            agal += "add vt3.x, vt3.x, vt3.z\n";
            agal += "div vt3.x, vt3.x, vc8.y\n";
            agal += "mul vt3.x, vt3.x, vc8.z\n";
            agal += "sub vt3.x, vc8.w, vt3.x\n";
            agal += "div vt3.y, vc9.w, vt3.x\n";
            agal += "mul vt0.xyz, vt0.xyz, vt3.y\n";
            agal += "add vt1, va0, vt0\n";
            agal += "mov vt1.z, vt3.x\n";
            agal += "mov vt1.w, vt0.w\n";
            agal += "m44 op, vt1, vc0\n";
            agal += "mov v0, vt2\n";
            
            var vertShader:ByteArray = assembler.assemble(Context3DProgramType.VERTEX, agal);

            agal = "mov oc, v0";
            var fragShader:ByteArray = assembler.assemble(Context3DProgramType.FRAGMENT, agal);
            
            mContext.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 7, Vector.<Number>([0xFF, 0xFF, 0xFF, 1]));
            mProgram = mContext.createProgram();
            mProgram.upload(vertShader, fragShader);
            mContext.setProgram(mProgram);
        }
        
        
        private var mAng:Number = 1 / Math.tan(45 / 2);
        private var mCenter:Matrix3D    = new Matrix3D(Vector.<Number>([mAng, 0, 0, 0, 0, mAng, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]));
        private var mVideoMat:Matrix;
        private var mCam:Matrix3D        = new Matrix3D();
        private var mRotation:Matrix3D    = new Matrix3D();
        private var mRotationX:Number = 0.0;
        private var mRotationY:Number = 0.0;
        private var mPivot:Vector3D = new Vector3D(0.0, 0.0, 2)
        
        public function onFrame(event:Event = null):void {
            
            mVideoData.draw(mVideo, mVideoMat);
            
            var color:uint;
            var colorObj:Object;
            var i:int = 0, j:int, k:int;
            var idx:int = 0;
            while (i < mNumCols) 
            {
                j = 0;
                while (j < mNumRows) 
                {
                    color = mVideoData.getPixel(j * PIXEL_SIZE, i * PIXEL_SIZE);
                    colorObj = getColorObj(color);
                    
                    k = 0;
                    while (k < 4) {
                        mVerticies[idx++] = j * PIXEL_SIZE;
                        mVerticies[idx++] = mVideoData.height - (i * PIXEL_SIZE);    
                        mVerticies[idx++] = 0;
                        mVerticies[idx++] = 10 + k;
                        mVerticies[idx++] = colorObj.r;
                        mVerticies[idx++] = colorObj.g;
                        mVerticies[idx++] = colorObj.b;
                        
                        k++;
                    }
                    
                    j++;
                    
                }
                
                i++;
                
            }
            mVBuffer.uploadFromVector(mVerticies, 0, mNumVerts);
            
            var w:int = mVideoData.width / PIXEL_SIZE;
            var h:int = mVideoData.height / PIXEL_SIZE;
            
            mCam.identity();
            mCam.appendTranslation( -w * PIXEL_SIZE * 0.5, -h * PIXEL_SIZE * 0.5, 1);
            mCam.appendScale(3.5 / mAppWidth, 3.5 /  mAppHeight, 1);
            
            mRotation.identity();
            var rx:Number = -((stage.mouseX / mAppWidth)  - 0.5) * 180;
            var ry:Number = -((stage.mouseY / mAppHeight) - 0.5) * 180;
            mRotationX += (rx - mRotationX) / 10;
            mRotationY += (ry - mRotationY) / 10;
            mRotation.appendRotation( mRotationY, Vector3D.X_AXIS, mPivot );
            mRotation.appendRotation( mRotationX, Vector3D.Y_AXIS, mPivot );
            
            mCam.append(mRotation);
            mCam.append(mCenter);
            
            mContext.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, mCam, true);
            
            var dat:Vector.<Number>;
            var size:Number = (mSliderSize.value / mSliderSize.maximum) * PIXEL_SIZE;
            dat = Vector.<Number>([size, size, size, 1]);
            mContext.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 9, dat, 1);
            
            dat = Vector.<Number>([1, 8, mSliderDepth.value, 1]);
            mContext.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 8, dat, 1);
            
            mContext.setBlendFactors(Context3DBlendFactor.SOURCE_COLOR, Context3DBlendFactor.ONE);
            
            mContext.clear(0.0, 0.0, 0.0, 1.0);
            mContext.drawTriangles(mIBuffer);
            mContext.present();
        }

    }
}