@@ -75,7 +75,6 @@ public class Node extends Spatial {
7575 * requiresUpdate() method.
7676 */
7777 private SafeArrayList <Spatial > updateList = null ;
78-
7978 /**
8079 * False if the update list requires rebuilding. This is Node.class
8180 * specific and therefore not included as part of the Spatial update flags.
@@ -100,7 +99,6 @@ public Node() {
10099 */
101100 public Node (String name ) {
102101 super (name );
103-
104102 // For backwards compatibility, only clear the "requires
105103 // update" flag if we are not a subclass of Node.
106104 // This prevents subclass from silently failing to receive
@@ -141,10 +139,21 @@ protected void setLightListRefresh(){
141139 }
142140 }
143141
142+ @ Override
143+ protected void setMatParamOverrideRefresh () {
144+ super .setMatParamOverrideRefresh ();
145+ for (Spatial child : children .getArray ()) {
146+ if ((child .refreshFlags & RF_MATPARAM_OVERRIDE ) != 0 ) {
147+ continue ;
148+ }
149+
150+ child .setMatParamOverrideRefresh ();
151+ }
152+ }
153+
144154 @ Override
145155 protected void updateWorldBound (){
146156 super .updateWorldBound ();
147-
148157 // for a node, the world bound is a combination of all it's children
149158 // bounds
150159 BoundingVolume resultBound = null ;
@@ -239,19 +248,20 @@ public void updateGeometricState(){
239248 // This branch has no geometric state that requires updates.
240249 return ;
241250 }
242-
243251 if ((refreshFlags & RF_LIGHTLIST ) != 0 ){
244252 updateWorldLightList ();
245253 }
246254
255+ if ((refreshFlags & RF_MATPARAM_OVERRIDE ) != 0 ) {
256+ updateMatParamOverrides ();
257+ }
247258 if ((refreshFlags & RF_TRANSFORM ) != 0 ){
248259 // combine with parent transforms- same for all spatial
249260 // subclasses.
250261 updateWorldTransforms ();
251262 }
252263
253264 refreshFlags &= ~RF_CHILD_LIGHTLIST ;
254-
255265 if (!children .isEmpty ()) {
256266 // the important part- make sure child geometric state is refreshed
257267 // first before updating own world bound. This saves
@@ -287,7 +297,6 @@ public int getTriangleCount() {
287297
288298 return count ;
289299 }
290-
291300 /**
292301 * <code>getVertexCount</code> returns the number of vertices contained
293302 * in all sub-branches of this node that contain geometry.
@@ -321,7 +330,6 @@ public int getVertexCount() {
321330 public int attachChild (Spatial child ) {
322331 return attachChildAt (child , children .size ());
323332 }
324-
325333 /**
326334 *
327335 * <code>attachChildAt</code> attaches a child to this node at an index. This node
@@ -345,20 +353,18 @@ public int attachChildAt(Spatial child, int index) {
345353 }
346354 child .setParent (this );
347355 children .add (index , child );
348-
349356 // XXX: Not entirely correct? Forces bound update up the
350357 // tree stemming from the attached child. Also forces
351358 // transform update down the tree-
352359 child .setTransformRefresh ();
353360 child .setLightListRefresh ();
361+ child .setMatParamOverrideRefresh ();
354362 if (logger .isLoggable (Level .FINE )) {
355363 logger .log (Level .FINE ,"Child ({0}) attached to this node ({1})" ,
356364 new Object []{child .getName (), getName ()});
357365 }
358-
359366 invalidateUpdateList ();
360367 }
361-
362368 return children .size ();
363369 }
364370
@@ -433,7 +439,8 @@ public Spatial detachChildAt(int index) {
433439 child .setTransformRefresh ();
434440 // lights are also inherited from parent
435441 child .setLightListRefresh ();
436-
442+ child .setMatParamOverrideRefresh ();
443+
437444 invalidateUpdateList ();
438445 }
439446 return child ;
@@ -519,7 +526,6 @@ public Spatial getChild(String name) {
519526 }
520527 return null ;
521528 }
522-
523529 /**
524530 * determines if the provided Spatial is contained in the children list of
525531 * this node.
@@ -567,39 +573,32 @@ public void setLodLevel(int lod){
567573
568574 public int collideWith (Collidable other , CollisionResults results ){
569575 int total = 0 ;
570-
571576 // optimization: try collideWith BoundingVolume to avoid possibly redundant tests on children
572577 // number 4 in condition is somewhat arbitrary. When there is only one child, the boundingVolume test is redundant at all.
573578 // The idea is when there are few children, it can be too expensive to test boundingVolume first.
574579 /*
575580 I'm removing this change until some issues can be addressed and I really
576581 think it needs to be implemented a better way anyway.
577-
578582 First, it causes issues for anyone doing collideWith() with BoundingVolumes
579583 and expecting it to trickle down to the children. For example, children
580584 with BoundingSphere bounding volumes and collideWith(BoundingSphere). Doing
581585 a collision check at the parent level then has to do a BoundingSphere to BoundingBox
582586 collision which isn't resolved. (Having to come up with a collision point in that
583587 case is tricky and the first sign that this is the wrong approach.)
584-
585588 Second, the rippling changes this caused to 'optimize' collideWith() for this
586589 special use-case are another sign that this approach was a bit dodgy. The whole
587590 idea of calculating a full collision just to see if the two shapes collide at all
588591 is very wasteful.
589-
590592 A proper implementation should support a simpler boolean check that doesn't do
591593 all of that calculation. For example, if 'other' is also a BoundingVolume (ie: 99.9%
592594 of all non-Ray cases) then a direct BV to BV intersects() test can be done. So much
593595 faster. And if 'other' _is_ a Ray then the BV.intersects(Ray) call can be done.
594-
595596 I don't have time to do it right now but I'll at least un-break a bunch of peoples'
596597 code until it can be 'optimized' properly. Hopefully it's not too late to back out
597598 the other dodgy ripples this caused. -pspeed (hindsight-expert ;))
598-
599599 Note: the code itself is relatively simple to implement but I don't have time to
600600 a) test it, and b) see if '> 4' is still a decent check for it. Could be it's fast
601601 enough to do all the time for > 1.
602-
603602 if (children.size() > 4)
604603 {
605604 BoundingVolume bv = this.getWorldBound();
@@ -692,7 +691,6 @@ public Node clone(boolean cloneMaterials){
692691 // Reset the fields of the clone that should be in a 'new' state.
693692 nodeClone .updateList = null ;
694693 nodeClone .updateListValid = false ; // safe because parent is nulled out in super.clone()
695-
696694 return nodeClone ;
697695 }
698696
@@ -732,7 +730,6 @@ public void cloneFields( Cloner cloner, Object original ) {
732730 // cloning this list is fine.
733731 this .updateList = cloner .clone (updateList );
734732 }
735-
736733 @ Override
737734 public void write (JmeExporter e ) throws IOException {
738735 super .write (e );
@@ -744,7 +741,6 @@ public void read(JmeImporter e) throws IOException {
744741 // XXX: Load children before loading itself!!
745742 // This prevents empty children list if controls query
746743 // it in Control.setSpatial().
747-
748744 children = new SafeArrayList ( Spatial .class ,
749745 e .getCapsule (this ).readSavableArrayList ("children" , null ) );
750746
@@ -754,7 +750,6 @@ public void read(JmeImporter e) throws IOException {
754750 child .parent = this ;
755751 }
756752 }
757-
758753 super .read (e );
759754 }
760755
@@ -775,15 +770,13 @@ public void updateModelBound() {
775770 }
776771 }
777772 }
778-
779773 @ Override
780774 public void depthFirstTraversal (SceneGraphVisitor visitor ) {
781775 for (Spatial child : children .getArray ()) {
782776 child .depthFirstTraversal (visitor );
783777 }
784778 visitor .visit (this );
785779 }
786-
787780 @ Override
788781 protected void breadthFirstTraversal (SceneGraphVisitor visitor , Queue <Spatial > queue ) {
789782 queue .addAll (children );
0 commit comments