forked from: 10k boxes

by signedvoid forked from 10k boxes (diff: 2)
♥0 | Line 432 | Modified 2013-04-25 17:15:22 | MIT License
play

ActionScript3 source code

/**
 * Copyright signedvoid ( http://wonderfl.net/user/signedvoid )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/iu0j
 */

// forked from shen_0_'s 10k boxes
package {
    import flash.display.Bitmap;

    import flash.display.BitmapData;

    import flash.display.Shape;

    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.Context3DTextureFormat;

    import flash.display3D.Context3DVertexBufferFormat;

    import flash.display3D.IndexBuffer3D;

    import flash.display3D.VertexBuffer3D;

    import flash.display3D.textures.Texture;

    import flash.events.Event;

    import flash.events.MouseEvent;

    import flash.geom.Matrix3D;

    import net.hires.debug.Stats;



    [SWF(frameRate=60, width="700", height="550")]

    public class Boxes2 extends Sprite {

        public static const NUM_MAX:int=1024;

        public static const NUM_PARTICLE:int=10000;





        public static const W:int=680;

        public static const H:int=530;

        public static const SIZE:int=5;

        public static const ROWS:int=H / SIZE;

        public static const COLS:int=W / SIZE;



        public static const SPEED:Number=Number((SIZE / .8)); //moving speed

        public static const SPEED_No_SQRT:Number=SPEED * SPEED * 0.5;



        ///////////////////stage3D

        private var obsList:Array=[];

        private var boxList:Array=[];

        private var nets:Array=[];



        private var program:ShaderProgram;

        private var context:Context3D;

        private var rotBmp:BitmapData;

        private var texture:Texture;



        private var iBuffer:IndexBuffer3D;

        private var vBuffer:VertexBuffer3D;

        private var uvBuffer:VertexBuffer3D;

        private var uvb:Vector.<Number>=new Vector.<Number>();

        private var ib:Vector.<uint>=new Vector.<uint>();

        private var vb:Vector.<Number>=new Vector.<Number>();

        private const vunit:int=4;

        private const uvunit:int=2;





        private var ortho:Matrix3D=new Matrix3D();

        private var r_rot_steps:Vector.<Number>=Vector.<Number>([0, 0, 0, 0]);





        //each time it draw 1024 boxes

        private var allWnums:int=0;

        private var allWIndex:int=0;





        //create boxes

        private var nums:int=NUM_PARTICLE;



        public function Boxes2() {

            stage.align=StageAlign.TOP_LEFT;

            stage.scaleMode=StageScaleMode.NO_SCALE;



            rotBmp=new BitmapData(16, 4, true, 0);

            const ox:Number=0.5;

            var sp:Shape=new Shape();

            sp.graphics.lineStyle(0, 0x555555, 0.5); //not smooth fix

            sp.graphics.beginFill(0x333333);

            sp.graphics.drawRect(ox, ox, 3, 3);

            sp.graphics.endFill();

            sp.graphics.lineStyle(0, 0x555555, 0.5); //smooth fix

            sp.graphics.beginFill(0xaaaaaa);

            sp.graphics.drawRect(ox + 4, ox, 3, 3);

            sp.graphics.endFill();

            sp.graphics.lineStyle(0, 0x9B8553, 0.5); //not smooth

            sp.graphics.beginFill(0x9B8553);

            sp.graphics.drawRect(ox + 8, ox, 3, 3);

            sp.graphics.endFill();

            sp.graphics.lineStyle(0, 0x50857A, 0.5); //smooth

            sp.graphics.beginFill(0x50857A);

            sp.graphics.drawRect(ox + 12, ox, 3, 3);

            sp.graphics.endFill();

            rotBmp.draw(sp);



            var rotBM:Bitmap=new Bitmap(rotBmp);

            rotBM.x=100;



            var i:int, j:int;

            for (j=0; j < ROWS; j++) {

                nets[j]=[];

                for (i=0; i < COLS; i++) {

                    nets[j][i]=null;

                }

            }





            createAllObstacle()



            stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, createContext3D);

            stage.stage3Ds[0].requestContext3D(Context3DRenderMode.AUTO);





            addChild(new Stats());

            addChild(rotBM);

        }



        //init context3D obj

        private function createContext3D(e:Event):void {

            context=(e.target as Stage3D).context3D;

            context.removeEventListener(Event.CONTEXT3D_CREATE, createContext3D);

            

            context.configureBackBuffer(W, H, 0, false);

            context.setRenderToBackBuffer();

            context.enableErrorChecking=true;

            

            //program

            program=new ShaderProgram(context, new VertexShader(), new FragmentShader());

            ortho=MatrixUtil.ortho(W, H, false);

            

            //index, vertex, uv

            const part:Number=0.25;

            for (var i:int=0; i < NUM_MAX; i++) {

                vb.push(0, 0, 0, 0);

                vb.push(0, 0, 0, 0);

                vb.push(0, 0, 0, 0);

                vb.push(0, 0, 0, 0);

                

                uvb.push(0, 0);

                uvb.push(part, 0);

                uvb.push(part, 1);

                uvb.push(0, 1);

                

                

                ib.push(i * 4 + 0, i * 4 + 1, i * 4 + 2, i * 4 + 0, i * 4 + 2, i * 4 + 3);

            }

            

            vb.fixed=true;

            uvb.fixed=true;

            ib.fixed=true;

            

            vBuffer=context.createVertexBuffer(vb.length / vunit, vunit);

            vBuffer.uploadFromVector(vb, 0, vb.length / vunit);

            

            uvBuffer=context.createVertexBuffer(uvb.length / uvunit, uvunit);

            uvBuffer.uploadFromVector(uvb, 0, uvb.length / uvunit);

            

            iBuffer=context.createIndexBuffer(ib.length);

            iBuffer.uploadFromVector(ib, 0, ib.length);

            

            r_rot_steps[0]=part;

            

            //texture

            texture=context.createTexture(16, 4, Context3DTextureFormat.BGRA, false);

            texture.uploadFromBitmapData(rotBmp);

            context.setTextureAt(0, texture);

            

            //setting

            context.setProgram(program.program);

            context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, ortho, true);

            context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, r_rot_steps);

            

            context.setVertexBufferAt(2, uvBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);

            //enter frame

            stage.addEventListener(Event.ENTER_FRAME, loop);

            stage.addEventListener(Event.RESIZE, resize);

            stage.addEventListener(MouseEvent.CLICK, change);

        }



        //event function

        private function loop(e:Event):void {

            context.clear(0, 0, 0);

            //var tt:Number=getTimer();

            boxsLoop();

            

            writeBegin();

            writeBuffer(obsList);

            writeBuffer(boxList);

            writeEnd();

            

            context.present();

            

        }

        

        private function resize(e:Event):void {

            context.configureBackBuffer(stage.stageWidth, stage.stageHeight, 0, false);

        }

        

        private function change(e:Event):void {

            nums=NUM_PARTICLE;

            boxList.length=0;

            obsList.length=0;

            var i:int, j:int;

            for (j=0; j < ROWS; j++) {

                for (i=0; i < COLS; i++) {

                    nets[j][i]=null;

                }

            }

            createAllObstacle()

        }

        

        

        private function boxsLoop():void {

            var box:Box, tx:int, ty:int, bool:Boolean;

            var len:int=boxList.length;

            for each (box in boxList) {

                if (box.getSleep()) {

                    continue;

                }



                if (!box.needMoving) {

                    tx=box.cx;

                    ty=box.cy;

                    bool=true;

                    if (ty < ROWS - 1) {

                        var box2:Box=getBox(tx, ty + 1);

                        if (!box2) {

                            box.setGoto(tx, ty + 1);

                            bool=false;

                        } else if (!box2.getFixed() || (box2.getSmooth())) {

                            if (tx > 0 && isEmpty(tx - 1, ty) && isEmpty(tx - 1, ty + 1)) {

                                box.setGoto(tx - 1, ty);

                                bool=false;

                            } else if (tx < COLS - 1 && isEmpty(tx + 1, ty) && isEmpty(tx + 1, ty + 1)) {

                                box.setGoto(tx + 1, ty);

                                bool=false;

                            }

                        }

                    }



                    if (bool) {

                        box.setSleep(true);

                    }

                }



                if (box.needMoving) {

                    box.move();

                }



            }





            if (nums > 0) {

                for (var i:int=5; i > 0; i--) {

                    var randX:int=Math.random() * COLS

                    if (!getBox(randX, Math.random() * 5)) {

                        createBox(randX, 0);

                    }

                }



            }



        }



        //obstacle

        private function createAllObstacle():void {

            var a:int=COLS - 20;

            var b:int=ROWS - 20;

            for (var i:int=0; i < 20; i++) {

                createObstacle(a * Math.random(), 10 + b * Math.random(), 20 * Math.random());

            }

        }

        

        private function createObstacle(x:int, y:int, len:int):void {

            for (var i:int=0; i < len; i++) {

                createBox(x + i, y, true);

            }

        }



        private function createBox(x:int, y:int, isFixed:Boolean=false):Box {

            if (!isEmpty(x, y)) {

                return null;

            }

            var box:Box=new Box(this, x, y, isFixed, Math.random() > 0.5);

            if (isFixed) {

                obsList.push(box);

            } else {

                boxList.push(box);

                nums--;

            }



            setCheckBox(x, y, box);

            return box;

        }





        





        //check this position box;

        private function getBox(x:int, y:int):Box {

            if (x > -1 && y > -1 && x < COLS && y < ROWS) {

                return nets[y][x];

            }

            return null;

        }



        private function isEmpty(x:int, y:int):Boolean {

            if (x > -1 && y > -1 && x < COLS && y < ROWS) {

                return !(nets[y][x]);

            }

            return false;

        }



        public function setCheckBox(x:int, y:int, box:Box):void {

            nets[y][x]=box;

        }

        

        public function wakeOther(x:int, y:int):void {

            //wake.wake.wake

            //wake.move.wake

            var box:Box=getBox(x - 1, y); //x-1,y

            if (box)

                box.setSleep(false);

            box=getBox(x + 1, y); //x+1,y

            if (box)

                box.setSleep(false);

            box=getBox(x, y - 1); //x,y-1

            if (box)

                box.setSleep(false);

            box=getBox(x - 1, y - 1); //x-1,y-1

            if (box)

                box.setSleep(false);

            box=getBox(x + 1, y - 1); //x+1,y-1

            if (box)

                box.setSleep(false);

        }

        

        private function writeBegin():void {

            allWnums=0;

            allWIndex=0;

        }



        private function writeBuffer(vs:Array):void {

            const len:int=vs.length;



            var oldX:Number, oldY:Number;

            var box:Box;

            var i:int;

            var id:int=0;

            while (i < len) {

                for (i=i; i < len; i++) {

                    box=vs[i];

                    oldX=box.x;

                    oldY=box.y;

                    id=box.getSkin();



                    vb[allWIndex++]=oldX;

                    vb[allWIndex++]=oldY;

                    vb[allWIndex++]=id;

                    allWIndex++;



                    vb[allWIndex++]=oldX + SIZE;

                    vb[allWIndex++]=oldY;

                    vb[allWIndex++]=id;

                    allWIndex++;



                    vb[allWIndex++]=oldX + SIZE;

                    vb[allWIndex++]=oldY + SIZE;

                    vb[allWIndex++]=id;

                    allWIndex++;



                    vb[allWIndex++]=oldX;

                    vb[allWIndex++]=oldY + SIZE;

                    vb[allWIndex++]=id;

                    allWIndex++;





                    allWnums++;

                    if (allWnums == NUM_MAX) {

                        allWIndex=0;

                        allWnums=0;

                        i++;

                        vBuffer.uploadFromVector(vb, 0, NUM_MAX * vunit);



                        context.setVertexBufferAt(0, vBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);

                        context.setVertexBufferAt(1, vBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);



                        context.drawTriangles(iBuffer, 0, 2 * NUM_MAX);

                        break;

                    }

                }

            }



        }



        private function writeEnd():void {

            if (allWIndex > 0) {

                var len:int=allWIndex / 16;

                vBuffer.uploadFromVector(vb, 0, len * vunit);



                context.setVertexBufferAt(0, vBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);

                context.setVertexBufferAt(1, vBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);



                context.drawTriangles(iBuffer, 0, 2 * len);

            }

        }

    }



}



