PageRenderTime 793ms CodeModel.GetById 170ms app.highlight 141ms RepoModel.GetById 422ms app.codeStats 0ms

/src/away3d/core/partition/OctreeNode.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 157 lines | 137 code | 18 blank | 2 comment | 20 complexity | 5283bacba07b0c51cc8735d1d91bf68f MD5 | raw file
  1package away3d.core.partition
  2{
  3	import away3d.arcane;
  4	import away3d.bounds.BoundingVolumeBase;
  5	import away3d.core.math.Plane3D;
  6	import away3d.entities.Entity;
  7	import away3d.primitives.WireframeCube;
  8	import away3d.primitives.WireframePrimitiveBase;
  9	
 10	import flash.geom.Vector3D;
 11	
 12	use namespace arcane;
 13	
 14	public class OctreeNode extends NodeBase
 15	{
 16		private var _centerX:Number;
 17		private var _centerY:Number;
 18		private var _centerZ:Number;
 19		private var _minX:Number;
 20		private var _minY:Number;
 21		private var _minZ:Number;
 22		private var _maxX:Number;
 23		private var _maxY:Number;
 24		private var _maxZ:Number;
 25		private var _quadSize:Number;
 26		private var _depth:Number;
 27		private var _leaf:Boolean;
 28		
 29		private var _rightTopFar:OctreeNode;
 30		private var _leftTopFar:OctreeNode;
 31		private var _rightBottomFar:OctreeNode;
 32		private var _leftBottomFar:OctreeNode;
 33		private var _rightTopNear:OctreeNode;
 34		private var _leftTopNear:OctreeNode;
 35		private var _rightBottomNear:OctreeNode;
 36		private var _leftBottomNear:OctreeNode;
 37		
 38		//private var _entityWorldBounds : Vector.<Number> = new Vector.<Number>();
 39		private var _halfExtent:Number;
 40		
 41		public function OctreeNode(maxDepth:int = 5, size:Number = 10000, centerX:Number = 0, centerY:Number = 0, centerZ:Number = 0, depth:int = 0)
 42		{
 43			init(size, centerX, centerY, centerZ, depth, maxDepth);
 44		}
 45		
 46		private function init(size:Number, centerX:Number, centerY:Number, centerZ:Number, depth:int, maxDepth:int):void
 47		{
 48			_halfExtent = size*.5;
 49			_centerX = centerX;
 50			_centerY = centerY;
 51			_centerZ = centerZ;
 52			_quadSize = size;
 53			_depth = depth;
 54			_minX = centerX - _halfExtent;
 55			_minY = centerY - _halfExtent;
 56			_minZ = centerZ - _halfExtent;
 57			_maxX = centerX + _halfExtent;
 58			_maxY = centerY + _halfExtent;
 59			_maxZ = centerZ + _halfExtent;
 60			
 61			_leaf = depth == maxDepth;
 62			
 63			if (!_leaf) {
 64				var hhs:Number = _halfExtent*.5;
 65				addNode(_leftTopNear = new OctreeNode(maxDepth, _halfExtent, centerX - hhs, centerY + hhs, centerZ - hhs, depth + 1));
 66				addNode(_rightTopNear = new OctreeNode(maxDepth, _halfExtent, centerX + hhs, centerY + hhs, centerZ - hhs, depth + 1));
 67				addNode(_leftBottomNear = new OctreeNode(maxDepth, _halfExtent, centerX - hhs, centerY - hhs, centerZ - hhs, depth + 1));
 68				addNode(_rightBottomNear = new OctreeNode(maxDepth, _halfExtent, centerX + hhs, centerY - hhs, centerZ - hhs, depth + 1));
 69				addNode(_leftTopFar = new OctreeNode(maxDepth, _halfExtent, centerX - hhs, centerY + hhs, centerZ + hhs, depth + 1));
 70				addNode(_rightTopFar = new OctreeNode(maxDepth, _halfExtent, centerX + hhs, centerY + hhs, centerZ + hhs, depth + 1));
 71				addNode(_leftBottomFar = new OctreeNode(maxDepth, _halfExtent, centerX - hhs, centerY - hhs, centerZ + hhs, depth + 1));
 72				addNode(_rightBottomFar = new OctreeNode(maxDepth, _halfExtent, centerX + hhs, centerY - hhs, centerZ + hhs, depth + 1));
 73			}
 74		}
 75		
 76		override protected function createDebugBounds():WireframePrimitiveBase
 77		{
 78			var cube:WireframeCube = new WireframeCube(_quadSize, _quadSize, _quadSize);
 79			cube.x = _centerX;
 80			cube.y = _centerY;
 81			cube.z = _centerZ;
 82			return cube;
 83		}
 84		
 85		override public function isInFrustum(planes:Vector.<Plane3D>, numPlanes:int):Boolean
 86		{
 87			for (var i:uint = 0; i < numPlanes; ++i) {
 88				var plane:Plane3D = planes[i];
 89				var flippedExtentX:Number = plane.a < 0? -_halfExtent : _halfExtent;
 90				var flippedExtentY:Number = plane.b < 0? -_halfExtent : _halfExtent;
 91				var flippedExtentZ:Number = plane.c < 0? -_halfExtent : _halfExtent;
 92				var projDist:Number = plane.a*(_centerX + flippedExtentX) + plane.b*(_centerY + flippedExtentY) + plane.c*(_centerZ + flippedExtentZ) - plane.d;
 93				if (projDist < 0)
 94					return false;
 95			}
 96			
 97			return true;
 98		}
 99		
100		override public function findPartitionForEntity(entity:Entity):NodeBase
101		{
102			var bounds:BoundingVolumeBase = entity.worldBounds;
103			var min:Vector3D = bounds.min;
104			var max:Vector3D = bounds.max;
105			return findPartitionForBounds(min.x, min.y, min.z, max.x, max.y, max.z);
106		}
107		
108		// TODO: this can be done quicker through inversion
109		private function findPartitionForBounds(minX:Number, minY:Number, minZ:Number, maxX:Number, maxY:Number, maxZ:Number):OctreeNode
110		{
111			var left:Boolean, right:Boolean;
112			var far:Boolean, near:Boolean;
113			var top:Boolean, bottom:Boolean;
114			
115			if (_leaf)
116				return this;
117			
118			right = maxX > _centerX;
119			left = minX < _centerX;
120			top = maxY > _centerY;
121			bottom = minY < _centerY;
122			far = maxZ > _centerZ;
123			near = minZ < _centerZ;
124			
125			if ((left && right) || (far && near))
126				return this;
127			
128			if (top) {
129				if (bottom)
130					return this;
131				if (near) {
132					if (left)
133						return _leftTopNear.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ);
134					else
135						return _rightTopNear.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ);
136				} else {
137					if (left)
138						return _leftTopFar.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ);
139					else
140						return _rightTopFar.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ);
141				}
142			} else {
143				if (near) {
144					if (left)
145						return _leftBottomNear.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ);
146					else
147						return _rightBottomNear.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ);
148				} else {
149					if (left)
150						return _leftBottomFar.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ);
151					else
152						return _rightBottomFar.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ);
153				}
154			}
155		}
156	}
157}