CircleSortWorld
/**
* Copyright Glidias ( http://wonderfl.net/user/Glidias )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/hzQI
*/
package {
import alternativ7.engine3d.containers.ConflictContainer;
import alternativ7.engine3d.containers.DistanceSortContainer;
import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Debug;
import alternativ7.engine3d.core.Object3D;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.core.Vertex;
import alternativ7.engine3d.core.View;
import alternativ7.engine3d.loaders.MaterialLoader;
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.materials.TextureMaterial;
import alternativ7.engine3d.objects.Mesh;
import flash.display.DisplayObject;
import flash.events.KeyboardEvent;
import flash.geom.Vector3D;
import flash.text.TextField;
import flash.ui.Keyboard;
import flash.system.LoaderContext;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import alternativ7.engine3d.alternativa3d;
use namespace alternativa3d;
/**
* Working with geometry.
*/
public class CircleSortWorld extends Sprite {
private var rootContainer:RadiusSortContainer = new RadiusSortContainer();
private var radiusSortContainer:RadiusSortContainer = rootContainer;
private var camera:Camera3D;
private var controller:SimpleObjectController;
private var materialLoader:MaterialLoader;
public function CircleSortWorld() {
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
// Camera and view
// Создание камеры и вьюпорта
camera = new Camera3D();
camera.view = new View(stage.stageWidth, stage.stageHeight);
addChild(camera.view);
addChild(camera.diagram);
// Initial position
// Установка начального положения камеры
camera.rotationX = -120*Math.PI/180;
camera.y = -400;
camera.z = 200;
controller = new SimpleObjectController(stage, camera, 500);
if (rootContainer != radiusSortContainer) rootContainer.addChild(radiusSortContainer);
// Debug mode
// Режим отладки
camera.addToDebug(Debug.EDGES, Object3D);
var child:Object3D;
var count:int = 0;
// Calculating of bounds
child = radiusSortContainer.addChild( new CircleObject(120, 15) ); //child.z = count++ * 40;
child = radiusSortContainer.addChild( new CircleObject(220, 30) ); // child.z = count++ * 40;
child = radiusSortContainer.addChild( new CircleObject(320, 45) ); //child.z = count++ * 40;
child = radiusSortContainer.addChild( new CircleObject(420, 60) ); // child.z = count++ * 40;
child = radiusSortContainer.addChild( new CircleObject(520, 75) ); // child.z = count++ * 40;
child = radiusSortContainer.addChild( new CircleObject(620, 100) );// child.z = count++ * 40;
child = radiusSortContainer.addChild( new CircleObject(720, 115) );// child.z = count++ * 40;
child = radiusSortContainer.addChild( new CircleObject(920, 130) ); //child.z = count++ * 40;
child = radiusSortContainer.addChild( new CircleObject(1020, 145) );//child.z = count++ * 40;
child = radiusSortContainer.addChild( new CircleObject(1220, 165) );// child.z = count++ * 40;
child = radiusSortContainer.addChild( new CircleObject(1320, 185) ); //child.z = count++ * 40;
child = radiusSortContainer.addChild( new CircleObject(1420, 195) );//child.z = count++ * 40;
// throw new Error(CircleObject.COUNT);
rootContainer.addChild(camera);
camera.visible = false;
// Listeners
// Подписка на события
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(Event.RESIZE, onResize);
//stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
materialLoader = new MaterialLoader();
materialLoader.load( new <TextureMaterial>[Cuber.TEXTURE_MATERIAL], new LoaderContext(true));
}
private function onEnterFrame(e:Event):void {
for (var child:Object3D = radiusSortContainer.childrenList; child != null; child = child.next) {
var circleObj:CircleObject = (child as CircleObject);
if (circleObj == null) continue;
circleObj.rotationZ += circleObj.ang_speed;
}
controller.update();
camera.render();
}
private function onKeyDown(e:KeyboardEvent):void {
if (e.keyCode == Keyboard.TAB) {
camera.debug = !camera.debug;
}
}
private function onResize(e:Event = null):void {
// Width and height of view
// Установка ширины и высоты вьюпорта
camera.view.width = stage.stageWidth;
camera.view.height = stage.stageHeight;
}
}
}
//package circlesortexample
//{
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Canvas;
import alternativ7.engine3d.core.Object3D;
import alternativ7.engine3d.alternativa3d;
use namespace alternativa3d;
/**
* Back-buffer for back-facing rings segments
* @author Glenn Ko
*/
//public
class BackBuffer implements IBackDraw
{
public var backArcList:Vector.<IBackDraw> = new Vector.<IBackDraw>();
public var numBackChildren:int = 0;
public function set backBufferLen(amt:int):void {
backArcList.fixed = false;
backArcList.length = amt;
backArcList.fixed = true;
}
public function get backBufferLen():int {
return backArcList.length;
}
private static var INSTANCE:BackBuffer;
public static function getInstance():BackBuffer {
return INSTANCE || (INSTANCE = new BackBuffer() );
}
public function BackBuffer()
{
}
public function flush(camera:Camera3D):void {
// Draw back-facing ring segments in reverse order
var i:int = numBackChildren;
while (--i > -1) {
backArcList[i].flush(camera);
backArcList[i] = null;
}
numBackChildren = 0;
}
}
//}
//package circlesortexample
//{
import alternativ7.engine3d.core.Camera3D;
/**
* Back buffer being held for each circle for drawing each back-ringed item.
* @author Glenn Ko
*/
//public
class BackBuffer2 implements IBackDraw
{
public var backArcList:Vector.<IBackDraw> = new Vector.<IBackDraw>();
public var numBackChildren:int = 0;
public function set backBufferLen(amt:int):void {
backArcList.fixed = false;
backArcList.length = amt;
backArcList.fixed = true;
}
public function get backBufferLen():int {
return backArcList.length;
}
public function BackBuffer2()
{
}
/* INTERFACE circlesortexample.IBackDraw */
// Does drawing of each individual item within each back-ring segment
public function flush(camera:Camera3D):void {
// Draw items in order as they were checked in
for (var i:int = 0; i < numBackChildren; i++) {
backArcList[i].flush(camera);
backArcList[i] = null;
}
numBackChildren = 0;
}
}
//}
//package circlesortexample
//{
import alternativ7.engine3d.containers.BSPContainer;
import alternativ7.engine3d.containers.ConflictContainer;
import alternativ7.engine3d.containers.KDContainer;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Canvas;
import alternativ7.engine3d.core.Object3D;
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.objects.Mesh;
import alternativ7.engine3d.primitives.Box;
import alternativ7.engine3d.alternativa3d;
use namespace alternativa3d;
/**
* This is a circle ring container
* @author Glenn Ko
*/
//public
class CircleObject extends KDContainer
{
public var _radius:Number;
public var ang_speed:Number;
public static var COUNT:int = 0;
private var _rootBackBuffer:BackBuffer = BackBuffer.getInstance();
public var _backBuffer:BackBuffer2 = new BackBuffer2();
public function CircleObject(radius:Number, numItems:int =64 )
{
this.distance = radius;
this._radius = radius;
COUNT += numItems;
ang_speed = -.005 + Math.random() * .005;
var meshes:Vector.<Object3D> = new Vector.<Object3D>(numItems, true);
// fixed length buffer setting. (adjust this if required to best fit).
_backBuffer.backBufferLen = numItems;
var degToRad:Number = 180 / Math.PI;
var angInc:Number =Math.PI * 2 / numItems;
var ang:Number = 0;
for (var i:int = 0; i < numItems; i++) {
var cube:Cuber = new Cuber(16, 16, 16, 1, 1, 1);
cube.parentCircle = this; // tight coupling
cube.x = Math.cos( ang ) * radius;
cube.y = Math.sin( ang ) * radius;
cube.rotationZ = ang;
meshes[i] = cube;
ang += angInc;
}
createTree(meshes, null);
}
override alternativa3d function draw(camera:Camera3D, parentCanvas:Canvas):void {
super.draw(camera, parentCanvas);
if (_backBuffer.numBackChildren > 0) {
_rootBackBuffer.backArcList[_rootBackBuffer.numBackChildren++] = _backBuffer;
}
}
}
//}
//package circlesortexample
//{
import alternativ7.engine3d.containers.LODContainer;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Canvas;
import alternativ7.engine3d.core.Face;
import alternativ7.engine3d.core.MipMapping;
import alternativ7.engine3d.core.VG;
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.materials.Material;
import alternativ7.engine3d.materials.TextureMaterial;
import alternativ7.engine3d.objects.Sprite3D;
import alternativ7.engine3d.primitives.Box;
import alternativ7.engine3d.alternativa3d;
use namespace alternativa3d;
/**
* Lod container of each circle ring item.
* @author Glenn Ko
*/
//public
class Cuber extends LODContainer implements IBackDraw
{
public var outerFace:Face;
public var innerFace:Face;
public var inInnerRing:Boolean;
public var parentCircle:CircleObject;
public static const TEXTURE_MATERIAL:TextureMaterial = createNewTextureMaterial();
private static function createNewTextureMaterial():TextureMaterial {
var mat:TextureMaterial = new TextureMaterial( null, false, false);
mat.diffuseMapURL = "http://glidias.freehostia.com/texture.jpg";
mat.mipMapping = MipMapping.OBJECT_DISTANCE;
return mat;
}
/*
private static var RANDOM_MATERIALS:Vector.<FillMaterial> = new <FillMaterial>[
new FillMaterial(Math.random() * 0xFFFFFF),
new FillMaterial(Math.random() * 0xFFFFFF),
new FillMaterial(Math.random() * 0xFFFFFF),
new FillMaterial(Math.random() * 0xFFFFFF),
new FillMaterial(Math.random() * 0xFFFFFF),
new FillMaterial(Math.random() * 0xFFFFFF),
new FillMaterial(Math.random() * 0xFFFFFF),
new FillMaterial(Math.random() * 0xFFFFFF),
new FillMaterial(Math.random() * 0xFFFFFF),
new FillMaterial(Math.random() * 0xFFFFFF)
];
private static function getRandomColorMaterial():FillMaterial {
return RANDOM_MATERIALS[int(Math.random() * RANDOM_MATERIALS.length)]
}
*/
private static const DEBUG_MATERIAL:FillMaterial = new FillMaterial(0xFF0000, 1, 1);
private var _backBuffer:BackBuffer = BackBuffer.getInstance();
public function Cuber(width:Number = 100, length:Number = 100, height:Number = 100, widthSegments:uint = 1, lengthSegments:uint = 1, heightSegments:uint = 1, reverse:Boolean = false, triangulate:Boolean = false, left:Material = null, right:Material = null, back:Material = null, front:Material = null, bottom:Material = null, top:Material = null)
{
//super(width, length, height, widthSegments, lengthSegments, heightSegments, reverse, triangulate, left, right, back, front, bottom, top);
//sorting = 0;
//weldVertices(0, 1);
var mat:Material = TEXTURE_MATERIAL;// getRandomColorMaterial(); /* 0xFFFFFF, 1) ;
var box:Box = new CuberBox(width, length, height, widthSegments, lengthSegments, heightSegments, reverse, triangulate, left, right, back, front, bottom, top);
box.sorting = 0;
box.setMaterialToAllFaces( mat);
if (mat is FillMaterial) box.weldVertices(0, 1);
outerFace = box.faceList;
//outerFace.material = DEBUG_MATERIAL;
innerFace = box.faceList.next;
//innerFace.material = DEBUG_MATERIAL
addLOD( box, 800);
var spr:Sprite3D = new Sprite3D(width + 2, height + 2, mat) ;
//spr.useHandCursor = true;
addLOD(spr, 6600);
}
override alternativa3d function calculateInverseMatrix():void {
// do nothing, already precalculated.
}
override alternativa3d function draw(camera:Camera3D, parentCanvas:Canvas):void {
super.calculateInverseMatrix();
var testInner:Boolean = RadiusSortContainer.ROOT_DRAW === RadiusSortContainer.ROOT_INNER;
inInnerRing = testInner;
var testFace:Face = testInner ? innerFace : outerFace;
///*
if (imd * testFace.normalX + imh * testFace.normalY + iml * testFace.normalZ > testFace.offset) {
parentCanvas = testInner ? RadiusSortContainer.ROOT_INNER_INNER : RadiusSortContainer.ROOT_OUTER_OUTER;
super.draw(camera, parentCanvas);
}
else {
var bb:BackBuffer2 = parentCircle._backBuffer;
bb.backArcList[bb.numBackChildren++] = this;
}
}
public function flush(camera:Camera3D):void {
super.draw( camera, inInnerRing ? RadiusSortContainer.ROOT_INNER_OUTER : RadiusSortContainer.ROOT_OUTER_INNER ) // back-face negative ^
}
override alternativa3d function getVG(camera:Camera3D):VG {
super.calculateInverseMatrix();
var testInner:Boolean = RadiusSortContainer.ROOT_DRAW === RadiusSortContainer.ROOT_INNER;
inInnerRing = testInner;
var testFace:Face = testInner ? innerFace : outerFace;
if (imd * testFace.normalX + imh * testFace.normalY + iml * testFace.normalZ > testFace.offset) {
super.draw(camera, testInner ? RadiusSortContainer.ROOT_INNER_INNER : RadiusSortContainer.ROOT_OUTER_OUTER);
}
else {
var bb:BackBuffer2 = parentCircle._backBuffer;
bb.backArcList[bb.numBackChildren++] = this;
}
return null;
return super.getVG(camera);
}
}
//}
//package circlesortexample
//{
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Canvas;
import alternativ7.engine3d.core.Face;
import alternativ7.engine3d.core.Vertex;
import alternativ7.engine3d.materials.Material;
import alternativ7.engine3d.primitives.Box;
import alternativ7.engine3d.alternativa3d;
use namespace alternativa3d;
/**
* ...
* @author Glenn Ko
*/
//public
class CuberBox extends Box
{
public function CuberBox(width:Number = 100, length:Number = 100, height:Number = 100, widthSegments:uint = 1, lengthSegments:uint = 1, heightSegments:uint = 1, reverse:Boolean = false, triangulate:Boolean = false, left:Material = null, right:Material = null, back:Material = null, front:Material = null, bottom:Material = null, top:Material = null)
{
super(width, length, height, widthSegments, lengthSegments, heightSegments, reverse, triangulate, left, right, back, front, bottom, top);
}
// Note: using the below method override only works in render loop assumption,
// and may screw up off-render localToGlobal/globalToLocal implementations!
///*
override alternativa3d function composeMatrix():void {
ma = _parent.ma;
mb = _parent.mb;
mc = _parent.mc;
md = _parent.md;
me = _parent.me;
mf = _parent.mf;
mg = _parent.mg;
mh = _parent.mh;
mi = _parent.mi;
mj = _parent.mj;
mk = _parent.mk;
ml = _parent.ml;
}
//*/
override alternativa3d function draw(camera:Camera3D, parentCanvas:Canvas):void {
// copy inverse matrix from Cuber parent since it's the same
imd = _parent.imd;
imh = _parent.imh;
iml = _parent.iml;
ima = _parent.ima;
imb = _parent.imb;
imc = _parent.imc;
ime = _parent.ime;
imf = _parent.imf;
img = _parent.img;
imi = _parent.imi;
imj = _parent.imj;
imk = _parent.imk;
transformId++;
var list:Face = prepareFaces(camera);
if (list == null) return;
if (culling > 0) {
list = camera.cull(list, culling);
if (list == null) return;
}
drawFaces(camera, parentCanvas.getChildCanvas(true, false), list);
}
}
//}
//package circlesortexample
//{
import alternativ7.engine3d.core.Camera3D;
/**
* Draw payload for backbuffer. A backbuffer implements IBackDraw as well and can be composited
* to parent backbuffers.
* @author Glenn Ko
*/
//public
interface IBackDraw
{
function flush(camera:Camera3D):void;
}
//}
//package circlesortexample
//{
import alternativ7.engine3d.alternativa3d;
import alternativ7.engine3d.containers.DistanceSortContainer;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Canvas;
import alternativ7.engine3d.core.Object3D;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.alternativa3d;
use namespace alternativa3d;
/**
* Uses "distance" value of any added child as a way of determining it's radial offset from container's
* center origin. Currently, we just assume the added children is already added in the order
* of distance from the center. Consider todo: pre-sorting and insertion sort methods.
*
* Objects are sorted from the nearest radial offset from camera's radial offsets, with various
* public canvas buffers for "back/front-facing" vs outer/inner objects that can be accessed as static vars
* to perform rendering to specific back-buffer canvases.
*
* @author Glenn Ko
*/
//public
class RadiusSortContainer extends Object3DContainer
{
private var _backBuffer:BackBuffer = BackBuffer.getInstance();
// precomputed depth order of canvas layers
public static var ROOT_OUTER:Canvas; // convex ring canvas
public static var ROOT_INNER:Canvas; // concave ring canvas
// for concave ring
public static var ROOT_INNER_INNER:Canvas;
public static var ROOT_INNER_OUTER:Canvas; // back buffer canvas
// for convex ring
public static var ROOT_OUTER_OUTER:Canvas;
public static var ROOT_OUTER_INNER:Canvas; // back buffer canvas
public static var ROOT_DRAW:Canvas;
public function RadiusSortContainer()
{
}
override alternativa3d function draw(camera:Camera3D, parentCanvas:Canvas ):void {
// Set up layers for inner children
ROOT_OUTER = parentCanvas.getChildCanvas(false, false);
ROOT_INNER = parentCanvas.getChildCanvas(false, false);
ROOT_INNER_INNER = ROOT_INNER.getChildCanvas(false, false);
ROOT_INNER_OUTER = ROOT_INNER.getChildCanvas(false, false);
ROOT_OUTER_OUTER = ROOT_OUTER.getChildCanvas(false, false);
ROOT_OUTER_INNER = ROOT_OUTER.getChildCanvas(false, false);
super.draw(camera, parentCanvas);
_backBuffer.flush(camera);
}
override alternativa3d function drawVisibleChildren(camera:Camera3D, canvas:Canvas):void {
// Camera radius 'd' calculation assumes camera and RadiusSortContainer is in same coordinate space,
// and container has no local rotation applied. (Consider:: more accruate calculation..)
var nx:Number = camera.x - x;
var ny:Number = camera.y - y;
var nz:Number = camera.z - z;
var d:Number = Math.sqrt( nx * nx + ny * ny + nz * nz );
camera.distance = d;
// This approach assumes all objects are pre-sorted from smallest radial distance to furthest.
var child:Object3D;
var i:int;
var c:int;
var rootDraw:Canvas;
// Find middle point (this linear search is incredibly dumb and should be improved...).
for ( i = 0; i < numVisibleChildren; i++ ) {
child = visibleChildren[i];
if (child.distance > d) break;
}
// Draw inner concave faces to inner canvas
rootDraw = ROOT_INNER;
ROOT_DRAW = rootDraw;
for ( c = i; c < numVisibleChildren; c++ ) {
child = visibleChildren[c];
child.draw(camera, rootDraw); // draw this as a inner face
}
// Draw outer convex faces to outer canvas
rootDraw = ROOT_OUTER;
ROOT_DRAW = rootDraw;
c = i;
while (--c > -1) {
child = visibleChildren[c];
child.draw(camera, rootDraw); // draw this as a outer face
}
}
}
//}