//Stage3D



import com.adobe.utils.AGALMiniAssembler;

import flash.display3D.Context3D;

import flash.display3D.Context3DProgramType;

import flash.display3D.Program3D;

import flash.geom.Matrix3D;

import flash.geom.Point;



class Box {

    public var cx:int=0;

    public var cy:int=0;

    public var toX:int=0;

    public var toY:int=0;

    public var x:Number=0;

    public var y:Number=0;



    public var needMoving:Boolean=false;



    private var _fixed:Boolean=false;

    private var _sleep:Boolean=false;

    private var _smooth:Boolean=true;

    private var _v:Point=new Point();

    private var _skin:int=0;



    private var world:Boxes2=null;



    public function Box(world:Boxes2, x:int, y:int, fixed:Boolean=false, smooth:Boolean=true) {

        this.world=world;

        setPos(x, y);

        _fixed=fixed;

        _smooth=smooth;

        _skin=fixed ? 0 : 2;

        _skin+=smooth ? 1 : 0;

    }



    //get fixed

    public function getFixed():Boolean {

        return _fixed;

    }



    public function getSkin():int {

        return _skin;

    }



    //sleep

    public function getSleep():Boolean {

        return _sleep;

    }



    public function getSmooth():Boolean {

        return _smooth;

    }



