|
|
@@ -61,9 +61,6 @@ import java.util.ArrayList;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
-import java.util.concurrent.ExecutorService;
|
|
|
-import java.util.concurrent.Executors;
|
|
|
-import java.util.concurrent.ThreadFactory;
|
|
|
import java.util.logging.Level;
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
@@ -104,34 +101,12 @@ public class TerrainQuad extends Node implements Terrain {
|
|
|
protected float offsetAmount;
|
|
|
|
|
|
protected int quadrant = 0; // 1=upper left, 2=lower left, 3=upper right, 4=lower right
|
|
|
-
|
|
|
- //protected LodCalculatorFactory lodCalculatorFactory;
|
|
|
- //protected LodCalculator lodCalculator;
|
|
|
-
|
|
|
- protected List<Vector3f> lastCameraLocations; // used for LOD calc
|
|
|
- private boolean lodCalcRunning = false;
|
|
|
- private int lodOffCount = 0;
|
|
|
private int maxLod = -1;
|
|
|
- private HashMap<String,UpdatedTerrainPatch> updatedPatches;
|
|
|
- private final Object updatePatchesLock = new Object();
|
|
|
private BoundingBox affectedAreaBBox; // only set in the root quad
|
|
|
|
|
|
private TerrainPicker picker;
|
|
|
private Vector3f lastScale = Vector3f.UNIT_XYZ;
|
|
|
|
|
|
- protected ExecutorService executor;
|
|
|
-
|
|
|
- protected ExecutorService createExecutorService() {
|
|
|
- return Executors.newSingleThreadExecutor(new ThreadFactory() {
|
|
|
- public Thread newThread(Runnable r) {
|
|
|
- Thread th = new Thread(r);
|
|
|
- th.setName("jME Terrain Thread");
|
|
|
- th.setDaemon(true);
|
|
|
- return th;
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
public TerrainQuad() {
|
|
|
super("Terrain");
|
|
|
}
|
|
|
@@ -220,24 +195,9 @@ public class TerrainQuad extends Node implements Terrain {
|
|
|
this.size = quadSize;
|
|
|
this.patchSize = patchSize;
|
|
|
this.stepScale = scale;
|
|
|
- //this.lodCalculatorFactory = lodCalculatorFactory;
|
|
|
- //this.lodCalculator = lodCalculator;
|
|
|
split(patchSize, heightMap);
|
|
|
}
|
|
|
|
|
|
- /*public void setLodCalculatorFactory(LodCalculatorFactory lodCalculatorFactory) {
|
|
|
- if (children != null) {
|
|
|
- for (int i = children.size(); --i >= 0;) {
|
|
|
- Spatial child = children.get(i);
|
|
|
- if (child instanceof TerrainQuad) {
|
|
|
- ((TerrainQuad) child).setLodCalculatorFactory(lodCalculatorFactory);
|
|
|
- } else if (child instanceof TerrainPatch) {
|
|
|
- ((TerrainPatch) child).setLodCalculator(lodCalculatorFactory.createCalculator((TerrainPatch) child));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }*/
|
|
|
-
|
|
|
/**
|
|
|
* Forces the recalculation of all normals on the terrain.
|
|
|
*/
|
|
|
@@ -253,16 +213,6 @@ public class TerrainQuad extends Node implements Terrain {
|
|
|
return heightMap;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Call from the update() method of a terrain controller to update
|
|
|
- * the LOD values of each patch.
|
|
|
- * This will perform the geometry calculation in a background thread and
|
|
|
- * do the actual update on the opengl thread.
|
|
|
- */
|
|
|
- public void update(List<Vector3f> locations, LodCalculator lodCalculator) {
|
|
|
- updateLOD(locations, lodCalculator);
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* update the normals if there were any height changes recently.
|
|
|
* Should only be called on the root quad
|
|
|
@@ -277,73 +227,20 @@ public class TerrainQuad extends Node implements Terrain {
|
|
|
setNormalRecalcNeeded(null); // set to false
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // do all of the LOD calculations
|
|
|
- protected void updateLOD(List<Vector3f> locations, LodCalculator lodCalculator) {
|
|
|
- // update any existing ones that need updating
|
|
|
- updateQuadLODs();
|
|
|
-
|
|
|
- if (lodCalculator.isLodOff()) {
|
|
|
- // we want to calculate the base lod at least once
|
|
|
- if (lodOffCount == 1)
|
|
|
- return;
|
|
|
- else
|
|
|
- lodOffCount++;
|
|
|
- } else
|
|
|
- lodOffCount = 0;
|
|
|
-
|
|
|
- if (lastCameraLocations != null) {
|
|
|
- if (lastCameraLocationsTheSame(locations) && !lodCalculator.isLodOff())
|
|
|
- return; // don't update if in same spot
|
|
|
- else
|
|
|
- lastCameraLocations = cloneVectorList(locations);
|
|
|
- }
|
|
|
- else {
|
|
|
- lastCameraLocations = cloneVectorList(locations);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (isLodCalcRunning()) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (getParent() instanceof TerrainQuad) {
|
|
|
- return; // we just want the root quad to perform this.
|
|
|
- }
|
|
|
-
|
|
|
- if (executor == null)
|
|
|
- executor = createExecutorService();
|
|
|
-
|
|
|
- UpdateLOD updateLodThread = new UpdateLOD(locations, lodCalculator);
|
|
|
- executor.execute(updateLodThread);
|
|
|
- }
|
|
|
-
|
|
|
- private synchronized boolean isLodCalcRunning() {
|
|
|
- return lodCalcRunning;
|
|
|
- }
|
|
|
-
|
|
|
- private synchronized void setLodCalcRunning(boolean running) {
|
|
|
- lodCalcRunning = running;
|
|
|
- }
|
|
|
-
|
|
|
- private List<Vector3f> cloneVectorList(List<Vector3f> locations) {
|
|
|
- List<Vector3f> cloned = new ArrayList<Vector3f>();
|
|
|
- for(Vector3f l : locations)
|
|
|
- cloned.add(l.clone());
|
|
|
- return cloned;
|
|
|
- }
|
|
|
-
|
|
|
- private boolean lastCameraLocationsTheSame(List<Vector3f> locations) {
|
|
|
- boolean theSame = true;
|
|
|
- for (Vector3f l : locations) {
|
|
|
- for (Vector3f v : lastCameraLocations) {
|
|
|
- if (!v.equals(l) ) {
|
|
|
- theSame = false;
|
|
|
- return false;
|
|
|
- }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Caches the transforms (except rotation) so the LOD calculator,
|
|
|
+ * which runs on a separate thread, can access them safely.
|
|
|
+ */
|
|
|
+ protected void cacheTerrainTransforms() {
|
|
|
+ for (int i = children.size(); --i >= 0;) {
|
|
|
+ Spatial child = children.get(i);
|
|
|
+ if (child instanceof TerrainQuad) {
|
|
|
+ ((TerrainQuad) child).cacheTerrainTransforms();
|
|
|
+ } else if (child instanceof TerrainPatch) {
|
|
|
+ ((TerrainPatch) child).cacheTerrainTransforms();
|
|
|
}
|
|
|
}
|
|
|
- return theSame;
|
|
|
}
|
|
|
|
|
|
private int collideWithRay(Ray ray, CollisionResults results) {
|
|
|
@@ -412,86 +309,10 @@ public class TerrainQuad extends Node implements Terrain {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- //public float getTextureCoordinateScale() {
|
|
|
- // return 1f/(float)totalSize;
|
|
|
- //}
|
|
|
public int getNumMajorSubdivisions() {
|
|
|
return 1;
|
|
|
}
|
|
|
-
|
|
|
- /**
|
|
|
- * Calculates the LOD of all child terrain patches.
|
|
|
- */
|
|
|
- private class UpdateLOD implements Runnable {
|
|
|
- private List<Vector3f> camLocations;
|
|
|
- private LodCalculator lodCalculator;
|
|
|
-
|
|
|
- UpdateLOD(List<Vector3f> camLocations, LodCalculator lodCalculator) {
|
|
|
- this.camLocations = camLocations;
|
|
|
- this.lodCalculator = lodCalculator;
|
|
|
- }
|
|
|
-
|
|
|
- public void run() {
|
|
|
- long start = System.currentTimeMillis();
|
|
|
- if (isLodCalcRunning()) {
|
|
|
- //System.out.println("thread already running");
|
|
|
- return;
|
|
|
- }
|
|
|
- //System.out.println("spawned thread "+toString());
|
|
|
- setLodCalcRunning(true);
|
|
|
-
|
|
|
- // go through each patch and calculate its LOD based on camera distance
|
|
|
- HashMap<String,UpdatedTerrainPatch> updated = new HashMap<String,UpdatedTerrainPatch>();
|
|
|
- boolean lodChanged = calculateLod(camLocations, updated, lodCalculator); // 'updated' gets populated here
|
|
|
-
|
|
|
- if (!lodChanged) {
|
|
|
- // not worth updating anything else since no one's LOD changed
|
|
|
- setLodCalcRunning(false);
|
|
|
- return;
|
|
|
- }
|
|
|
- // then calculate its neighbour LOD values for seaming in the shader
|
|
|
- findNeighboursLod(updated);
|
|
|
-
|
|
|
- fixEdges(updated); // 'updated' can get added to here
|
|
|
-
|
|
|
- reIndexPages(updated, lodCalculator.usesVariableLod());
|
|
|
-
|
|
|
- setUpdateQuadLODs(updated); // set back to main ogl thread
|
|
|
-
|
|
|
- setLodCalcRunning(false);
|
|
|
- //double duration = (System.currentTimeMillis()-start);
|
|
|
- //System.out.println("terminated in "+duration);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void setUpdateQuadLODs(HashMap<String,UpdatedTerrainPatch> updated) {
|
|
|
- synchronized (updatePatchesLock) {
|
|
|
- updatedPatches = updated;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Back on the ogl thread: update the terrain patch geometries
|
|
|
- * @param updatedPatches to be updated
|
|
|
- */
|
|
|
- private void updateQuadLODs() {
|
|
|
- synchronized (updatePatchesLock) {
|
|
|
-
|
|
|
- if (updatedPatches == null || updatedPatches.isEmpty())
|
|
|
- return;
|
|
|
-
|
|
|
- // do the actual geometry update here
|
|
|
- for (UpdatedTerrainPatch utp : updatedPatches.values()) {
|
|
|
- utp.updateAll();
|
|
|
- }
|
|
|
-
|
|
|
- updatedPatches.clear();
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- public boolean hasPatchesToUpdate() {
|
|
|
- return updatedPatches != null && !updatedPatches.isEmpty();
|
|
|
- }
|
|
|
|
|
|
protected boolean calculateLod(List<Vector3f> location, HashMap<String,UpdatedTerrainPatch> updates, LodCalculator lodCalculator) {
|
|
|
|