PageRenderTime 243ms CodeModel.GetById 120ms app.highlight 7ms RepoModel.GetById 114ms app.codeStats 0ms

/src/away3d/core/partition/Partition3D.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 142 lines | 82 code | 26 blank | 34 comment | 18 complexity | 1843073b06ae3de3c591f20c63d01c3b MD5 | raw file
  1package away3d.core.partition
  2{
  3	import away3d.arcane;
  4	import away3d.core.traverse.PartitionTraverser;
  5	import away3d.entities.Entity;
  6	
  7	use namespace arcane;
  8	
  9	/**
 10	 * Partition3D is the core of a space partition system. The space partition system typically subdivides the 3D scene
 11	 * hierarchically into a number of non-overlapping subspaces, forming a tree data structure. This is used to more
 12	 * efficiently perform frustum culling, potential visibility determination and collision detection.
 13	 */
 14	public class Partition3D
 15	{
 16		protected var _rootNode:NodeBase;
 17		private var _updatesMade:Boolean;
 18		private var _updateQueue:EntityNode;
 19		
 20		/**
 21		 * Creates a new Partition3D object.
 22		 * @param rootNode The root node of the space partition system. This will indicate which type of data structure will be used.
 23		 */
 24		public function Partition3D(rootNode:NodeBase)
 25		{
 26			_rootNode = rootNode || new NullNode();
 27		}
 28		
 29		public function get showDebugBounds():Boolean
 30		{
 31			return _rootNode.showDebugBounds;
 32		}
 33		
 34		public function set showDebugBounds(value:Boolean):void
 35		{
 36			_rootNode.showDebugBounds = value;
 37		}
 38		
 39		/**
 40		 * Sends a traverser through the partition tree.
 41		 * @param traverser
 42		 *
 43		 * @see away3d.core.traverse.PartitionTraverser
 44		 */
 45		public function traverse(traverser:PartitionTraverser):void
 46		{
 47			if (_updatesMade)
 48				updateEntities();
 49			
 50			++PartitionTraverser._collectionMark;
 51			
 52			_rootNode.acceptTraverser(traverser);
 53		}
 54		
 55		/**
 56		 * Mark a scene graph entity for updating. This will trigger a reassignment within the tree, based on the
 57		 * object's bounding box, upon the next traversal.
 58		 * @param entity The entity to be updated in the tree.
 59		 */
 60		arcane function markForUpdate(entity:Entity):void
 61		{
 62			var node:EntityNode = entity.getEntityPartitionNode();
 63			// already marked to be updated
 64			var t:EntityNode = _updateQueue;
 65			
 66			// if already marked for update
 67			while (t) {
 68				if (node == t)
 69					return;
 70				
 71				t = t._updateQueueNext;
 72			}
 73			
 74			node._updateQueueNext = _updateQueue;
 75			
 76			_updateQueue = node;
 77			_updatesMade = true;
 78		}
 79		
 80		/**
 81		 * Removes an entity from the partition tree.
 82		 * @param entity The entity to be removed.
 83		 */
 84		arcane function removeEntity(entity:Entity):void
 85		{
 86			var node:EntityNode = entity.getEntityPartitionNode();
 87			var t:EntityNode;
 88			
 89			node.removeFromParent();
 90			
 91			// remove from update list if it's in
 92			if (node == _updateQueue)
 93				_updateQueue = node._updateQueueNext;
 94			else {
 95				t = _updateQueue;
 96				while (t && t._updateQueueNext != node)
 97					t = t._updateQueueNext;
 98				if (t)
 99					t._updateQueueNext = node._updateQueueNext;
100			}
101			
102			node._updateQueueNext = null;
103			
104			// any updates have been made undone
105			if (!_updateQueue)
106				_updatesMade = false;
107		}
108		
109		/**
110		 * Updates all entities that were marked for update.
111		 */
112		private function updateEntities():void
113		{
114			var node:EntityNode = _updateQueue;
115			var targetNode:NodeBase;
116			var t:EntityNode;
117			
118			// clear updateQueue early to allow for newly marked entity updates
119			_updateQueue = null;
120			_updatesMade = false;
121			
122			do {
123				targetNode = _rootNode.findPartitionForEntity(node.entity);
124				
125				// if changed, find and attach the mesh node to the best suited partition node
126				if (node.parent != targetNode) {
127					if (node)
128						node.removeFromParent();
129					
130					targetNode.addNode(node);
131				}
132				
133				t = node._updateQueueNext;
134				node._updateQueueNext = null;
135				
136				//call an internal update on the entity to fire any attached logic
137				node.entity.internalUpdate();
138				
139			} while ((node = t) != null);
140		}
141	}
142}