Beautifl - Flash Gallery

Thumbnail : 3D Landscape UPDATED
3D Landscape UPDATED
Coft 2012-06-29 MIT License

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

package {
    import flash.display.Bitmap;
    import flash.geom.ColorTransform;
    import flash.geom.Matrix3D;
    import com.adobe.utils.AGALMiniAssembler
    import flash.display.Sprite;
    import flash.display.Stage3D
    import flash.display3D.*
    import flash.display3D.textures.*
    import flash.events.Event
    import flash.display.BitmapData
    import flash.geom.Vector3D
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.events.MouseEvent;
    import flash.display.Shape;
    import flash.filters.BlurFilter;
    import flash.geom.Matrix;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.filters.GlowFilter;
    import flash.display.MovieClip;

    public class MW extends Sprite {
        private var stage3D:Stage3D
        private var context:Context3D
        private var _width:Number
        private var _height:Number
        public function MW() {
            addEventListener("addedToStage", added)
        }
        private function added(e:Event):void {
            var ref:* = this.parent
            ref.frameRate = 60
            stage3D = ref.stage3Ds[0]
            stage3D.addEventListener("context3DCreate", init3d)
            stage3D.requestContext3D()
            _width = 640
            _height = 360
            Key.initialize(ref)
        }
        private var scene:Bitmap
        private function init3d(e:Event):void {
            scene = new Bitmap(new BitmapData(640,360,false))
            context = stage3D.context3D
            context.configureBackBuffer(640,360,4)
            context.clear()
            context.present()
            start()
        }
        private function start():void {
            start_grid()
            start_gfx()
            start_scene()
            start_frame()
        }
        private var sandbox:Boolean = false
        private var grid:Vector.<int>
        private var green:Vector.<Boolean>
        private var cobble:Vector.<int>
        private var left:Vector.<int>
        private var tile:Texture
        private var programBg:Program3D
        private var programSmoke:Program3D
        private var camera:Vector3D
        private var defMatrix:Matrix3D
        private function start_grid():void {
            var bmp:BitmapData = new BitmapData(64, 64, false)
            bmp.perlinNoise(4,4,1,2,true,true,7,true)
            var max:uint = 1 << 12
            grid = new <int>[]
            green = new <Boolean>[]
            cobble = new <int>[]
            for(var i:uint = 0; i < max; i++) {
                grid[i] = (bmp.getPixel(i & 63, i >> 6) & 255) >> 5
                green[i] = true
                cobble[i] = ((bmp.getPixel(i & 63, i >> 6) & 255) >> 4) + 2
            }
        }
        private function start_gfx():void {
            tile = context.createTexture(64,64,"bgra",true)
            var bmp:BitmapData = new BitmapData(64,64,true,0)
            bmp.noise(5,0,255,7,true)
            bmp.colorTransform(new Rectangle(0,0,32,32), new ColorTransform((1-0.1)*.7, (1-0.4)*0.7,(1-0)*0.7,1,255*0.1,255*0.4,255*0))
            bmp.colorTransform(new Rectangle(32,0,32,32), new ColorTransform((1-0.4)*0.3, (1-0.2)*0.3,(1-0)*0.3,1,255*0.4,255*0.2,255*0))
            bmp.colorTransform(new Rectangle(32,32,32,32), new ColorTransform((1-0.5)*0.2, (1-0.5)*0.2,(1-0.5)*0.2,1,255*0.5,255*0.5,255*0.5))
            bmp.colorTransform(new Rectangle(0,32,32,32), new ColorTransform(0,0,0,0))
            var smp:BitmapData = new BitmapData(32,32,true,0)
            var mask:BitmapData = new BitmapData(32,32,true,0)
            var sp:Shape = new Shape()
            sp.graphics.beginFill(0,0.7)
            sp.graphics.drawCircle(16,16,10)
            sp.filters = [new BlurFilter(5,5,2)]
            mask.draw(sp)
            smp.perlinNoise(4,4,6,2,true,true,7,true)
            var fin:BitmapData = new BitmapData(32,32,true,0)
            fin.copyPixels(smp, smp.rect, new Point(), mask, new Point(), true)
            bmp.draw(fin, new Matrix(1,0,0,1,0,32))
            for(var i:uint = 0; i < 7; i++) {
                tile.uploadFromBitmapData(bmp, i)
                if(i < 6) {
                    var mipmap:BitmapData = new BitmapData(bmp.width/2, bmp.height/2, true, 0)
                    mipmap.draw(bmp, new Matrix(0.5,0,0,0.5),null,null,null,true)
                    bmp = mipmap
                }
            }
            context.setTextureAt(0, tile)
            context.setBlendFactors("sourceAlpha", "oneMinusSourceAlpha")
        }
        private function rebuildArea(i:uint):void {
            var _x:uint = (i & 7) << 3
            var _y:uint = (i >> 3) << 3
            var _X:uint = _x + 8
            var _Y:uint = _y + 8
            var vecs:Vector.<Number> = new <Number>[]
            var uvs:Vector.<Number> = new <Number>[]
            var tris:Vector.<uint> = new <uint>[]
            var v:uint = 0
            var u:uint = 0
            var t:uint = 0
            var ind:uint = 0
            left[i] = 0
            for(var x:uint = _x; x < _X; x++) {
                for(var y:uint = _y; y < _Y; y++) {
                    var index:uint = x | (y << 6)
                    var h:int = grid[index]
                    vecs[v++] = x
                    vecs[v++] = y
                    vecs[v++] = h
                    vecs[v++] = x+1
                    vecs[v++] = y
                    vecs[v++] = h
                    vecs[v++] = x+1
                    vecs[v++] = y+1
                    vecs[v++] = h
                    vecs[v++] = x
                    vecs[v++] = y + 1
                    vecs[v++] = h
                    var g:Number = green[index] || sandbox ? 0 : 0.5
                    var k:Number = 0
                    left[i] += (cobble[index] >= h) ? cobble[index] - h : 0
                    if(h >= cobble[index] && !sandbox) {
                        g = 0.5
                        k = 0.5
                    }
                    uvs[u++] = 0.01 + g
                    uvs[u++] = 0.01 + k
                    uvs[u++] = 0.49 + g
                    uvs[u++] = 0.01 + k
                    uvs[u++] = 0.49 + g
                    uvs[u++] = 0.49 + k
                    uvs[u++] = 0.01 + g
                    uvs[u++] = 0.49 + k
                    tris[t++] = ind
                    tris[t++] = ind+1
                    tris[t++] = ind+3
                    tris[t++] = ind+1
                    tris[t++] = ind+2
                    tris[t++] = ind+3
                    ind += 4
                    if(x < 63) {
                        var p1:int = grid[index]
                           var p2:int = grid[index+1]
                        var m:int = (p1 < p2) ? p1 : p2
                        var M:int = (p1 > p2) ? p1 : p2
                        var c1:int = cobble[index]
                        var c2:int = cobble[index+1]
                        var C:int = ((c1 < c2) ? c1 : c2)
                        for(var c:int = m; c < M; c++) {
                            vecs[v++] = x+1
                            vecs[v++] = y
                            vecs[v++] = c
                            vecs[v++] = x+1
                            vecs[v++] = y
                            vecs[v++] = c+1
                            vecs[v++] = x+1
                            vecs[v++] = y+1
                            vecs[v++] = c+1
                            vecs[v++] = x+1
                            vecs[v++] = y+1
                            vecs[v++] = c
                            if(c >= C && !sandbox) {
                                k = 0.5
                            } else {
                                k = 0
                            }
                            uvs[u++] = 0.51
                            uvs[u++] = 0.01 + k
                            uvs[u++] = 0.99
                            uvs[u++] = 0.01 + k
                            uvs[u++] = 0.99
                            uvs[u++] = 0.49 + k
                            uvs[u++] = 0.51
                            uvs[u++] = 0.49 + k
                            tris[t++] = ind
                            tris[t++] = ind+1
                            tris[t++] = ind+3
                            tris[t++] = ind+1
                            tris[t++] = ind+2
                            tris[t++] = ind+3
                            ind += 4
                        }
                    }
                    if(y < 63) {
                        p1 = grid[index]
                        p2 = grid[index+64]
                        m = (p1 < p2) ? p1 : p2
                        M = (p1 > p2) ? p1 : p2
                        c1 = cobble[index]
                        c2 = cobble[index+64]
                        C = ((c1 < c2) ? c1 : c2)
                        for(c = m; c < M; c++) {
                            vecs[v++] = x
                               vecs[v++] = y+1
                            vecs[v++] = c
                            vecs[v++] = x+1
                            vecs[v++] = y+1
                            vecs[v++] = c
                            vecs[v++] = x+1
                            vecs[v++] = y+1
                            vecs[v++] = c+1
                            vecs[v++] = x
                            vecs[v++] = y+1
                            vecs[v++] = c+1
                            if(c >= C && !sandbox) {
                                k = 0.5
                            } else {
                                k = 0
                            }
                            uvs[u++] = 0.51
                            uvs[u++] = 0.01 + k
                            uvs[u++] = 0.99
                            uvs[u++] = 0.01 + k
                            uvs[u++] = 0.99
                            uvs[u++] = 0.49 + k
                            uvs[u++] = 0.51
                            uvs[u++] = 0.49 + k
                            tris[t++] = ind
                            tris[t++] = ind+1
                            tris[t++] = ind+3
                            tris[t++] = ind+1
                            tris[t++] = ind+2
                            tris[t++] = ind+3
                            ind += 4
                        }
                    }
                }
            }
            areas[i] = [vecs, uvs, tris]
        }
        private var areas:Vector.<Array>
        private function start_scene():void {
            areas = new <Array>[]
            left = new <int>[]
            for(var i:uint = 0; i < 64; i++) {
                rebuildArea(i)
            }
            var agalVec:AGALMiniAssembler = new AGALMiniAssembler()
            var codeVec:String = "m44 op, va0, vc0 \n" + 
                                 "mov v0, va0 \n" +
                                 "mov v1, va1 \n" +
                                 "m44 v2, va0, vc0"
            var agalFrag:AGALMiniAssembler = new AGALMiniAssembler()
            var codeFrag:String = "mov ft0, v0 \n" + 
                                  "tex ft4, v1, fs0<2d,nearest,mipnearest> \n" +
                                  "div ft0, ft0.z, fc0.x \n" +

                                  "sub ft2, v0, fc1 \n" +
                                  "dp3 ft2.w, ft2, ft2 \n" +
                                  "div ft2.w, fc1.w, ft2.w \n" +
                                  "div ft2.z, ft2.w, ft2.w \n" +
                                  "add ft2.w, ft2.w, ft2.z \n" +
                                  
                                  "sub ft3, v0, fc3 \n" +
                                  "dp3 ft3.w, ft3, ft3 \n" +
                                  "div ft3.w, fc3.w, ft3.w \n" +
                                  "add ft2.w, ft2.w, ft3.w \n" +
                                  
                                  "sub ft3, v0, fc4 \n" +
                                  "dp3 ft3.w, ft3, ft3 \n" +
                                  "div ft3.w, fc4.w, ft3.w \n" +
                                  "add ft2.w, ft2.w, ft3.w \n" +
                                  
                                  "sub ft3, v0, fc5 \n" +
                                  "dp3 ft3.w, ft3, ft3 \n" +
                                  "div ft3.w, fc5.w, ft3.w \n" +
                                  "add ft2.w, ft2.w, ft3.w \n" +
                                  
                                  "sub ft3, v0, fc6 \n" +
                                  "dp3 ft3.w, ft3, ft3 \n" +
                                  "div ft3.w, fc6.w, ft3.w \n" +
                                  "add ft2.w, ft2.w, ft3.w \n" +
                                  
                                  "mul oc, ft4, ft2.w"
            agalVec.assemble("vertex", codeVec)
            agalFrag.assemble("fragment", codeFrag)
            programBg = context.createProgram()
            programBg.upload(agalVec.agalcode, agalFrag.agalcode)
            agalVec = new AGALMiniAssembler()
            codeVec = "m44 op, va0, vc0 \n" + 
                                 "mov v0, va1"
            agalFrag = new AGALMiniAssembler()
            codeFrag = "tex oc, v0, fs0<2d,nearest,mipnearest>"
            agalVec.assemble("vertex", codeVec)
            agalFrag.assemble("fragment", codeFrag)
            programSmoke = context.createProgram()
            programSmoke.upload(agalVec.agalcode, agalFrag.agalcode)
            defMatrix = getMatrix()
        }
        private function start_frame():void {
            camera = new Vector3D(32,32,3)
            stage.addEventListener("enterFrame", render)
            stage.scaleMode = "noScale"
            stage.align = "topLeft"
            stage.addEventListener("resize", resize)
            resize(new Event("resize"))
            stage.addEventListener("enterFrame", freeLook)
            stage.addEventListener("enterFrame", lookAround)
            stage.addEventListener("mouseDown", fire)
            particles = new <Array>[]
            projectiles = new <Array>[]
            chain = []
            score = txt(24,"Dirt left: 99999")
            score.pos = new Point(1,0)
            score.dispatchEvent(new Event("resize"))
            stage.addChild(score)
            lastdirt = 9000
            gratz = txt(65, "Congratulations!")
            gratz.sin = 0
            gratz.addEventListener("enterFrame", glow)
            gratz.alpha = 0
            gratz.pos = new Point(0.5,0.5)
            gratz.dispatchEvent(new Event("resize"))
            stage.addChild(gratz)
            stage.quality = "medium"
            rescore()
        }
        private function glow(e:Event):void {
            gratz.alpha *= 0.997
            if(gratz.alpha < 0.05) {
                gratz.visible = false
            } else {
                gratz.visible = true
                gratz.sin += 0.9
                gratz.filters = [new GlowFilter(0xFFFF00,0.4 + 0.4*Math.sin(gratz.sin),32,5,2,1)]
            }
        }
        private var gratz:MovieClip
        private var score:MovieClip
        private function txt(size:uint, t:String):MovieClip {
            var ans:TextField = new TextField()
            var format:TextFormat = new TextFormat()
            format.size = size
            format.color = 0xFFFFFF
            ans.defaultTextFormat = format
            ans.width = 500
            ans.height = 200
            ans.text = t
            ans.width = ans.textWidth + 8
            ans.height = ans.textHeight + 8
            ans.selectable = false
            var mc:MovieClip = new MovieClip()
            mc.graphics.beginFill(0, 1/255)
            mc.graphics.drawRect(0,0,ans.textWidth, ans.textHeight)
            mc.graphics.endFill()
            mc.addChild(ans)
            mc.pos = new Point()
            mc.addEventListener("resize", repos)
            mc.mouseEnabled = false
            return mc
        }
        private function repos(e:Event):void {
            var field:* = e.currentTarget
            field.x = field.pos.x * stage.stageWidth - field.width * field.pos.x
            field.y = field.pos.y * stage.stageHeight - field.height * field.pos.y
        }
        private var lastdirt:uint
        private var dirtleft:uint
        private function rescore():void {
            var field:* = score
            field = field.getChildAt(0)
            dirtleft = 0
            for(var i:uint = 0; i < 64; i++) {
                dirtleft += left[i]
            }
            field.text = "Dirt left: " + dirtleft
            if(lastdirt > 0 && dirtleft == 0) {
                gratz.alpha = 1
            }
            lastdirt = dirtleft
        }
        private var yaw:Number = 0
        private var pitch:Number = 80
        private var vec:Vector3D = new Vector3D(0,0,0)
        private function freeLook(e:Event):void {
            yaw += (stage.mouseX - stage.stageWidth/2)/100
            pitch += (stage.mouseY - stage.stageHeight/2)/100
            pitch = (pitch > 89) ? 89 : pitch
            pitch = (pitch < -89) ? -89 : pitch
        }
        private function lookAround(e:Event):void {
            var p:Point = new Point()
            p.x += int(Key.isDown(68))
            p.x -= int(Key.isDown(65))
            p.y -= int(Key.isDown(87))
            p.y += int(Key.isDown(83))
            var F:Vector3D = new Vector3D(0,0,1)
            var R:Vector3D = new Vector3D(1,0,0)
            var m:Matrix3D = new Matrix3D()
            m.appendRotation(-90, new Vector3D(1,0,0))
            m.appendRotation(yaw, new Vector3D(0,0,1))
            F = m.transformVector(F)
            R = m.transformVector(R)
            var fin:Vector3D = new Vector3D(R.x*p.x + F.x*p.y, R.y*p.x + F.y*p.y, R.z*p.x + F.z*p.y)
            var save:Number = vec.z
            fin.normalize()
            var speed:Number = 3
            if(camera.z > 5) {
                speed *= Math.sqrt(camera.z - 4)
            }
            if(Key.isDown(16)) {
                speed *= 3
            }
            var acc:Number = 0.003
            fin.scaleBy(speed/60)
            var dif:Vector3D = fin.subtract(vec)
            if(dif.length > acc) {
                dif.normalize()
                dif.scaleBy(acc)
                vec = vec.add(dif)
            } else {
                vec = fin
            }
            vec.z = save
            var terminal:Number = 33/60
            if(vec.z < -terminal) {
                vec.z = 0.9 * vec.z - 0.1 * terminal
            }
            if(vec.z > terminal*0.5) {
                vec.z = 0.9 * vec.z + 0.1 * terminal*0.5
            }
            camera = camera.add(vec)
            var atX:int = camera.x
            var atY:int = camera.y
            var max:uint = 64
            if(atX >= 0 && atY >= 0 && atX < max && atY < max) {
                var h:Number = -grid[atX | (atY << 6)]
                if(camera.z < h+0.6) {
                    camera.z = h+0.6
                    vec.z = 0
                    if(Key.isDown(32)) {
                        vec.z = 0.15
                    }
                }
            }
            if(Key.isDown(86)) {
                if(vec.z < 0) {
                    vec.z *= 0.95
                }
                vec.z += 0.008
            }
            vec.z -= 0.006
            var a:uint = 0
            var f:uint = projectiles.length
            for(var i:int = 0; i < f - a; i++) {
                var proj:Array = projectiles[i+a]
                proj[0] = proj[0].add(proj[1])
                var hit:Boolean = false
                if(proj[0].x < 0 || proj[0].y < 0 || proj[0].x >= 64 || proj[0].y >= 64) {
                    hit = true
                } else {
                    if(-grid[(proj[0].x << 0) | (proj[0].y << 6)] > proj[0].z) {
                        hit = true
                        chain.push([proj[0].clone(),0,0])
                        lights.push([proj[0].clone(),16])
                    }
                }
                if(hit) {
                    i--
                    a++
                } else {
                    projectiles[i] = projectiles[i+a]
                }
                if(Math.random() < 100/(100 + particles.length)) {
                    particles.push([proj[0].clone(), new Vector3D(Math.random()*0.02-0.01, Math.random()*0.02-0.01, 0.1), 55])
                }
            }
            if(a > 0) {
                projectiles.splice(-a, a)
            }
            a = 0
            f = particles.length
            for(i = 0; i < f - a; i++) {
                proj = particles[i+a]
                hit = false
                if(proj[2]-- < 0) {
                    hit = true
                } else {
                    proj[1].z -= 0.002
                    proj[0] = proj[0].add(proj[1])
                    if(proj[0].x < 0 || proj[0].y < 0 || proj[0].x >= 64 || proj[0].y >= 64) {
                        hit = true
                    } else {
                        if(-grid[(proj[0].x >> 0) | (proj[0].y << 6)] > proj[0].z) {
                            hit = true
                        }
                    }
                }
                if(hit) {
                    i--
                    a++
                } else {
                    particles[i] = particles[i+a]
                }
            }
            if(a > 0) {
                particles.splice(-a, a)
            }
            a = 0
            f = chain.length
            for(i = 0; i < f - a; i++) {
                proj = chain[i+a]
                if(proj[2]-- < 0) {
                    proj[1] += 0.9
                    explode(proj[0], proj[1])
                    if(proj[1] >= 3) {
                        i--
                        a++
                    } else {
                        chain[i] = chain[i+a]
                    }
                    proj[2] = 2
                } else {
                    chain[i] = chain[i+a]
                }
            }
            if(a > 0) {
                chain.splice(-a, a)
            }
            var M:Boolean = Key.isDown(77)
            if(M && !lastM) {
                sandbox = !sandbox
                for(i = 0; i < 64; i++) {
                    rebuildArea(i)
                }
            }
            lastM = M
        }
        private var lastM:Boolean
        private var particles:Vector.<Array>
        private var projectiles:Vector.<Array>
        private function fire(e:MouseEvent):void {
            if(sandbox) {
                var l:Vector.<Number> = light()
                explode(new Vector3D(l[0], l[1], l[2]), 7)
            } else {
                var F:Vector3D = new Vector3D(0,0,-1)
                var m:Matrix3D = new Matrix3D()
                m.appendRotation(-90+pitch, new Vector3D(1,0,0))
                m.appendRotation(yaw, new Vector3D(0,0,1))
                F = m.transformVector(F)
                F.normalize()
                F.scaleBy(42/30)
                projectiles.push([camera.clone(), F])
            }
        }
        private function resize(e:Event):void {
            _width = stage.stageWidth
            _height = stage.stageHeight
            defMatrix = getMatrix()
            context.configureBackBuffer(_width, _height, 4)
            scene.bitmapData = new BitmapData(_width,_height,false)
        }
        private function light():Vector.<Number> {
            var p:Vector3D = camera.clone()
            var inc:Vector3D = new Vector3D(0,0,-1)
            var m:Matrix3D = new Matrix3D()
            m.appendRotation(-90+pitch, new Vector3D(1,0,0))
            m.appendRotation(yaw, new Vector3D(0,0,1))
            inc = m.transformVector(inc)
            inc.normalize()
            inc.scaleBy(0.01)
            var n:uint = 0
            for(var goon:Boolean = true;goon;) {
                p = p.add(inc)
                var cX:int = p.x >> 0
                var cY:int = p.y >> 0
                var i:int = cX | (cY << 6)
                if(i >= 0 && i < (1 << 12)) {
                    var h:Number = grid[i]
                    goon = -grid[(p.x << 0) | (p.y << 6)] < p.z
                } else {
                    goon = false
                }
                if(n++ & 2048) {
                    goon = false
                }
            }
            return new <Number>[p.x, p.y, -p.z, 0.01]
        }
        private var chain:Array
        private function explode(pos:Vector3D, strength:Number):void {
            var _x:int = pos.x - 8
            var _y:int = pos.y - 8
            _x = (_x < 0) ? 0 : _x
            _y = (_y < 0) ? 0 : _y
            var _X:int = pos.x + 8
            var _Y:int = pos.y + 8
            _X = (_X > 64) ? 64 : _X
            _Y = (_Y > 64) ? 64 : _Y
            var list:Vector.<int> = new Vector.<int>(64,true)
            for(var x:uint = _x; x < _X; x++) {
                for(var y:uint = _y; y < _Y; y++) {
                    if(sandbox) {
                        var h:Number = 5 - Math.sqrt((x-pos.x)*(x-pos.x) + (y - pos.y)*(y - pos.y))
                    } else {
                        h = Math.sqrt(strength - Math.sqrt((x-pos.x)*(x-pos.x) + (y - pos.y)*(y - pos.y)))
                    }
                    h = (h < 0) ? 0 : h
                    if(h >> 0) {
                        var i:uint = x | (y << 6)
                        var last:uint = grid[i]
                        grid[i] += h >> 0
                        green[i] = false
                        if(grid[i] > cobble[i] && !sandbox) {
                            grid[i] = (cobble[i] > last) ? cobble[i] : last
                        }
                    }
                    list[(x >> 3) | ((y >> 3) << 3)] = 1
                }
            }
            for(i = 0; i < 64; i++) {
                if(list[i]) {
                    rebuildArea(i)
                }
            }
            if(!sandbox) {
                var f:Number = 8*strength/(particles.length/50 + 1)
                for(i = 0; i < 8*strength; i++) {
                    var off:Vector3D = new Vector3D(Math.random()-0.5, Math.random()-0.5, Math.random()-0.5)
                    off.normalize()
                    off.scaleBy(Math.random())
                    var at:Vector3D = pos.add(off)
                    var vec:Vector3D = at.subtract(pos)
                    vec.normalize()
                    vec.scaleBy(6/60 * (1+2*Math.random()))
                    particles.push([at, vec, 100])
                }
                quake += 0.15
            }
            rescore()
        }
        private var quake:Number = 0
        private var lights:Vector.<Array> = new <Array>[]
        private function render(e:Event):void {
            context.clear()
            var m:Matrix3D = new Matrix3D()
            quake *= 0.9
            quake = (quake < 0.01) ? 0 : quake
            m.appendTranslation(-camera.x + quake*(Math.random()-0.5), -camera.y + quake*(Math.random()-0.5), camera.z + quake*(Math.random()-0.5))
            m.appendRotation(-yaw, new Vector3D(0,0,1))
            m.appendRotation(-90+pitch, new Vector3D(1,0,0))
            var m2:Matrix3D = m.clone()
            m2.append(defMatrix)
            context.setProgramConstantsFromMatrix("vertex", 0, m2, true)
            context.setProgramConstantsFromVector("fragment", 0, new <Number>[32*4,0,0,0])
            context.setProgramConstantsFromVector("fragment", 1, light())
            context.setProgramConstantsFromVector("fragment", 2, new <Number>[10000, 0, 0, 0])
            var f:uint = lights.length
            var a:uint = 0
            var lightsSet:Vector.<int> = new Vector.<int>(8)
            for(var i:int = 0; i < f - a; i++) {
                var l:Array = lights[i+a]
                l[1] *= 0.85
                if(l[1] < 0.5) {
                    i--
                    a++
                } else {
                    if(i < 4) {
                        context.setProgramConstantsFromVector("fragment", 3 + i, new <Number>[l[0].x, l[0].y, -l[0].z, l[1]])
                        lightsSet[i] = 1
                    }
                    lights[i] = lights[i+a]
                }
            }
            for(i = 0; i < 4; i++) {
                if(!lightsSet[i]) {
                    context.setProgramConstantsFromVector("fragment", 3 + i, new <Number>[0,0,0,0])
                }
            }
            if(a > 0) {
                lights.splice(-a, a)
            }
            context.setProgram(programBg)
            context.setDepthTest(true, "less")
            for(i = 0; i < 64; i++) {
                var vBuf:VertexBuffer3D = context.createVertexBuffer(areas[i][0].length/3, 3)
                var uBuf:VertexBuffer3D = context.createVertexBuffer(areas[i][1].length/2, 2)
                var tBuf:IndexBuffer3D = context.createIndexBuffer(areas[i][2].length)
                vBuf.uploadFromVector(areas[i][0], 0, areas[i][0].length/3)
                   uBuf.uploadFromVector(areas[i][1], 0, areas[i][1].length/2)
                tBuf.uploadFromVector(areas[i][2], 0, areas[i][2].length)
                context.setVertexBufferAt(0, vBuf, 0, "float3")
                context.setVertexBufferAt(1, uBuf, 0, "float2")
                context.drawTriangles(tBuf, 0, areas[i][2].length/3)
            }
            f = particles.length
            if(f > 0) {
                var vec:Vector.<Number> = new <Number>[]
                var uvs:Vector.<Number> = new <Number>[]
                var tris:Vector.<uint> = new <uint>[]
                var order:Vector.<Number> = new <Number>[]
                var v:uint = 0
                for(i = 0; i < f; i++) {
                    var v3d:Vector3D = particles[i][0]
                    order[v++] = v3d.x
                    order[v++] = v3d.y
                    order[v++] = -v3d.z
                }
                var size:Number = 0.2
                m.transformVectors(order, order)
                v = 0
                var u:uint = 0
                var t:uint = 0
                var ind:uint = 0
                for(i = 0; i < f; i++) {
                    var min:Number = -Infinity
                    var of:int = -1
                    for(var j:uint = 0; j < f; j++) {
                        if(order[3*j+2] > min) {
                            min = order[3*j+2]
                            of = j
                        }
                    }
                    if(of < 0) {
                        i = f
                    } else {
                        vec[v++] = order[3*of] - size
                        vec[v++] = order[3*of+1] - size
                        vec[v++] = order[3*of+2]
                        vec[v++] = order[3*of] + size
                        vec[v++] = order[3*of+1] - size
                        vec[v++] = order[3*of+2]
                        vec[v++] = order[3*of] + size
                        vec[v++] = order[3*of+1] + size
                        vec[v++] = order[3*of+2]
                        vec[v++] = order[3*of] - size
                        vec[v++] = order[3*of+1] + size
                        vec[v++] = order[3*of+2]
                        uvs[u++] = 0.01
                        uvs[u++] = 0.51
                        uvs[u++] = 0.49
                        uvs[u++] = 0.51
                        uvs[u++] = 0.49
                        uvs[u++] = 0.99
                        uvs[u++] = 0.01
                        uvs[u++] = 0.99
                        tris[t++] = ind
                        tris[t++] = ind+1
                        tris[t++] = ind+3
                        tris[t++] = ind+1
                        tris[t++] = ind+2
                        tris[t++] = ind+3
                        ind += 4
                        order[3*of+2] = -Infinity
                    }
                }
                context.setProgram(programSmoke)
                context.setProgramConstantsFromMatrix("vertex", 0, defMatrix, true)
                vBuf = context.createVertexBuffer(vec.length/3, 3)
                uBuf = context.createVertexBuffer(uvs.length/2, 2)
                tBuf = context.createIndexBuffer(tris.length)
                    vBuf.uploadFromVector(vec, 0, vec.length/3)
                   uBuf.uploadFromVector(uvs, 0, uvs.length/2)
                    tBuf.uploadFromVector(tris, 0, tris.length)
                    context.setVertexBufferAt(0, vBuf, 0, "float3")
                context.setVertexBufferAt(1, uBuf, 0, "float2")
                context.drawTriangles(tBuf, 0, tris.length/3)
            }
            if(drawOnScreen) {
                context.drawToBitmapData(scene.bitmapData)
            }
            context.present()
            var O:Boolean = Key.isDown(79)
            if(O && !lastO) {
                drawOnScreen = !drawOnScreen
                if(drawOnScreen) {
                    stage3D.visible = false
                    addChild(scene)
                } else {
                    stage3D.visible = true
                    removeChild(scene)
                }


            }
            lastO = O
        }
        private var lastO:Boolean
        private var drawOnScreen:Boolean = false
        private function getMatrix():Matrix3D {
            var _far:Number = 500
            var _near:Number = 0.01
            var angle:Number = 90
            return new Matrix3D(new <Number>[
            16 * Math.max(_height, _width*9/16) / (9 * Math.tan(angle*Math.PI/360) * _width), 0, 0, 0,
            0, - 16 * Math.max(_height, _width*9/16) / (Math.tan(angle*Math.PI/360) * 9 * _height), 0, 0,
            0, 0, _far/(_far - _near), 1,
            0, 0, _far*_near/(_near-_far), 0])
        }
    }
}
import flash.display.Stage
import flash.events.KeyboardEvent
import flash.events.Event
    class Key {
        private static var keysDown:Object = new Object();
        public static function initialize(stage:Stage):void {
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
            stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
            stage.addEventListener(Event.DEACTIVATE, clearKeys);
        }
        public static function isDown(keyCode:uint):Boolean {
            return Boolean(keyCode in keysDown);
        }
        private static function keyPressed(event:KeyboardEvent):void {
            keysDown[event.keyCode] = true;
        }
        private static function keyReleased(event:KeyboardEvent):void {
            if (event.keyCode in keysDown) {
                delete keysDown[event.keyCode];
            }
        }
        private static function clearKeys(event:Event):void {
            keysDown = new Object();
        }
    }