package
{
import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.PerspectiveMatrix3D;
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.ErrorEvent;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.geom.Matrix3D;
import flash.geom.Point;
import flash.geom.Vector3D;
import flash.ui.Keyboard;
public class Context3DExample extends Sprite
{
public const viewWidth:Number = 640;
public const viewHeight:Number = 400;
public const zNear:Number = 1;
public const zFar:Number = 500;
public const fov:Number = 45;
private var stage3D:Stage3D;
private var renderContext:Context3D;
private var indexList:IndexBuffer3D;
private var vertexes:VertexBuffer3D;
private var projection:PerspectiveMatrix3D = new PerspectiveMatrix3D();
private var model:Matrix3D = new Matrix3D();
private var view:Matrix3D = new Matrix3D();
private var finalTransform:Matrix3D = new Matrix3D();
//For rotation the cube
private const pivot:Vector3D = new Vector3D();
private const VERTEX_SHADER:String = "m44 op, va0, vc0\n" + "mov v0, va1";
private const FRAGMENT_SHADER:String = "mov oc, v0";
private var vertexAssembly:AGALMiniAssembler = new AGALMiniAssembler();
private var fragmentAssembly:AGALMiniAssembler = new AGALMiniAssembler();
private var programPair:Program3D;
private var lastPosition:Point = new Point();
public function Context3DExample():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
this.stage.scaleMode = StageScaleMode.NO_SCALE;
this.stage.align = StageAlign.TOP_LEFT;
//this.stage.nativeWindow.activate(); //AIR only
stage3D = this.stage.stage3Ds[0];
stage3D.x = 10;
stage3D.y = 10;
//Add event listener before requesting the context
stage3D.addEventListener(Event.CONTEXT3D_CREATE, contextCreated);
stage3D.addEventListener(ErrorEvent.ERROR, contextCreationError);
stage3D.requestContext3D(Context3DRenderMode.AUTO);
//Compile shaders
vertexAssembly.assemble(Context3DProgramType.VERTEX, VERTEX_SHADER, false);
fragmentAssembly.assemble(Context3DProgramType.FRAGMENT, FRAGMENT_SHADER, false);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
}
private function contextCreated(e:Event):void
{
renderContext = Stage3D(e.target).context3D;
trace("3D driver: " + renderContext.driverInfo);
setupScene();
}
private function setupScene():void
{
renderContext.enableErrorChecking = true;
renderContext.configureBackBuffer(viewWidth, viewHeight, 2, false);
renderContext.setCulling(Context3DTriangleFace.BACK);
//Create vertex index list for the triangles forming a cube
var triangles:Vector.<uint> = Vector.<uint>([
2, 1, 0, //front face
3, 2, 0,
4, 7, 5, //bottom face
7, 6, 5,
8, 11, 9, //back face
9, 11, 10,
12, 15, 13, //top face
13, 15, 14,
16, 19, 17, //left face
17, 19, 18,
20, 23, 21, //right face
21, 23, 22,
]);
indexList = renderContext.createIndexBuffer(triangles.length);
indexList.uploadFromVector(triangles, 0, triangles.length);
//Create vertexes - cube faces do not share vertexes
const dataPerVertex:int = 6;
var vertexData:Vector.<Number> = Vector.<Number>([
// x, y, z, r, g, b,
0, 0, 0, 1, 0, 0, //front face
0, 1, 0, 1, 0, 0,
1, 1, 0, 1, 0, 0,
1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 1, 0, //bottom face
1, 0, 0, 0, 1, 0,
1, 0, 1, 0, 1, 0,
0, 0, 1, 0, 1, 0,
0, 0, 1, 1, 0, 0, //back face
1, 0, 1, 1, 0, 0,
1, 1, 1, 1, 0, 0,
0, 1, 1, 1, 0, 0,
0, 1, 1, 0, 1, 0, //top face
1, 1, 1, 0, 1, 0,
1, 1, 0, 0, 1, 0,
0, 1, 0, 0, 1, 0,
0, 1, 1, 0, 0, 1, //left face
0, 1, 0, 0, 0, 1,
0, 0, 0, 0, 0, 1,
0, 0, 1, 0, 0, 1,
1, 1, 0, 0, 0, 1, //right face
1, 1, 1, 0, 0, 1,
1, 0, 1, 0, 0, 1,
1, 0, 0, 0, 0, 1,
]);
vertexes = renderContext.createVertexBuffer(vertexData.length / dataPerVertex, dataPerVertex);
vertexes.uploadFromVector(vertexData, 0, vertexData.length / dataPerVertex);
//Identify vertex data inputs for vertex program
renderContext.setVertexBufferAt(
0, vertexes, 0, Context3DVertexBufferFormat.FLOAT_3); //va0 is position
renderContext.setVertexBufferAt(
1, vertexes, 3, Context3DVertexBufferFormat.FLOAT_3); //va1 is color
//Upload programs to render context
programPair = renderContext.createProgram();
programPair.upload(vertexAssembly.agalcode, fragmentAssembly.agalcode);
renderContext.setProgram(programPair);
//Set up 3D transforms
projection.perspectiveFieldOfViewRH(fov, viewWidth / viewHeight, zNear, zFar);
model.appendTranslation(-.5, -.5, -.5); //center cube on origin
view.appendTranslation(0, 0, -2); //Move view back
this.stage.addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void
{
//Rotate model on each frame
//model.appendRotation(.5, Vector3D.Z_AXIS, pivot);
//model.appendRotation(.5, Vector3D.Y_AXIS, pivot);
//model.appendRotation(.5, Vector3D.X_AXIS, pivot);
//Combine transforms
finalTransform.identity();
finalTransform.append(model);
finalTransform.append(view);
finalTransform.append(projection);
//Pass the final transform to the vertex shader as program constant, vc0
renderContext.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, finalTransform, true);
//Clear is required before drawTriangles on each frame
renderContext.clear(.3, .3, .3);
//Draw the 12 triangles that make up the cube
renderContext.drawTriangles(indexList, 0, 12);
//Show the frame
renderContext.present();
}
private function contextCreationError(e:ErrorEvent):void
{
trace(e.errorID + ": " + e.text);
}
private function mouseMove(e:MouseEvent):void
{
if (e.buttonDown)
{
model.appendRotation((e.localX - lastPosition.x), Vector3D.Y_AXIS, pivot);
model.appendRotation((e.localY - lastPosition.y), Vector3D.X_AXIS, pivot);
}
lastPosition.x = e.localX;
lastPosition.y = e.localY;
}
private function keyDown(e:KeyboardEvent):void
{
var x:Number = 0;
var z:Number = 0;
switch (e.keyCode)
{
case Keyboard.W: z = 0.1; break;
case Keyboard.S: z = -0.1; break;
case Keyboard.A: x = -0.1; break;
case Keyboard.D: x = 0.1; break;
default: return;
}
view.appendTranslation(x, 0, z);
}
}
}