forked from: Simple 3D

by Thumasz forked from 3D Landscape UPDATED (diff: 1)
♥0 | Line 378 | Modified 2012-06-27 21:27:16 | MIT License
play

ActionScript3 source code

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

// forked from Coft's Simple 3D
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;
    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 {
            stage3D.visible = false
            scene = new Bitmap(new BitmapData(640,360,false))
            addChild(scene)
            context = stage3D.context3D
            context.configureBackBuffer(640,360,4)
            context.clear()
            context.present()
            start()
        }
        private var waitdraw:int
        private function start():void {
            side = 6
            start_grid()
            start_gfx()
            start_scene()
            start_frame()
            waitdraw = 333
        }
        private var side:uint
        private var grid:Vector.<int>
        private var tile:Texture
        private var bgVec:Vector.<Number>
        private var bgUvs:Vector.<Number>
        private var bgTri:Vector.<uint>
        private var programBg: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 << (2*side)
            grid = new <int>[]
            for(var i:uint = 0; i < max; i++) {
                grid[i] = (bmp.getPixel(i & 63, i >> 6) & 255) >> 5
            }
        }
        private function start_gfx():void {
            tile = context.createTexture(64,64,"bgra", false)
            var bmp:BitmapData = new BitmapData(64,64,false)
            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))
            tile.uploadFromBitmapData(bmp)
            context.setTextureAt(0, tile)
        }
        private function start_scene():void {
            var v:uint = 0
            bgVec = new <Number>[]
            var u:uint = 0
            bgUvs = new <Number>[]
            var t:uint = 0
            bgTri = new <uint>[]
            var ind:uint = 0
            for(var a:uint = 0; !(a >> side); a++) {
                for(var b:uint = 0; !(b >> side); b++) {
                    var h:int = grid[a | (b << side)]
                    bgVec[v++] = a
                    bgVec[v++] = b
                    bgVec[v++] = h
                    bgVec[v++] = a+1
                    bgVec[v++] = b
                    bgVec[v++] = h
                    bgVec[v++] = a+1
                    bgVec[v++] = b+1
                    bgVec[v++] = h
                    bgVec[v++] = a
                    bgVec[v++] = b + 1
                    bgVec[v++] = h
                    bgUvs[u++] = 0.01
                    bgUvs[u++] = 0.01
                    bgUvs[u++] = 0.49
                    bgUvs[u++] = 0.01
                    bgUvs[u++] = 0.49
                    bgUvs[u++] = 0.49
                    bgUvs[u++] = 0.01
                    bgUvs[u++] = 0.49
                    bgTri[t++] = ind
                    bgTri[t++] = ind+1
                    bgTri[t++] = ind+3
                    bgTri[t++] = ind+1
                    bgTri[t++] = ind+2
                    bgTri[t++] = ind+3
                    ind += 4
                }
            }
            for(a = 0; !(a + 1 >> side); a++) {
                for(b = 0; !(b >> side); b++) {
                    var p1:int = grid[a | (b << side)]
                    var p2:int = grid[1+a | (b << side)]
                    var m:int = (p1 < p2) ? p1 : p2
                    var M:int = (p1 > p2) ? p1 : p2
                    for(var c:int = m; c < M; c++) {
                        bgVec[v++] = a+1
                        bgVec[v++] = b
                        bgVec[v++] = c
                        bgVec[v++] = a+1
                        bgVec[v++] = b
                        bgVec[v++] = c+1
                        bgVec[v++] = a+1
                        bgVec[v++] = b+1
                        bgVec[v++] = c+1
                        bgVec[v++] = a+1
                        bgVec[v++] = b+1
                        bgVec[v++] = c
                        bgUvs[u++] = 0.51
                        bgUvs[u++] = 0.01
                        bgUvs[u++] = 0.99
                        bgUvs[u++] = 0.01
                        bgUvs[u++] = 0.99
                        bgUvs[u++] = 0.49
                        bgUvs[u++] = 0.51
                        bgUvs[u++] = 0.49
                        bgTri[t++] = ind
                        bgTri[t++] = ind+1
                        bgTri[t++] = ind+3
                        bgTri[t++] = ind+1
                        bgTri[t++] = ind+2
                        bgTri[t++] = ind+3
                        ind += 4
                    }
                }
            }
            for(a = 0; !(a >> side); a++) {
                for(b = 0; !(b + 1 >> side); b++) {
                    p1 = grid[a | (b << side)]
                    p2 = grid[a | (b + 1 << side)]
                    m = (p1 < p2) ? p1 : p2
                    M = (p1 > p2) ? p1 : p2
                    for(c = m; c < M; c++) {
                        bgVec[v++] = a
                        bgVec[v++] = b+1
                        bgVec[v++] = c
                        bgVec[v++] = a+1
                        bgVec[v++] = b+1
                        bgVec[v++] = c
                        bgVec[v++] = a+1
                        bgVec[v++] = b+1
                        bgVec[v++] = c+1
                        bgVec[v++] = a
                        bgVec[v++] = b+1
                        bgVec[v++] = c+1
                        bgUvs[u++] = 0.51
                        bgUvs[u++] = 0.01
                        bgUvs[u++] = 0.99
                        bgUvs[u++] = 0.01
                        bgUvs[u++] = 0.99
                        bgUvs[u++] = 0.49
                        bgUvs[u++] = 0.51
                        bgUvs[u++] = 0.49
                        bgTri[t++] = ind
                        bgTri[t++] = ind+1
                        bgTri[t++] = ind+3
                        bgTri[t++] = ind+1
                        bgTri[t++] = ind+2
                        bgTri[t++] = ind+3
                        ind += 4
                    }
                }
            }
            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,mipnone> \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" +
                                  "mul oc, ft4, ft2.w"
            agalVec.assemble("vertex", codeVec)
            agalFrag.assemble("fragment", codeFrag)
            programBg = context.createProgram()
            programBg.upload(agalVec.agalcode, agalFrag.agalcode)
            defMatrix = getMatrix()
        }
        private function start_frame():void {
            camera = new Vector3D((1 << side)/2,(1 << side)/2,15)
            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)
        }
        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(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
            camera = camera.add(vec)
            var atX:int = camera.x
            var atY:int = camera.y
            var max:uint = 1 << side
            if(atX >= 0 && atY >= 0 && atX < max && atY < max) {
                var h:Number = -grid[atX | (atY << side)]
                if(camera.z < h+0.6) {
                    camera.z = h+0.6
                    vec.z = 0
                    if(Key.isDown(32)) {
                        vec.z = 0.15
                    }
                }
            }
            vec.z -= 0.006
        }
        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)
            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 << side)
                if(i >= 0 && i < (1 << 2*side)) {
                    var h:Number = grid[i]
                    goon = -grid[(p.x << 0) | (p.y << side)] < p.z
                } else {
                    goon = false
                }
            }
            return new <Number>[p.x, p.y, -p.z, 1]
        }
        private function render(e:Event):void {
            context.clear()
            var m:Matrix3D = new Matrix3D()
            m.appendTranslation(-camera.x, -camera.y, camera.z)
            m.appendRotation(-yaw, new Vector3D(0,0,1))
            m.appendRotation(-90+pitch, new Vector3D(1,0,0))
            m.append(defMatrix)
            context.setProgramConstantsFromMatrix("vertex", 0, m, 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])
            context.setProgram(programBg)
            context.setDepthTest(true, "less")
            var vBuf:VertexBuffer3D = context.createVertexBuffer(bgVec.length/3, 3)
            var uBuf:VertexBuffer3D = context.createVertexBuffer(bgUvs.length/2, 2)
            var tBuf:IndexBuffer3D = context.createIndexBuffer(bgTri.length)
            vBuf.uploadFromVector(bgVec, 0, bgVec.length/3)
            uBuf.uploadFromVector(bgUvs, 0, bgUvs.length/2)
            tBuf.uploadFromVector(bgTri, 0, bgTri.length)
            context.setVertexBufferAt(0, vBuf, 0, "float3")
            context.setVertexBufferAt(1, uBuf, 0, "float2")
            context.drawTriangles(tBuf, 0, bgTri.length/3)
            if(waitdraw-- == 0) {
                stage3D.visible = true
                removeChild(scene)
            }
            if(waitdraw >= 0) {
                context.drawToBitmapData(scene.bitmapData)
            }
            context.present()
        }
        private function getMatrix():Matrix3D {
            var _far:Number = 100
            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();
        }
    }