PageRenderTime 48ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/sandy/haxe/tags/3.1.2/src/sandy/core/scenegraph/Shape3D.hx

http://sandy.googlecode.com/
Haxe | 925 lines | 563 code | 68 blank | 294 comment | 121 complexity | c7318ce4c7aac15805997100341a1375 MD5 | raw file
  1. package sandy.core.scenegraph;
  2. import flash.display.Sprite;
  3. import flash.events.Event;
  4. import flash.events.MouseEvent;
  5. import flash.geom.Point;
  6. import sandy.bounds.BBox;
  7. import sandy.bounds.BSphere;
  8. import sandy.core.Scene3D;
  9. import sandy.core.data.BSPNode;
  10. import sandy.core.data.Matrix4;
  11. import sandy.core.data.Point3D;
  12. import sandy.core.data.Polygon;
  13. import sandy.core.data.UVCoord;
  14. import sandy.core.data.Vertex;
  15. import sandy.events.BubbleEvent;
  16. import sandy.events.Shape3DEvent;
  17. import sandy.materials.Appearance;
  18. import sandy.materials.Material;
  19. import sandy.materials.WireFrameMaterial;
  20. import sandy.math.IntersectionMath;
  21. import sandy.view.CullingState;
  22. import sandy.view.Frustum;
  23. import sandy.HaxeTypes;
  24. /**
  25. * The Shape3D class is the base class of all true 3D shapes.
  26. *
  27. * <p>It represents a node in the object tree of the world.<br/>
  28. * A Shape3D is a leaf node and can not have any child nodes.</p>
  29. * <p>It must be the child of a branch group or a transform group,
  30. * but transformations can be applied to the Shape directly.</p>
  31. *
  32. * @author Thomas Pfeiffer - kiroukou
  33. * @author Niel Drummond - haXe port
  34. * @author Russell Weir - haXe port
  35. *
  36. */
  37. class Shape3D extends ATransformable, implements IDisplayable
  38. {
  39. /**
  40. * Animated flag.
  41. * <p>If the geometry vertices are dynamically modified by some animation engine or mathematic function, some polygon may disapear with no reason.
  42. * The normal Point3D is used to compute the polygon visibility, and if you don't update the normal Point3D after the vertices modifications, there's an error.
  43. * To fix that problem, Sandy3D offers that new property appeared in 3.0.3 release, which once set to true, automatically update the normal Point3Ds for you.
  44. * As a performance warning, don't set this value to true if your model geometry isn't animated.</p>
  45. */
  46. public var animated:Bool;
  47. /**
  48. * The array of polygons building this object.
  49. */
  50. public var aPolygons:Array<Polygon>;
  51. /**
  52. * Array containing the visible polygons of that shape.
  53. * Contente is available after the SCENE_RENDER_DISPLAYLIST
  54. * event of the current scene has been dispatched
  55. */
  56. public var aVisiblePolygons(default,null) : Array<Polygon>;
  57. /**
  58. * The container for this object.
  59. * This container property exist if the useSingleContainer is set to true.
  60. * It is a direct access to the Shape3D container to, for example, apply nice effects such as filters etc.
  61. */
  62. public var container(__getContainer,null):Sprite;
  63. /**
  64. * The depth of this object.
  65. * In case the useSingleContainer mode is enabled (default mode), this
  66. * value returns the means depth of the Shape in the camera frame.
  67. * This value is mainly used as a z-sorting value.
  68. */
  69. public var depth(__getDepth,__setDepth):Float;
  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(__getEnableClipping,__setEnableClipping):Bool;
  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:Bool;
  89. /**
  90. * <p>
  91. * Enable the Frustum near plane clipping on the visible polygons.
  92. * Enable this when you need a perfect intersection between the front camera plane.
  93. * This is mainly used when you need the camera to move on a long plane.</p>
  94. *
  95. * <p>Important: Enable the clipping makes process a bit slower, especially with big scenes.</p>
  96. */
  97. public var enableNearClipping:Bool;
  98. /**
  99. * The forced depth for this object.
  100. *
  101. * <p>To make this feature work, you must enable the ForcedDepth system too.<br/>
  102. * The higher the depth is, the sooner the more far the object will be represented.</p>
  103. */
  104. public var forcedDepth:Float;
  105. /**
  106. * The geometry of this object.
  107. */
  108. public var geometry(__getGeometry,__setGeometry):Geometry3D;
  109. /**
  110. * Change the geometryCenter of the Shape3D.
  111. * To change the geometryCenter point of a shape, simply set this geometryCenter property.
  112. * The geometryCenter property requires a Point3D. This Point3D is an position offset relative to the original geometry one.
  113. * For example, a Sphere primitive creates automatically a geometry which center is the 0,0,0 position. If you rotate this sphere as this,
  114. * it will rotate around its center.
  115. * Now if you set the geometryCenter property, this rotation center will change.
  116. *
  117. * The updateBoundingVolumes method which does update the bounding volumes to enable a correct frustum culling is automatically called.
  118. *
  119. * @example To change the geometryCenter center at runtime
  120. * <listing version="3.1">
  121. * var l_oSphere:Sphere = new Sphere("mySphere", 50, 3 );
  122. * // Change the rotation reference to -50 offset in Y direction from the orinal one
  123. * // and that corresponds to the bottom of the sphere
  124. * l_oSphere.geometryCenter = new Point3D( 0, -50, 0 );
  125. * l_oSphere.rotateZ = 45;
  126. * </listing>
  127. */
  128. public var geometryCenter(__getGeometryCenter,__setGeometryCenter):Point3D;
  129. /**
  130. * Returns the material currently used by the renderer
  131. * @return Material the material used to render
  132. */
  133. public var material(__getMaterial,__setMaterial):Material;
  134. /**
  135. * No sorting.
  136. * Only convex shapes are guaranteed to display correctly in this mode.
  137. */
  138. public static inline var SORT_NONE:Int = 0;
  139. /**
  140. * Average distance sorting.
  141. * Default sorting mode.
  142. * Carefully designed models will display just fine, but ordering problems are common.
  143. * This is also the only possible sorting mode with <code>useSingleContainer</code> set to <code>false</code>.
  144. */
  145. public static inline var SORT_AVGZ:Int = 1;
  146. /**
  147. * In this mode mesh is sorted using BSP tree, but no faces are split for you (means sorting problems are still possible).
  148. * Experimental.
  149. */
  150. public static inline var SORT_LAZY_BSP:Int = 2;
  151. /**
  152. * In this mode mesh is sorted using BSP tree, but no tree is built for you (you need to set <code>bsp</code> property yourself).
  153. * Experimental.
  154. */
  155. public static inline var SORT_CUSTOM_BSP:Int = 3;
  156. /**
  157. * Root node of BSP tree.
  158. */
  159. public var bsp:BSPNode;
  160. /**
  161. * Creates a 3D object
  162. *
  163. * <p>This creates a new 3D geometry object. That object will handle the rendering of a static Geometry3D object into a real 3D object and finally to the 2D camera representation.</p>
  164. *
  165. * @param p_sName A string identifier for this object
  166. * @param p_oGeometry The geometry of this object
  167. * @param p_oAppearance The appearance of this object. If no apperance is given, the DEFAULT_APPEARANCE will be applied.
  168. * @param p_bUseSingleContainer Whether tis object should use a single container to draw on
  169. */
  170. public function new( ?p_sName:String = "", ?p_oGeometry:Geometry3D, ?p_oAppearance:Appearance, ?p_bUseSingleContainer:Bool=true )
  171. {
  172. // public initializers
  173. aPolygons = new Array();
  174. enableNearClipping = false;
  175. enableClipping = false;
  176. enableForcedDepth = false;
  177. forcedDepth = 0;
  178. animated = false;
  179. aVisiblePolygons = new Array();
  180. // private initializers
  181. m_bEv = false;
  182. m_oGeomCenter = new Point3D();
  183. m_bBackFaceCulling = true;
  184. m_bWasOver = false;
  185. m_bUseSingleContainer = true;
  186. m_nDepth = 0;
  187. m_bMouseInteractivity = false;
  188. m_bForcedSingleContainer = false;
  189. m_nSortingMode = SORT_AVGZ;
  190. super( p_sName );
  191. // -- Add this graphical object to the World display list
  192. m_oContainer = new Sprite();
  193. m_oContainer.name = name;
  194. // --
  195. geometry = p_oGeometry;
  196. // -- HACK to make sure that the correct container system will be applied
  197. m_bUseSingleContainer = !p_bUseSingleContainer;
  198. useSingleContainer = p_bUseSingleContainer;
  199. // --
  200. appearance = ( p_oAppearance != null ) ? p_oAppearance : new Appearance( new WireFrameMaterial() );
  201. // --
  202. updateBoundingVolumes();
  203. }
  204. /**
  205. * Clears the graphics object of this object's container.
  206. *
  207. * <p>The the graphics that were drawn on the Graphics object is erased,
  208. * and the fill and line style settings are reset.</p>
  209. */
  210. public function clear():Void
  211. {
  212. if( m_oContainer != null )
  213. m_oContainer.graphics.clear();
  214. changed = true;
  215. }
  216. /**
  217. * This method returns a clone of this Shape3D.
  218. * The current appearance will be applied, and the geometry is cloned (not referenced to curent one).
  219. *
  220. * @param p_sName The name of the new shape you are going to create
  221. * @param p_bKeepTransform Boolean value which, if set to true, applies the current local transformations to the cloned shape. Default value is false.
  222. *
  223. * @return The clone
  224. */
  225. public function clone( ?p_sName:String = "", ?p_bKeepTransform:Bool=false ):Shape3D
  226. {
  227. var o = new Shape3D( p_sName, null, appearance, m_bUseSingleContainer);
  228. o.copy(this, p_bKeepTransform);
  229. return o;
  230. }
  231. /**
  232. * Tests this node against the camera frustum to get its visibility.
  233. *
  234. * <p>If this node and its children are not within the frustum,
  235. * the node is set to cull and it would not be displayed.<p/>
  236. * <p>The method also updates the bounding volumes to make the more accurate culling system possible.<br/>
  237. * First the bounding sphere is updated, and if intersecting,
  238. * the bounding box is updated to perform the more precise culling.</p>
  239. * <p><b>[MANDATORY] The update method must be called first!</b></p>
  240. *
  241. * @param p_oScene The current scene
  242. * @param p_oFrustum The frustum of the current camera
  243. * @param p_oViewMatrix The view martix of the curren camera
  244. * @param p_bChanged
  245. */
  246. public override function cull( p_oFrustum:Frustum, p_oViewMatrix:Matrix4, p_bChanged:Bool ):Void
  247. {
  248. super.cull( p_oFrustum, p_oViewMatrix, p_bChanged );
  249. if( culled == Frustum.OUTSIDE ) return;
  250. /////////////////////////
  251. //// BOUNDING SPHERE ////
  252. /////////////////////////
  253. boundingSphere.transform( viewMatrix );
  254. culled = p_oFrustum.sphereInFrustum( boundingSphere );
  255. // --
  256. if( culled == Frustum.INTERSECT )
  257. {
  258. ////////////////////////
  259. //// BOUNDING BOX ////
  260. ////////////////////////
  261. culled = p_oFrustum.boxInFrustum( boundingBox.transform( viewMatrix ) );
  262. }
  263. // --
  264. if( culled != CullingState.OUTSIDE && m_oAppearance != null )
  265. {
  266. scene.renderer.addToDisplayList(this);
  267. }
  268. if( m_bEv || m_bMouseInteractivity )
  269. {
  270. if( m_bWasOver == true && m_oLastContainer.hitTestPoint(m_oLastContainer.mouseX, m_oLastContainer.mouseY) == false )
  271. {
  272. m_oEB.dispatchEvent( new Shape3DEvent( MouseEvent.MOUSE_OUT, this, m_oLastEvent.polygon, m_oLastEvent.uv, m_oLastEvent.point, m_oLastEvent.event ) );
  273. m_bWasOver = false;
  274. if( m_oLastContainer != m_oContainer )
  275. {
  276. m_oLastEvent.polygon._onTextureInteraction( m_oLastEvent.event );
  277. m_oLastEvent.polygon._stopMouseInteraction();
  278. }
  279. }
  280. }
  281. }
  282. /**
  283. * Performs a z-sorting and renders the objects visible polygons.
  284. *
  285. * <p>The method is called only if the object renders on a single container<br/>
  286. * - ( useSingleContainer = true ).</p>
  287. *
  288. * @param p_oScene The current scene
  289. * @param p_oContainer The container to draw on
  290. */
  291. public function display( ?p_oContainer:Sprite ):Void
  292. {
  293. // not using static consts here for speed
  294. if (m_nSortingMode < SORT_LAZY_BSP ) {
  295. // old sorting methods
  296. if ((m_nSortingMode == SORT_AVGZ ) || (m_bBackFaceCulling == false))
  297. #if flash
  298. untyped aVisiblePolygons.sortOn( "m_nDepth", Array.NUMERIC | Array.DESCENDING );
  299. #else
  300. aVisiblePolygons.sort( function(a,b) {return a.depth>b.depth?1:a.depth<b.depth?-1:0;} );
  301. #end
  302. for (l_oFace in aVisiblePolygons)
  303. l_oFace.display (m_oContainer);
  304. } else {
  305. // new experimental BSP sorting
  306. var camPt:Point3D = new Point3D (
  307. scene.camera.modelMatrix.n14,
  308. scene.camera.modelMatrix.n24,
  309. scene.camera.modelMatrix.n34
  310. ); // cam -> world
  311. invModelMatrix.transform (camPt); // world -> local
  312. displayBSPTree (bsp, camPt);
  313. }
  314. }
  315. private function displayBSPTree (tree:BSPNode, camPt:Point3D):Void {
  316. var face:Polygon;
  317. var dist:Float = tree.plane.a * camPt.x + tree.plane.b * camPt.y + tree.plane.c * camPt.z + tree.plane.d;
  318. if (dist > 0) {
  319. // display negative, this, positive
  320. if (tree.negative != null)
  321. displayBSPTree (tree.negative, camPt);
  322. for (face in tree.faces)
  323. if (face.visible) // aVisiblePolygons.indexOf?
  324. face.display (m_oContainer);
  325. if (tree.positive != null)
  326. displayBSPTree (tree.positive, camPt);
  327. } else {
  328. // display positive, this, negative
  329. if (tree.positive != null)
  330. displayBSPTree (tree.positive, camPt);
  331. for (face in tree.faces)
  332. if (face.visible) // aVisiblePolygons.indexOf?
  333. face.display (m_oContainer);
  334. if (tree.negative != null)
  335. displayBSPTree (tree.negative, camPt);
  336. }
  337. }
  338. /**
  339. * Destroy this object and all its faces
  340. * container object is removed, and graphics cleared. All polygons have their
  341. */
  342. public override function destroy():Void
  343. {
  344. // FIXME Fix it - it should be more like
  345. if( m_oGeometry != null ) m_oGeometry.dispose();
  346. if( m_oAppearance != null ) m_oAppearance.dispose();
  347. // --
  348. clear();
  349. if( m_oContainer != null )
  350. {
  351. if( m_oContainer.parent != null ) m_oContainer.parent.removeChild( m_oContainer );
  352. m_oContainer = null;
  353. }
  354. // --
  355. __destroyPolygons();
  356. m_oGeometry = null;
  357. aVisiblePolygons = null;
  358. aPolygons = null;
  359. boundingBox = null;
  360. boundingSphere = null;
  361. // --
  362. super.destroy();
  363. }
  364. /**
  365. * Sets SORT_NONE or SORT_AVGZ sorting mode. Deprecated.
  366. * @internal this is now here for backward compatibility only.
  367. */
  368. public function setConvexFlag (convex:Bool):Void
  369. {
  370. sortingMode = convex ? SORT_NONE : SORT_AVGZ;
  371. }
  372. /**
  373. * Changes the backface culling side.
  374. *
  375. * When you want to display a cube and you are outside the cube, you see its external faces.<br/>
  376. * The internal faces are not drawn due to back face culling
  377. *
  378. * In case you are inside the cube, by default Sandy's engine still doesn't draw the internal faces
  379. * (because you should not be in there).
  380. *
  381. * If you need to be only inside the cube, you can call this method to change which side is culled.
  382. * The faces will be visible only from the interior of the cube.
  383. *
  384. * If you want to be both on the inside and the outside, you want to make the faces visible from on both sides.
  385. * In that case you just have to set enableBackFaceCulling to false.
  386. */
  387. public function swapCulling():Void
  388. {
  389. for( v in aPolygons )
  390. {
  391. v.swapCulling();
  392. }
  393. changed = true;
  394. }
  395. /**
  396. * Returns a string representation of this object
  397. *
  398. * @return The fully qualified name of this object and its geometry
  399. */
  400. public override function toString ():String
  401. {
  402. return "sandy.core.scenegraph.Shape3D" + " " + m_oGeometry.toString();
  403. }
  404. /**
  405. * Updates the bounding volumes of this object.
  406. */
  407. public override function updateBoundingVolumes():Void
  408. {
  409. if( m_oGeometry != null )
  410. {
  411. boundingBox = BBox.create( m_oGeometry.aVertex );
  412. boundingSphere.resetFromBox(boundingBox);
  413. if( parent != null )
  414. parent.onChildBoundsChanged(this);
  415. }
  416. }
  417. /////////////////////////////////////////////////////////////////////
  418. ///// Getters / Setters /////
  419. /////////////////////////////////////////////////////////////////////
  420. // appearance
  421. private override function __getAppearance():Appearance
  422. {
  423. return m_oAppearance;
  424. }
  425. private override function __setAppearance( p_oApp:Appearance ):Appearance
  426. {
  427. // Now we register to the update event
  428. m_oAppearance = p_oApp;
  429. // --
  430. if( m_oGeometry != null )
  431. {
  432. for ( v in aPolygons )
  433. v.appearance = m_oAppearance;
  434. }
  435. changed = true;
  436. return p_oApp;
  437. }
  438. // container
  439. private function __getContainer():Sprite
  440. {
  441. return m_oContainer;
  442. }
  443. // depth
  444. private function __getDepth():Float
  445. {
  446. return m_nDepth;
  447. }
  448. private function __setDepth( p_nDepth:Float ):Float
  449. {
  450. m_nDepth = p_nDepth;
  451. changed = true;
  452. return p_nDepth;
  453. }
  454. // enableBackFaceCulling
  455. private override function __getEnableBackFaceCulling():Bool
  456. {
  457. return m_bBackFaceCulling;
  458. }
  459. private override function __setEnableBackFaceCulling( b:Bool ):Bool
  460. {
  461. if( b != m_bBackFaceCulling )
  462. {
  463. m_bBackFaceCulling = b;
  464. changed = true;
  465. }
  466. return b;
  467. }
  468. // enableClipping
  469. private function __getEnableClipping():Bool
  470. {
  471. return m_bClipping;
  472. }
  473. private override function __setEnableClipping( p_bClippingValue:Bool ):Bool
  474. {
  475. m_bClipping = p_bClippingValue;
  476. return p_bClippingValue;
  477. }
  478. // enableEvents (override from Node.hx)
  479. private override function __getEnableEvents():Bool
  480. {
  481. return m_bEv;
  482. }
  483. private override function __setEnableEvents( b:Bool ):Bool
  484. {
  485. // no change
  486. if( b == m_bEv )
  487. return b;
  488. if( b )
  489. subscribeEvents();
  490. else
  491. unsubscribeEvents();
  492. m_bEv = b;
  493. return b;
  494. }
  495. // enableInteractivity (from Node.hx)
  496. private override function __getEnableInteractivity():Bool
  497. {
  498. return m_bMouseInteractivity;
  499. }
  500. private override function __setEnableInteractivity( p_bState:Bool ):Bool
  501. {
  502. if( p_bState != m_bMouseInteractivity )
  503. {
  504. changed = true;
  505. // --
  506. if( p_bState )
  507. {
  508. if( m_bUseSingleContainer == true )
  509. {
  510. useSingleContainer = false;
  511. m_bForcedSingleContainer = true;
  512. }
  513. }
  514. else
  515. {
  516. if( m_bForcedSingleContainer == true )
  517. {
  518. useSingleContainer = true;
  519. m_bForcedSingleContainer = false;
  520. }
  521. }
  522. // --
  523. for ( l_oPolygon in aPolygons )
  524. {
  525. l_oPolygon.enableInteractivity = p_bState;
  526. }
  527. m_bMouseInteractivity = p_bState;
  528. }
  529. return p_bState;
  530. }
  531. // geometry
  532. private function __getGeometry():Geometry3D
  533. {
  534. return m_oGeometry;
  535. }
  536. private function __setGeometry( p_geometry:Geometry3D ):Geometry3D
  537. {
  538. if( p_geometry == null ) return null;
  539. // TODO shall we clone the geometry?
  540. m_oGeometry = p_geometry;
  541. updateBoundingVolumes();
  542. // -- we generate the possible missing normals
  543. m_oGeometry.generateFaceNormals();//Must be called first
  544. m_oGeometry.generateVertexNormals();//must be called second
  545. // --
  546. __destroyPolygons();
  547. __generatePolygons( m_oGeometry );
  548. changed = true;
  549. return p_geometry;
  550. }
  551. // geometryCenter
  552. private function __getGeometryCenter():Point3D
  553. {
  554. return m_oGeomCenter;
  555. }
  556. private function __setGeometryCenter( p_oGeomCenter:Point3D ):Point3D
  557. {
  558. var l_oDiff:Point3D = p_oGeomCenter.clone();
  559. l_oDiff.sub( m_oGeomCenter );
  560. // --
  561. if( m_oGeometry != null )
  562. {
  563. for ( l_oVertex in m_oGeometry.aVertex )
  564. {
  565. l_oVertex.x += l_oDiff.x;
  566. l_oVertex.y += l_oDiff.y;
  567. l_oVertex.z += l_oDiff.z;
  568. }
  569. }
  570. // --
  571. m_oGeomCenter.copy( p_oGeomCenter );
  572. // --
  573. updateBoundingVolumes();
  574. changed = true;
  575. return p_oGeomCenter;
  576. }
  577. // material
  578. public function __getMaterial():Material
  579. {
  580. return ( aPolygons[0].visible ) ? m_oAppearance.frontMaterial : m_oAppearance.backMaterial;
  581. }
  582. public function __setMaterial(v):Material
  583. {
  584. return throw "not implemented";
  585. }
  586. // scene (from Node.hx)
  587. private override function __setScene( p_oScene:Scene3D )
  588. {
  589. super.__setScene(p_oScene);
  590. if(aPolygons != null) {
  591. for( l_oPoly in aPolygons )
  592. {
  593. l_oPoly.scene = null;
  594. l_oPoly.scene = p_oScene;
  595. }
  596. }
  597. return p_oScene;
  598. }
  599. // useSingleContainer (from Node.hx)
  600. private override function __getUseSingleContainer ():Bool
  601. {
  602. return m_bUseSingleContainer;
  603. }
  604. private override function __setUseSingleContainer( p_bUseSingleContainer:Bool ):Bool
  605. {
  606. var l_oFace:Polygon;
  607. // No change
  608. if( p_bUseSingleContainer == m_bUseSingleContainer )
  609. return p_bUseSingleContainer;
  610. // update enableEvents that relies on useSingleContainer
  611. var useEvents = enableEvents;
  612. unsubscribeEvents();
  613. // --
  614. if( p_bUseSingleContainer )
  615. {
  616. for ( l_oFace in aPolygons )
  617. {
  618. if( l_oFace.container.parent != null )
  619. {
  620. l_oFace.container.graphics.clear();
  621. l_oFace.container.parent.removeChild( l_oFace.container );
  622. this.broadcaster.removeChild( l_oFace.broadcaster );
  623. }
  624. }
  625. }
  626. else
  627. {
  628. if( m_oContainer.parent != null )
  629. {
  630. m_oContainer.graphics.clear();
  631. m_oContainer.parent.removeChild( m_oContainer );
  632. }
  633. // --
  634. for ( l_oFace in aPolygons )
  635. {
  636. this.broadcaster.addChild( l_oFace.broadcaster );
  637. // we reset the polygon container to the original one, and add it to the world container
  638. l_oFace.container.graphics.clear();
  639. }
  640. }
  641. m_bUseSingleContainer = p_bUseSingleContainer;
  642. // reapply events
  643. if(useEvents)
  644. subscribeEvents();
  645. //--
  646. changed = true;
  647. return p_bUseSingleContainer;
  648. }
  649. /**
  650. * Faces sorting method.
  651. * With <code>useSingleContainer</code> set to <code>false</code> only <code>SORT_AVGZ</code> is possible.
  652. */
  653. public var sortingMode(__getSortingMode,__setSortingMode):Int;
  654. private inline function __getSortingMode ():Int {
  655. return m_bUseSingleContainer ? m_nSortingMode : SORT_AVGZ;
  656. }
  657. private inline function __setSortingMode (mode:Int):Int {
  658. if (m_bUseSingleContainer) {
  659. if (mode == SORT_LAZY_BSP) {
  660. bsp = BSPNode.makeLazyBSP (aPolygons, 0.01 * boundingSphere.radius);
  661. }
  662. m_nSortingMode = mode;
  663. changed = true;
  664. }
  665. return mode;
  666. }
  667. /////////////////////////////////////////////////////////////////////
  668. ///// PRIVATE /////
  669. /////////////////////////////////////////////////////////////////////
  670. private override function copy( src:Node, includeTransforms:Bool=false, includeGeometry:Bool=true ) : Void
  671. {
  672. if(!Std.is(src,Shape3D))
  673. throw "Invalid src";
  674. var o:Shape3D = cast src;
  675. var finalEvents = o.enableEvents;
  676. super.copy( src, includeTransforms );
  677. if(includeGeometry)
  678. geometry = o.geometry.clone();
  679. animated = o.animated;
  680. // aPolygons - set by geometry
  681. // aVisiblePolygons - ignore
  682. enableForcedDepth = o.enableForcedDepth;
  683. enableNearClipping = o.enableNearClipping;
  684. forcedDepth = o.forcedDepth;
  685. //m_oAppearance
  686. appearance = o.m_oAppearance;
  687. //m_bEv = o.m_bEv;
  688. //enableEvents (in Node.hx)
  689. //m_oGeomCenter
  690. geometryCenter = o.m_oGeomCenter.clone();
  691. //m_bBackFaceCulling (in Node.hx)
  692. m_bWasOver = false;
  693. m_oLastEvent = null;
  694. m_oLastContainer = null;
  695. //m_oGeometry - above
  696. //m_bUseSingleContainer (Node.hx)
  697. //m_oContainer - don't set
  698. //m_bMouseInteractivity (enableInteractivity) (in Node.hx)
  699. m_nDepth = o.m_nDepth;
  700. unsubscribeEvents();
  701. if(finalEvents)
  702. subscribeEvents();
  703. }
  704. private function __destroyPolygons():Void
  705. {
  706. if( aPolygons != null && aPolygons.length > 0 )
  707. {
  708. var i:Int = 0, l:Int = aPolygons.length;
  709. while( i<l )
  710. {
  711. if( broadcaster != null ) broadcaster.removeChild( aPolygons[i].broadcaster );
  712. if( aPolygons[i] != null ) aPolygons[i].destroy();
  713. // --
  714. aPolygons[i] = null;
  715. // --
  716. i ++;
  717. }
  718. }
  719. aPolygons.splice(0,aPolygons.length);
  720. }
  721. private function __generatePolygons( p_oGeometry:Geometry3D ):Void
  722. {
  723. var i:Int = 0, j:Int = 0, l:Int = p_oGeometry.aFacesVertexID.length;
  724. aPolygons = new Array();
  725. // --
  726. for( i in 0...l )
  727. {
  728. aPolygons[i] = new Polygon( this, p_oGeometry, p_oGeometry.aFacesVertexID[i], p_oGeometry.aFacesUVCoordsID[i], i, i );
  729. if( m_oAppearance != null ) aPolygons[i].appearance = m_oAppearance;
  730. this.broadcaster.addChild( aPolygons[i].broadcaster );
  731. }
  732. }
  733. private function _onInteraction( p_oEvt:Event ):Void
  734. {
  735. // we need to get the polygon which has been clicked.
  736. var l_oClick:Point = new Point( m_oContainer.mouseX, m_oContainer.mouseY );
  737. var l_oA:Point = new Point(), l_oB:Point = new Point(), l_oC:Point = new Point();
  738. var l_oPoly:Polygon;
  739. var l_aSId:Array<Int> = untyped aPolygons.sortOn( 'm_nDepth', Array.NUMERIC | Array.RETURNINDEXEDARRAY );
  740. var l:Int = aPolygons.length, j:Int;
  741. for( j in 0...l )
  742. {
  743. l_oPoly = aPolygons[ l_aSId[ j ] ];
  744. if( !l_oPoly.visible && m_bBackFaceCulling ) continue;
  745. // --
  746. var l_nSize:Int = l_oPoly.vertices.length;
  747. var l_nTriangles:Int = l_nSize - 2;
  748. for( i in 0...l_nTriangles )
  749. {
  750. l_oA.x = l_oPoly.vertices[i].sx; l_oA.y = l_oPoly.vertices[i].sy;
  751. l_oB.x = l_oPoly.vertices[i+1].sx; l_oB.y = l_oPoly.vertices[i+1].sy;
  752. l_oC.x = l_oPoly.vertices[(i+2)%l_nSize].sx; l_oC.y = l_oPoly.vertices[(i+2)%l_nSize].sy;
  753. // --
  754. if( IntersectionMath.isPointInTriangle2D( l_oClick, l_oA, l_oB, l_oC ) )
  755. {
  756. var l_oUV:UVCoord = l_oPoly.getUVFrom2D( l_oClick );
  757. var l_oPt3d:Point3D = l_oPoly.get3DFrom2D( l_oClick );
  758. m_oLastContainer = m_oContainer;
  759. m_oLastEvent = new Shape3DEvent( p_oEvt.type, this, l_oPoly, l_oUV, l_oPt3d, p_oEvt );
  760. m_oEB.dispatchEvent( m_oLastEvent );
  761. // to be able to dispatch mouse out event
  762. if( p_oEvt.type == MouseEvent.MOUSE_OVER )
  763. m_bWasOver = true;
  764. return;
  765. }
  766. }
  767. }
  768. }
  769. private function subscribeEvents()
  770. {
  771. if( m_bUseSingleContainer == false )
  772. {
  773. for ( v in aPolygons )
  774. {
  775. v.enableEvents = true;
  776. }
  777. }
  778. else
  779. {
  780. m_oContainer.addEventListener(MouseEvent.CLICK, _onInteraction,false,0,true);
  781. m_oContainer.addEventListener(MouseEvent.MOUSE_UP, _onInteraction,false,0,true);
  782. m_oContainer.addEventListener(MouseEvent.MOUSE_DOWN, _onInteraction,false,0,true);
  783. m_oContainer.addEventListener(MouseEvent.ROLL_OVER, _onInteraction,false,0,true);
  784. m_oContainer.addEventListener(MouseEvent.ROLL_OUT, _onInteraction,false,0,true);
  785. m_oContainer.addEventListener(MouseEvent.DOUBLE_CLICK, _onInteraction,false,0,true);
  786. m_oContainer.addEventListener(MouseEvent.MOUSE_MOVE, _onInteraction,false,0,true);
  787. m_oContainer.addEventListener(MouseEvent.MOUSE_OVER, _onInteraction,false,0,true);
  788. m_oContainer.addEventListener(MouseEvent.MOUSE_OUT, _onInteraction,false,0,true);
  789. m_oContainer.addEventListener(MouseEvent.MOUSE_WHEEL, _onInteraction,false,0,true);
  790. }
  791. }
  792. private function unsubscribeEvents()
  793. {
  794. for ( v in aPolygons )
  795. {
  796. v.enableEvents = false;
  797. }
  798. m_oContainer.removeEventListener(MouseEvent.CLICK, _onInteraction);
  799. m_oContainer.removeEventListener(MouseEvent.MOUSE_UP, _onInteraction);
  800. m_oContainer.removeEventListener(MouseEvent.MOUSE_DOWN, _onInteraction);
  801. m_oContainer.removeEventListener(MouseEvent.ROLL_OVER, _onInteraction);
  802. m_oContainer.removeEventListener(MouseEvent.ROLL_OUT, _onInteraction);
  803. m_oContainer.removeEventListener(MouseEvent.DOUBLE_CLICK, _onInteraction);
  804. m_oContainer.removeEventListener(MouseEvent.MOUSE_MOVE, _onInteraction);
  805. m_oContainer.removeEventListener(MouseEvent.MOUSE_OVER, _onInteraction);
  806. m_oContainer.removeEventListener(MouseEvent.MOUSE_OUT, _onInteraction);
  807. m_oContainer.removeEventListener(MouseEvent.MOUSE_WHEEL, _onInteraction);
  808. }
  809. /**
  810. * Updates polygons, face and vertex normals when geometry vertex values have changed.
  811. * Do not call if the geometry has been modified in any way other than
  812. * when the x,y,z positions of some vertices have changed. If the provided
  813. * geometry is not the same as the existing geometry, this will have the
  814. * same effect as assigning a new geometry.
  815. *
  816. * @param p_oGeometry Geometry object which must be the same size as existing geometry
  817. */
  818. private function updateForGeometryChange( p_oGeometry:Geometry3D, updateNormals:Bool=true, updateBounds:Bool=true ) : Void
  819. {
  820. if(m_oGeometry == null || m_oGeometry.aFacesVertexID.length != p_oGeometry.aFacesVertexID.length) {
  821. __setGeometry( p_oGeometry );
  822. return;
  823. }
  824. m_oGeometry = p_oGeometry;
  825. if(updateBounds)
  826. updateBoundingVolumes();
  827. if(updateNormals)
  828. m_oGeometry.updateFaceNormals(); // Must be called first
  829. //m_oGeometry.updateVertexNormals(); // Vertex normals already tied to face normals
  830. var l:Int = m_oGeometry.aFacesVertexID.length;
  831. // --
  832. for( i in 0...l )
  833. {
  834. aPolygons[i].update( m_oGeometry.aFacesVertexID[i] );
  835. }
  836. changed = true;
  837. }
  838. // ______________
  839. // [PRIVATE] DATA________________________________________________
  840. private var m_oAppearance:Appearance ; // The Appearance of this Shape3D
  841. private var m_bEv:Bool; // The event system state (enable or not)
  842. private var m_oGeomCenter:Point3D;
  843. private var m_bBackFaceCulling:Bool;
  844. private var m_bClipping:Bool;
  845. // interaction
  846. public var m_bWasOver:Bool;
  847. public var m_oLastEvent:Shape3DEvent;
  848. public var m_oLastContainer:Sprite;
  849. /** Geometry of this object */
  850. private var m_oGeometry:Geometry3D;
  851. private var m_bUseSingleContainer:Bool;
  852. public var m_nDepth:Float;
  853. private var m_oContainer:Sprite;
  854. private var m_bMouseInteractivity:Bool;
  855. private var m_bForcedSingleContainer:Bool;
  856. private var m_nSortingMode:Int;
  857. }