    public function move():void {

        var tx:Number=this.x - toX * Boxes2.SIZE;

        var ty:Number=this.y - toY * Boxes2.SIZE;

        if ((tx * tx + ty * ty) < Boxes2.SPEED_No_SQRT) {

            world.wakeOther(cx, cy);

            world.setCheckBox(cx, cy, null);

            setPos(toX, toY);

            needMoving=false;

            _v.x=0;

            _v.y=0;

        } else {

            this.x+=_v.x;

            this.y+=_v.y;

        }

    }



    public function setGoto(xa:int, ya:int):void {

        world.setCheckBox(xa, ya, this);

        toX=xa;

        toY=ya;

        needMoving=false;

        _v.x=0;

        _v.y=0;



        //set the moving speed

        if (toX != cx || toY != cy) {

            needMoving=true;

            var v:int=toX - cx;

            if (v != 0) {

                _v.x=v < 0 ? -Boxes2.SPEED : Boxes2.SPEED;

            }



            v=toY - cy;

            if (v != 0) {

                _v.y=v < 0 ? -Boxes2.SPEED : Boxes2.SPEED;

            }



        }

    }



    public function setPos(xa:int, ya:int):void {

        cx=xa;

        cy=ya;

        x=xa * Boxes2.SIZE;

        y=ya * Boxes2.SIZE;

    }



