Softened terrain API to allow for different tiling implementations. Added MultiTerrainLodControl
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9434 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
b5aa49bc16
commit
33a69d4536
@ -154,6 +154,9 @@ public class LODGeomap extends GeoMap {
|
||||
*/
|
||||
public IntBuffer writeIndexArrayLodDiff(IntBuffer store, int lod, boolean rightLod, boolean topLod, boolean leftLod, boolean bottomLod) {
|
||||
|
||||
//if (true)
|
||||
//return writeIndexArrayLodVariable(store, lod, height, lod, lod, lod);
|
||||
|
||||
IntBuffer buffer2 = store;
|
||||
int numIndexes = calculateNumIndexesLodDiff(lod);
|
||||
if (store == null) {
|
||||
@ -275,7 +278,7 @@ public class LODGeomap extends GeoMap {
|
||||
buffer.put(idx);
|
||||
idx = (row + 2 * lod) * getWidth();
|
||||
buffer.put(idx);
|
||||
if (row < getWidth() - lod - 2 - 1) { //if not the last one
|
||||
if (row < getWidth() - 1 - 2 * lod) { //if not the last one
|
||||
idx = (row + 2 * lod) * getWidth() + lod;
|
||||
buffer.put(idx);
|
||||
idx = (row + 2 * lod) * getWidth();
|
||||
@ -917,10 +920,12 @@ public class LODGeomap extends GeoMap {
|
||||
|
||||
public void put(int value) {
|
||||
try {
|
||||
delegate.put(value);
|
||||
count++;
|
||||
if (count > delegate.limit())
|
||||
throw new BufferOverflowException();
|
||||
delegate.put(value);
|
||||
} catch (BufferOverflowException e) {
|
||||
//System.out.println("err buffer size: "+delegate.capacity());
|
||||
System.out.println("err buffer size: "+delegate.capacity());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package com.jme3.terrain.geomipmap;
|
||||
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.Camera;
|
||||
import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
|
||||
import com.jme3.terrain.geomipmap.lodcalc.LodCalculator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An extension of the TerrainLodControl that handles
|
||||
* multiple terrains at once. This is to be used if you
|
||||
* have your own tiling/paging terrain system, such as
|
||||
* TerrainGrid.
|
||||
*
|
||||
* @author Brent Owens
|
||||
*/
|
||||
public class MultiTerrainLodControl extends TerrainLodControl {
|
||||
|
||||
List<TerrainQuad> terrains = new ArrayList<TerrainQuad>();
|
||||
private List<TerrainQuad> addedTerrains = new ArrayList<TerrainQuad>();
|
||||
private List<TerrainQuad> removedTerrains = new ArrayList<TerrainQuad>();
|
||||
|
||||
public MultiTerrainLodControl(List<Camera> cameras) {
|
||||
this.cameras = cameras;
|
||||
lodCalculator = new DistanceLodCalculator(65, 2.7f);
|
||||
}
|
||||
|
||||
public MultiTerrainLodControl(Camera camera) {
|
||||
List<Camera> cams = new ArrayList<Camera>();
|
||||
cams.add(camera);
|
||||
this.cameras = cams;
|
||||
lodCalculator = new DistanceLodCalculator(65, 2.7f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a terrain that will have its LOD handled by this control.
|
||||
* It will be added next update run. You should only call this from
|
||||
* the render thread.
|
||||
*/
|
||||
public void addTerrain(TerrainQuad tq) {
|
||||
addedTerrains.add(tq);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a terrain that will no longer have its LOD handled by this control.
|
||||
* It will be removed next update run. You should only call this from
|
||||
* the render thread.
|
||||
*/
|
||||
public void removeTerrain(TerrainQuad tq) {
|
||||
removedTerrains.remove(tq);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UpdateLOD getLodThread(List<Vector3f> locations, LodCalculator lodCalculator) {
|
||||
return new UpdateMultiLOD(locations, lodCalculator);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareTerrain() {
|
||||
if (!addedTerrains.isEmpty()) {
|
||||
for (TerrainQuad t : addedTerrains) {
|
||||
if (!terrains.contains(t))
|
||||
terrains.add(t);
|
||||
}
|
||||
addedTerrains.clear();
|
||||
}
|
||||
|
||||
if (!removedTerrains.isEmpty()) {
|
||||
terrains.removeAll(removedTerrains);
|
||||
removedTerrains.clear();
|
||||
}
|
||||
|
||||
for (TerrainQuad terrain : terrains)
|
||||
terrain.cacheTerrainTransforms();// cache the terrain's world transforms so they can be accessed on the separate thread safely
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the parent UpdateLOD runnable to process
|
||||
* multiple terrains.
|
||||
*/
|
||||
protected class UpdateMultiLOD extends UpdateLOD {
|
||||
|
||||
|
||||
protected UpdateMultiLOD(List<Vector3f> camLocations, LodCalculator lodCalculator) {
|
||||
super(camLocations, lodCalculator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, UpdatedTerrainPatch> call() throws Exception {
|
||||
|
||||
setLodCalcRunning(true);
|
||||
|
||||
HashMap<String,UpdatedTerrainPatch> updated = new HashMap<String,UpdatedTerrainPatch>();
|
||||
|
||||
for (TerrainQuad terrainQuad : terrains) {
|
||||
// go through each patch and calculate its LOD based on camera distance
|
||||
terrainQuad.calculateLod(camLocations, updated, lodCalculator); // 'updated' gets populated here
|
||||
}
|
||||
|
||||
for (TerrainQuad terrainQuad : terrains) {
|
||||
// then calculate the neighbour LOD values for seaming
|
||||
terrainQuad.findNeighboursLod(updated);
|
||||
}
|
||||
|
||||
for (TerrainQuad terrainQuad : terrains) {
|
||||
// check neighbour quads that need their edges seamed
|
||||
terrainQuad.fixEdges(updated);
|
||||
}
|
||||
|
||||
for (TerrainQuad terrainQuad : terrains) {
|
||||
// perform the edge seaming, if it requires it
|
||||
terrainQuad.reIndexPages(updated, lodCalculator.usesVariableLod());
|
||||
}
|
||||
|
||||
//setUpdateQuadLODs(updated); // set back to main ogl thread
|
||||
setLodCalcRunning(false);
|
||||
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ package com.jme3.terrain.geomipmap;
|
||||
* With this you can have a parent, control or spatial, that manages a group of
|
||||
* TerrainQuads by linking them together through these four methods.
|
||||
*
|
||||
* The general orientation of TerrainQuads and their sun-quads is as such:
|
||||
* The general orientation of TerrainQuads and their sub-quads is as such:
|
||||
*
|
||||
*
|
||||
* +-- x+ ---->
|
||||
@ -32,11 +32,23 @@ package com.jme3.terrain.geomipmap;
|
||||
*/
|
||||
public interface NeighbourFinder {
|
||||
|
||||
/**
|
||||
* Get the TerrainQuad to the right of the supplied 'center' quad.
|
||||
*/
|
||||
public TerrainQuad getRightQuad(TerrainQuad center);
|
||||
|
||||
/**
|
||||
* Get the TerrainQuad to the left of the supplied 'center' quad.
|
||||
*/
|
||||
public TerrainQuad getLeftQuad(TerrainQuad center);
|
||||
|
||||
/**
|
||||
* Get the TerrainQuad above the supplied 'center' quad.
|
||||
*/
|
||||
public TerrainQuad getTopQuad(TerrainQuad center);
|
||||
|
||||
/**
|
||||
* Get the TerrainQuad below the supplied 'center' quad.
|
||||
*/
|
||||
public TerrainQuad getDownQuad(TerrainQuad center);
|
||||
}
|
||||
|
@ -50,9 +50,15 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Tells the terrain to update its Level of Detail.
|
||||
@ -72,19 +78,20 @@ import java.util.concurrent.ThreadFactory;
|
||||
public class TerrainLodControl extends AbstractControl {
|
||||
|
||||
private Terrain terrain;
|
||||
private List<Camera> cameras;
|
||||
protected List<Camera> cameras;
|
||||
private List<Vector3f> cameraLocations = new ArrayList<Vector3f>();
|
||||
private LodCalculator lodCalculator;
|
||||
protected LodCalculator lodCalculator;
|
||||
private boolean hasResetLod = false; // used when enabled is set to false
|
||||
|
||||
private HashMap<String,UpdatedTerrainPatch> updatedPatches;
|
||||
private final Object updatePatchesLock = new Object();
|
||||
|
||||
protected List<Vector3f> lastCameraLocations; // used for LOD calc
|
||||
private boolean lodCalcRunning = false;
|
||||
private AtomicBoolean lodCalcRunning = new AtomicBoolean(false);
|
||||
private int lodOffCount = 0;
|
||||
|
||||
protected ExecutorService executor;
|
||||
protected Future<HashMap<String, UpdatedTerrainPatch>> indexer;
|
||||
|
||||
public TerrainLodControl() {
|
||||
}
|
||||
@ -177,6 +184,7 @@ public class TerrainLodControl extends AbstractControl {
|
||||
if (isLodCalcRunning()) {
|
||||
return;
|
||||
}
|
||||
setLodCalcRunning(true);
|
||||
|
||||
//if (getParent() instanceof TerrainQuad) {
|
||||
// return; // we just want the root quad to perform this.
|
||||
@ -185,25 +193,47 @@ public class TerrainLodControl extends AbstractControl {
|
||||
if (executor == null)
|
||||
executor = createExecutorService();
|
||||
|
||||
TerrainQuad terrain = (TerrainQuad)getSpatial();
|
||||
terrain.cacheTerrainTransforms();// cache the terrain's world transforms so they can be accessed on the separate thread safely
|
||||
prepareTerrain();
|
||||
|
||||
UpdateLOD updateLodThread = new UpdateLOD(locations, lodCalculator);
|
||||
executor.execute(updateLodThread);
|
||||
UpdateLOD updateLodThread = getLodThread(locations, lodCalculator);
|
||||
indexer = executor.submit(updateLodThread);
|
||||
}
|
||||
|
||||
private void setUpdateQuadLODs(HashMap<String,UpdatedTerrainPatch> updated) {
|
||||
synchronized (updatePatchesLock) {
|
||||
updatedPatches = updated;
|
||||
}
|
||||
protected void prepareTerrain() {
|
||||
TerrainQuad terrain = (TerrainQuad)getSpatial();
|
||||
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) {
|
||||
return new UpdateLOD(locations, lodCalculator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Back on the ogl thread: update the terrain patch geometries
|
||||
* @param updatedPatches to be updated
|
||||
*/
|
||||
private void updateQuadLODs() {
|
||||
synchronized (updatePatchesLock) {
|
||||
if (indexer != null) {
|
||||
if (indexer.isDone()) {
|
||||
try {
|
||||
|
||||
HashMap<String, UpdatedTerrainPatch> updated = indexer.get();
|
||||
if (updated != null) {
|
||||
// do the actual geometry update here
|
||||
for (UpdatedTerrainPatch utp : updated.values()) {
|
||||
utp.updateAll();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(TerrainLodControl.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (ExecutionException ex) {
|
||||
Logger.getLogger(TerrainLodControl.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} finally {
|
||||
indexer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*synchronized (updatePatchesLock) {
|
||||
|
||||
if (updatedPatches == null || updatedPatches.isEmpty())
|
||||
return;
|
||||
@ -213,13 +243,13 @@ public class TerrainLodControl extends AbstractControl {
|
||||
utp.updateAll();
|
||||
}
|
||||
|
||||
updatedPatches.clear();
|
||||
}
|
||||
updatedPatches = null;
|
||||
}*/
|
||||
}
|
||||
|
||||
public boolean hasPatchesToUpdate() {
|
||||
return updatedPatches != null && !updatedPatches.isEmpty();
|
||||
}
|
||||
//public boolean hasPatchesToUpdate() {
|
||||
// return updatedPatches != null && !updatedPatches.isEmpty();
|
||||
//}
|
||||
|
||||
private boolean lastCameraLocationsTheSame(List<Vector3f> locations) {
|
||||
boolean theSame = true;
|
||||
@ -234,12 +264,12 @@ public class TerrainLodControl extends AbstractControl {
|
||||
return theSame;
|
||||
}
|
||||
|
||||
private synchronized boolean isLodCalcRunning() {
|
||||
return lodCalcRunning;
|
||||
protected synchronized boolean isLodCalcRunning() {
|
||||
return lodCalcRunning.get();
|
||||
}
|
||||
|
||||
private synchronized void setLodCalcRunning(boolean running) {
|
||||
lodCalcRunning = running;
|
||||
protected synchronized void setLodCalcRunning(boolean running) {
|
||||
lodCalcRunning.set(running);
|
||||
}
|
||||
|
||||
private List<Vector3f> cloneVectorList(List<Vector3f> locations) {
|
||||
@ -320,22 +350,20 @@ public class TerrainLodControl extends AbstractControl {
|
||||
/**
|
||||
* Calculates the LOD of all child terrain patches.
|
||||
*/
|
||||
private class UpdateLOD implements Runnable {
|
||||
private List<Vector3f> camLocations;
|
||||
private LodCalculator lodCalculator;
|
||||
protected class UpdateLOD implements Callable<HashMap<String,UpdatedTerrainPatch>> {
|
||||
protected List<Vector3f> camLocations;
|
||||
protected LodCalculator lodCalculator;
|
||||
|
||||
UpdateLOD(List<Vector3f> camLocations, LodCalculator lodCalculator) {
|
||||
protected 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());
|
||||
public HashMap<String, UpdatedTerrainPatch> call() throws Exception {
|
||||
//long start = System.currentTimeMillis();
|
||||
//if (isLodCalcRunning()) {
|
||||
// return null;
|
||||
//}
|
||||
setLodCalcRunning(true);
|
||||
|
||||
TerrainQuad terrainQuad = (TerrainQuad)getSpatial();
|
||||
@ -347,7 +375,7 @@ public class TerrainLodControl extends AbstractControl {
|
||||
if (!lodChanged) {
|
||||
// not worth updating anything else since no one's LOD changed
|
||||
setLodCalcRunning(false);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -358,11 +386,11 @@ public class TerrainLodControl extends AbstractControl {
|
||||
|
||||
terrainQuad.reIndexPages(updated, lodCalculator.usesVariableLod());
|
||||
|
||||
setUpdateQuadLODs(updated); // set back to main ogl thread
|
||||
//setUpdateQuadLODs(updated); // set back to main ogl thread
|
||||
|
||||
setLodCalcRunning(false);
|
||||
//double duration = (System.currentTimeMillis()-start);
|
||||
//System.out.println("terminated in "+duration);
|
||||
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ import java.util.List;
|
||||
public class TerrainPatch extends Geometry {
|
||||
|
||||
protected LODGeomap geomap;
|
||||
protected int lod = -1; // this terrain patch's LOD
|
||||
protected int lod = 0; // this terrain patch's LOD
|
||||
private int maxLod = -1;
|
||||
protected int previousLod = -1;
|
||||
protected int lodLeft, lodTop, lodRight, lodBottom; // it's neighbour's LODs
|
||||
@ -234,7 +234,7 @@ public class TerrainPatch extends Geometry {
|
||||
|
||||
UpdatedTerrainPatch utp = updated.get(getName());
|
||||
|
||||
if (utp != null && (utp.isReIndexNeeded() || utp.isFixEdges()) ) {
|
||||
if (utp != null && utp.isReIndexNeeded() ) {
|
||||
int pow = (int) Math.pow(2, utp.getNewLod());
|
||||
boolean left = utp.getLeftLod() > utp.getNewLod();
|
||||
boolean top = utp.getTopLod() > utp.getNewLod();
|
||||
|
@ -201,6 +201,7 @@ public class TerrainQuad extends Node implements Terrain {
|
||||
|
||||
public void setNeighbourFinder(NeighbourFinder neighbourFinder) {
|
||||
this.neighbourFinder = neighbourFinder;
|
||||
resetCachedNeighbours();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -360,6 +361,8 @@ public class TerrainQuad extends Node implements Terrain {
|
||||
}
|
||||
TerrainPatch right = patch.rightNeighbour;
|
||||
TerrainPatch down = patch.bottomNeighbour;
|
||||
TerrainPatch left = patch.leftNeighbour;
|
||||
TerrainPatch top = patch.topNeighbour;
|
||||
|
||||
UpdatedTerrainPatch utp = updated.get(patch.getName());
|
||||
if (utp == null) {
|
||||
@ -370,34 +373,55 @@ public class TerrainQuad extends Node implements Terrain {
|
||||
if (right != null) {
|
||||
UpdatedTerrainPatch utpR = updated.get(right.getName());
|
||||
if (utpR == null) {
|
||||
utpR = new UpdatedTerrainPatch(right, right.lod);
|
||||
utpR = new UpdatedTerrainPatch(right);
|
||||
updated.put(utpR.getName(), utpR);
|
||||
utpR.setNewLod(right.lod);
|
||||
}
|
||||
|
||||
utp.setRightLod(utpR.getNewLod());
|
||||
utpR.setLeftLod(utp.getNewLod());
|
||||
}
|
||||
if (down != null) {
|
||||
UpdatedTerrainPatch utpD = updated.get(down.getName());
|
||||
if (utpD == null) {
|
||||
utpD = new UpdatedTerrainPatch(down, down.lod);
|
||||
utpD = new UpdatedTerrainPatch(down);
|
||||
updated.put(utpD.getName(), utpD);
|
||||
utpD.setNewLod(down.lod);
|
||||
}
|
||||
|
||||
utp.setBottomLod(utpD.getNewLod());
|
||||
utpD.setTopLod(utp.getNewLod());
|
||||
}
|
||||
|
||||
|
||||
if (left != null) {
|
||||
UpdatedTerrainPatch utpL = updated.get(left.getName());
|
||||
if (utpL == null) {
|
||||
utpL = new UpdatedTerrainPatch(left);
|
||||
updated.put(utpL.getName(), utpL);
|
||||
utpL.setNewLod(left.lod);
|
||||
}
|
||||
utp.setLeftLod(utpL.getNewLod());
|
||||
utpL.setRightLod(utp.getNewLod());
|
||||
}
|
||||
if (top != null) {
|
||||
UpdatedTerrainPatch utpT = updated.get(top.getName());
|
||||
if (utpT == null) {
|
||||
utpT = new UpdatedTerrainPatch(top);
|
||||
updated.put(utpT.getName(), utpT);
|
||||
utpT.setNewLod(top.lod);
|
||||
}
|
||||
utp.setTopLod(utpT.getNewLod());
|
||||
utpT.setBottomLod(utp.getNewLod());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the cached references of neighbours.
|
||||
* TerrainQuad caches neighbours for faster LOD checks.
|
||||
* Sometimes you might want to reset this cache (for instance in TerrainGrid)
|
||||
*/
|
||||
protected void resetCachedNeighbours() {
|
||||
public void resetCachedNeighbours() {
|
||||
if (children != null) {
|
||||
for (int x = children.size(); --x >= 0;) {
|
||||
Spatial child = children.get(x);
|
||||
@ -441,33 +465,41 @@ public class TerrainQuad extends Node implements Terrain {
|
||||
if (right != null) {
|
||||
UpdatedTerrainPatch utpR = updated.get(right.getName());
|
||||
if (utpR == null) {
|
||||
utpR = new UpdatedTerrainPatch(right, right.lod);
|
||||
utpR = new UpdatedTerrainPatch(right);
|
||||
updated.put(utpR.getName(), utpR);
|
||||
utpR.setNewLod(right.lod);
|
||||
}
|
||||
utpR.setLeftLod(utp.getNewLod());
|
||||
utpR.setFixEdges(true);
|
||||
}
|
||||
if (down != null) {
|
||||
UpdatedTerrainPatch utpD = updated.get(down.getName());
|
||||
if (utpD == null) {
|
||||
utpD = new UpdatedTerrainPatch(down, down.lod);
|
||||
utpD = new UpdatedTerrainPatch(down);
|
||||
updated.put(utpD.getName(), utpD);
|
||||
utpD.setNewLod(down.lod);
|
||||
}
|
||||
utpD.setTopLod(utp.getNewLod());
|
||||
utpD.setFixEdges(true);
|
||||
}
|
||||
if (top != null){
|
||||
UpdatedTerrainPatch utpT = updated.get(top.getName());
|
||||
if (utpT == null) {
|
||||
utpT = new UpdatedTerrainPatch(top, top.lod);
|
||||
utpT = new UpdatedTerrainPatch(top);
|
||||
updated.put(utpT.getName(), utpT);
|
||||
utpT.setNewLod(top.lod);
|
||||
}
|
||||
utpT.setBottomLod(utp.getNewLod());
|
||||
utpT.setFixEdges(true);
|
||||
}
|
||||
if (left != null){
|
||||
UpdatedTerrainPatch utpL = updated.get(left.getName());
|
||||
if (utpL == null) {
|
||||
utpL = new UpdatedTerrainPatch(left, left.lod);
|
||||
utpL = new UpdatedTerrainPatch(left);
|
||||
updated.put(utpL.getName(), utpL);
|
||||
utpL.setNewLod(left.lod);
|
||||
}
|
||||
utpL.setRightLod(utp.getNewLod());
|
||||
utpL.setFixEdges(true);
|
||||
}
|
||||
}
|
||||
@ -1278,6 +1310,8 @@ public class TerrainQuad extends Node implements Terrain {
|
||||
}
|
||||
|
||||
protected TerrainQuad getQuad(int quad) {
|
||||
if (quad == 0)
|
||||
return this;
|
||||
if (children != null)
|
||||
for (int x = children.size(); --x >= 0;) {
|
||||
Spatial child = children.get(x);
|
||||
@ -1355,7 +1389,7 @@ public class TerrainQuad extends Node implements Terrain {
|
||||
else if (tp.getQuadrant() == 4)
|
||||
return getPatch(2);
|
||||
else if (tp.getQuadrant() == 1) {
|
||||
// find the patch above and ask it for child 2.
|
||||
// find the patch above and ask it for child 3.
|
||||
TerrainQuad quad = findLeftQuad();
|
||||
if (quad != null)
|
||||
return quad.getPatch(3);
|
||||
@ -1370,34 +1404,35 @@ public class TerrainQuad extends Node implements Terrain {
|
||||
|
||||
protected TerrainQuad findRightQuad() {
|
||||
boolean useFinder = false;
|
||||
if (getParent() == null || !(getParent() instanceof TerrainQuad))
|
||||
if (neighbourFinder == null)
|
||||
if (getParent() == null || !(getParent() instanceof TerrainQuad)) {
|
||||
if (neighbourFinder == null)
|
||||
return null;
|
||||
else
|
||||
useFinder = true;
|
||||
}
|
||||
|
||||
TerrainQuad pQuad = (TerrainQuad) getParent();
|
||||
TerrainQuad pQuad = null;
|
||||
if (!useFinder)
|
||||
pQuad = (TerrainQuad) getParent();
|
||||
|
||||
if (quadrant == 1)
|
||||
return pQuad.getQuad(3);
|
||||
else if (quadrant == 2)
|
||||
return pQuad.getQuad(4);
|
||||
else if (quadrant == 3) {
|
||||
TerrainQuad quad = null;
|
||||
if (useFinder)
|
||||
quad = neighbourFinder.getRightQuad(this);
|
||||
else
|
||||
quad = pQuad.findRightQuad();
|
||||
TerrainQuad quad = pQuad.findRightQuad();
|
||||
if (quad != null)
|
||||
return quad.getQuad(1);
|
||||
} else if (quadrant == 4) {
|
||||
TerrainQuad quad = null;
|
||||
if (useFinder)
|
||||
quad = neighbourFinder.getRightQuad(this);
|
||||
else
|
||||
quad = pQuad.findRightQuad();
|
||||
TerrainQuad quad = pQuad.findRightQuad();
|
||||
if (quad != null)
|
||||
return quad.getQuad(2);
|
||||
} else if (quadrant == 0) {
|
||||
// at the top quad
|
||||
if (useFinder) {
|
||||
TerrainQuad quad = neighbourFinder.getRightQuad(this);
|
||||
return quad;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -1405,34 +1440,35 @@ public class TerrainQuad extends Node implements Terrain {
|
||||
|
||||
protected TerrainQuad findDownQuad() {
|
||||
boolean useFinder = false;
|
||||
if (getParent() == null || !(getParent() instanceof TerrainQuad))
|
||||
if (neighbourFinder == null)
|
||||
if (getParent() == null || !(getParent() instanceof TerrainQuad)) {
|
||||
if (neighbourFinder == null)
|
||||
return null;
|
||||
else
|
||||
useFinder = true;
|
||||
}
|
||||
|
||||
TerrainQuad pQuad = (TerrainQuad) getParent();
|
||||
TerrainQuad pQuad = null;
|
||||
if (!useFinder)
|
||||
pQuad = (TerrainQuad) getParent();
|
||||
|
||||
if (quadrant == 1)
|
||||
return pQuad.getQuad(2);
|
||||
else if (quadrant == 3)
|
||||
return pQuad.getQuad(4);
|
||||
else if (quadrant == 2) {
|
||||
TerrainQuad quad = null;
|
||||
if (useFinder)
|
||||
quad = neighbourFinder.getDownQuad(this);
|
||||
else
|
||||
quad = pQuad.findDownQuad();
|
||||
TerrainQuad quad = pQuad.findDownQuad();
|
||||
if (quad != null)
|
||||
return quad.getQuad(1);
|
||||
} else if (quadrant == 4) {
|
||||
TerrainQuad quad = null;
|
||||
if (useFinder)
|
||||
quad = neighbourFinder.getDownQuad(this);
|
||||
else
|
||||
quad = pQuad.findDownQuad();
|
||||
TerrainQuad quad = pQuad.findDownQuad();
|
||||
if (quad != null)
|
||||
return quad.getQuad(3);
|
||||
} else if (quadrant == 0) {
|
||||
// at the top quad
|
||||
if (useFinder) {
|
||||
TerrainQuad quad = neighbourFinder.getDownQuad(this);
|
||||
return quad;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -1440,34 +1476,35 @@ public class TerrainQuad extends Node implements Terrain {
|
||||
|
||||
protected TerrainQuad findTopQuad() {
|
||||
boolean useFinder = false;
|
||||
if (getParent() == null || !(getParent() instanceof TerrainQuad))
|
||||
if (neighbourFinder == null)
|
||||
if (getParent() == null || !(getParent() instanceof TerrainQuad)) {
|
||||
if (neighbourFinder == null)
|
||||
return null;
|
||||
else
|
||||
useFinder = true;
|
||||
}
|
||||
|
||||
TerrainQuad pQuad = (TerrainQuad) getParent();
|
||||
TerrainQuad pQuad = null;
|
||||
if (!useFinder)
|
||||
pQuad = (TerrainQuad) getParent();
|
||||
|
||||
if (quadrant == 2)
|
||||
return pQuad.getQuad(1);
|
||||
else if (quadrant == 4)
|
||||
return pQuad.getQuad(3);
|
||||
else if (quadrant == 1) {
|
||||
TerrainQuad quad = null;
|
||||
if (useFinder)
|
||||
quad = neighbourFinder.getTopQuad(this);
|
||||
else
|
||||
quad = pQuad.findTopQuad();
|
||||
TerrainQuad quad = pQuad.findTopQuad();
|
||||
if (quad != null)
|
||||
return quad.getQuad(2);
|
||||
} else if (quadrant == 3) {
|
||||
TerrainQuad quad = null;
|
||||
if (useFinder)
|
||||
quad = neighbourFinder.getTopQuad(this);
|
||||
else
|
||||
quad = pQuad.findTopQuad();
|
||||
TerrainQuad quad = pQuad.findTopQuad();
|
||||
if (quad != null)
|
||||
return quad.getQuad(4);
|
||||
} else if (quadrant == 0) {
|
||||
// at the top quad
|
||||
if (useFinder) {
|
||||
TerrainQuad quad = neighbourFinder.getTopQuad(this);
|
||||
return quad;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -1475,34 +1512,35 @@ public class TerrainQuad extends Node implements Terrain {
|
||||
|
||||
protected TerrainQuad findLeftQuad() {
|
||||
boolean useFinder = false;
|
||||
if (getParent() == null || !(getParent() instanceof TerrainQuad))
|
||||
if (neighbourFinder == null)
|
||||
if (getParent() == null || !(getParent() instanceof TerrainQuad)) {
|
||||
if (neighbourFinder == null)
|
||||
return null;
|
||||
else
|
||||
useFinder = true;
|
||||
}
|
||||
|
||||
TerrainQuad pQuad = (TerrainQuad) getParent();
|
||||
TerrainQuad pQuad = null;
|
||||
if (!useFinder)
|
||||
pQuad = (TerrainQuad) getParent();
|
||||
|
||||
if (quadrant == 3)
|
||||
return pQuad.getQuad(1);
|
||||
else if (quadrant == 4)
|
||||
return pQuad.getQuad(2);
|
||||
else if (quadrant == 1) {
|
||||
TerrainQuad quad = null;
|
||||
if (useFinder)
|
||||
quad = neighbourFinder.getLeftQuad(this);
|
||||
else
|
||||
quad = pQuad.findLeftQuad();
|
||||
TerrainQuad quad = pQuad.findLeftQuad();
|
||||
if (quad != null)
|
||||
return quad.getQuad(3);
|
||||
} else if (quadrant == 2) {
|
||||
TerrainQuad quad = null;
|
||||
if (useFinder)
|
||||
quad = neighbourFinder.getLeftQuad(this);
|
||||
else
|
||||
quad = pQuad.findLeftQuad();
|
||||
TerrainQuad quad = pQuad.findLeftQuad();
|
||||
if (quad != null)
|
||||
return quad.getQuad(4);
|
||||
} else if (quadrant == 0) {
|
||||
// at the top quad
|
||||
if (useFinder) {
|
||||
TerrainQuad quad = neighbourFinder.getLeftQuad(this);
|
||||
return quad;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -49,29 +49,24 @@ public class UpdatedTerrainPatch {
|
||||
private int previousLod;
|
||||
private int rightLod,topLod,leftLod,bottomLod;
|
||||
private IntBuffer newIndexBuffer;
|
||||
private boolean reIndexNeeded = false;
|
||||
//private boolean reIndexNeeded = false;
|
||||
private boolean fixEdges = false;
|
||||
|
||||
public UpdatedTerrainPatch(TerrainPatch updatedPatch) {
|
||||
this.updatedPatch = updatedPatch;
|
||||
}
|
||||
|
||||
public UpdatedTerrainPatch(TerrainPatch updatedPatch, int newLod) {
|
||||
this.updatedPatch = updatedPatch;
|
||||
this.newLod = newLod;
|
||||
}
|
||||
|
||||
public UpdatedTerrainPatch(TerrainPatch updatedPatch, int newLod, int prevLOD, boolean reIndexNeeded) {
|
||||
this.updatedPatch = updatedPatch;
|
||||
this.newLod = newLod;
|
||||
this.previousLod = prevLOD;
|
||||
this.reIndexNeeded = reIndexNeeded;
|
||||
if (this.newLod <= 0)
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return updatedPatch.getName();
|
||||
}
|
||||
|
||||
protected boolean lodChanged() {
|
||||
if (reIndexNeeded && previousLod != newLod)
|
||||
if ( previousLod != newLod)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@ -88,16 +83,16 @@ public class UpdatedTerrainPatch {
|
||||
protected int getNewLod() {
|
||||
return newLod;
|
||||
}
|
||||
|
||||
|
||||
public void setNewLod(int newLod) {
|
||||
this.newLod = newLod;
|
||||
if (this.newLod < 0)
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException("newLod cannot be less than zero, was: "+newLod);
|
||||
}
|
||||
|
||||
protected IntBuffer getNewIndexBuffer() {
|
||||
/*protected IntBuffer getNewIndexBuffer() {
|
||||
return newIndexBuffer;
|
||||
}
|
||||
}*/
|
||||
|
||||
protected void setNewIndexBuffer(IntBuffer newIndexBuffer) {
|
||||
this.newIndexBuffer = newIndexBuffer;
|
||||
@ -144,12 +139,16 @@ public class UpdatedTerrainPatch {
|
||||
}
|
||||
|
||||
public boolean isReIndexNeeded() {
|
||||
return reIndexNeeded;
|
||||
if (lodChanged() || isFixEdges())
|
||||
return true;
|
||||
//if (leftLod != newLod || rightLod != newLod || bottomLod != newLod || topLod != newLod)
|
||||
// return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setReIndexNeeded(boolean reIndexNeeded) {
|
||||
/*public void setReIndexNeeded(boolean reIndexNeeded) {
|
||||
this.reIndexNeeded = reIndexNeeded;
|
||||
}
|
||||
}*/
|
||||
|
||||
public boolean isFixEdges() {
|
||||
return fixEdges;
|
||||
@ -159,9 +158,9 @@ public class UpdatedTerrainPatch {
|
||||
this.fixEdges = fixEdges;
|
||||
}
|
||||
|
||||
public int getPreviousLod() {
|
||||
/*public int getPreviousLod() {
|
||||
return previousLod;
|
||||
}
|
||||
}*/
|
||||
|
||||
public void setPreviousLod(int previousLod) {
|
||||
this.previousLod = previousLod;
|
||||
@ -173,11 +172,11 @@ public class UpdatedTerrainPatch {
|
||||
updatedPatch.setLodTop(topLod);
|
||||
updatedPatch.setLodLeft(leftLod);
|
||||
updatedPatch.setLodBottom(bottomLod);
|
||||
if (newIndexBuffer != null && (reIndexNeeded || fixEdges)) {
|
||||
if (newIndexBuffer != null && isReIndexNeeded()) {
|
||||
updatedPatch.setPreviousLod(previousLod);
|
||||
updatedPatch.getMesh().clearBuffer(Type.Index);
|
||||
updatedPatch.getMesh().setBuffer(Type.Index, 3, newIndexBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -71,12 +71,12 @@ public class DistanceLodCalculator implements LodCalculator {
|
||||
int prevLOD = terrainPatch.getLod();
|
||||
UpdatedTerrainPatch utp = updates.get(terrainPatch.getName());
|
||||
if (utp == null) {
|
||||
utp = new UpdatedTerrainPatch(terrainPatch, 0);
|
||||
utp = new UpdatedTerrainPatch(terrainPatch);
|
||||
updates.put(utp.getName(), utp);
|
||||
}
|
||||
utp.setNewLod(0);
|
||||
utp.setPreviousLod(prevLOD);
|
||||
utp.setReIndexNeeded(true);
|
||||
//utp.setReIndexNeeded(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -89,15 +89,15 @@ public class DistanceLodCalculator implements LodCalculator {
|
||||
//System.out.println("lod change: "+lod+" > "+i+" dist: "+distance);
|
||||
}
|
||||
int prevLOD = terrainPatch.getLod();
|
||||
//previousLod = lod;
|
||||
//lod = i;
|
||||
|
||||
UpdatedTerrainPatch utp = updates.get(terrainPatch.getName());
|
||||
if (utp == null) {
|
||||
utp = new UpdatedTerrainPatch(terrainPatch, i);//save in here, do not update actual variables
|
||||
utp = new UpdatedTerrainPatch(terrainPatch);//save in here, do not update actual variables
|
||||
updates.put(utp.getName(), utp);
|
||||
}
|
||||
utp.setNewLod(i);
|
||||
utp.setPreviousLod(prevLOD);
|
||||
utp.setReIndexNeeded(reIndexNeeded);
|
||||
//utp.setReIndexNeeded(reIndexNeeded);
|
||||
|
||||
return reIndexNeeded;
|
||||
}
|
||||
|
@ -106,15 +106,15 @@ public class PerspectiveLodCalculator implements LodCalculator {
|
||||
}
|
||||
int prevLOD = patch.getLod();
|
||||
|
||||
//previousLod = lod;
|
||||
//lod = i;
|
||||
|
||||
UpdatedTerrainPatch utp = updates.get(patch.getName());
|
||||
if (utp == null) {
|
||||
utp = new UpdatedTerrainPatch(patch, i);//save in here, do not update actual variables
|
||||
utp = new UpdatedTerrainPatch(patch);//save in here, do not update actual variables
|
||||
updates.put(utp.getName(), utp);
|
||||
}
|
||||
utp.setNewLod(i);
|
||||
utp.setPreviousLod(prevLOD);
|
||||
utp.setReIndexNeeded(reIndexNeeded);
|
||||
//utp.setReIndexNeeded(reIndexNeeded);
|
||||
return reIndexNeeded;
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,13 @@ import com.jme3.material.Material;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.Vector2f;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.shape.Sphere;
|
||||
import com.jme3.terrain.ProgressMonitor;
|
||||
import com.jme3.terrain.Terrain;
|
||||
import com.jme3.terrain.geomipmap.MultiTerrainLodControl;
|
||||
import com.jme3.terrain.geomipmap.NeighbourFinder;
|
||||
import com.jme3.terrain.geomipmap.TerrainLodControl;
|
||||
import com.jme3.terrain.geomipmap.TerrainQuad;
|
||||
import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
|
||||
import com.jme3.texture.Texture;
|
||||
@ -29,7 +31,8 @@ import java.util.List;
|
||||
/**
|
||||
* Demonstrates the NeighbourFinder interface for TerrainQuads,
|
||||
* allowing you to tile terrains together without having to use
|
||||
* TerrainGrid.
|
||||
* TerrainGrid. It also introduces the MultiTerrainLodControl that
|
||||
* will seam the edges of all the terrains supplied.
|
||||
*
|
||||
* @author sploreg
|
||||
*/
|
||||
@ -75,7 +78,31 @@ public class TerrainTestTile extends SimpleApplication {
|
||||
rootNode.addLight(ambLight);
|
||||
|
||||
cam.setLocation(new Vector3f(0, 256, 0));
|
||||
cam.lookAtDirection(new Vector3f(0, -1f, 0).normalizeLocal(), Vector3f.UNIT_X);
|
||||
cam.lookAtDirection(new Vector3f(0, -1, -1).normalizeLocal(), Vector3f.UNIT_Y);
|
||||
|
||||
|
||||
Sphere s = new Sphere(12, 12, 3);
|
||||
Geometry g = new Geometry("marker");
|
||||
g.setMesh(s);
|
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
|
||||
mat.setColor("Color", ColorRGBA.Red);
|
||||
g.setMaterial(mat);
|
||||
g.setLocalTranslation(0, -100, 0);
|
||||
rootNode.attachChild(g);
|
||||
|
||||
Geometry g2 = new Geometry("marker");
|
||||
g2.setMesh(s);
|
||||
mat.setColor("Color", ColorRGBA.Red);
|
||||
g2.setMaterial(mat);
|
||||
g2.setLocalTranslation(10, -100, 0);
|
||||
rootNode.attachChild(g2);
|
||||
|
||||
Geometry g3 = new Geometry("marker");
|
||||
g3.setMesh(s);
|
||||
mat.setColor("Color", ColorRGBA.Red);
|
||||
g3.setMaterial(mat);
|
||||
g3.setLocalTranslation(0, -100, 10);
|
||||
rootNode.attachChild(g3);
|
||||
}
|
||||
|
||||
public void loadHintText() {
|
||||
@ -110,6 +137,8 @@ public class TerrainTestTile extends SimpleApplication {
|
||||
* the use of NeighbourFinder.
|
||||
* It just links up the left,right,top,bottom TerrainQuads
|
||||
* so LOD can work.
|
||||
* It does not implement many of the Terrain interface's methods,
|
||||
* you will want to do that for your own implementations.
|
||||
*/
|
||||
private class TiledTerrain extends Node implements Terrain, NeighbourFinder {
|
||||
|
||||
@ -132,41 +161,43 @@ public class TerrainTestTile extends SimpleApplication {
|
||||
matTerrain.setFloat("DiffuseMap_0_scale", grassScale);
|
||||
|
||||
// CREATE THE TERRAIN
|
||||
terrain1 = new TerrainQuad("terrain", 65, 513, null);
|
||||
TerrainLodControl control1 = new TerrainLodControl(terrain1, getCamera());
|
||||
control1.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier
|
||||
terrain1.addControl(control1);
|
||||
terrain1 = new TerrainQuad("terrain 1", 65, 513, null);
|
||||
terrain1.setMaterial(matTerrain);
|
||||
terrain1.setLocalTranslation(-256, -100, -256);
|
||||
terrain1.setLocalScale(1f, 1f, 1f);
|
||||
this.attachChild(terrain1);
|
||||
|
||||
terrain2 = new TerrainQuad("terrain", 65, 513, null);
|
||||
TerrainLodControl control2 = new TerrainLodControl(terrain2, getCamera());
|
||||
control2.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier
|
||||
terrain2.addControl(control2);
|
||||
terrain2 = new TerrainQuad("terrain 2", 65, 513, null);
|
||||
terrain2.setMaterial(matTerrain);
|
||||
terrain2.setLocalTranslation(-256, -100, 256);
|
||||
terrain2.setLocalScale(1f, 1f, 1f);
|
||||
this.attachChild(terrain2);
|
||||
|
||||
terrain3 = new TerrainQuad("terrain", 65, 513, null);
|
||||
TerrainLodControl control3 = new TerrainLodControl(terrain3, getCamera());
|
||||
control3.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier
|
||||
terrain3.addControl(control3);
|
||||
terrain3 = new TerrainQuad("terrain 3", 65, 513, null);
|
||||
terrain3.setMaterial(matTerrain);
|
||||
terrain3.setLocalTranslation(256, -100, -256);
|
||||
terrain3.setLocalScale(1f, 1f, 1f);
|
||||
this.attachChild(terrain3);
|
||||
|
||||
terrain4 = new TerrainQuad("terrain", 65, 513, null);
|
||||
TerrainLodControl control4 = new TerrainLodControl(terrain4, getCamera());
|
||||
control4.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier
|
||||
terrain4.addControl(control4);
|
||||
terrain4 = new TerrainQuad("terrain 4", 65, 513, null);
|
||||
terrain4.setMaterial(matTerrain);
|
||||
terrain4.setLocalTranslation(256, -100, 256);
|
||||
terrain4.setLocalScale(1f, 1f, 1f);
|
||||
this.attachChild(terrain4);
|
||||
|
||||
terrain1.setNeighbourFinder(this);
|
||||
terrain2.setNeighbourFinder(this);
|
||||
terrain3.setNeighbourFinder(this);
|
||||
terrain4.setNeighbourFinder(this);
|
||||
|
||||
MultiTerrainLodControl lodControl = new MultiTerrainLodControl(getCamera());
|
||||
lodControl.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier
|
||||
lodControl.addTerrain(terrain1);
|
||||
lodControl.addTerrain(terrain2);
|
||||
lodControl.addTerrain(terrain3);// order of these seems to matter
|
||||
lodControl.addTerrain(terrain4);
|
||||
this.addControl(lodControl);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,6 +205,7 @@ public class TerrainTestTile extends SimpleApplication {
|
||||
* 2 4
|
||||
*/
|
||||
public TerrainQuad getRightQuad(TerrainQuad center) {
|
||||
//System.out.println("lookup neighbour");
|
||||
if (center == terrain1)
|
||||
return terrain3;
|
||||
if (center == terrain2)
|
||||
@ -187,6 +219,7 @@ public class TerrainTestTile extends SimpleApplication {
|
||||
* 2 4
|
||||
*/
|
||||
public TerrainQuad getLeftQuad(TerrainQuad center) {
|
||||
//System.out.println("lookup neighbour");
|
||||
if (center == terrain3)
|
||||
return terrain1;
|
||||
if (center == terrain4)
|
||||
@ -200,6 +233,7 @@ public class TerrainTestTile extends SimpleApplication {
|
||||
* 2 4
|
||||
*/
|
||||
public TerrainQuad getTopQuad(TerrainQuad center) {
|
||||
//System.out.println("lookup neighbour");
|
||||
if (center == terrain2)
|
||||
return terrain1;
|
||||
if (center == terrain4)
|
||||
@ -213,6 +247,7 @@ public class TerrainTestTile extends SimpleApplication {
|
||||
* 2 4
|
||||
*/
|
||||
public TerrainQuad getDownQuad(TerrainQuad center) {
|
||||
//System.out.println("lookup neighbour");
|
||||
if (center == terrain1)
|
||||
return terrain2;
|
||||
if (center == terrain3)
|
||||
|
Loading…
x
Reference in New Issue
Block a user