@ -39,6 +39,7 @@ import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter ;
import com.jme3.export.JmeImporter ;
import com.jme3.export.Savable ;
import com.jme3.export.Savable ;
import com.jme3.material.Material ;
import com.jme3.material.Material ;
import com.jme3.util.SafeArrayList ;
import java.io.IOException ;
import java.io.IOException ;
import java.util.ArrayList ;
import java.util.ArrayList ;
import java.util.List ;
import java.util.List ;
@ -65,7 +66,7 @@ public class Node extends Spatial implements Savable {
/ * *
/ * *
* This node ' s children .
* This node ' s children .
* /
* /
protected ArrayList < Spatial > children = new ArrayList < Spatial > ( 1 ) ;
protected Safe ArrayList< Spatial > children = new Safe ArrayList< Spatial > ( Spatial . class ) ;
/ * *
/ * *
* Serialization only . Do not use .
* Serialization only . Do not use .
@ -99,7 +100,7 @@ public class Node extends Spatial implements Savable {
@Override
@Override
protected void setTransformRefresh ( ) {
protected void setTransformRefresh ( ) {
super . setTransformRefresh ( ) ;
super . setTransformRefresh ( ) ;
for ( Spatial child : children ) {
for ( Spatial child : children . getArray ( ) ) {
if ( ( child . refreshFlags & RF_TRANSFORM ) ! = 0 )
if ( ( child . refreshFlags & RF_TRANSFORM ) ! = 0 )
continue ;
continue ;
@ -110,7 +111,7 @@ public class Node extends Spatial implements Savable {
@Override
@Override
protected void setLightListRefresh ( ) {
protected void setLightListRefresh ( ) {
super . setLightListRefresh ( ) ;
super . setLightListRefresh ( ) ;
for ( Spatial child : children ) {
for ( Spatial child : children . getArray ( ) ) {
if ( ( child . refreshFlags & RF_LIGHTLIST ) ! = 0 )
if ( ( child . refreshFlags & RF_LIGHTLIST ) ! = 0 )
continue ;
continue ;
@ -121,11 +122,11 @@ public class Node extends Spatial implements Savable {
@Override
@Override
protected void updateWorldBound ( ) {
protected void updateWorldBound ( ) {
super . updateWorldBound ( ) ;
super . updateWorldBound ( ) ;
// for a node, the world bound is a combination of all it's children
// for a node, the world bound is a combination of all it's children
// bounds
// bounds
BoundingVolume resultBound = null ;
BoundingVolume resultBound = null ;
for ( int i = 0 , cSize = children . size ( ) ; i < cSize ; i + + ) {
for ( Spatial child : children . getArray ( ) ) {
Spatial child = children . get ( i ) ;
// child bound is assumed to be updated
// child bound is assumed to be updated
assert ( child . refreshFlags & RF_BOUND ) = = 0 ;
assert ( child . refreshFlags & RF_BOUND ) = = 0 ;
if ( resultBound ! = null ) {
if ( resultBound ! = null ) {
@ -145,11 +146,11 @@ public class Node extends Spatial implements Savable {
public void updateLogicalState ( float tpf ) {
public void updateLogicalState ( float tpf ) {
super . updateLogicalState ( tpf ) ;
super . updateLogicalState ( tpf ) ;
// FIXME: Iterating through the children list backwards
if ( children . isEmpty ( ) ) {
// to avoid IndexOutOfBoundsException. This is sometimes unreliable,
return ;
// a more robust solution is needed.
}
for ( int i = children . size ( ) - 1 ; i > = 0 ; i - - ) {
Spatial child = children . get ( i ) ;
for ( Spatial child : children . getArray ( ) ) {
child . updateLogicalState ( tpf ) ;
child . updateLogicalState ( tpf ) ;
}
}
}
}
@ -166,15 +167,16 @@ public class Node extends Spatial implements Savable {
updateWorldTransforms ( ) ;
updateWorldTransforms ( ) ;
}
}
// the important part- make sure child geometric state is refreshed
if ( ! children . isEmpty ( ) ) {
// first before updating own world bound. This saves
// the important part- make sure child geometric state is refreshed
// a round-trip later on.
// first before updating own world bound. This saves
// NOTE 9/19/09
// a round-trip later on.
// Although it does save a round trip,
// NOTE 9/19/09
for ( int i = 0 , cSize = children . size ( ) ; i < cSize ; i + + ) {
// Although it does save a round trip,
Spatial child = children . get ( i ) ;
for ( Spatial child : children . getArray ( ) ) {
child . updateGeometricState ( ) ;
child . updateGeometricState ( ) ;
}
}
}
if ( ( refreshFlags & RF_BOUND ) ! = 0 ) {
if ( ( refreshFlags & RF_BOUND ) ! = 0 ) {
updateWorldBound ( ) ;
updateWorldBound ( ) ;
@ -428,8 +430,7 @@ public class Node extends Spatial implements Savable {
if ( name = = null )
if ( name = = null )
return null ;
return null ;
for ( int x = 0 , cSize = getQuantity ( ) ; x < cSize ; x + + ) {
for ( Spatial child : children . getArray ( ) ) {
Spatial child = children . get ( x ) ;
if ( name . equals ( child . getName ( ) ) ) {
if ( name . equals ( child . getName ( ) ) ) {
return child ;
return child ;
} else if ( child instanceof Node ) {
} else if ( child instanceof Node ) {
@ -454,8 +455,7 @@ public class Node extends Spatial implements Savable {
if ( children . contains ( spat ) )
if ( children . contains ( spat ) )
return true ;
return true ;
for ( int i = 0 , max = getQuantity ( ) ; i < max ; i + + ) {
for ( Spatial child : children . getArray ( ) ) {
Spatial child = children . get ( i ) ;
if ( child instanceof Node & & ( ( Node ) child ) . hasChild ( spat ) )
if ( child instanceof Node & & ( ( Node ) child ) . hasChild ( spat ) )
return true ;
return true ;
}
}
@ -483,14 +483,14 @@ public class Node extends Spatial implements Savable {
@Override
@Override
public void setLodLevel ( int lod ) {
public void setLodLevel ( int lod ) {
super . setLodLevel ( lod ) ;
super . setLodLevel ( lod ) ;
for ( int i = 0 ; i < children . size ( ) ; i + + ) {
for ( Spatial child : children . getArray ( ) ) {
children . get ( i ) . setLodLevel ( lod ) ;
child . setLodLevel ( lod ) ;
}
}
}
}
public int collideWith ( Collidable other , CollisionResults results ) {
public int collideWith ( Collidable other , CollisionResults results ) {
int total = 0 ;
int total = 0 ;
for ( Spatial child : children ) {
for ( Spatial child : children . getArray ( ) ) {
total + = child . collideWith ( other , results ) ;
total + = child . collideWith ( other , results ) ;
}
}
return total ;
return total ;
@ -575,7 +575,7 @@ public class Node extends Spatial implements Savable {
@Override
@Override
public Spatial deepClone ( ) {
public Spatial deepClone ( ) {
Node nodeClone = ( Node ) super . clone ( ) ;
Node nodeClone = ( Node ) super . clone ( ) ;
nodeClone . children = new ArrayList < Spatial > ( ) ;
nodeClone . children = new Safe ArrayList< Spatial > ( Spatial . class ) ;
for ( Spatial child : children ) {
for ( Spatial child : children ) {
Spatial childClone = child . deepClone ( ) ;
Spatial childClone = child . deepClone ( ) ;
childClone . parent = nodeClone ;
childClone . parent = nodeClone ;
@ -587,7 +587,7 @@ public class Node extends Spatial implements Savable {
@Override
@Override
public void write ( JmeExporter e ) throws IOException {
public void write ( JmeExporter e ) throws IOException {
super . write ( e ) ;
super . write ( e ) ;
e . getCapsule ( this ) . writeSavableArrayList ( children , "children" , null ) ;
e . getCapsule ( this ) . writeSavableArrayList ( new ArrayList ( children ) , "children" , null ) ;
}
}
@Override
@Override
@ -596,12 +596,12 @@ public class Node extends Spatial implements Savable {
// This prevents empty children list if controls query
// This prevents empty children list if controls query
// it in Control.setSpatial().
// it in Control.setSpatial().
children = e . getCapsule ( this ) . readSavableArrayList ( "children" , null ) ;
children = new SafeArrayList ( Spatial . class ,
e . getCapsule ( this ) . readSavableArrayList ( "children" , null ) ) ;
// go through children and set parent to this node
// go through children and set parent to this node
if ( children ! = null ) {
if ( children ! = null ) {
for ( int x = 0 , cSize = children . size ( ) ; x < cSize ; x + + ) {
for ( Spatial child : children . getArray ( ) ) {
Spatial child = children . get ( x ) ;
child . parent = this ;
child . parent = this ;
}
}
}
}
@ -612,8 +612,8 @@ public class Node extends Spatial implements Savable {
@Override
@Override
public void setModelBound ( BoundingVolume modelBound ) {
public void setModelBound ( BoundingVolume modelBound ) {
if ( children ! = null ) {
if ( children ! = null ) {
for ( int i = 0 , max = children . size ( ) ; i < max ; i + + ) {
for ( Spatial child : children . getArray ( ) ) {
children . get ( i ) . setModelBound ( modelBound ! = null ? modelBound . clone ( null ) : null ) ;
child . setModelBound ( modelBound ! = null ? modelBound . clone ( null ) : null ) ;
}
}
}
}
}
}
@ -621,16 +621,16 @@ public class Node extends Spatial implements Savable {
@Override
@Override
public void updateModelBound ( ) {
public void updateModelBound ( ) {
if ( children ! = null ) {
if ( children ! = null ) {
for ( int i = 0 , max = children . size ( ) ; i < max ; i + + ) {
for ( Spatial child : children . getArray ( ) ) {
children . get ( i ) . updateModelBound ( ) ;
child . updateModelBound ( ) ;
}
}
}
}
}
}
@Override
@Override
public void depthFirstTraversal ( SceneGraphVisitor visitor ) {
public void depthFirstTraversal ( SceneGraphVisitor visitor ) {
for ( int i = 0 , max = children . size ( ) ; i < max ; i + + ) {
for ( Spatial child : children . getArray ( ) ) {
children . get ( i ) . depthFirstTraversal ( visitor ) ;
child . depthFirstTraversal ( visitor ) ;
}
}
visitor . visit ( this ) ;
visitor . visit ( this ) ;
}
}