package
{
import com.adobe.utils.*;
import flash.display.*;
import flash.display3D.*;
import flash.events.*;
import flash.geom.*;
import flash.text.*;
import flash.ui.Keyboard;
import mx.utils.StringUtil;
public class Main extends Sprite
{
[Embed(source="course1.png")]
private const CourseBitmap:Class;
private var bitmap:Bitmap = new CourseBitmap;
private var bitmapData:BitmapData = bitmap.bitmapData;
private var context3D:Context3D;
private var vertexBuffer:VertexBuffer3D;
private var indexBuffer:IndexBuffer3D;
private var projectionTransform:PerspectiveMatrix3D;
private var cameraWorldTransform:Matrix3D;
private var viewTransform:Matrix3D;
private var carVelocity:Vector3D = new Vector3D;
private var carAcceleration:Number = 0;
private var carRotation:Number = 0;
private var tf:TextField = new TextField;
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
stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
stage.stage3Ds[0].requestContext3D();
addEventListener(Event.ENTER_FRAME, onRender);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
tf.defaultTextFormat = new TextFormat(null, 20, 0x000000);
tf.autoSize = TextFieldAutoSize.LEFT;
addChild(tf);
}
private function onContext3DCreate(e:Event):void
{
context3D = stage.stage3Ds[0].context3D;
context3D.configureBackBuffer(800, 600, 2);
context3D.setCulling(Context3DTriangleFace.BACK);
const vertices:Vector.<Number> = Vector.<Number>([
// x, y, z, r, g, b,
0, 0, 0, 1, 1, 1,
1, 0, 0, 1, 1, 1,
1, 0, 1, 1, 1, 1,
0, 0, 1, 1, 1, 1,
0, 1, 0, 1, 1, 0,
1, 1, 0, 1, 1, 0,
1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 0,
]);
const indices:Vector.<uint> = Vector.<uint>([
0, 4, 5, 5, 1, 0,
1, 5, 6, 6, 2, 1,
2, 6, 7, 7, 3, 2,
3, 7, 4, 4, 0, 3,
]);
var vertexData:Vector.<Number> = new Vector.<Number>;
var indexData:Vector.<uint> = new Vector.<uint>;
var numVertices:int = 0;
for (var y:int = 0; y < 64; y++)
{
for (var x:int = 0; x < 64; x++)
{
var color:uint = bitmapData.getPixel(x, y);
if (color == 0) continue;
for (var i:int = 0; i < 8; i++)
{
var base:int = i * 6;
vertexData.push(vertices[base + 0] + x);
vertexData.push(vertices[base + 1]);
vertexData.push(vertices[base + 2] + y);
vertexData.push(vertices[base + 3]);
vertexData.push(vertices[base + 4]);
vertexData.push(vertices[base + 5]);
}
for (i = 0; i < indices.length; i++)
{
indexData.push(numVertices + indices[i]);
}
numVertices += 8;
}
}
// vertexBuffer
vertexBuffer = context3D.createVertexBuffer(numVertices, 6);
vertexBuffer.uploadFromVector(vertexData, 0, numVertices);
// indexBuffer
indexBuffer = context3D.createIndexBuffer(indexData.length);
indexBuffer.uploadFromVector(indexData, 0, indexData.length);
// program
var vertexProgram:AGALMiniAssembler = new AGALMiniAssembler;
vertexProgram.assemble(Context3DProgramType.VERTEX,
"m44 op va0 vc0\n" +
"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);
//
cameraWorldTransform = new Matrix3D;
cameraWorldTransform.appendTranslation(32, 0.2, 52);
cameraWorldTransform.appendRotation(90, Vector3D.Y_AXIS, cameraWorldTransform.position);
viewTransform = cameraWorldTransform.clone();
viewTransform.invert();
projectionTransform = new PerspectiveMatrix3D;
projectionTransform.perspectiveFieldOfViewLH(45 * Math.PI / 180, 800 / 600, 0.1, 50);
//
context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
context3D.setVertexBufferAt(1, vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_3);
context3D.setProgram(program);
}
private function onRender(e:Event):void
{
if (!context3D) return;
context3D.clear(0.39, 0.58, 0.93);
updateViewMatrix();
var m:Matrix3D = new Matrix3D;
m.append(viewTransform);
m.append(projectionTransform);
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);
context3D.drawTriangles(indexBuffer);
context3D.present();
tf.text = StringUtil.substitute(
"Velocity:{0}",
carVelocity.z.toFixed(3));
}
private function updateViewMatrix():void
{
carVelocity.z = calculateUpdateVelocity(carVelocity.z, carAcceleration, 1);
var degrees:Number = carRotation * (carVelocity.z == 0 ? 3 : 1);
cameraWorldTransform.appendRotation(
degrees, Vector3D.Y_AXIS, cameraWorldTransform.position);
var pos:Vector3D = cameraWorldTransform.transformVector(carVelocity);
var color:uint = bitmapData.getPixel(pos.x, pos.z);
if (color == 0)
{
cameraWorldTransform.position = pos;
}
else
{
carVelocity.z = 0;
carAcceleration = 0;
}
viewTransform.copyFrom(cameraWorldTransform);
viewTransform.invert();
}
private function calculateUpdateVelocity(
curVelocity:Number, curAcceleration:Number, maxVelocity:Number):Number
{
var newVelocity:Number = curVelocity + curAcceleration;
if (maxVelocity < newVelocity) return maxVelocity;
if (newVelocity < 0) return 0;
return newVelocity;
}
private function onKeyDown(e:KeyboardEvent):void
{
switch (e.keyCode)
{
case Keyboard.Z:
carAcceleration = -0.003;
break;
case Keyboard.X:
carAcceleration = 0.001;
break;
case Keyboard.LEFT:
carRotation = -1;
break;
case Keyboard.RIGHT:
carRotation = 1;
break;
}
}
private function onKeyUp(e:KeyboardEvent):void
{
switch (e.keyCode)
{
case Keyboard.Z:
case Keyboard.X:
carAcceleration = 0;
break;
case Keyboard.LEFT:
case Keyboard.RIGHT:
carRotation = 0;
break;
}
}
}
}