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 2D Particle Test Optimized

http://wonderfl.net/c/eTBH
の座標計算をvertexシェーダに任せたバージョン
速度はダンチ
汎用性はゼロ
/**
 * Copyright 9balls ( http://wonderfl.net/user/9balls )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/by41
 */

package {
    import com.adobe.utils.AGALMiniAssembler;
    import com.bit101.components.NumericStepper;
    import com.bit101.components.PushButton;
    import flash.display.Sprite;
    import flash.display.Stage3D;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.display3D.Context3D;
    import flash.display3D.Context3DProgramType;
    import flash.display3D.Context3DRenderMode;
    import flash.display3D.Context3DTriangleFace;
    import flash.display3D.Context3DVertexBufferFormat;
    import flash.display3D.IndexBuffer3D;
    import flash.display3D.Program3D;
    import flash.display3D.VertexBuffer3D;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix3D;
    import flash.text.TextField;
    import flash.utils.ByteArray;
    import frocessing.color.ColorHSV;
    import net.hires.debug.Stats;

    /**
     * ...
     * @author
     */
    public class Main extends Sprite {
        private const NUM_PARTICLES:uint = 16383;
        private const NUM_BUFFERS_MAX:uint = 300;
        private const WIDTH:uint = 466;
        private const HEIGHT:uint = 466;
        private const SIZE:Number = 0.5;
        //
        private var stage3D:Stage3D;
        private var context3D:Context3D;
        //Particle
        private var programP:Program3D;
        private var vBufferVXY:VertexBuffer3D;
        private var vBufferRGB:VertexBuffer3D;
        private var vBufferOffset:VertexBuffer3D;
        private var iBuffer:IndexBuffer3D;
        private var t:int = 0;
        private var initPosConsts:Vector.<Vector.<Number>>;
        private var radConst:Vector.<Number>;
        //
        private var numBuffers:uint = 1;
        private var tfR:TextField;
        private var tfP:TextField;

        public function Main():void {
            Wonderfl.disable_capture();
            stage.frameRate = 60;
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            //set ui
            addChild(new Stats());
            var tfB:TextField = new TextField();
            tfB.textColor = 0xffffff;
            tfB.text = "Buffers : ";
            tfB.x = 100;
            addChild(tfB);
            var stepper:NumericStepper = new NumericStepper(this, 150, 0, onStepper);
            stepper.minimum = 1;
            stepper.maximum = NUM_BUFFERS_MAX;
            stepper.width = 60;
            tfP = new TextField();
            tfP.textColor = 0xffffff;
            tfP.text = "Particle : " + NUM_PARTICLES;
            tfP.x = 250;
            addChild(tfP);
            tfR = new TextField();
            tfR.textColor = 0xffffff;
            tfR.x = 400;
            addChild(tfR);
            new PushButton(this, 350, 0, "Reset", onReset);
            //
            stage3D = stage.stage3Ds[0];
            stage3D.x = 0;
            stage3D.y = 0;
            stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
            stage3D.requestContext3D(Context3DRenderMode.AUTO);
        }

        private function onStepper(e:Event):void {
            numBuffers = (e.currentTarget as NumericStepper).value;
            tfP.text = "Particle : " + NUM_PARTICLES * numBuffers;
        }

        private function onReset(e:MouseEvent):void {
            t = -100;
            for (var i:int = 0; i < NUM_BUFFERS_MAX; i++){
                initPosConsts[i] = Vector.<Number>([Math.random() * WIDTH, Math.random() * HEIGHT, 0, 1]);
            }
        }

        private function onContextCreate(e:Event):void {
            context3D = stage3D.context3D;
            //context3D.enableErrorChecking = true;
            //
            createShaders();
            setConstant();
            setBuffer();
            //
            context3D.configureBackBuffer(WIDTH, HEIGHT, 0, false);
            context3D.setCulling(Context3DTriangleFace.BACK);
            context3D.setVertexBufferAt(0, vBufferVXY, 0, Context3DVertexBufferFormat.FLOAT_2);
            context3D.setVertexBufferAt(1, vBufferRGB, 0, Context3DVertexBufferFormat.FLOAT_3);
            context3D.setVertexBufferAt(2, vBufferOffset, 0, Context3DVertexBufferFormat.FLOAT_2);
            context3D.setProgram(programP);
            //
            stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
        }



        private function onEnterFrame(e:Event):void {
            context3D.clear(0, 0, 0, 1);
            radConst[3] = ++t;
            context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 5, radConst);
            for (var i:int = 0; i < numBuffers; i++){
                context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, initPosConsts[i]);
                context3D.drawTriangles(iBuffer);
            }
            context3D.present();
        }

        private function createShaders():void {
            var agalAssembler:AGALMiniAssembler = new AGALMiniAssembler();
            //Particle
            var code:String = "";
            code += "mov vt0, vc4\n";
            code += "mul vt1.xy, va0.xy, vc5.w\n";
            code += "add vt0.xy, vt0.xy, vt1.xy\n";
            code += "div vt0.xy, vt0.xy, vc5.z\n"; //vt0.xyz=x/D...(4.12 or 3.12)
            code += "frc vt1.xy, vt0.xy\n"; //vt1.xyz=frc(x/D)...(0.12)
            code += "sub vt0.xy, vt0.xy, vt1.xy\n"; //vt0.xyz=int(x/D)...(4 or 3)
            code += "mul vt0.xy, vt0.xy, vc5.x\n"; //vt0.xyz*=pi...(4pi or 3pi)
            code += "cos vt0.xy, vt0.xy\n"; //vt0.xyz=cos(vt0.xyz)...(1 or -1)
            code += "sge vt2.xy, vc5.y, vt0.xy\n"; //vt2.xyz=(0>=vt0.xyz)?1:0...(0 or 1)
            code += "mul vt0.xy, vt1.xy, vt0.xy\n"; //vt0.xyz=frc(x/D)*(1 or -1)...(0.12 or -0.12)
            code += "add vt0.xy, vt0.xy, vt2.xy\n"; //vt0.xyz+=(0 or 1)...(0.12 or 0.78)
            code += "mul vt0.xy, vt0.xy, vc5.z\n"; //vt0.xyz*=D
            //
            code += "add vt0, vt0, va2\n";
            code += "m44 vt0, vt0, vc0\n";
            code += "mov op, vt0\n";
            code += "mov v0, va1\n";
            var vertexShader:ByteArray = agalAssembler.assemble(Context3DProgramType.VERTEX, code);
            var fragmentShader:ByteArray = agalAssembler.assemble(Context3DProgramType.FRAGMENT, "mov oc, v0\n");
            programP = context3D.createProgram();
            programP.upload(vertexShader, fragmentShader);
        }

        private function setConstant():void {
            var mtxP:Matrix3D = new Matrix3D();
            mtxP.appendScale(4 / WIDTH, -4 / HEIGHT, 1);
            mtxP.appendTranslation(-1, 1, 0);
            context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, mtxP, true);
            //
            initPosConsts = new Vector.<Vector.<Number>>(NUM_BUFFERS_MAX);
            initPosConsts[0] = Vector.<Number>([WIDTH / 2, HEIGHT / 2, 0, 1]);
            for (var i:int = 1; i < NUM_BUFFERS_MAX; i++){
                initPosConsts[i] = Vector.<Number>([Math.random() * WIDTH, Math.random() * HEIGHT, 0, 1]);
            }
            radConst = Vector.<Number>([Math.PI, -1, WIDTH, 0]);
        }

        private function setBuffer():void {
            //Particle
            var numVertices:uint = NUM_PARTICLES * 4;
            var numIndices:uint = NUM_PARTICLES * 6;
            //
            vBufferVXY = context3D.createVertexBuffer(numVertices, 2);
            vBufferRGB = context3D.createVertexBuffer(numVertices, 3);
            var cVec:Vector.<Number> = new Vector.<Number>(numVertices * 3);
            var vVec:Vector.<Number> = new Vector.<Number>(numVertices * 2);
            var radius:Number;
            var theta:Number;
            var velX:Number;
            var velY:Number;
            var color:ColorHSV = new ColorHSV();
            var r:Number;
            var g:Number;
            var b:Number;
            var index:uint = 0;
            var index2:uint = 0;
            for (var i:int = 0; i < NUM_PARTICLES; i++){
                radius = Math.random() * 2 + 1;
                theta = 2 * Math.PI * Math.random();
                velX = radius * Math.cos(theta);
                velY = radius * Math.sin(theta);
                vVec[index++] = velX;
                vVec[index++] = velY;
                vVec[index++] = velX;
                vVec[index++] = velY;
                vVec[index++] = velX;
                vVec[index++] = velY;
                vVec[index++] = velX;
                vVec[index++] = velY;
                //
                color.value = 0x1000000 * Math.random();
                r = color.r / 255.0;
                g = color.g / 255.0;
                b = color.b / 255.0;
                cVec[index2++] = r;
                cVec[index2++] = g;
                cVec[index2++] = b;
                cVec[index2++] = r;
                cVec[index2++] = g;
                cVec[index2++] = b;
                cVec[index2++] = r;
                cVec[index2++] = g;
                cVec[index2++] = b;
                cVec[index2++] = r;
                cVec[index2++] = g;
                cVec[index2++] = b;
            }
            vBufferVXY.uploadFromVector(vVec, 0, numVertices);
            vBufferRGB.uploadFromVector(cVec, 0, numVertices);
            //
            vBufferOffset = context3D.createVertexBuffer(numVertices, 2);
            var offsetVec:Vector.<Number> = new Vector.<Number>(numVertices * 2);
            index = 0;
            for (i = 0; i < NUM_PARTICLES; i++){
                offsetVec[index++] = -SIZE;
                offsetVec[index++] = -SIZE;
                offsetVec[index++] = -SIZE;
                offsetVec[index++] = SIZE;
                offsetVec[index++] = SIZE;
                offsetVec[index++] = -SIZE;
                offsetVec[index++] = SIZE;
                offsetVec[index++] = SIZE;
            }
            vBufferOffset.uploadFromVector(offsetVec, 0, numVertices);
            //
            iBuffer = context3D.createIndexBuffer(numIndices);
            var iVec:Vector.<uint> = new Vector.<uint>(numIndices);
            index = 0;
            var p:uint;
            for (i = 0; i < NUM_PARTICLES; i++){
                p = i << 2;
                iVec[index++] = p;
                iVec[index++] = p + 2;
                iVec[index++] = p + 1;
                iVec[index++] = p + 1;
                iVec[index++] = p + 2;
                iVec[index++] = p + 3;
            }
            iBuffer.uploadFromVector(iVec, 0, numIndices);
        }

    }
}