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

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

http://sandy.googlecode.com/
Haxe | 933 lines | 538 code | 74 blank | 321 comment | 123 complexity | 23498fc63e36c2901fa633b5f276b77b 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. import flash.display.Sprite;
  17. import flash.events.Event;
  18. import flash.events.MouseEvent;
  19. import flash.geom.Point;
  20. import sandy.bounds.BBox;
  21. import sandy.bounds.BSphere;
  22. import sandy.core.SandyFlags;
  23. import sandy.core.Scene3D;
  24. import sandy.core.data.Matrix4;
  25. import sandy.core.data.Polygon;
  26. import sandy.core.data.Vector;
  27. import sandy.core.data.Vertex;
  28. import sandy.events.BubbleEvent;
  29. import sandy.materials.Appearance;
  30. import sandy.materials.Material;
  31. import sandy.materials.WireFrameMaterial;
  32. import sandy.math.IntersectionMath;
  33. import sandy.view.CullingState;
  34. import sandy.view.Frustum;
  35. import sandy.core.data.UVCoord;
  36. import sandy.events.Shape3DEvent;
  37. /**
  38. * The Shape3D class is the base class of all true 3D shapes.
  39. *
  40. * <p>It represents a node in the object tree of the world.<br/>
  41. * A Shape3D is a leaf node and can not have any child nodes.</p>
  42. * <p>It must be the child of a branch group or a transform group,
  43. * but transformations can be applied to the Shape directly.</p>
  44. *
  45. * @author Thomas Pfeiffer - kiroukou
  46. * @author Niel Drummond - haXe port
  47. *
  48. */
  49. class Shape3D extends ATransformable, implements IDisplayable
  50. {
  51. /**
  52. * Default material for the DEFAULT_APPEARANCE object
  53. */
  54. public static var DEFAULT_MATERIAL:Material = new WireFrameMaterial();
  55. /**
  56. * 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
  57. */
  58. public static var DEFAULT_APPEARANCE:Appearance = new Appearance( DEFAULT_MATERIAL );
  59. /**
  60. * The array of polygons building this object.
  61. */
  62. public var aPolygons:Array<Polygon>;
  63. /**
  64. * This property will remains null until a material needs it, defining the SandyFlag INVERT_MODEL_MATRIX
  65. * In that case, that property will return the invert model matrix on that node
  66. */
  67. public var invModelMatrix:Matrix4;
  68. /**
  69. * <p>
  70. * Enable the Frustum near plane clipping on the visible polygons.
  71. * Enable this when you need a perfect intersection between the front camera plane.
  72. * This is mainly used when you need the camera to move on a long plane.</p>
  73. *
  74. * <p>Important: Enable the clipping makes process a bit slower, especially with big scenes.</p>
  75. */
  76. public var enableNearClipping:Bool;
  77. /**
  78. * <p>
  79. * Enable the Frustum clipping on the visible polygons.
  80. * Enable this when you need a perfect intersection between the camera and some object shapes.
  81. * In case you need to make the camera look inside and outide a box, or other immerssive things.</p>
  82. *
  83. * <p>Important: Enable the clipping makes process a bit slower, especially with big scenes.</p>
  84. *
  85. * <p>Specify if this object polygons should be clipped against the camera frustum planes.</p>
  86. */
  87. public var enableClipping:Bool;
  88. /**
  89. * Should forced depth be enable for this object?.
  90. *
  91. * <p>If true it is possible to force this object to be drawn at a specific depth,<br/>
  92. * if false the normal Z-sorting algorithm is applied.</p>
  93. * <p>When correctly used, this feature allows you to aVoid some Z-sorting problems.</p>
  94. */
  95. public var enableForcedDepth:Bool;
  96. /**
  97. * The forced depth for this object.
  98. *
  99. * <p>To make this feature work, you must enable the ForcedDepth system too.<br/>
  100. * The higher the depth is, the sooner the more far the object will be represented.</p>
  101. */
  102. public var forcedDepth:Float;
  103. /**
  104. * Creates a 3D object
  105. *
  106. * <p>[<b>Todo</b>: some more explanations]</p>
  107. *
  108. * @param p_sName A string identifier for this object
  109. * @param p_oGeometry The geometry of this object
  110. * @param p_oAppearance The appearance of this object. If no apperance is given, the DEFAULT_APPEARANCE will be applied.
  111. * @param p_bUseSingleContainer Whether tis object should use a single container to draw on
  112. */
  113. public function new( ?p_sName:String, ?p_oGeometry:Geometry3D, ?p_oAppearance:Appearance, ?p_bUseSingleContainer:Bool )
  114. {
  115. aPolygons = new Array();
  116. enableNearClipping = false;
  117. enableClipping = false;
  118. enableForcedDepth = false;
  119. forcedDepth = 0;
  120. m_bEv = false;
  121. m_oGeomCenter = new Vector();
  122. m_bBackFaceCulling = true;
  123. m_bClipped = false;
  124. m_bUseSingleContainer = true;
  125. m_nDepth = 0;
  126. m_aToProject = new Array();
  127. m_aVisiblePoly = new Array();
  128. m_bMouseInteractivity = false;
  129. m_bForcedSingleContainer = false;
  130. m_bNotConvex = true;
  131. invModelMatrix = new Matrix4 ();
  132. if( p_sName == null ) p_sName = "";
  133. if ( p_bUseSingleContainer == null ) p_bUseSingleContainer =true;
  134. super( p_sName );
  135. // -- Add this graphical object to the World display list
  136. m_oContainer = new Sprite();
  137. // --
  138. geometry = p_oGeometry;
  139. // -- HACK to make sure that the correct container system will be applied
  140. m_bUseSingleContainer = !p_bUseSingleContainer;
  141. useSingleContainer = p_bUseSingleContainer;
  142. // --
  143. appearance = ( p_oAppearance != null ) ? p_oAppearance : Shape3D.DEFAULT_APPEARANCE;
  144. // --
  145. updateBoundingVolumes();
  146. }
  147. /**
  148. * setter that allow user to change the way to render this object.
  149. * set to true, the shape will be rendered into a single Sprite object, which is accessible through the container property.
  150. * set to false, the container property does not target anything, but all the polygons will be rendered into their own dedidated container.
  151. *
  152. * <p>If true, this object renders itself on a single container ( Sprite ),<br/>
  153. * if false, each polygon is rendered on its own container.</p>
  154. */
  155. override public var useSingleContainer( __getUseSingleContainer,__setUseSingleContainer ):Bool;
  156. override private function __setUseSingleContainer( p_bUseSingleContainer:Bool ):Bool
  157. {
  158. var l_oFace:Polygon;
  159. // --
  160. if( p_bUseSingleContainer == m_bUseSingleContainer ) return p_bUseSingleContainer;
  161. // --
  162. if( p_bUseSingleContainer )
  163. {
  164. for ( l_oFace in aPolygons )
  165. {
  166. if( l_oFace.container.parent != null )
  167. {
  168. l_oFace.container.graphics.clear();
  169. l_oFace.container.parent.removeChild( l_oFace.container );
  170. this.broadcaster.removeChild( l_oFace.broadcaster );
  171. }
  172. }
  173. }
  174. else
  175. {
  176. if( m_oContainer.parent != null )
  177. {
  178. m_oContainer.graphics.clear();
  179. m_oContainer.parent.removeChild( m_oContainer );
  180. }
  181. // --
  182. for ( l_oFace in aPolygons )
  183. {
  184. this.broadcaster.addChild( l_oFace.broadcaster );
  185. // we reset the polygon container to the original one, and add it to the world container
  186. l_oFace.container.graphics.clear();
  187. }
  188. }
  189. m_bUseSingleContainer = p_bUseSingleContainer;
  190. return p_bUseSingleContainer;
  191. }
  192. /**
  193. * @private
  194. */
  195. override private function __getUseSingleContainer ():Bool
  196. {return m_bUseSingleContainer;}
  197. /**
  198. * Updates the bounding volumes of this object.
  199. */
  200. public function updateBoundingVolumes():Void
  201. {
  202. if( m_oGeometry != null )
  203. {
  204. boundingSphere = BSphere.create( m_oGeometry.aVertex );
  205. boundingBox = BBox.create( m_oGeometry.aVertex );
  206. }
  207. }
  208. /**
  209. * Tests this node against the camera frustum to get its visibility.
  210. *
  211. * <p>If this node and its children are not within the frustum,
  212. * the node is set to cull and it would not be displayed.<p/>
  213. * <p>The method also updates the bounding volumes to make the more accurate culling system possible.<br/>
  214. * First the bounding sphere is updated, and if intersecting,
  215. * the bounding box is updated to perform the more precise culling.</p>
  216. * <p><b>[MANDATORY] The update method must be called first!</b></p>
  217. *
  218. * @param p_oScene The current scene
  219. * @param p_oFrustum The frustum of the current camera
  220. * @param p_oViewMatrix The view martix of the curren camera
  221. * @param p_bChanged
  222. */
  223. public override function cull( p_oScene:Scene3D, p_oFrustum:Frustum, p_oViewMatrix:Matrix4, p_bChanged:Bool ):Void
  224. {
  225. super.cull( p_oScene, p_oFrustum, p_oViewMatrix, p_bChanged );
  226. if( culled == Frustum.OUTSIDE ) return;
  227. /////////////////////////
  228. //// BOUNDING SPHERE ////
  229. /////////////////////////
  230. if( !boundingSphere.uptodate ) boundingSphere.transform( viewMatrix );
  231. culled = p_oFrustum.sphereInFrustum( boundingSphere );
  232. // --
  233. if( culled == Frustum.INTERSECT && boundingBox != null )
  234. {
  235. ////////////////////////
  236. //// BOUNDING BOX ////
  237. ////////////////////////
  238. if( !boundingBox.uptodate ) boundingBox.transform( viewMatrix );
  239. culled = p_oFrustum.boxInFrustum( boundingBox );
  240. }
  241. m_bClipped = ((culled == CullingState.INTERSECT) && ( enableClipping || enableNearClipping ));
  242. }
  243. /**
  244. * Renders this 3D object.
  245. *
  246. * @param p_oScene The current scene
  247. * @param p_oCamera The current camera
  248. */
  249. public override function render( p_oScene:Scene3D, p_oCamera:Camera3D ):Void
  250. {
  251. // IF no appearance has bene applied, no display
  252. if( m_oAppearance == null ) return;
  253. var m11:Float, m21:Float, m31:Float,
  254. m12:Float, m22:Float, m32:Float,
  255. m13:Float, m23:Float, m33:Float,
  256. m14:Float, m24:Float, m34:Float,
  257. x:Float, y:Float, z:Float, tx:Float, ty:Float, tz:Float;
  258. var l_nZNear:Float = p_oCamera.near, l_aPoints:Array<Vertex> = m_oGeometry.aVertex,
  259. l_oMatrix:Matrix4 = viewMatrix, l_oFrustum:Frustum = p_oCamera.frustrum,
  260. l_aVertexNormals:Array<Dynamic> = m_oGeometry.aVertexNormals,
  261. l_oVertexNormal:Vertex, l_oVertex:Vertex, l_oFace:Polygon, l_nMinZ:Float;
  262. // -- Now we can transform the objet vertices into the camera coordinates
  263. l_oMatrix = viewMatrix;
  264. m11 = l_oMatrix.n11; m21 = l_oMatrix.n21; m31 = l_oMatrix.n31;
  265. m12 = l_oMatrix.n12; m22 = l_oMatrix.n22; m32 = l_oMatrix.n32;
  266. m13 = l_oMatrix.n13; m23 = l_oMatrix.n23; m33 = l_oMatrix.n33;
  267. m14 = l_oMatrix.n14; m24 = l_oMatrix.n24; m34 = l_oMatrix.n34;
  268. for ( l_oVertex in l_aPoints )
  269. {
  270. l_oVertex.wx = (x=l_oVertex.x) * m11 + (y=l_oVertex.y) * m12 + (z=l_oVertex.z) * m13 + m14;
  271. l_oVertex.wy = x * m21 + y * m22 + z * m23 + m24;
  272. l_oVertex.wz = x * m31 + y * m32 + z * m33 + m34;
  273. l_oVertex.projected = false;
  274. }
  275. // -- The polygons will be clipped, we shall allocate a new array container the clipped vertex.
  276. m_aVisiblePoly = [];
  277. m_nVisiblePoly = 0;
  278. m_nDepth = 0;
  279. for ( l_oFace in aPolygons )
  280. {
  281. l_oFace.isClipped = false;
  282. // --
  283. x = l_oFace.normal.x ; y = l_oFace.normal.y ; z = l_oFace.normal.z ;
  284. // --
  285. tx = x * m11+ y * m12+ z * m13;
  286. ty = x * m21+ y * m22+ z * m23;
  287. tz = x * m31+ y * m32+ z * m33;
  288. // -- visibility computation
  289. x = l_oFace.a.wx*tx + l_oFace.a.wy*ty + l_oFace.a.wz*tz;
  290. l_oFace.visible = x < 0;
  291. // --
  292. if( l_oFace.visible || !m_bBackFaceCulling)
  293. {
  294. l_oFace.precompute();
  295. l_nMinZ = l_oFace.minZ;
  296. // --
  297. if( m_bClipped && enableClipping ) // NEED COMPLETE CLIPPING
  298. {
  299. l_oFace.clip( l_oFrustum );
  300. // -- We project the vertices
  301. if( l_oFace.cvertices.length > 2 )
  302. {
  303. p_oCamera.projectArray( l_oFace.cvertices );
  304. if( !enableForcedDepth ) m_nDepth += l_oFace.m_nDepth;
  305. else l_oFace.depth = forcedDepth;
  306. // -- we manage the display list depending on the mode choosen
  307. m_aVisiblePoly[(m_nVisiblePoly++)] = l_oFace;
  308. }
  309. }
  310. else if( enableNearClipping && l_nMinZ < l_nZNear ) // PARTIALLY VISIBLE
  311. {
  312. l_oFace.clipFrontPlane( l_oFrustum );
  313. // -- We project the vertices
  314. if( l_oFace.cvertices.length > 2 )
  315. {
  316. p_oCamera.projectArray( l_oFace.cvertices );
  317. if( !enableForcedDepth ) m_nDepth += l_oFace.m_nDepth;
  318. else l_oFace.depth = forcedDepth;
  319. // -- we manage the display list depending on the mode choosen
  320. m_aVisiblePoly[(m_nVisiblePoly++)] = l_oFace;
  321. }
  322. }
  323. else if( l_nMinZ >= l_nZNear )
  324. {
  325. p_oCamera.projectArray( l_oFace.vertices );
  326. if( !enableForcedDepth ) m_nDepth += l_oFace.m_nDepth;
  327. else l_oFace.depth = forcedDepth;
  328. // -- we manage the display list depending on the mode choosen
  329. m_aVisiblePoly[(m_nVisiblePoly++)] = l_oFace;
  330. }
  331. else
  332. continue;
  333. if( l_oFace.hasAppearanceChanged )
  334. {
  335. if( p_oScene.materialManager.isRegistered( l_oFace.appearance.frontMaterial ) == false )
  336. {
  337. p_oScene.materialManager.register( l_oFace.appearance.frontMaterial );
  338. }
  339. if( l_oFace.appearance.frontMaterial != l_oFace.appearance.backMaterial )
  340. {
  341. if( p_oScene.materialManager.isRegistered( l_oFace.appearance.backMaterial ) == false )
  342. {
  343. p_oScene.materialManager.register( l_oFace.appearance.backMaterial );
  344. }
  345. }
  346. l_oFace.hasAppearanceChanged = false;
  347. }
  348. }
  349. }
  350. // --
  351. if( m_bUseSingleContainer )
  352. {
  353. if(enableForcedDepth) m_nDepth = forcedDepth;
  354. else m_nDepth /= m_aVisiblePoly.length;
  355. p_oCamera.addToDisplayList( this );
  356. }
  357. else
  358. {
  359. p_oCamera.addArrayToDisplayList( untyped( m_aVisiblePoly ) );
  360. }
  361. var l_nFlags:Int = appearance.flags;
  362. if( l_nFlags == 0 ) return;
  363. var i:Int;
  364. l_oMatrix = modelMatrix;
  365. m11 = l_oMatrix.n11; m21 = l_oMatrix.n21; m31 = l_oMatrix.n31;
  366. m12 = l_oMatrix.n12; m22 = l_oMatrix.n22; m32 = l_oMatrix.n32;
  367. m13 = l_oMatrix.n13; m23 = l_oMatrix.n23; m33 = l_oMatrix.n33;
  368. if( appearance.flags & SandyFlags.POLYGON_NORMAL_WORLD > 0 )
  369. {
  370. // -- Now we transform the normals.
  371. for ( l_oPoly in m_aVisiblePoly )
  372. {
  373. l_oVertex = l_oPoly.normal;
  374. l_oVertex.wx = (x=l_oVertex.x) * m11 + (y=l_oVertex.y) * m12 + (z=l_oVertex.z) * m13;
  375. l_oVertex.wy = x * m21 + y * m22 + z * m23;
  376. l_oVertex.wz = x * m31 + y * m32 + z * m33;
  377. }
  378. }
  379. if( appearance.flags & SandyFlags.VERTEX_NORMAL_WORLD > 0 )
  380. {
  381. // -- Now we transform the normals.
  382. i = m_oGeometry.aVertexNormals.length;
  383. while( --i > -1 )
  384. {
  385. if( m_oGeometry.aVertex[(i)].projected )
  386. {
  387. l_oVertex = m_oGeometry.aVertexNormals[(i)];
  388. l_oVertex.wx = (x=l_oVertex.x) * m11 + (y=l_oVertex.y) * m12 + (z=l_oVertex.z) * m13;
  389. l_oVertex.wy = x * m21 + y * m22 + z * m23;
  390. l_oVertex.wz = x * m31 + y * m32 + z * m33;
  391. }
  392. }
  393. }
  394. }
  395. public function __getVisiblePolygonsCount():Int
  396. {
  397. return m_nVisiblePoly;
  398. }
  399. /**
  400. * Clears the graphics object of this object's container.
  401. *
  402. * <p>The the graphics that were drawn on the Graphics object is erased,
  403. * and the fill and line style settings are reset.</p>
  404. */
  405. public function clear():Void
  406. {
  407. if( m_oContainer != null ) m_oContainer.graphics.clear();
  408. }
  409. /**
  410. * Performs a z-sorting and renders the objects visible polygons.
  411. *
  412. * <p>The method is called only if the object renders on a single container<br/>
  413. * - ( useSingleContainer = true ).</p>
  414. *
  415. * @param p_oScene The current scene
  416. * @param p_oContainer The container to draw on
  417. */
  418. public function display( p_oScene:Scene3D, ?p_oContainer:Sprite ):Void
  419. {
  420. if (m_bNotConvex) {
  421. // sort only if convex flag is not set
  422. #if flash
  423. untyped m_aVisiblePoly.sortOn( "m_nDepth", Array.NUMERIC | Array.DESCENDING );
  424. #else
  425. m_aVisiblePoly.sort( function(a,b) {return a.depth>b.depth?1:a.depth<b.depth?-1:0;} );
  426. #end
  427. }
  428. for ( l_oPoly in m_aVisiblePoly )
  429. {
  430. l_oPoly.display( p_oScene, m_oContainer );
  431. }
  432. }
  433. /**
  434. * The contianer for this object.
  435. * This container property exist if the useSingleContainer is set to true.
  436. * It is a direct access to the Shape3D container to, for example, apply nice effects such as filters etc.
  437. */
  438. public var container(__getContainer,null):Sprite;
  439. private function __getContainer():Sprite
  440. {return m_oContainer;}
  441. /**
  442. * The depth of this object.
  443. * In case the useSingleContainer mode is enabled (default mode), this value returns the means depth of the Shape in the camera frame.
  444. * This value is mainly used as a z-sorting value.
  445. */
  446. public var depth(__getDepth,__setDepth):Float;
  447. private function __getDepth():Float
  448. {return m_nDepth;}
  449. private function __setDepth( p_nDepth:Float ):Float {
  450. return p_nDepth;
  451. }
  452. /**
  453. * This property call allows you to get the geometryCenter offset vector of the Shape.
  454. * Modifying this vector will impact the way the shape is rendered, mainly its rotation center.
  455. *
  456. * @return a vector which corresponds to the 2 directions offset.
  457. */
  458. public var geometryCenter(__getGeometryCenter,__setGeometryCenter):Vector;
  459. private function __getGeometryCenter():Vector
  460. {return m_oGeomCenter;}
  461. /**
  462. * Change the geometryCenter of the Shape3D.
  463. * To change the geometryCenter point of a shape, simply set this geometryCenter property.
  464. * The geometryCenter property requires a vector. This vector is an position offset relative to the original geometry one.
  465. * For example, a Sphere primitive creates automatically a geometry which center is the 0,0,0 position. If you rotate this sphere as this,
  466. * it will rotate around its center.
  467. * Now if you set the geometryCenter property, this rotation center will change.
  468. *
  469. * The updateBoundingVolumes method which does update the bounding volumes to enable a correct frustum culling is automatically called.
  470. *
  471. * @example To change the geometryCenter center at runtime
  472. * <listing version="3.0">
  473. * var l_oSphere:Sphere = new Sphere("mySphere", 50, 3 );
  474. * // Change the rotation reference to -50 offset in Y direction from the orinal one
  475. * // and that corresponds to the bottom of the sphere
  476. * l_oSphere.geometryCenter = new Vector( 0, -50, 0 );
  477. * l_oSphere.rotateZ = 45;
  478. * </listing>
  479. */
  480. private function __setGeometryCenter( p_oGeomCenter:Vector ):Vector
  481. {
  482. var l_oDiff:Vector = p_oGeomCenter.clone();
  483. l_oDiff.sub( m_oGeomCenter );
  484. // --
  485. if( m_oGeometry != null )
  486. {
  487. for ( l_oVertex in m_oGeometry.aVertex )
  488. {
  489. l_oVertex.x += l_oDiff.x;
  490. l_oVertex.y += l_oDiff.y;
  491. l_oVertex.z += l_oDiff.z;
  492. }
  493. }
  494. // --
  495. m_oGeomCenter.copy( p_oGeomCenter );
  496. // --
  497. updateBoundingVolumes();
  498. return p_oGeomCenter;
  499. }
  500. /**
  501. * The appearance of this object.
  502. */
  503. override private function __setAppearance( p_oApp:Appearance ):Appearance
  504. {
  505. // Now we register to the update event
  506. m_oAppearance = p_oApp;
  507. // --
  508. if( m_oGeometry != null )
  509. {
  510. for ( v in aPolygons )
  511. v.appearance = m_oAppearance;
  512. }
  513. return p_oApp;
  514. }
  515. /**
  516. * @private
  517. */
  518. override public var appearance(__getAppearance,__setAppearance):Appearance;
  519. override private function __getAppearance():Appearance
  520. {
  521. return m_oAppearance;
  522. }
  523. /**
  524. * The geometry of this object.
  525. */
  526. private function __setGeometry( p_geometry:Geometry3D ):Geometry3D
  527. {
  528. if( p_geometry == null ) return null;
  529. // TODO shall we clone the geometry?
  530. m_oGeometry = p_geometry;
  531. updateBoundingVolumes();
  532. // -- we generate the possible missing normals
  533. m_oGeometry.generateFaceNormals();//Must be called first
  534. m_oGeometry.generateVertexNormals();//must be called second
  535. // --
  536. __destroyPolygons();
  537. __generatePolygons( m_oGeometry );
  538. return p_geometry;
  539. }
  540. /**
  541. * @private
  542. */
  543. public var geometry(__getGeometry,__setGeometry):Geometry3D;
  544. private function __getGeometry():Geometry3D
  545. {
  546. return m_oGeometry;
  547. }
  548. /**
  549. * Should back face culling be enabled for this object?.
  550. *
  551. * <p>If set to false all faces of this object are drawn.<br/>
  552. * A true value enables the back face culling algorithm - Default true</p>
  553. */
  554. override private function __setEnableBackFaceCulling( b:Bool ):Bool
  555. {
  556. if( b != m_bBackFaceCulling )
  557. {
  558. m_bBackFaceCulling = b;
  559. changed = true;
  560. }
  561. return b;
  562. }
  563. /**
  564. * @private
  565. */
  566. override public var enableBackFaceCulling(__getEnableBackFaceCulling,__setEnableBackFaceCulling):Bool;
  567. override private function __getEnableBackFaceCulling():Bool
  568. {
  569. return m_bBackFaceCulling;
  570. }
  571. /**
  572. * Enable the interactivity on this shape and its polygon.
  573. * Be careful, this mode have some requirements :
  574. * - to have useSingleContainer set to false. It is done automatically if enabled
  575. *
  576. * The original settings are back to their original state when the mode is disabled
  577. */
  578. override private function __setEnableInteractivity( p_bState:Bool ):Bool
  579. {
  580. if( p_bState != m_bMouseInteractivity )
  581. {
  582. if( p_bState )
  583. {
  584. if( m_bUseSingleContainer == true )
  585. {
  586. m_bUseSingleContainer = false;
  587. m_bForcedSingleContainer = true;
  588. }
  589. }
  590. else
  591. {
  592. if( m_bForcedSingleContainer == true )
  593. {
  594. useSingleContainer = true;
  595. m_bForcedSingleContainer = false;
  596. }
  597. }
  598. // --
  599. for ( l_oPolygon in aPolygons )
  600. {
  601. l_oPolygon.enableInteractivity = p_bState;
  602. }
  603. m_bMouseInteractivity = p_bState;
  604. }
  605. return p_bState;
  606. }
  607. override public var enableInteractivity(__getEnableInteractivity,__setEnableInteractivity):Bool;
  608. override private function __getEnableInteractivity():Bool
  609. { return m_bMouseInteractivity; }
  610. /**
  611. * Enables the event system for mouse events.
  612. *
  613. * <p>When set to true, the onPress, onRollOver and onRollOut events are broadcast.<br/>
  614. * The event system is enabled or disabled for all faces of this object.<br/>
  615. * As an alternative, you have the possibility to enable events only for specific faces.</p>
  616. *
  617. * <p>Once this feature is enabled, the animation is more CPU intensive.</p>
  618. *
  619. * <p>Example
  620. * <code>
  621. * var l_oShape:Shape3D = new Sphere("sphere");
  622. * l_oShape.enableEvents = true;
  623. * l_oShape.addEventListener( MouseEvent.CLICK, onClick );
  624. *
  625. * function onClick( p_eEvent:Shape3DEvent ):Void
  626. * {
  627. * var l_oPoly:Polygon = ( p_eEvent.polygon );
  628. * var l_oPointAtClick:Vector = p_eEvent.point;
  629. * // -- get the normalized uv of the point under mouse position
  630. * var l_oIntersectionUV:UVCoord = p_eEvent.uv;
  631. * // -- get the correct material
  632. * var l_oMaterial:BitmapMaterial = (l_oPoly.visible ? l_oPoly.appearance.frontMaterial : l_oPoly.appearance.backMaterial) as BitmapMaterial;
  633. * }
  634. * </code>
  635. */
  636. override public var enableEvents(__getEnableEvents,__setEnableEvents):Bool;
  637. override private function __getEnableEvents():Bool
  638. {
  639. return false;
  640. }
  641. override private function __setEnableEvents( b:Bool ):Bool
  642. {
  643. // To use only when use Single container is disabled
  644. var v:Polygon = null;
  645. if( b )
  646. {
  647. if( !m_bEv )
  648. {
  649. if( m_bUseSingleContainer == false )
  650. {
  651. for ( v in aPolygons )
  652. {
  653. v.enableEvents = true;
  654. }
  655. }
  656. else
  657. {
  658. m_oContainer.addEventListener(MouseEvent.CLICK, _onInteraction);
  659. m_oContainer.addEventListener(MouseEvent.MOUSE_UP, _onInteraction);
  660. m_oContainer.addEventListener(MouseEvent.MOUSE_DOWN, _onInteraction);
  661. m_oContainer.addEventListener(MouseEvent.ROLL_OVER, _onInteraction);
  662. m_oContainer.addEventListener(MouseEvent.ROLL_OUT, _onInteraction);
  663. m_oContainer.addEventListener(MouseEvent.DOUBLE_CLICK, _onInteraction);
  664. m_oContainer.addEventListener(MouseEvent.MOUSE_MOVE, _onInteraction);
  665. m_oContainer.addEventListener(MouseEvent.MOUSE_OVER, _onInteraction);
  666. m_oContainer.addEventListener(MouseEvent.MOUSE_OUT, _onInteraction);
  667. m_oContainer.addEventListener(MouseEvent.MOUSE_WHEEL, _onInteraction);
  668. }
  669. }
  670. }
  671. else if( !b && m_bEv )
  672. {
  673. if( m_bUseSingleContainer == false )
  674. {
  675. for ( v in aPolygons )
  676. {
  677. v.enableEvents = false;
  678. }
  679. }
  680. else
  681. {
  682. m_oContainer.removeEventListener(MouseEvent.CLICK, _onInteraction);
  683. m_oContainer.removeEventListener(MouseEvent.MOUSE_UP, _onInteraction);
  684. m_oContainer.removeEventListener(MouseEvent.MOUSE_DOWN, _onInteraction);
  685. m_oContainer.removeEventListener(MouseEvent.ROLL_OVER, _onInteraction);
  686. m_oContainer.removeEventListener(MouseEvent.ROLL_OUT, _onInteraction);
  687. m_oContainer.removeEventListener(MouseEvent.DOUBLE_CLICK, _onInteraction);
  688. m_oContainer.removeEventListener(MouseEvent.MOUSE_MOVE, _onInteraction);
  689. m_oContainer.removeEventListener(MouseEvent.MOUSE_OVER, _onInteraction);
  690. m_oContainer.removeEventListener(MouseEvent.MOUSE_OUT, _onInteraction);
  691. m_oContainer.removeEventListener(MouseEvent.MOUSE_WHEEL, _onInteraction);
  692. }
  693. }
  694. m_bEv = b;
  695. return b;
  696. }
  697. private function _onInteraction( p_oEvt:Event ):Void
  698. {
  699. // we need to get the polygon which has been clicked.
  700. var l_oClick:Point = new Point( m_oContainer.mouseX, m_oContainer.mouseY );
  701. var l_oA:Point = new Point(), l_oB:Point = new Point(), l_oC:Point = new Point();
  702. var l_oPoly:Polygon;
  703. var l_aSId:Array<Int> = untyped aPolygons.sortOn( 'm_nDepth', Array.NUMERIC | Array.RETURNINDEXEDARRAY );
  704. var l:Int = aPolygons.length, j:Int;
  705. for( j in 0...l )
  706. //j = l;
  707. //while( --j > -1 )
  708. {
  709. l_oPoly = aPolygons[ l_aSId[ j ] ];
  710. if( !l_oPoly.visible && m_bBackFaceCulling ) continue;
  711. // --
  712. var l_nSize:Int = l_oPoly.vertices.length;
  713. var l_nTriangles:Int = l_nSize - 2;
  714. for( i in 0...l_nTriangles )
  715. {
  716. l_oA.x = l_oPoly.vertices[i].sx; l_oA.y = l_oPoly.vertices[i].sy;
  717. l_oB.x = l_oPoly.vertices[i+1].sx; l_oB.y = l_oPoly.vertices[i+1].sy;
  718. l_oC.x = l_oPoly.vertices[(i+2)%l_nSize].sx; l_oC.y = l_oPoly.vertices[(i+2)%l_nSize].sy;
  719. // --
  720. if( IntersectionMath.isPointInTriangle2D( l_oClick, l_oA, l_oB, l_oC ) )
  721. {
  722. var l_oUV:UVCoord = l_oPoly.getUVFrom2D( l_oClick );
  723. var l_oPt3d:Vector = l_oPoly.get3DFrom2D( l_oClick );
  724. m_oEB.broadcastEvent( new Shape3DEvent( p_oEvt.type, this, l_oPoly, l_oUV, l_oPt3d, p_oEvt ) );
  725. return;
  726. }
  727. }
  728. }
  729. //m_oEB.broadcastEvent( new BubbleEvent( p_oEvt.type, this, p_oEvt ) );
  730. }
  731. /**
  732. * Changes the backface culling side.
  733. *
  734. * <p>When you want to display a cube and you are the cube, you see its external faces.<br/>
  735. * The internal faces are not drawn due to back face culling</p>
  736. *
  737. * <p>In case you are inside the cube, by default Sandy's engine still doesn't draw the internal faces
  738. * (because you should not be in there).</p>
  739. *
  740. * <p>If you need to be only inside the cube, you can call this method to change which side is culled.<br/>
  741. * The faces will be visible only from the interior of the cube.</p>
  742. *
  743. * <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/>
  744. * In that case you just have to set enableBackFaceCulling to false.</p>
  745. */
  746. public function swapCulling():Void
  747. {
  748. for ( v in aPolygons )
  749. {
  750. v.swapCulling();
  751. }
  752. changed = true;
  753. }
  754. /**
  755. * Destroy this object and all its faces
  756. * container object is removed, and graphics cleared. All polygons have their
  757. */
  758. public override function destroy():Void
  759. {
  760. // FIXME Fix it - it should be more like
  761. m_oGeometry.dispose();
  762. // --
  763. clear();
  764. if( m_oContainer.parent != null ) m_oContainer.parent.removeChild( m_oContainer );
  765. if( m_oContainer != null ) m_oContainer = null;
  766. // --
  767. __destroyPolygons();
  768. // --
  769. super.destroy();
  770. }
  771. /**
  772. * This method returns a clone of this Shape3D.
  773. * The current appearance will be applied, and the geometry is cloned (not referenced to curent one).
  774. *
  775. * @param p_sName The name of the new shape you are going to create
  776. * @param p_bKeepTransform Boolean value which, if set to true, applies the current local transformations to the cloned shape. Default value is false.
  777. *
  778. * @return The clone
  779. */
  780. public function clone( ?p_sName:String, ?p_bKeepTransform:Bool ):Shape3D
  781. {
  782. if ( p_sName == null ) p_sName = "";
  783. if ( p_bKeepTransform == null ) p_bKeepTransform = false;
  784. var l_oClone:Shape3D = new Shape3D( p_sName, geometry.clone(), appearance, m_bUseSingleContainer );
  785. // --
  786. if( p_bKeepTransform == true ) l_oClone.matrix = this.matrix;
  787. // --
  788. return l_oClone;
  789. }
  790. /**
  791. * Returns a string representation of this object
  792. *
  793. * @return The fully qualified name of this object and its geometry
  794. */
  795. public override function toString ():String
  796. {
  797. return "sandy.core.scenegraph.Shape3D" + " " + m_oGeometry.toString();
  798. }
  799. /**
  800. * Sets internal convex flag. Set this to true if you know that this shape is convex.
  801. * @internal this is implemented as simple write-only flag to avoid any computation costs whatsoever.
  802. */
  803. public function setConvexFlag (convex:Bool):Void
  804. {
  805. m_bNotConvex = !convex;
  806. }
  807. ///////////////////
  808. ///// PRIVATE /////
  809. ///////////////////
  810. private function __destroyPolygons():Void
  811. {
  812. if( aPolygons != null && aPolygons.length > 0 )
  813. {
  814. var i:Int = 0, l:Int = aPolygons.length;
  815. while( i<l )
  816. {
  817. if( broadcaster != null ) broadcaster.removeChild( aPolygons[i].broadcaster );
  818. if( aPolygons[i] != null ) aPolygons[i].destroy();
  819. // --
  820. aPolygons[i] = null;
  821. // --
  822. i ++;
  823. }
  824. }
  825. aPolygons.splice(0,aPolygons.length);
  826. aPolygons = null;
  827. }
  828. private function __generatePolygons( p_oGeometry:Geometry3D ):Void
  829. {
  830. var i:Int = 0, j:Int = 0, l:Int = p_oGeometry.aFacesVertexID.length;
  831. aPolygons = new Array();
  832. // --
  833. for( i in 0...l )
  834. {
  835. aPolygons[i] = new Polygon( this, p_oGeometry, p_oGeometry.aFacesVertexID[i], p_oGeometry.aFacesUVCoordsID[i], i, i );
  836. if( m_oAppearance != null ) aPolygons[(i)].appearance = m_oAppearance;
  837. this.broadcaster.addChild( aPolygons[(i)].broadcaster );
  838. }
  839. }
  840. // ______________
  841. // [PRIVATE] DATA________________________________________________
  842. private var m_oAppearance:Appearance ; // The Appearance of this Shape3D
  843. private var m_bEv:Bool; // The event system state (enable or not)
  844. private var m_oGeomCenter:Vector;
  845. private var m_bBackFaceCulling:Bool;
  846. private var m_bClipped:Bool;
  847. /** Geometry of this object */
  848. private var m_oGeometry:Geometry3D;
  849. private var m_bUseSingleContainer:Bool;
  850. public var m_nDepth:Float;
  851. private var m_oContainer:Sprite;
  852. private var m_aToProject:Array<Dynamic>;
  853. private var m_aVisiblePoly:Array<Polygon>;
  854. private var m_nVisiblePoly:Int;
  855. private var m_bMouseInteractivity:Bool;
  856. private var m_bForcedSingleContainer:Bool;
  857. private var m_bNotConvex:Bool;
  858. }