    public function setSleep(bool:Boolean):void {

        if (_sleep != bool) {

            _sleep=bool;

        }

    }

}















class ShaderProgram {



    public function ShaderProgram(context:Context3D, vsh:AGALMiniAssembler, fsh:AGALMiniAssembler) {

        program=context.createProgram();

        program.upload(vsh.agalcode, fsh.agalcode);

    }



    public var program:Program3D=null;

}



class VertexShader extends AGALMiniAssembler {



    public function VertexShader() {

        assemble(Context3DProgramType.VERTEX, src);

    }



    private var src:String="m44 op, va0, vc0 \n" +

        "mov v0, va2 \n" +

        "mul vt0.x, va1.x, vc4.x \n" + //offset = base frame% x step

        "add v0.x, va2.x, vt0.x \n" + //new u = u + offset

        "";

}



class FragmentShader extends AGALMiniAssembler {



    public function FragmentShader() {

        assemble(Context3DProgramType.FRAGMENT, src);

    }



    private var src:String="mov ft0, v0\n" +

        "tex ft1, ft0.xy, " +

        "fs0 <2d,linear,nomip>\n" +

        "mov oc, ft1\n";

}



class MatrixUtil {



    public static function ortho(w:int, h:int, rev:Boolean):Matrix3D {

        var m:Matrix3D=new Matrix3D();

        m.appendTranslation(-w * 0.5, -h * 0.5, 0);

        m.appendScale(2 / w, rev ? 2 / h : -2 / h, 1);

        return m;

    }

}