@ -74,12 +74,12 @@ import java.util.logging.Logger;
* This control serializes , but it does not save the Camera reference .
* This control serializes , but it does not save the Camera reference .
* This camera reference has to be manually added in when you load the
* This camera reference has to be manually added in when you load the
* terrain to the scene !
* terrain to the scene !
*
*
* When the control or the terrain are removed from the scene , you should call
* When the control or the terrain are removed from the scene , you should call
* TerrainLodControl . detachAndCleanUpControl ( ) to remove any threads it created
* TerrainLodControl . detachAndCleanUpControl ( ) to remove any threads it created
* to handle the LOD processing . If you supply your own executor service , then
* to handle the LOD processing . If you supply your own executor service , then
* you have to handle its thread termination yourself .
* you have to handle its thread termination yourself .
*
*
* @author Brent Owens
* @author Brent Owens
* /
* /
public class TerrainLodControl extends AbstractControl {
public class TerrainLodControl extends AbstractControl {
@ -92,15 +92,15 @@ public class TerrainLodControl extends AbstractControl {
private HashMap < String , UpdatedTerrainPatch > updatedPatches ;
private HashMap < String , UpdatedTerrainPatch > updatedPatches ;
private final Object updatePatchesLock = new Object ( ) ;
private final Object updatePatchesLock = new Object ( ) ;
protected List < Vector3f > lastCameraLocations ; // used for LOD calc
protected List < Vector3f > lastCameraLocations ; // used for LOD calc
private AtomicBoolean lodCalcRunning = new AtomicBoolean ( false ) ;
private AtomicBoolean lodCalcRunning = new AtomicBoolean ( false ) ;
private int lodOffCount = 0 ;
private int lodOffCount = 0 ;
protected ExecutorService executor ;
protected ExecutorService executor ;
protected Future < HashMap < String , UpdatedTerrainPatch > > indexer ;
protected Future < HashMap < String , UpdatedTerrainPatch > > indexer ;
private boolean forceUpdate = true ;
private boolean forceUpdate = true ;
public TerrainLodControl ( ) {
public TerrainLodControl ( ) {
}
}
@ -111,7 +111,7 @@ public class TerrainLodControl extends AbstractControl {
this . cameras = cams ;
this . cameras = cams ;
lodCalculator = new DistanceLodCalculator ( 65 , 2 . 7f ) ; // a default calculator
lodCalculator = new DistanceLodCalculator ( 65 , 2 . 7f ) ; // a default calculator
}
}
/ * *
/ * *
* Only uses the first camera right now .
* Only uses the first camera right now .
* @param terrain to act upon ( must be a Spatial )
* @param terrain to act upon ( must be a Spatial )
@ -134,7 +134,7 @@ public class TerrainLodControl extends AbstractControl {
public void setExecutor ( ExecutorService executor ) {
public void setExecutor ( ExecutorService executor ) {
this . executor = executor ;
this . executor = executor ;
}
}
protected ExecutorService createExecutorService ( ) {
protected ExecutorService createExecutorService ( ) {
return Executors . newSingleThreadExecutor ( new ThreadFactory ( ) {
return Executors . newSingleThreadExecutor ( new ThreadFactory ( ) {
public Thread newThread ( Runnable r ) {
public Thread newThread ( Runnable r ) {
@ -145,14 +145,14 @@ public class TerrainLodControl extends AbstractControl {
}
}
} ) ;
} ) ;
}
}
@Override
@Override
protected void controlUpdate ( float tpf ) {
protected void controlUpdate ( float tpf ) {
//list of cameras for when terrain supports multiple cameras (ie split screen)
//list of cameras for when terrain supports multiple cameras (ie split screen)
if ( lodCalculator = = null )
if ( lodCalculator = = null )
return ;
return ;
if ( ! enabled ) {
if ( ! enabled ) {
if ( ! hasResetLod ) {
if ( ! hasResetLod ) {
// this will get run once
// this will get run once
@ -160,7 +160,7 @@ public class TerrainLodControl extends AbstractControl {
lodCalculator . turnOffLod ( ) ;
lodCalculator . turnOffLod ( ) ;
}
}
}
}
if ( cameras ! = null ) {
if ( cameras ! = null ) {
cameraLocations . clear ( ) ;
cameraLocations . clear ( ) ;
for ( Camera c : cameras ) // populate them
for ( Camera c : cameras ) // populate them
@ -170,7 +170,7 @@ public class TerrainLodControl extends AbstractControl {
updateLOD ( cameraLocations , lodCalculator ) ;
updateLOD ( cameraLocations , lodCalculator ) ;
}
}
}
}
/ * *
/ * *
* Call this when you remove the terrain or this control from the scene .
* Call this when you remove the terrain or this control from the scene .
* It will clear up any threads it had .
* It will clear up any threads it had .
@ -186,7 +186,7 @@ public class TerrainLodControl extends AbstractControl {
if ( getSpatial ( ) = = null ) {
if ( getSpatial ( ) = = null ) {
return ;
return ;
}
}
// update any existing ones that need updating
// update any existing ones that need updating
updateQuadLODs ( ) ;
updateQuadLODs ( ) ;
@ -196,9 +196,9 @@ public class TerrainLodControl extends AbstractControl {
return ;
return ;
else
else
lodOffCount + + ;
lodOffCount + + ;
} else
} else
lodOffCount = 0 ;
lodOffCount = 0 ;
if ( lastCameraLocations ! = null ) {
if ( lastCameraLocations ! = null ) {
if ( ! forceUpdate & & lastCameraLocationsTheSame ( locations ) & & ! lodCalculator . isLodOff ( ) )
if ( ! forceUpdate & & lastCameraLocationsTheSame ( locations ) & & ! lodCalculator . isLodOff ( ) )
return ; // don't update if in same spot
return ; // don't update if in same spot
@ -218,9 +218,9 @@ public class TerrainLodControl extends AbstractControl {
if ( executor = = null )
if ( executor = = null )
executor = createExecutorService ( ) ;
executor = createExecutorService ( ) ;
prepareTerrain ( ) ;
prepareTerrain ( ) ;
UpdateLOD updateLodThread = getLodThread ( locations , lodCalculator ) ;
UpdateLOD updateLodThread = getLodThread ( locations , lodCalculator ) ;
indexer = executor . submit ( updateLodThread ) ;
indexer = executor . submit ( updateLodThread ) ;
}
}
@ -232,12 +232,12 @@ public class TerrainLodControl extends AbstractControl {
public void forceUpdate ( ) {
public void forceUpdate ( ) {
this . forceUpdate = true ;
this . forceUpdate = true ;
}
}
protected void prepareTerrain ( ) {
protected void prepareTerrain ( ) {
TerrainQuad terrain = ( TerrainQuad ) getSpatial ( ) ;
TerrainQuad terrain = ( TerrainQuad ) getSpatial ( ) ;
terrain . cacheTerrainTransforms ( ) ; // cache the terrain's world transforms so they can be accessed on the separate thread safely
terrain . cacheTerrainTransforms ( ) ; // cache the terrain's world transforms so they can be accessed on the separate thread safely
}
}
protected UpdateLOD getLodThread ( List < Vector3f > locations , LodCalculator lodCalculator ) {
protected UpdateLOD getLodThread ( List < Vector3f > locations , LodCalculator lodCalculator ) {
return new UpdateLOD ( locations , lodCalculator ) ;
return new UpdateLOD ( locations , lodCalculator ) ;
}
}
@ -249,7 +249,7 @@ public class TerrainLodControl extends AbstractControl {
if ( indexer ! = null ) {
if ( indexer ! = null ) {
if ( indexer . isDone ( ) ) {
if ( indexer . isDone ( ) ) {
try {
try {
HashMap < String , UpdatedTerrainPatch > updated = indexer . get ( ) ;
HashMap < String , UpdatedTerrainPatch > updated = indexer . get ( ) ;
if ( updated ! = null ) {
if ( updated ! = null ) {
// do the actual geometry update here
// do the actual geometry update here
@ -257,7 +257,7 @@ public class TerrainLodControl extends AbstractControl {
utp . updateAll ( ) ;
utp . updateAll ( ) ;
}
}
}
}
} catch ( InterruptedException ex ) {
} catch ( InterruptedException ex ) {
Logger . getLogger ( TerrainLodControl . class . getName ( ) ) . log ( Level . SEVERE , null , ex ) ;
Logger . getLogger ( TerrainLodControl . class . getName ( ) ) . log ( Level . SEVERE , null , ex ) ;
} catch ( ExecutionException ex ) {
} catch ( ExecutionException ex ) {
@ -268,7 +268,7 @@ public class TerrainLodControl extends AbstractControl {
}
}
}
}
}
}
private boolean lastCameraLocationsTheSame ( List < Vector3f > locations ) {
private boolean lastCameraLocationsTheSame ( List < Vector3f > locations ) {
boolean theSame = true ;
boolean theSame = true ;
for ( Vector3f l : locations ) {
for ( Vector3f l : locations ) {
@ -281,7 +281,7 @@ public class TerrainLodControl extends AbstractControl {
}
}
return theSame ;
return theSame ;
}
}
protected synchronized boolean isLodCalcRunning ( ) {
protected synchronized boolean isLodCalcRunning ( ) {
return lodCalcRunning . get ( ) ;
return lodCalcRunning . get ( ) ;
}
}
@ -297,11 +297,11 @@ public class TerrainLodControl extends AbstractControl {
return cloned ;
return cloned ;
}
}
@Override
@Override
public Object jmeClone ( ) {
public Object jmeClone ( ) {
if ( spatial instanceof Terrain ) {
if ( spatial instanceof Terrain ) {
TerrainLodControl cloned = new TerrainLodControl ( ( Terrain ) spatial , cameras ) ;
TerrainLodControl cloned = new TerrainLodControl ( ( Terrain ) spatial , cameras ) ;
@ -310,21 +310,23 @@ public class TerrainLodControl extends AbstractControl {
return cloned ;
return cloned ;
}
}
return null ;
return null ;
}
}
@Override
@Override
public void cloneFields ( Cloner cloner , Object original ) {
public void cloneFields ( Cloner cloner , Object original ) {
super . cloneFields ( cloner , original ) ;
this . lodCalculator = cloner . clone ( lodCalculator ) ;
this . lodCalculator = cloner . clone ( lodCalculator ) ;
try {
try {
// Not deep clone of the cameras themselves
// Not deep clone of the cameras themselves
this . cameras = cloner . javaClone ( cameras ) ;
this . cameras = cloner . javaClone ( cameras ) ;
} catch ( CloneNotSupportedException e ) {
} catch ( CloneNotSupportedException e ) {
throw new RuntimeException ( "Error cloning" , e ) ;
throw new RuntimeException ( "Error cloning" , e ) ;
}
}
}
}
@Override
@Override
public Control cloneForSpatial ( Spatial spatial ) {
public Control cloneForSpatial ( Spatial spatial ) {
if ( spatial instanceof Terrain ) {
if ( spatial instanceof Terrain ) {
@ -346,7 +348,7 @@ public class TerrainLodControl extends AbstractControl {
cams . add ( camera ) ;
cams . add ( camera ) ;
setCameras ( cams ) ;
setCameras ( cams ) ;
}
}
public void setCameras ( List < Camera > cameras ) {
public void setCameras ( List < Camera > cameras ) {
this . cameras = cameras ;
this . cameras = cameras ;
cameraLocations . clear ( ) ;
cameraLocations . clear ( ) ;
@ -374,7 +376,7 @@ public class TerrainLodControl extends AbstractControl {
public void setLodCalculator ( LodCalculator lodCalculator ) {
public void setLodCalculator ( LodCalculator lodCalculator ) {
this . lodCalculator = lodCalculator ;
this . lodCalculator = lodCalculator ;
}
}
@Override
@Override
public void setEnabled ( boolean enabled ) {
public void setEnabled ( boolean enabled ) {
this . enabled = enabled ;
this . enabled = enabled ;
@ -386,8 +388,8 @@ public class TerrainLodControl extends AbstractControl {
lodCalculator . turnOnLod ( ) ;
lodCalculator . turnOnLod ( ) ;
}
}
}
}
/ * *
/ * *
* Calculates the LOD of all child terrain patches .
* Calculates the LOD of all child terrain patches .
* /
* /
@ -408,7 +410,7 @@ public class TerrainLodControl extends AbstractControl {
setLodCalcRunning ( true ) ;
setLodCalcRunning ( true ) ;
TerrainQuad terrainQuad = ( TerrainQuad ) getSpatial ( ) ;
TerrainQuad terrainQuad = ( TerrainQuad ) getSpatial ( ) ;
// go through each patch and calculate its LOD based on camera distance
// go through each patch and calculate its LOD based on camera distance
HashMap < String , UpdatedTerrainPatch > updated = new HashMap < String , UpdatedTerrainPatch > ( ) ;
HashMap < String , UpdatedTerrainPatch > updated = new HashMap < String , UpdatedTerrainPatch > ( ) ;
boolean lodChanged = terrainQuad . calculateLod ( camLocations , updated , lodCalculator ) ; // 'updated' gets populated here
boolean lodChanged = terrainQuad . calculateLod ( camLocations , updated , lodCalculator ) ; // 'updated' gets populated here
@ -418,8 +420,8 @@ public class TerrainLodControl extends AbstractControl {
setLodCalcRunning ( false ) ;
setLodCalcRunning ( false ) ;
return null ;
return null ;
}
}
// then calculate its neighbour LOD values for seaming in the shader
// then calculate its neighbour LOD values for seaming in the shader
terrainQuad . findNeighboursLod ( updated ) ;
terrainQuad . findNeighboursLod ( updated ) ;
@ -430,7 +432,7 @@ public class TerrainLodControl extends AbstractControl {
//setUpdateQuadLODs(updated); // set back to main ogl thread
//setUpdateQuadLODs(updated); // set back to main ogl thread
setLodCalcRunning ( false ) ;
setLodCalcRunning ( false ) ;
return updated ;
return updated ;
}
}
}
}