forked from: forked from: PapervisionMini3D
// forked from zerogravity's forked from: PapervisionMini3D
// forked from timknip's PapervisionMini3D
package {
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.display.TriangleCulling;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.Utils3D;
import flash.text.TextField;
import flash.text.TextFormat;
import net.hires.debug.Stats;
[SWF (width="640", height="480", backgroundColor="#000000", frameRate="60")]
public class PapervisionMini3D extends Sprite {
private var _container :Sprite;
private var _info :TextField;
private var _scene :SceneGraph3D;
private var _camera :Camera3D;
private var _cube :TriangleMesh3D;
private var _stats :Stats;
private var _modelingTransform :IRenderPipeProcessor;
private var _viewingTransform :IRenderPipeProcessor;
private var _renderSessionData :RenderSessionData;
public function PapervisionMini3D() {
super();
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.LOW;
_container = new Sprite();
addChild(_container);
_container.x = stage.stageWidth / 2;
_container.y = stage.stageHeight / 2;
_stats = new Stats();
addChild(_stats);
_info = new TextField();
addChild(_info);
_info.x = _info.y = 5;
_info.width = 400;
_info.height = 400;
_info.multiline = true;
_info.selectable = false;
_info.defaultTextFormat = new TextFormat("Arial", 12, 0xff000);
_info.text = "";
_modelingTransform = new ModelingTransform();
_viewingTransform = new ViewingTransform();
_renderSessionData = new RenderSessionData();
_scene = new SceneGraph3D();
_camera = new Camera3D(50, 1.333, 0.01, 500, "Camera01");
_camera.z = 30;
_cube = buildCube();
_scene.addChild(_camera);
_scene.addChild(_cube);
stage.addEventListener(Event.RESIZE, onStageResize);
addEventListener(Event.ENTER_FRAME, onRenderTick);
}
private function onRenderTick(e:Event=null):void {
renderScene();
_cube.rotationY += (Math.PI/180)*.2;
Utils3D.projectVectors(_cube.viewTransform, _cube.vertices,
_cube.screenVertices, _cube.uvtData);
_container.graphics.clear();
draw(_cube.screenVertices, _cube.indices, _cube.uvtData);
}
public function renderScene():void {
_renderSessionData.sceneGraph = _scene;
_renderSessionData.camera = _camera;
_modelingTransform.process(_renderSessionData);
_camera.update();
_renderSessionData.projection.rawData = _camera.worldTransform.rawData;
_renderSessionData.projection.invert();
_renderSessionData.projection.append(_camera.projection);
_viewingTransform.process(_renderSessionData);
}
private function draw(verts:Vector.<Number>, indices :Vector.<int>, uvt:Vector.<Number>):void {
var g :Graphics = _container.graphics;
g.lineStyle(0, 0xff0000);
g.drawTriangles(verts, indices, uvt, TriangleCulling.NEGATIVE);
g.endFill();
}
protected function onStageResize(e:Event=null):void {
_camera.aspect = stage.stageWidth / stage.stageHeight;
_container.x = stage.stageWidth / 2;
_container.y = stage.stageHeight / 2;
_stats.x = stage.stageWidth - _stats.width - 10;
_stats.y = 10;
}
private function buildCube(scale:Number=200):TriangleMesh3D {
var mesh :TriangleMesh3D = new TriangleMesh3D("cube");
mesh.vertices.push(-1 * scale, -1 * scale, 1 * scale);
mesh.vertices.push(1 * scale, -1 * scale, 1 * scale);
mesh.vertices.push(1 * scale, 1 * scale, 1 * scale);
mesh.vertices.push(-1 * scale, 1 * scale, 1 * scale);
mesh.vertices.push(-1 * scale, 1 * scale, -1 * scale);
mesh.vertices.push(-1 * scale, -1 * scale, -1 * scale);
mesh.vertices.push(-1 * scale, -1 * scale, 1 * scale);
mesh.vertices.push(-1 * scale, 1 * scale, 1 * scale);
mesh.screenVertices.push(0,0, 0,0, 0,0, 0,0);
mesh.screenVertices.push(0,0, 0,0, 0,0, 0,0);
mesh.uvtData.push(0,0,0, 0,0,0, 0,0,0, 0,0,0);
mesh.uvtData.push(0,0,0, 0,0,0, 0,0,0, 0,0,0);
mesh.indices = new Vector.<int>();
mesh.indices.push(0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7);
return mesh;
}
}
}
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;
internal class DisplayObjectContainer3D {
public var name :String;
public var children :Vector.<DisplayObjectContainer3D>;
public var parent :DisplayObjectContainer3D;
public function DisplayObjectContainer3D(name:String=null) {
this.name = name;
children = new Vector.<DisplayObjectContainer3D>();
}
public function addChild(child:DisplayObjectContainer3D):DisplayObjectContainer3D {
if(children.indexOf(child) == -1) {
children.push(child);
}
return child;
}
public function removeChild(child:DisplayObjectContainer3D):DisplayObjectContainer3D {
var idx :int = children.indexOf(child);
if(idx >= 0) {
child = children.splice(idx, 1)[0];
child.parent = null;
return child;
}
return null;
}
}
internal class DisplayObject3D extends DisplayObjectContainer3D {
public var localTransform :Matrix3D;
public var worldTransform :Matrix3D;
public var viewTransform :Matrix3D;
public var components :Vector.<Vector3D>;
private var _orientation :Vector3D;
private var _translation :Vector3D;
private var _scale :Vector3D;
public function DisplayObject3D(name:String=null) {
super(name);
localTransform = new Matrix3D();
worldTransform = new Matrix3D();
viewTransform = new Matrix3D();
_orientation = new Vector3D();
_translation = new Vector3D();
_scale = new Vector3D(1, 1, 1);
components = new Vector.<Vector3D>(3, true);
components[0] = _translation;
components[1] = _orientation;
components[2] = _scale;
}
public function set x(value:Number):void {
_translation.x = value;
}
public function get x():Number {
return _translation.x;
}
public function set y(value:Number):void {
_translation.y = value;
}
public function get y():Number {
return _translation.y;
}
public function set z(value:Number):void {
_translation.z = value;
}
public function get z():Number {
return _translation.z;
}
public function set rotationX(value:Number):void {
_orientation.x = value;
}
public function get rotationX():Number {
return _orientation.x;
}
public function set rotationY(value:Number):void {
_orientation.y = value;
}
public function get rotationY():Number {
return _orientation.y;
}
public function set rotationZ(value:Number):void {
_orientation.z = value;
}
public function get rotationZ():Number {
return _orientation.z;
}
public function updateTransform():void {
localTransform.recompose(components);
}
}
internal class Vertices3D extends DisplayObject3D {
public var vertices :Vector.<Number>;
public var viewVertices :Vector.<Number>;
public var screenVertices :Vector.<Number>;
public var uvtData :Vector.<Number>;
public var indices :Vector.<int>;
public function Vertices3D(name:String=null) {
super(name);
vertices = new Vector.<Number>();
viewVertices = new Vector.<Number>();
screenVertices = new Vector.<Number>();
uvtData = new Vector.<Number>();
}
}
internal class TriangleMesh3D extends Vertices3D {
public function TriangleMesh3D(name:String=null) {
super(name);
}
}
internal class SceneGraph3D extends DisplayObject3D {
}
internal class Camera3D extends DisplayObject3D {
public var projection :Matrix3D;
private var _fov :Number;
private var _aspect :Number;
private var _near :Number;
private var _far :Number;
private var _dirty :Boolean;
public function Camera3D(fov:Number=90, aspect:Number=1.333,
near:Number=1, far:Number=10000, name:String=null) {
super(name);
this.fov = fov;
this.aspect = aspect;
this.near = near;
this.far = far;
update();
}
public function set fov(value:Number):void {
if(value != _fov) {
_fov = value;
_dirty = true;
}
}
public function get fov():Number { return _fov; }
public function set aspect(value:Number):void {
if(_aspect != value) {
_aspect = value;
_dirty = true;
}
}
public function get aspect():Number { return _aspect; }
public function set near(value:Number):void {
if(_near != value) {
_near = value;
_dirty = true;
}
}
public function get near():Number { return _near; }
public function set far(value:Number):void {
if(_far != value) {
_far = value;
_dirty = true;
}
}
public function get far():Number { return _far; }
public function update():void {
if(_dirty) {
_dirty = false;
projection = init(_fov, _aspect, _near, _far);
}
}
private function init(fovy:Number=90, aspect:Number=1.333,
near:Number=1, far:Number = 10000):Matrix3D {
var fov2:Number = (fovy/2) * (Math.PI/180);
var tan:Number = Math.tan(fov2);
var f:Number = 1 / tan;
var v:Vector.<Number> = new Vector.<Number>(16, true);
v[0] = f / aspect;
v[1] = v[2] = v[3] = v[4] = 0;
v[5] = f;
v[6] = v[7] = v[8] = v[9] = v[12] = v[13] = v[15] = 0;
v[10] = (near+far) / (near-far);
v[11] = (2*far*near) / (near-far);
v[14] = -1;
return new Matrix3D(v);
}
}
internal class RenderSessionData {
public var sceneGraph :DisplayObject3D;
public var camera :Camera3D;
public var projection :Matrix3D;
public function RenderSessionData() {
projection = new Matrix3D();
}
}
internal interface IRenderPipeProcessor {
function process(renderSessionData:RenderSessionData):void;
}
internal class ModelingTransform implements IRenderPipeProcessor {
public function ModelingTransform() {}
public function process(renderSessionData:RenderSessionData):void {
transform(renderSessionData.sceneGraph);
}
private function transform(object:DisplayObject3D):void {
for each(var child:DisplayObject3D in object.children) {
child.updateTransform();
child.worldTransform.rawData = object.worldTransform.rawData;
child.worldTransform.append(child.localTransform);
transform(child);
}
}
}
internal class ViewingTransform implements IRenderPipeProcessor {
public function ViewingTransform() {}
public function process(renderSessionData:RenderSessionData):void {
transform(renderSessionData.sceneGraph, renderSessionData.projection);
}
private function transform(object:DisplayObject3D, projection:Matrix3D):void {
for each(var child:DisplayObject3D in object.children) {
child.viewTransform.rawData = child.worldTransform.rawData;
child.viewTransform.append(projection);
transform(child, projection);
}
}
}