/src/away3d/entities/Entity.as

http://github.com/away3d/away3d-core-fp11 · ActionScript · 440 lines · 268 code · 67 blank · 105 comment · 37 complexity · 59074dd68783e1167907e71eb2769be5 MD5 · raw file

  1. package away3d.entities
  2. {
  3. import away3d.arcane;
  4. import away3d.bounds.*;
  5. import away3d.containers.*;
  6. import away3d.core.math.Matrix3DUtils;
  7. import away3d.core.partition.*;
  8. import away3d.core.pick.*;
  9. import away3d.errors.*;
  10. import away3d.library.assets.*;
  11. import flash.geom.*;
  12. use namespace arcane;
  13. /**
  14. * The Entity class provides an abstract base class for all scene graph objects that are considered having a
  15. * "presence" in the scene, in the sense that it can be considered an actual object with a position and a size (even
  16. * if infinite or idealised), rather than a grouping.
  17. * Entities can be partitioned in a space partitioning system and in turn collected by an EntityCollector.
  18. *
  19. * @see away3d.partition.Partition3D
  20. * @see away3d.core.traverse.EntityCollector
  21. */
  22. public class Entity extends ObjectContainer3D
  23. {
  24. private var _showBounds:Boolean;
  25. private var _partitionNode:EntityNode;
  26. private var _boundsIsShown:Boolean = false;
  27. private var _shaderPickingDetails:Boolean;
  28. arcane var _pickingCollisionVO:PickingCollisionVO;
  29. arcane var _pickingCollider:IPickingCollider;
  30. arcane var _staticNode:Boolean;
  31. protected var _bounds:BoundingVolumeBase;
  32. protected var _boundsInvalid:Boolean = true;
  33. private var _worldBounds:BoundingVolumeBase;
  34. private var _worldBoundsInvalid:Boolean = true;
  35. override public function set ignoreTransform(value:Boolean):void
  36. {
  37. if (_scene)
  38. _scene.invalidateEntityBounds(this);
  39. super.ignoreTransform = value;
  40. }
  41. /**
  42. * Used by the shader-based picking system to determine whether a separate render pass is made in order
  43. * to offer more details for the picking collision object, including local position, normal vector and uv value.
  44. * Defaults to false.
  45. *
  46. * @see away3d.core.pick.ShaderPicker
  47. */
  48. public function get shaderPickingDetails():Boolean
  49. {
  50. return _shaderPickingDetails;
  51. }
  52. public function set shaderPickingDetails(value:Boolean):void
  53. {
  54. _shaderPickingDetails = value;
  55. }
  56. /**
  57. * Defines whether or not the object will be moved or animated at runtime. This property is used by some partitioning systems to improve performance.
  58. * Warning: if set to true, they may not be processed by certain partition systems using static visibility lists, unless they're specifically assigned to the visibility list.
  59. */
  60. public function get staticNode():Boolean
  61. {
  62. return _staticNode;
  63. }
  64. public function set staticNode(value:Boolean):void
  65. {
  66. _staticNode = value;
  67. }
  68. /**
  69. * Returns a unique picking collision value object for the entity.
  70. */
  71. public function get pickingCollisionVO():PickingCollisionVO
  72. {
  73. if (!_pickingCollisionVO)
  74. _pickingCollisionVO = new PickingCollisionVO(this);
  75. return _pickingCollisionVO;
  76. }
  77. /**
  78. * Tests if a collision occurs before shortestCollisionDistance, using the data stored in PickingCollisionVO.
  79. * @param shortestCollisionDistance
  80. * @return
  81. */
  82. arcane function collidesBefore(shortestCollisionDistance:Number, findClosest:Boolean):Boolean
  83. {
  84. shortestCollisionDistance = shortestCollisionDistance;
  85. findClosest = findClosest;
  86. return true;
  87. }
  88. /**
  89. *
  90. */
  91. public function get showBounds():Boolean
  92. {
  93. return _showBounds;
  94. }
  95. public function set showBounds(value:Boolean):void
  96. {
  97. if (value == _showBounds)
  98. return;
  99. _showBounds = value;
  100. if (_showBounds)
  101. addBounds();
  102. else
  103. removeBounds();
  104. }
  105. /**
  106. * @inheritDoc
  107. */
  108. override public function get minX():Number
  109. {
  110. if (_boundsInvalid)
  111. updateBounds();
  112. return _bounds.min.x;
  113. }
  114. /**
  115. * @inheritDoc
  116. */
  117. override public function get minY():Number
  118. {
  119. if (_boundsInvalid)
  120. updateBounds();
  121. return _bounds.min.y;
  122. }
  123. /**
  124. * @inheritDoc
  125. */
  126. override public function get minZ():Number
  127. {
  128. if (_boundsInvalid)
  129. updateBounds();
  130. return _bounds.min.z;
  131. }
  132. /**
  133. * @inheritDoc
  134. */
  135. override public function get maxX():Number
  136. {
  137. if (_boundsInvalid)
  138. updateBounds();
  139. return _bounds.max.x;
  140. }
  141. /**
  142. * @inheritDoc
  143. */
  144. override public function get maxY():Number
  145. {
  146. if (_boundsInvalid)
  147. updateBounds();
  148. return _bounds.max.y;
  149. }
  150. /**
  151. * @inheritDoc
  152. */
  153. override public function get maxZ():Number
  154. {
  155. if (_boundsInvalid)
  156. updateBounds();
  157. return _bounds.max.z;
  158. }
  159. /**
  160. * The bounding volume approximating the volume occupied by the Entity.
  161. */
  162. public function get bounds():BoundingVolumeBase
  163. {
  164. if (_boundsInvalid)
  165. updateBounds();
  166. return _bounds;
  167. }
  168. public function set bounds(value:BoundingVolumeBase):void
  169. {
  170. removeBounds();
  171. _bounds = value;
  172. _worldBounds = value.clone();
  173. invalidateBounds();
  174. if (_showBounds)
  175. addBounds();
  176. }
  177. public function get worldBounds():BoundingVolumeBase
  178. {
  179. if (_worldBoundsInvalid)
  180. updateWorldBounds();
  181. return _worldBounds;
  182. }
  183. private function updateWorldBounds():void
  184. {
  185. _worldBounds.transformFrom(bounds, sceneTransform);
  186. _worldBoundsInvalid = false;
  187. }
  188. /**
  189. * @inheritDoc
  190. */
  191. override arcane function set implicitPartition(value:Partition3D):void
  192. {
  193. if (value == _implicitPartition)
  194. return;
  195. if (_implicitPartition)
  196. notifyPartitionUnassigned();
  197. super.implicitPartition = value;
  198. notifyPartitionAssigned();
  199. }
  200. /**
  201. * @inheritDoc
  202. */
  203. override public function set scene(value:Scene3D):void
  204. {
  205. if (value == _scene)
  206. return;
  207. if (_scene)
  208. _scene.unregisterEntity(this);
  209. // callback to notify object has been spawned. Casts to please FDT
  210. if (value)
  211. value.registerEntity(this);
  212. super.scene = value;
  213. }
  214. override public function get assetType():String
  215. {
  216. return AssetType.ENTITY;
  217. }
  218. /**
  219. * Used by the raycast-based picking system to determine how the geometric contents of an entity are processed
  220. * in order to offer more details for the picking collision object, including local position, normal vector and uv value.
  221. * Defaults to null.
  222. *
  223. * @see away3d.core.pick.RaycastPicker
  224. */
  225. public function get pickingCollider():IPickingCollider
  226. {
  227. return _pickingCollider;
  228. }
  229. public function set pickingCollider(value:IPickingCollider):void
  230. {
  231. _pickingCollider = value;
  232. }
  233. /**
  234. * Creates a new Entity object.
  235. */
  236. public function Entity()
  237. {
  238. super();
  239. _bounds = getDefaultBoundingVolume();
  240. _worldBounds = getDefaultBoundingVolume();
  241. }
  242. /**
  243. * Gets a concrete EntityPartition3DNode subclass that is associated with this Entity instance
  244. */
  245. public function getEntityPartitionNode():EntityNode
  246. {
  247. return _partitionNode ||= createEntityPartitionNode();
  248. }
  249. public function isIntersectingRay(rayPosition:Vector3D, rayDirection:Vector3D):Boolean
  250. {
  251. if(!pickingCollisionVO.localRayPosition) pickingCollisionVO.localRayPosition = new Vector3D();
  252. if(!pickingCollisionVO.localRayDirection) pickingCollisionVO.localRayDirection = new Vector3D();
  253. if(!pickingCollisionVO.localNormal) pickingCollisionVO.localNormal = new Vector3D();
  254. // convert ray to entity space
  255. var localRayPosition:Vector3D = pickingCollisionVO.localRayPosition;
  256. var localRayDirection:Vector3D = pickingCollisionVO.localRayDirection;
  257. Matrix3DUtils.transformVector(inverseSceneTransform, rayPosition, localRayPosition);
  258. Matrix3DUtils.deltaTransformVector(inverseSceneTransform, rayDirection, localRayDirection);
  259. // check for ray-bounds collision
  260. var rayEntryDistance:Number = bounds.rayIntersection(localRayPosition, localRayDirection, pickingCollisionVO.localNormal);
  261. if (rayEntryDistance < 0)
  262. return false;
  263. // Store collision data.
  264. pickingCollisionVO.rayEntryDistance = rayEntryDistance;
  265. pickingCollisionVO.rayPosition = rayPosition;
  266. pickingCollisionVO.rayDirection = rayDirection;
  267. pickingCollisionVO.rayOriginIsInsideBounds = rayEntryDistance == 0;
  268. return true;
  269. }
  270. /**
  271. * Factory method that returns the current partition node. Needs to be overridden by concrete subclasses
  272. * such as Mesh to return the correct concrete subtype of EntityPartition3DNode (for Mesh = MeshPartition3DNode,
  273. * most IRenderables (particles fe) would return RenderablePartition3DNode, I suppose)
  274. */
  275. protected function createEntityPartitionNode():EntityNode
  276. {
  277. throw new AbstractMethodError();
  278. }
  279. /**
  280. * Creates the default bounding box to be used by this type of Entity.
  281. * @return
  282. */
  283. protected function getDefaultBoundingVolume():BoundingVolumeBase
  284. {
  285. // point lights should be using sphere bounds
  286. // directional lights should be using null bounds
  287. return new AxisAlignedBoundingBox();
  288. }
  289. /**
  290. * Updates the bounding volume for the object. Overriding methods need to set invalid flag to false!
  291. */
  292. protected function updateBounds():void
  293. {
  294. throw new AbstractMethodError();
  295. }
  296. /**
  297. * @inheritDoc
  298. */
  299. override protected function invalidateSceneTransform():void
  300. {
  301. if (!_ignoreTransform) {
  302. super.invalidateSceneTransform();
  303. _worldBoundsInvalid = true;
  304. notifySceneBoundsInvalid();
  305. }
  306. }
  307. /**
  308. * Invalidates the bounding volume, causing to be updated when requested.
  309. */
  310. protected function invalidateBounds():void
  311. {
  312. _boundsInvalid = true;
  313. _worldBoundsInvalid = true;
  314. notifySceneBoundsInvalid();
  315. }
  316. override protected function updateMouseChildren():void
  317. {
  318. // If there is a parent and this child does not have a triangle collider, use its parent's triangle collider.
  319. if (_parent && !pickingCollider) {
  320. if (_parent is Entity) {
  321. var collider:IPickingCollider = Entity(_parent).pickingCollider;
  322. if (collider)
  323. pickingCollider = collider;
  324. }
  325. }
  326. super.updateMouseChildren();
  327. }
  328. /**
  329. * Notify the scene that the global scene bounds have changed, so it can be repartitioned.
  330. */
  331. private function notifySceneBoundsInvalid():void
  332. {
  333. if (_scene)
  334. _scene.invalidateEntityBounds(this);
  335. }
  336. /**
  337. * Notify the scene that a new partition was assigned.
  338. */
  339. private function notifyPartitionAssigned():void
  340. {
  341. if (_scene)
  342. _scene.registerPartition(this); //_onAssignPartitionCallback(this);
  343. }
  344. /**
  345. * Notify the scene that a partition was unassigned.
  346. */
  347. private function notifyPartitionUnassigned():void
  348. {
  349. if (_scene)
  350. _scene.unregisterPartition(this);
  351. }
  352. private function addBounds():void
  353. {
  354. if (!_boundsIsShown) {
  355. _boundsIsShown = true;
  356. addChild(_bounds.boundingRenderable);
  357. }
  358. }
  359. private function removeBounds():void
  360. {
  361. if (_boundsIsShown) {
  362. _boundsIsShown = false;
  363. removeChild(_bounds.boundingRenderable);
  364. _bounds.disposeRenderable();
  365. }
  366. }
  367. arcane function internalUpdate():void
  368. {
  369. if (_controller)
  370. _controller.update();
  371. }
  372. }
  373. }