package
{
import com.adobe.utils.*;
import flash.display.*;
import flash.display3D.*;
import flash.events.*;
import flash.geom.*;
import flash.text.*;
import flash.ui.*;
import mx.utils.*;
public class Main extends Sprite
{
private const viewWidth:int = 800;
private const viewHeight:int = 600;
private var context3D:Context3D;
private var vertexBuffer:VertexBuffer3D;
private var indexBuffer:IndexBuffer3D;
private var keyDown:Array = new Array;
private var tf:TextField = new TextField;
private var camDist:Number = 3;
private var camLat:int = 30;
private var camLong:int = 120;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
var stage3D:Stage3D = stage.stage3Ds[0];
stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
stage3D.requestContext3D();
stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent):void{
keyDown[e.keyCode] = true;
});
stage.addEventListener(KeyboardEvent.KEY_UP, function(e:KeyboardEvent):void{
keyDown[e.keyCode] = false;
});
stage.addEventListener(Event.DEACTIVATE, function(e:Event):void{
keyDown = new Array;
});
tf.defaultTextFormat = new TextFormat(null, 20, 0xffffff);
tf.autoSize = TextFieldAutoSize.LEFT;
addChild(tf);
}
private function onContext3DCreate(e:Event):void
{
context3D = (e.target as Stage3D).context3D;
context3D.configureBackBuffer(viewWidth, viewHeight, 2);
//context3D.setCulling(Context3DTriangleFace.BACK);
// vertexBuffer
const vertices:Vector.<Number> = Vector.<Number>([
// x, y, z, r, g, b,
0, 0, 0, 1, 0, 0,
0, 1, 0, 0, 1, 0,
1, 0, 0, 0, 0, 1,
]);
const perVertex:int = 6;
const numVertices:int = vertices.length / perVertex;
vertexBuffer = context3D.createVertexBuffer(numVertices, perVertex);
vertexBuffer.uploadFromVector(vertices, 0, numVertices);
// indexBuffer
const indices:Vector.<uint> = Vector.<uint>([
0, 1, 2,
]);
indexBuffer = context3D.createIndexBuffer(indices.length);
indexBuffer.uploadFromVector(indices, 0, indices.length);
// program
var vertexProgram:AGALMiniAssembler = new AGALMiniAssembler;
vertexProgram.assemble(Context3DProgramType.VERTEX,
"m44 vt0 va0 vc0\n" + // vt0 = mul(position, world)
"m44 vt0 vt0 vc4\n" + // vt0 = mul(vt0, view)
"m44 op vt0 vc8\n" + // output position = mul(vt0, projection)
"mov v0 va1"
);
var fragmentProgram:AGALMiniAssembler = new AGALMiniAssembler;
fragmentProgram.assemble(Context3DProgramType.FRAGMENT,
"mov oc v0"
);
var program:Program3D = context3D.createProgram();
program.upload(vertexProgram.agalcode, fragmentProgram.agalcode);
context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
context3D.setVertexBufferAt(1, vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_3);
context3D.setProgram(program);
var projection:PerspectiveMatrix3D = new PerspectiveMatrix3D;
projection.perspectiveFieldOfViewRH(ToRadians(45), viewWidth / viewHeight, 0.1, 100);
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 8, projection, true);
stage.addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void
{
if (IsKeyDown(Keyboard.UP)) camLat = Math.min(camLat + 2, 90);
if (IsKeyDown(Keyboard.DOWN)) camLat = Math.max(camLat - 2, -90);
if (IsKeyDown(Keyboard.LEFT)) camLong = (camLong + 2) % 360;
if (IsKeyDown(Keyboard.RIGHT)) camLong = (camLong + 358) % 360;
if (IsKeyDown(Keyboard.PAGE_UP)) camDist = Math.max(camDist - 0.1, 0.1);
if (IsKeyDown(Keyboard.PAGE_DOWN)) camDist += 0.1;
var rad:Number = ToRadians(camLat);
var y:Number = Math.sin(rad) * camDist;
var r:Number = Math.cos(rad) * camDist;
rad = ToRadians(camLong);
var x:Number = Math.cos(rad) * r;
var z:Number = Math.sin(rad) * r;
tf.text = StringUtil.substitute(
"driverInfo: {0}\nlat:{1} long:{2} dist:{3}\nx:{4} y:{5} z:{6}",
context3D.driverInfo, camLat, camLong, camDist.toFixed(1),
x.toFixed(1), y.toFixed(1), z.toFixed(1));
var view:Matrix3D = lookAt(new Vector3D(x, y, z), new Vector3D, Vector3D.Y_AXIS);
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 4, view, true);
//
context3D.clear(.3, .3, .3);
var world:Matrix3D = new Matrix3D;
world.identity();
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, world, true);
context3D.drawTriangles(indexBuffer);
world.identity();
world.appendTranslation(0, 0, -1);
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, world, true);
context3D.drawTriangles(indexBuffer);
context3D.present();
}
private function IsKeyDown(keyCode:uint):Boolean
{
return (keyDown[keyCode]) ? true : false;
}
private function ToRadians(degrees:Number):Number
{
return degrees * Math.PI / 180;
}
private function lookAt(eye:Vector3D, at:Vector3D, up:Vector3D):Matrix3D
{
var m:Vector.<Number> = new Vector.<Number>(16);
at.x = eye.x - at.x;
at.y = eye.y - at.y;
at.z = eye.z - at.z;
m[2] = at.x / at.length;
m[6] = at.y / at.length;
m[10] = at.z / at.length;
at.x = up.y * m[10] - up.z * m[6];
at.y = up.z * m[2] - up.x * m[10];
at.z = up.x * m[6] - up.y * m[2];
m[0] = at.x / at.length;
m[4] = at.y / at.length;
m[8] = at.z / at.length;
m[1] = m[6] * m[8] - m[10] * m[4];
m[5] = m[10] * m[0] - m[2] * m[8];
m[9] = m[2] * m[4] - m[6] * m[0];
m[12] = -(eye.x * m[0] + eye.y * m[4] + eye.z * m[8]);
m[13] = -(eye.x * m[1] + eye.y * m[5] + eye.z * m[9]);
m[14] = -(eye.x * m[2] + eye.y * m[6] + eye.z * m[10]);
m[3] = m[7] = m[11] = 0;
m[15] = 1;
var matrix:Matrix3D = new Matrix3D;
matrix.rawData = m;
return matrix;
}
}
}