PageRenderTime 5858ms CodeModel.GetById 22ms RepoModel.GetById 2ms app.codeStats 1ms

/sandy/as3/branches/3.0.1/src/sandy/core/scenegraph/Shape3D.as

http://sandy.googlecode.com/
ActionScript | 788 lines | 439 code | 55 blank | 294 comment | 93 complexity | e38e1e840b66244f1c96a2105b583b0e MD5 | raw file
  1. /*
  2. # ***** BEGIN LICENSE BLOCK *****
  3. Copyright the original author or authors.
  4. Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.mozilla.org/MPL/MPL-1.1.html
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. # ***** END LICENSE BLOCK *****
  14. */
  15. package sandy.core.scenegraph
  16. {
  17. import flash.display.Sprite;
  18. import flash.events.Event;
  19. import flash.events.MouseEvent;
  20. import sandy.bounds.BBox;
  21. import sandy.bounds.BSphere;
  22. import sandy.core.Scene3D;
  23. import sandy.core.World3D;
  24. import sandy.core.data.Edge3D;
  25. import sandy.core.data.Matrix4;
  26. import sandy.core.data.Polygon;
  27. import sandy.core.data.Vector;
  28. import sandy.core.data.Vertex;
  29. import sandy.events.BubbleEvent;
  30. import sandy.materials.Appearance;
  31. import sandy.materials.Material;
  32. import sandy.materials.WireFrameMaterial;
  33. import sandy.view.CullingState;
  34. import sandy.view.Frustum;
  35. /**
  36. * The Shape3D class is the base class of all true 3D shapes.
  37. *
  38. * <p>It represents a node in the object tree of the world.<br/>
  39. * A Shape3D is a leaf node and can not have any child nodes.</p>
  40. * <p>It must be the child of a branch group or a transform group,
  41. * but transformations can be applied to the Shape directly.</p>
  42. *
  43. * @author Thomas Pfeiffer - kiroukou
  44. * @version 3.0
  45. * @date 26.07.2007
  46. */
  47. public class Shape3D extends ATransformable implements IDisplayable
  48. {
  49. /**
  50. * Default material for the DEFAULT_APPEARANCE object
  51. */
  52. public static var DEFAULT_MATERIAL:Material = new WireFrameMaterial();
  53. /**
  54. * Default appearance for Shape3D instances. If no apperance is given, this default one will be applied using the DEFAULT_MATERIAL as front and back material
  55. */
  56. public static var DEFAULT_APPEARANCE:Appearance = new Appearance( DEFAULT_MATERIAL );
  57. /**
  58. * The array of polygons building this object.
  59. */
  60. public var aPolygons:Array = new Array();
  61. /**
  62. * <p>
  63. * Enable the Frustum near plane clipping on the visible polygons.
  64. * Enable this when you need a perfect intersection between the front camera plane.
  65. * This is mainly used when you need the camera to move on a long plane.</p>
  66. *
  67. * <p>Important: Enable the clipping makes process a bit slower, especially with big scenes.</p>
  68. */
  69. public var enableNearClipping:Boolean = false;
  70. /**
  71. * <p>
  72. * Enable the Frustum clipping on the visible polygons.
  73. * Enable this when you need a perfect intersection between the camera and some object shapes.
  74. * In case you need to make the camera look inside and outide a box, or other immerssive things.</p>
  75. *
  76. * <p>Important: Enable the clipping makes process a bit slower, especially with big scenes.</p>
  77. *
  78. * <p>Specify if this object polygons should be clipped against the camera frustum planes.</p>
  79. */
  80. public var enableClipping:Boolean = false;
  81. /**
  82. * Should forced depth be enable for this object?.
  83. *
  84. * <p>If true it is possible to force this object to be drawn at a specific depth,<br/>
  85. * if false the normal Z-sorting algorithm is applied.</p>
  86. * <p>When correctly used, this feature allows you to avoid some Z-sorting problems.</p>
  87. */
  88. public var enableForcedDepth:Boolean = false;
  89. /**
  90. * The forced depth for this object.
  91. *
  92. * <p>To make this feature work, you must enable the ForcedDepth system too.<br/>
  93. * The higher the depth is, the sooner the more far the object will be represented.</p>
  94. */
  95. public var forcedDepth:Number = 0;
  96. /**
  97. * Creates a 3D object
  98. *
  99. * <p>[<b>Todo</b>: some more explanations]</p>
  100. *
  101. * @param p_sName A string identifier for this object
  102. * @param p_oGeometry The geometry of this object
  103. * @param p_oAppearance The appearance of this object. If no apperance is given, the DEFAULT_APPEARANCE will be applied.
  104. * @param p_bUseSingleContainer Whether tis object should use a single container to draw on
  105. */
  106. public function Shape3D( p_sName:String = "", p_oGeometry:Geometry3D = null, p_oAppearance:Appearance = null, p_bUseSingleContainer:Boolean=true )
  107. {
  108. super( p_sName );
  109. // -- Add this graphical object to the World display list
  110. m_oContainer = new Sprite();
  111. // --
  112. geometry = p_oGeometry;
  113. // -- HACK to make sure that the correct container system will be applied
  114. m_bUseSingleContainer = !p_bUseSingleContainer;
  115. useSingleContainer = p_bUseSingleContainer;
  116. // --
  117. appearance = ( p_oAppearance ) ? p_oAppearance : Shape3D.DEFAULT_APPEARANCE;
  118. // --
  119. updateBoundingVolumes();
  120. }
  121. /**
  122. * setter that allow user to change the way to render this object.
  123. * set to true, the shape will be rendered into a single Sprite object, which is accessible through the container property.
  124. * set to false, the container property does not target anything, but all the polygons will be rendered into their own dedidated container.
  125. *
  126. * <p>If true, this object renders itself on a single container ( Sprite ),<br/>
  127. * if false, each polygon is rendered on its own container.</p>
  128. */
  129. public function set useSingleContainer( p_bUseSingleContainer:Boolean ):void
  130. {
  131. var l_oFace:Polygon;
  132. // --
  133. if( p_bUseSingleContainer == m_bUseSingleContainer ) return;
  134. // --
  135. if( p_bUseSingleContainer )
  136. {
  137. for each( l_oFace in aPolygons )
  138. {
  139. if( l_oFace.container.parent )
  140. {
  141. l_oFace.container.graphics.clear();
  142. l_oFace.container.parent.removeChild( l_oFace.container );
  143. this.broadcaster.removeChild( l_oFace.broadcaster );
  144. }
  145. }
  146. }
  147. else
  148. {
  149. if( m_oContainer.parent )
  150. {
  151. m_oContainer.graphics.clear();
  152. m_oContainer.parent.removeChild( m_oContainer );
  153. }
  154. // --
  155. for each( l_oFace in aPolygons )
  156. {
  157. this.broadcaster.addChild( l_oFace.broadcaster );
  158. // we reset the polygon container to the original one, and add it to the world container
  159. l_oFace.container.graphics.clear();
  160. }
  161. }
  162. m_bUseSingleContainer = p_bUseSingleContainer;
  163. }
  164. /**
  165. * Updates the bounding volumes of this object.
  166. */
  167. public function updateBoundingVolumes():void
  168. {
  169. if( m_oGeometry )
  170. {
  171. boundingSphere = BSphere.create( m_oGeometry.aVertex );
  172. boundingBox = BBox.create( m_oGeometry.aVertex );
  173. }
  174. }
  175. /**
  176. * Tests this node against the camera frustum to get its visibility.
  177. *
  178. * <p>If this node and its children are not within the frustum,
  179. * the node is set to cull and it would not be displayed.<p/>
  180. * <p>The method also updates the bounding volumes to make the more accurate culling system possible.<br/>
  181. * First the bounding sphere is updated, and if intersecting,
  182. * the bounding box is updated to perform the more precise culling.</p>
  183. * <p><b>[MANDATORY] The update method must be called first!</b></p>
  184. *
  185. * @param p_oScene The current scene
  186. * @param p_oFrustum The frustum of the current camera
  187. * @param p_oViewMatrix The view martix of the curren camera
  188. * @param p_bChanged
  189. */
  190. public override function cull( p_oScene:Scene3D, p_oFrustum:Frustum, p_oViewMatrix:Matrix4, p_bChanged:Boolean ):void
  191. {
  192. super.cull( p_oScene, p_oFrustum, p_oViewMatrix, p_bChanged );
  193. if( culled == Frustum.OUTSIDE ) return;
  194. /////////////////////////
  195. //// BOUNDING SPHERE ////
  196. /////////////////////////
  197. if( !boundingSphere.uptodate ) boundingSphere.transform( viewMatrix );
  198. culled = p_oFrustum.sphereInFrustum( boundingSphere );
  199. // --
  200. if( culled == Frustum.INTERSECT && boundingBox )
  201. {
  202. ////////////////////////
  203. //// BOUNDING BOX ////
  204. ////////////////////////
  205. if( !boundingBox.uptodate ) boundingBox.transform( viewMatrix );
  206. culled = p_oFrustum.boxInFrustum( boundingBox );
  207. }
  208. // -- We update the clipped property if necessary and requested by the user.
  209. m_bClipped = false;
  210. // -- FIXME TO SIMPLIFY THIS BECUASE IT CERTAINLY COST A LOT FOR NOTHING!
  211. if( culled == CullingState.INTERSECT )
  212. {
  213. if( enableClipping || enableNearClipping )
  214. {
  215. m_bClipped = true;
  216. }
  217. }
  218. }
  219. /**
  220. * Renders this 3D object.
  221. *
  222. * @param p_oScene The current scene
  223. * @param p_oCamera The current camera
  224. */
  225. public override function render( p_oScene:Scene3D, p_oCamera:Camera3D ):void
  226. {
  227. // IF no appearance has bene applied, no display
  228. if( m_oAppearance == null ) return;
  229. var l_nZNear:Number = p_oCamera.near;
  230. var l_aPoints:Array = m_oGeometry.aVertex,
  231. l_oMatrix:Matrix4 = viewMatrix, l_oFrustum:Frustum = p_oCamera.frustrum,
  232. l_aNormals:Array = m_oGeometry.aFacesNormals,
  233. l_aVertexNormals:Array = m_oGeometry.aVertexNormals,
  234. m11:Number = l_oMatrix.n11, m21:Number = l_oMatrix.n21, m31:Number = l_oMatrix.n31,
  235. m12:Number = l_oMatrix.n12, m22:Number = l_oMatrix.n22, m32:Number = l_oMatrix.n32,
  236. m13:Number = l_oMatrix.n13, m23:Number = l_oMatrix.n23, m33:Number = l_oMatrix.n33,
  237. m14:Number = l_oMatrix.n14, m24:Number = l_oMatrix.n24, m34:Number = l_oMatrix.n34;
  238. var l_oVertexNormal:Vertex, l_oNormal:Vertex, l_oVertex:Vertex;
  239. var l_oFace:Polygon;
  240. // -- Now we transform the normals.
  241. for each( l_oNormal in l_aNormals )
  242. {
  243. l_oNormal.wx = l_oNormal.x * m11 + l_oNormal.y * m12 + l_oNormal.z * m13;
  244. l_oNormal.wy = l_oNormal.x * m21 + l_oNormal.y * m22 + l_oNormal.z * m23;
  245. l_oNormal.wz = l_oNormal.x * m31 + l_oNormal.y * m32 + l_oNormal.z * m33;
  246. }
  247. // -- Now we can transform the objet vertices into the camera coordinates
  248. for each( l_oVertex in l_aPoints )
  249. {
  250. l_oVertex.wx = l_oVertex.x * m11 + l_oVertex.y * m12 + l_oVertex.z * m13 + m14;
  251. l_oVertex.wy = l_oVertex.x * m21 + l_oVertex.y * m22 + l_oVertex.z * m23 + m24;
  252. l_oVertex.wz = l_oVertex.x * m31 + l_oVertex.y * m32 + l_oVertex.z * m33 + m34;
  253. l_oVertex.projected = false;
  254. }
  255. // -- The polygons will be clipped, we shall allocate a new array container the clipped vertex.
  256. m_aVisiblePoly.splice( 0 );
  257. m_nDepth = 0;
  258. // --
  259. for each( l_oFace in aPolygons )
  260. {
  261. l_oFace.isClipped = false;
  262. // -- lauch precomputation
  263. l_oFace.computeVisibility();
  264. // --
  265. if ( l_oFace.visible || !m_bBackFaceCulling)
  266. {
  267. l_oFace.precomputeBounds();
  268. // we process the frustum clipping
  269. if( m_bClipped && enableClipping )
  270. {
  271. l_oFace.clip( l_oFrustum );
  272. // -- We project the vertices
  273. if( l_oFace.cvertices.length > 0 )
  274. {
  275. p_oCamera.projectArray( l_oFace.cvertices );
  276. if( !enableForcedDepth ) m_nDepth += l_oFace.meanBounds.z;
  277. // -- we manage the display list depending on the mode choosen
  278. if( m_bUseSingleContainer )
  279. m_aVisiblePoly.push( l_oFace );
  280. else
  281. {
  282. if( enableForcedDepth ) l_oFace.depth = forcedDepth;
  283. p_oCamera.addToDisplayList( l_oFace );
  284. }
  285. }
  286. }
  287. else
  288. {
  289. if( l_oFace.minBounds.z > l_nZNear )
  290. {
  291. if( !enableForcedDepth ) m_nDepth += l_oFace.meanBounds.z;
  292. // -- We project the vertices
  293. p_oCamera.projectArray( l_oFace.vertices );
  294. // -- we manage the display list depending on the mode choosen
  295. if( m_bUseSingleContainer )
  296. m_aVisiblePoly.push( l_oFace );
  297. else
  298. {
  299. if( enableForcedDepth ) l_oFace.depth = forcedDepth;
  300. p_oCamera.addToDisplayList( l_oFace );
  301. }
  302. }
  303. // otherwise we can perform a clipping against the front plane only
  304. else if( m_bClipped && enableNearClipping )
  305. {
  306. l_oFace.clipFrontPlane( l_oFrustum );
  307. // -- We project the vertices
  308. if( l_oFace.cvertices.length > 0 )
  309. {
  310. //p_oCamera.projectArray( l_oFace.vertices ); // not needed anymore exept bitmapmaterial with enableAccurateClipping set to false
  311. p_oCamera.projectArray( l_oFace.cvertices );
  312. if( !enableForcedDepth ) m_nDepth += l_oFace.meanBounds.z;
  313. // -- we manage the display list depending on the mode choosen
  314. if( m_bUseSingleContainer )
  315. m_aVisiblePoly.push( l_oFace );
  316. else
  317. {
  318. if( enableForcedDepth ) l_oFace.depth = forcedDepth;
  319. p_oCamera.addToDisplayList( l_oFace );
  320. }
  321. }
  322. }
  323. }
  324. }
  325. }
  326. // --
  327. if( m_bUseSingleContainer )
  328. {
  329. if(enableForcedDepth)m_nDepth = forcedDepth;
  330. else m_nDepth /= m_aVisiblePoly.length;
  331. p_oCamera.addToDisplayList( this );
  332. }
  333. }
  334. /**
  335. * Clears the graphics object of this object's container.
  336. *
  337. * <p>The the graphics that were drawn on the Graphics object is erased,
  338. * and the fill and line style settings are reset.</p>
  339. */
  340. public function clear():void
  341. {
  342. if( m_oContainer ) m_oContainer.graphics.clear();
  343. }
  344. /**
  345. * Performs a z-sorting and renders the objects visible polygons.
  346. *
  347. * <p>The method is called only if the object renders on a single container<br/>
  348. * - ( useSingleContainer = true ).</p>
  349. *
  350. * @param p_oScene The current scene
  351. * @param p_oContainer The container to draw on
  352. */
  353. public function display( p_oScene:Scene3D, p_oContainer:Sprite = null ):void
  354. {
  355. m_aVisiblePoly.sortOn( "depth", Array.NUMERIC | Array.DESCENDING );
  356. // --
  357. for each( var l_oPoly:Polygon in m_aVisiblePoly )
  358. {
  359. l_oPoly.display( p_oScene, m_oContainer );
  360. }
  361. }
  362. /**
  363. * The contianer for this object.
  364. * This container property exist if the useSingleContainer is set to true.
  365. * It is a direct access to the Shape3D container to, for example, apply nice effects such as filters etc.
  366. */
  367. public function get container():Sprite
  368. {return m_oContainer;}
  369. /**
  370. * The depth of this object.
  371. * In case the useSingleContainer mode is enabled (default mode), this value returns the means depth of the Shape in the camera frame.
  372. * This value is mainly used as a z-sorting value.
  373. */
  374. public function get depth():Number
  375. {return m_nDepth;}
  376. /**
  377. * This property call allows you to get the geometryCenter offset vector of the Shape.
  378. * Modifying this vector will impact the way the shape is rendered, mainly its rotation center.
  379. *
  380. * @return a vector which corresponds to the 2 directions offset.
  381. */
  382. public function get geometryCenter():Vector
  383. {return m_oGeomCenter;}
  384. /**
  385. * Change the geometryCenter of the Shape3D.
  386. * To change the geometryCenter point of a shape, simply set this geometryCenter property.
  387. * The geometryCenter property requires a vector. This vector is an position offset relative to the original geometry one.
  388. * For example, a Sphere primitive creates automatically a geometry which center is the 0,0,0 position. If you rotate this sphere as this,
  389. * it will rotate around its center.
  390. * Now if you set the geometryCenter property, this rotation center will change.
  391. *
  392. * The updateBoundingVolumes method which does update the bounding volumes to enable a correct frustum culling is automatically called.
  393. *
  394. * @example To change the geometryCenter center at runtime
  395. * <listing version="3.0">
  396. * var l_oSphere:Sphere = new Sphere("mySphere", 50, 3 );
  397. * // Change the rotation reference to -50 offset in Y direction from the orinal one
  398. * // and that corresponds to the bottom of the sphere
  399. * l_oSphere.geometryCenter = new Vector( 0, -50, 0 );
  400. * l_oSphere.rotateZ = 45;
  401. * </listing>
  402. */
  403. public function set geometryCenter( p_oGeomCenter:Vector ):void
  404. {
  405. var l_oDiff:Vector = p_oGeomCenter.clone();
  406. l_oDiff.sub( m_oGeomCenter );
  407. // --
  408. if( m_oGeometry )
  409. {
  410. for each( var l_oVertex:Vertex in m_oGeometry.aVertex )
  411. {
  412. l_oVertex.x += l_oDiff.x;
  413. l_oVertex.y += l_oDiff.y;
  414. l_oVertex.z += l_oDiff.z;
  415. }
  416. }
  417. // --
  418. m_oGeomCenter.copy( p_oGeomCenter );
  419. // --
  420. updateBoundingVolumes();
  421. }
  422. /**
  423. * The appearance of this object.
  424. */
  425. public function set appearance( p_oApp:Appearance ):void
  426. {
  427. // Now we register to the update event
  428. m_oAppearance = p_oApp;
  429. // --
  430. if( m_oGeometry )
  431. {
  432. for each( var v:Polygon in aPolygons )
  433. v.appearance = m_oAppearance;
  434. }
  435. }
  436. /**
  437. * @private
  438. */
  439. public function get appearance():Appearance
  440. {
  441. return m_oAppearance;
  442. }
  443. /**
  444. * The geometry of this object.
  445. */
  446. public function set geometry( p_geometry:Geometry3D ):void
  447. {
  448. if( p_geometry == null ) return;
  449. // TODO shall we clone the geometry?
  450. m_oGeometry = p_geometry;
  451. updateBoundingVolumes();
  452. // -- we generate the possible missing normals
  453. m_oGeometry.generateFaceNormals();//Must be called first
  454. m_oGeometry.generateVertexNormals();//must be called second
  455. // --
  456. __destroyPolygons();
  457. __generatePolygons( m_oGeometry );
  458. }
  459. /**
  460. * @private
  461. */
  462. public function get geometry():Geometry3D
  463. {
  464. return m_oGeometry;
  465. }
  466. /**
  467. * Should back face culling be enabled for this object?.
  468. *
  469. * <p>If set to false all faces of this object are drawn.<br/>
  470. * A true value enables the back face culling algorithm - Default true</p>
  471. */
  472. public function set enableBackFaceCulling( b:Boolean ):void
  473. {
  474. if( b != m_bBackFaceCulling )
  475. {
  476. m_bBackFaceCulling = b;
  477. changed = true;
  478. }
  479. }
  480. /**
  481. * @private
  482. */
  483. public function get enableBackFaceCulling():Boolean
  484. {
  485. return m_bBackFaceCulling;
  486. }
  487. /**
  488. * Enable the interactivity on this shape and its polygon.
  489. * Be careful, this mode have some requirements :
  490. * - to have useSingleContainer set to false. It is done automatically if enabled
  491. *
  492. * The original settings are back to their original state when the mode is disabled
  493. */
  494. public function set enableInteractivity( p_bState:Boolean ):void
  495. {
  496. if( p_bState != m_bMouseInteractivity )
  497. {
  498. if( p_bState )
  499. {
  500. if( m_bUseSingleContainer == true )
  501. {
  502. m_bUseSingleContainer = false;
  503. m_bForcedSingleContainer = true;
  504. }
  505. }
  506. else
  507. {
  508. if( m_bForcedSingleContainer == true )
  509. {
  510. useSingleContainer = true;
  511. m_bForcedSingleContainer = false;
  512. }
  513. }
  514. // --
  515. for each( var l_oPolygon:Polygon in aPolygons )
  516. {
  517. l_oPolygon.enableInteractivity = p_bState;
  518. }
  519. m_bMouseInteractivity = p_bState;
  520. }
  521. }
  522. public function get enableInteractivity():Boolean
  523. { return m_bMouseInteractivity; }
  524. /**
  525. * Enables the event system for mouse events.
  526. *
  527. * <p>When set to true, the onPress, onRollOver and onRollOut events are broadcast.<br/>
  528. * The event system is enabled or disabled for all faces of this object.<br/>
  529. * As an alternative, you have the possibility to enable events only for specific faces.</p>
  530. *
  531. * <p>Once this feature is enabled, the animation is more CPU intensive.</p>
  532. */
  533. public function set enableEvents( b:Boolean ):void
  534. {
  535. // To use only when use Single container is disabled
  536. var v:Polygon = null;
  537. if( b )
  538. {
  539. if( !m_bEv )
  540. {
  541. if( m_bUseSingleContainer == false )
  542. {
  543. for each( v in aPolygons )
  544. {
  545. v.enableEvents = true;
  546. }
  547. }
  548. else
  549. {
  550. m_oContainer.addEventListener(MouseEvent.CLICK, _onInteraction);
  551. m_oContainer.addEventListener(MouseEvent.MOUSE_UP, _onInteraction);
  552. m_oContainer.addEventListener(MouseEvent.MOUSE_DOWN, _onInteraction);
  553. m_oContainer.addEventListener(MouseEvent.ROLL_OVER, _onInteraction);
  554. m_oContainer.addEventListener(MouseEvent.ROLL_OUT, _onInteraction);
  555. m_oContainer.addEventListener(MouseEvent.DOUBLE_CLICK, _onInteraction);
  556. m_oContainer.addEventListener(MouseEvent.MOUSE_MOVE, _onInteraction);
  557. m_oContainer.addEventListener(MouseEvent.MOUSE_OVER, _onInteraction);
  558. m_oContainer.addEventListener(MouseEvent.MOUSE_OUT, _onInteraction);
  559. m_oContainer.addEventListener(MouseEvent.MOUSE_WHEEL, _onInteraction);
  560. }
  561. }
  562. }
  563. else if( !b && m_bEv )
  564. {
  565. if( m_bUseSingleContainer == false )
  566. {
  567. for each( v in aPolygons )
  568. {
  569. v.enableEvents = false;
  570. }
  571. }
  572. else
  573. {
  574. m_oContainer.removeEventListener(MouseEvent.CLICK, _onInteraction);
  575. m_oContainer.removeEventListener(MouseEvent.MOUSE_UP, _onInteraction);
  576. m_oContainer.removeEventListener(MouseEvent.MOUSE_DOWN, _onInteraction);
  577. m_oContainer.removeEventListener(MouseEvent.ROLL_OVER, _onInteraction);
  578. m_oContainer.removeEventListener(MouseEvent.ROLL_OUT, _onInteraction);
  579. m_oContainer.removeEventListener(MouseEvent.DOUBLE_CLICK, _onInteraction);
  580. m_oContainer.removeEventListener(MouseEvent.MOUSE_MOVE, _onInteraction);
  581. m_oContainer.removeEventListener(MouseEvent.MOUSE_OVER, _onInteraction);
  582. m_oContainer.removeEventListener(MouseEvent.MOUSE_OUT, _onInteraction);
  583. m_oContainer.removeEventListener(MouseEvent.MOUSE_WHEEL, _onInteraction);
  584. }
  585. }
  586. m_bEv = b;
  587. }
  588. protected function _onInteraction( p_oEvt:Event ):void
  589. {
  590. m_oEB.broadcastEvent( new BubbleEvent( p_oEvt.type, this, p_oEvt ) );
  591. }
  592. /**
  593. * Changes the backface culling side.
  594. *
  595. * <p>When you want to display a cube and you are the cube, you see its external faces.<br/>
  596. * The internal faces are not drawn due to back face culling</p>
  597. *
  598. * <p>In case you are inside the cube, by default Sandy's engine still doesn't draw the internal faces
  599. * (because you should not be in there).</p>
  600. *
  601. * <p>If you need to be only inside the cube, you can call this method to change which side is culled.<br/>
  602. * The faces will be visible only from the interior of the cube.</p>
  603. *
  604. * <p>If you want to be both on the inside and the outside, you want to make the faces visible from on both sides.<br/>
  605. * In that case you just have to set enableBackFaceCulling to false.</p>
  606. */
  607. public function swapCulling():void
  608. {
  609. for each( var v:Polygon in aPolygons )
  610. {
  611. v.swapCulling();
  612. }
  613. changed = true;
  614. }
  615. /**
  616. * Destroy this object and all its faces
  617. * container object is removed, and graphics cleared. All polygons have their
  618. */
  619. public override function destroy():void
  620. {
  621. // FIXME Fix it - it should be more like
  622. m_oGeometry.dispose();
  623. // --
  624. clear();
  625. if( m_oContainer.parent ) m_oContainer.parent.removeChild( m_oContainer );
  626. if( m_oContainer ) m_oContainer = null;
  627. // --
  628. __destroyPolygons();
  629. // --
  630. super.destroy();
  631. }
  632. /**
  633. * This method returns a clone of this Shape3D.
  634. * The current appearance will be applied, and the geometry is cloned (not referenced to curent one).
  635. *
  636. * @param p_sName The name of the new shape you are going to create
  637. * @param p_bKeepTransform Boolean value which, if set to true, applies the current local transformations to the cloned shape. Default value is false.
  638. *
  639. * @return The clone
  640. */
  641. public function clone( p_sName:String="", p_bKeepTransform:Boolean = false ):Shape3D
  642. {
  643. var l_oClone:Shape3D = new Shape3D( p_sName, geometry.clone(), appearance, m_bUseSingleContainer );
  644. // --
  645. if( p_bKeepTransform == true ) l_oClone.matrix = this.matrix;
  646. // --
  647. return l_oClone;
  648. }
  649. /**
  650. * Returns a string representation of this object
  651. *
  652. * @return The fully qualified name of this object and its geometry
  653. */
  654. public override function toString ():String
  655. {
  656. return "sandy.core.scenegraph.Shape3D" + " " + m_oGeometry.toString();
  657. }
  658. ///////////////////
  659. ///// PRIVATE /////
  660. ///////////////////
  661. private function __destroyPolygons():void
  662. {
  663. if( aPolygons != null && aPolygons.length > 0 )
  664. {
  665. var i:int, l:int = aPolygons.length;
  666. while( i<l )
  667. {
  668. if( broadcaster != null ) broadcaster.removeChild( aPolygons[i].broadcaster );
  669. if( aPolygons[i] ) Polygon( aPolygons[int(i)] ).destroy();
  670. // --
  671. aPolygons[int(i)] = null;
  672. // --
  673. i ++;
  674. }
  675. }
  676. aPolygons.splice(0);
  677. aPolygons = null;
  678. }
  679. private function __generatePolygons( p_oGeometry:Geometry3D ):void
  680. {
  681. var i:int = 0, j:int = 0, l:int = p_oGeometry.aFacesVertexID.length;
  682. aPolygons = new Array( l );
  683. // --
  684. for( i=0; i < l; i += 1 )
  685. {
  686. aPolygons[i] = new Polygon( this, p_oGeometry, p_oGeometry.aFacesVertexID[i], p_oGeometry.aFacesUVCoordsID[i], i, i );
  687. if( m_oAppearance ) aPolygons[int(i)].appearance = m_oAppearance;
  688. this.broadcaster.addChild( aPolygons[int(i)].broadcaster );
  689. }
  690. // -- attempt to create the neighboors relation between polygons
  691. var a:int = aPolygons.length, lCount:uint = 0;
  692. var lP1:Polygon, lP2:Polygon;
  693. var l_aEdges:Array;
  694. for( i = 0; i < a-1; i+=1 )
  695. {
  696. for( j=i+1; j < a; j+=1 )
  697. {
  698. lP1 = aPolygons[int(i)];
  699. lP2 = aPolygons[int(j)];
  700. l_aEdges = lP2.aEdges;
  701. // --
  702. lCount = 0;
  703. // -- check if they share at least 2 vertices
  704. for each( var l_oEdge:Edge3D in lP1.aEdges )
  705. if( l_aEdges.indexOf( l_oEdge ) > -1 ) lCount += 1;
  706. // --
  707. if( lCount > 0 )
  708. {
  709. lP1.aNeighboors.push( lP2 );
  710. lP2.aNeighboors.push( lP1 );
  711. }
  712. }
  713. }
  714. }
  715. // ______________
  716. // [PRIVATE] DATA________________________________________________
  717. private var m_oAppearance:Appearance ; // The Appearance of this Shape3D
  718. private var m_bEv:Boolean = false; // The event system state (enable or not)
  719. protected var m_oGeomCenter:Vector = new Vector();
  720. private var m_bBackFaceCulling:Boolean = true;
  721. private var m_bClipped:Boolean = false;
  722. /** Geometry of this object */
  723. private var m_oGeometry:Geometry3D;
  724. protected var m_bUseSingleContainer:Boolean = true;
  725. protected var m_nDepth:Number = 0;
  726. protected var m_oContainer:Sprite;
  727. private var m_aToProject:Array = new Array();
  728. private var m_aVisiblePoly:Array = new Array();
  729. private var m_bMouseInteractivity:Boolean = false;
  730. private var m_bForcedSingleContainer:Boolean = false;
  731. }
  732. }