diff --git a/engine/mountains.zip b/engine/mountains.zip index 76184e0bb..59b7ce0a3 100644 Binary files a/engine/mountains.zip and b/engine/mountains.zip differ diff --git a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java index 0a195dd11..bc8567c62 100644 --- a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java +++ b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java @@ -81,7 +81,7 @@ public class TerrainGrid extends TerrainQuad { } public void run() { - + for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { int quadIdx = i * 4 + j; @@ -99,13 +99,14 @@ public class TerrainGrid extends TerrainQuad { log.log(Level.FINE, "Loaded TerrainQuad {0}", q.getName()); } cache.put(temp, q); - + if (isCenter(quadIdx)) { // if it should be attached as a child right now, attach it final int quadrant = getQuadrant(quadIdx); final TerrainQuad newQuad = q; // back on the OpenGL thread: getControl(UpdateControl.class).enqueue(new Callable() { + public Object call() throws Exception { attachQuadAt(newQuad, quadrant, temp); return null; @@ -117,20 +118,21 @@ public class TerrainGrid extends TerrainQuad { } } - + private boolean isCenter(int quadIndex) { return quadIndex == 9 || quadIndex == 5 || quadIndex == 10 || quadIndex == 6; } - + private int getQuadrant(int quadIndex) { - if (quadIndex == 9) + if (quadIndex == 9) { return 1; - else if (quadIndex == 5) + } else if (quadIndex == 5) { return 2; - else if (quadIndex == 10) + } else if (quadIndex == 10) { return 3; - else if (quadIndex == 6) + } else if (quadIndex == 6) { return 4; + } return 0; // error } @@ -161,7 +163,7 @@ public class TerrainGrid extends TerrainQuad { new Vector3f(-1, 0, 1), new Vector3f(0, 0, 1), new Vector3f(1, 0, 1), new Vector3f(2, 0, 1), new Vector3f(-1, 0, 0), new Vector3f(0, 0, 0), new Vector3f(1, 0, 0), new Vector3f(2, 0, 0), new Vector3f(-1, 0, -1), new Vector3f(0, 0, -1), new Vector3f(1, 0, -1), new Vector3f(-2, 0, -1)}; - + addControl(new UpdateControl()); } @@ -190,6 +192,7 @@ public class TerrainGrid extends TerrainQuad { for (TerrainGridListener l : this.listeners.values()) { l.gridMoved(camCell); } + updatePhysics(); } @Override @@ -205,6 +208,7 @@ public class TerrainGrid extends TerrainQuad { for (TerrainGridListener l : this.listeners.values()) { l.gridMoved(camCell); } + updatePhysics(); } super.update(locations); @@ -234,8 +238,8 @@ public class TerrainGrid extends TerrainQuad { q.setQuadrant((short) quadrant); this.attachChild(q); - Vector3f loc = cam.mult(this.quadSize-1).subtract(quarterSize, 0, quarterSize);// quadrant location handled TerrainQuad automatically now - q.setLocalTranslation(loc ); + Vector3f loc = cam.mult(this.quadSize - 1).subtract(quarterSize, 0, quarterSize);// quadrant location handled TerrainQuad automatically now + q.setLocalTranslation(loc); if (quadControls != null) { quadControls[quadrant - 1].setEnabled(false); @@ -246,11 +250,11 @@ public class TerrainGrid extends TerrainQuad { //quadControls[quadrant - 1].setPhysicsLocation(cam.add(this.quadOrigins[quadrant - 1])); } else { } - + updateModelBound(); } - private void updateChildrens(Vector3f cam) { + public void updatePhysics() { RigidBodyControl control = getControl(RigidBodyControl.class); if (control != null) { this.space = control.getPhysicsSpace(); @@ -261,22 +265,29 @@ public class TerrainGrid extends TerrainQuad { for (int i = 0; i < 4; i++) { int collisionGroupsCollideWith = control.getCollideWithGroups(); int collisionGroups = control.getCollisionGroup(); - quadControls[i] = new RigidBodyControl(new HeightfieldCollisionShape(new float[quadSize * quadSize], getLocalScale()), 0); + TerrainQuad q = getQuad(i + 1); + quadControls[i] = new RigidBodyControl(new HeightfieldCollisionShape(q == null ? new float[quadSize * quadSize] : q.getHeightMap(), getLocalScale()), 0); quadControls[i].setCollideWithGroups(collisionGroupsCollideWith); quadControls[i].setCollisionGroup(collisionGroups); //quadControls[i].setPhysicsSpace(space); //this.addControl(quadControls[i]); - //space.add(quadControls[i]); + if (q != null) { + getQuad(i + 1).addControl(quadControls[i]); + space.add(quadControls[i]); + } } } + } + private void updateChildrens(Vector3f cam) { //TerrainQuad q1 = cache.get(cam.add(quadIndex[9])); //TerrainQuad q2 = cache.get(cam.add(quadIndex[5])); //TerrainQuad q3 = cache.get(cam.add(quadIndex[10])); //TerrainQuad q4 = cache.get(cam.add(quadIndex[6])); // --------------------------------------------------- - // what does this block do? + // LRU cache is used, so elements that need to remain + // should be touched. // --------------------------------------------------- int dx = 0; int dy = 0; @@ -308,26 +319,27 @@ public class TerrainGrid extends TerrainQuad { } // --------------------------------------------------- // --------------------------------------------------- - - if (executor == null) + + if (executor == null) { executor = createExecutorService(); + } executor.submit(new UpdateQuadCache(cam)); - -/* if (q1 == null || q2 == null || q3 == null || q4 == null) { - try { - executor.submit(new UpdateQuadCache(cam, true)).get(); // BLOCKING - q1 = cache.get(cam.add(quadIndex[9])); - q2 = cache.get(cam.add(quadIndex[5])); - q3 = cache.get(cam.add(quadIndex[10])); - q4 = cache.get(cam.add(quadIndex[6])); - } catch (InterruptedException ex) { - Logger.getLogger(TerrainGrid.class.getName()).log(Level.SEVERE, null, ex); - return; - } catch (ExecutionException ex) { - Logger.getLogger(TerrainGrid.class.getName()).log(Level.SEVERE, null, ex); - return; - } + + /* if (q1 == null || q2 == null || q3 == null || q4 == null) { + try { + executor.submit(new UpdateQuadCache(cam, true)).get(); // BLOCKING + q1 = cache.get(cam.add(quadIndex[9])); + q2 = cache.get(cam.add(quadIndex[5])); + q3 = cache.get(cam.add(quadIndex[10])); + q4 = cache.get(cam.add(quadIndex[6])); + } catch (InterruptedException ex) { + Logger.getLogger(TerrainGrid.class.getName()).log(Level.SEVERE, null, ex); + return; + } catch (ExecutionException ex) { + Logger.getLogger(TerrainGrid.class.getName()).log(Level.SEVERE, null, ex); + return; + } } executor.execute(new UpdateQuadCache(cam)); @@ -342,11 +354,11 @@ public class TerrainGrid extends TerrainQuad { attachQuadAt(q2, 2, cam); // quadIndex[5] attachQuadAt(q3, 3, cam); // quadIndex[10] attachQuadAt(q4, 4, cam); // quadIndex[6] -*/ + */ this.currentCell = cam; // this.updateModelBound(); } - + public void addListener(String id, TerrainGridListener listener) { this.listeners.put(id, listener); } @@ -368,15 +380,54 @@ public class TerrainGrid extends TerrainQuad { public void setQuadSize(int quadSize) { this.quadSize = quadSize; } - + @Override public void adjustHeight(List xz, List height) { - Vector3f currentGridLocation = getCurrentCell().mult( getLocalScale() ).multLocal( quadSize-1 ); - for ( Vector2f vect : xz ) - { + Vector3f currentGridLocation = getCurrentCell().mult(getLocalScale()).multLocal(quadSize - 1); + for (Vector2f vect : xz) { vect.x -= currentGridLocation.x; vect.y -= currentGridLocation.z; } - super.adjustHeight( xz, height ); + super.adjustHeight(xz, height); + } + + @Override + protected TerrainQuad findDownQuad() { + if (quadrant == 1) { + return cache.get(currentCell.add(quadIndex[13])); + } else if (quadrant == 3) { + return cache.get(currentCell.add(quadIndex[14])); + } + return null; + } + + @Override + protected TerrainQuad findLeftQuad() { + if (quadrant == 1) { + return cache.get(currentCell.add(quadIndex[8])); + } else if (quadrant == 2) { + return cache.get(currentCell.add(quadIndex[4])); + } + return null; + } + + @Override + protected TerrainQuad findRightQuad() { + if (quadrant == 3) { + return cache.get(currentCell.add(quadIndex[11])); + } else if (quadrant == 4) { + return cache.get(currentCell.add(quadIndex[7])); + } + return null; + } + + @Override + protected TerrainQuad findTopQuad() { + if (quadrant == 2) { + return cache.get(currentCell.add(quadIndex[1])); + } else if (quadrant == 4) { + return cache.get(currentCell.add(quadIndex[2])); + } + return null; } } diff --git a/engine/src/test/jme3test/terrain/TerrainFractalGridTest.java b/engine/src/test/jme3test/terrain/TerrainFractalGridTest.java index 84ed5ad20..3529aa2ac 100644 --- a/engine/src/test/jme3test/terrain/TerrainFractalGridTest.java +++ b/engine/src/test/jme3test/terrain/TerrainFractalGridTest.java @@ -15,9 +15,11 @@ import com.jme3.input.controls.ActionListener; import com.jme3.input.controls.KeyTrigger; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; import com.jme3.terrain.geomipmap.TerrainGrid; +import com.jme3.terrain.geomipmap.TerrainGridListener; import com.jme3.terrain.geomipmap.TerrainLodControl; import com.jme3.terrain.heightmap.FractalHeightMapGrid; import com.jme3.texture.Texture; @@ -39,6 +41,7 @@ public class TerrainFractalGridTest extends SimpleApplication { private float dirtScale = 16; private float rockScale = 128; private boolean usePhysics = true; + private boolean physicsAdded = false; public static void main(final String[] args) { TerrainFractalGridTest app = new TerrainFractalGridTest(); @@ -132,12 +135,11 @@ public class TerrainFractalGridTest extends SimpleApplication { ground.addPreFilter(this.iterate); - this.terrain = new TerrainGrid("terrain", 65, 257, new FractalHeightMapGrid(ground, null, 256f)); + this.terrain = new TerrainGrid("terrain", 65, 257, new FractalHeightMapGrid(ground, "D:\\work5\\temp", 256f)); this.terrain.setMaterial(this.mat_terrain); this.terrain.setLocalTranslation(0, 0, 0); this.terrain.setLocalScale(2f, 1f, 2f); - this.terrain.initialize(Vector3f.ZERO); this.rootNode.attachChild(this.terrain); List cameras = new ArrayList(); @@ -145,28 +147,40 @@ public class TerrainFractalGridTest extends SimpleApplication { TerrainLodControl control = new TerrainLodControl(this.terrain, cameras); this.terrain.addControl(control); - BulletAppState bulletAppState = new BulletAppState(); + final BulletAppState bulletAppState = new BulletAppState(); stateManager.attach(bulletAppState); - this.getCamera().setLocation(new Vector3f(0, 256, 0)); + this.getCamera().setLocation(new Vector3f(0, 0, 0)); this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f)); if (usePhysics) { - RigidBodyControl body = new RigidBodyControl(new HeightfieldCollisionShape(terrain.getHeightMap(), terrain.getLocalScale()), 0); - terrain.addControl(body); - bulletAppState.getPhysicsSpace().add(terrain); - CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(0.5f, 1.8f, 1); - this.player3 = new CharacterControl(capsuleShape, 0.5f); - this.player3.setJumpSpeed(20); - this.player3.setFallSpeed(30); - this.player3.setGravity(30); - - this.player3.setPhysicsLocation(new Vector3f(0, 256, 0)); - - bulletAppState.getPhysicsSpace().add(this.player3); + terrain.addListener("physicsStartListener", new TerrainGridListener() { + + public void gridMoved(Vector3f newCenter) { + terrain.removeListener("physicsStartListener"); + RigidBodyControl body = new RigidBodyControl(new HeightfieldCollisionShape(terrain.getHeightMap(), terrain.getLocalScale()), 0); + terrain.addControl(body); + bulletAppState.getPhysicsSpace().add(terrain); + CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(0.5f, 1.8f, 1); + player3 = new CharacterControl(capsuleShape, 0.5f); + player3.setJumpSpeed(20); + player3.setFallSpeed(10); + player3.setGravity(10); + + player3.setPhysicsLocation(new Vector3f(cam.getLocation().x, 256, cam.getLocation().z)); + + bulletAppState.getPhysicsSpace().add(player3); + physicsAdded = true; + } + + public Material tileLoaded(Material material, Vector3f cell) { + return material; + } + }); } + this.terrain.initialize(cam.getLocation()); this.initKeys(); } @@ -183,7 +197,6 @@ public class TerrainFractalGridTest extends SimpleApplication { this.inputManager.addListener(this.actionListener, "Downs"); this.inputManager.addListener(this.actionListener, "Jumps"); } - private boolean left; private boolean right; private boolean up; @@ -225,23 +238,23 @@ public class TerrainFractalGridTest extends SimpleApplication { @Override public void simpleUpdate(final float tpf) { - Vector3f camDir = this.cam.getDirection().clone().multLocal(0.6f); - Vector3f camLeft = this.cam.getLeft().clone().multLocal(0.4f); - this.walkDirection.set(0, 0, 0); - if (this.left) { - this.walkDirection.addLocal(camLeft); - } - if (this.right) { - this.walkDirection.addLocal(camLeft.negate()); - } - if (this.up) { - this.walkDirection.addLocal(camDir); - } - if (this.down) { - this.walkDirection.addLocal(camDir.negate()); - } + Vector3f camDir = this.cam.getDirection().clone().multLocal(0.6f); + Vector3f camLeft = this.cam.getLeft().clone().multLocal(0.4f); + this.walkDirection.set(0, 0, 0); + if (this.left) { + this.walkDirection.addLocal(camLeft); + } + if (this.right) { + this.walkDirection.addLocal(camLeft.negate()); + } + if (this.up) { + this.walkDirection.addLocal(camDir); + } + if (this.down) { + this.walkDirection.addLocal(camDir.negate()); + } - if (usePhysics) { + if (usePhysics && physicsAdded) { this.player3.setWalkDirection(this.walkDirection); this.cam.setLocation(this.player3.getPhysicsLocation()); } diff --git a/engine/src/test/jme3test/terrain/TerrainGridTest.java b/engine/src/test/jme3test/terrain/TerrainGridTest.java index 60a40265a..7c660a8e8 100644 --- a/engine/src/test/jme3test/terrain/TerrainGridTest.java +++ b/engine/src/test/jme3test/terrain/TerrainGridTest.java @@ -1,6 +1,5 @@ package jme3test.terrain; - import com.jme3.app.SimpleApplication; import com.jme3.app.state.ScreenshotAppState; import com.jme3.asset.plugins.HttpZipLocator; @@ -17,6 +16,7 @@ import com.jme3.material.Material; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.terrain.geomipmap.TerrainGrid; +import com.jme3.terrain.geomipmap.TerrainGridListener; import com.jme3.terrain.geomipmap.TerrainLodControl; import com.jme3.terrain.heightmap.ImageBasedHeightMapGrid; import com.jme3.terrain.heightmap.Namer; @@ -32,6 +32,7 @@ public class TerrainGridTest extends SimpleApplication { private float dirtScale = 16; private float rockScale = 128; private boolean usePhysics = true; + private boolean physicsAdded = false; public static void main(final String[] args) { TerrainGridTest app = new TerrainGridTest(); @@ -44,7 +45,7 @@ public class TerrainGridTest extends SimpleApplication { File file = new File("mountains.zip"); if (!file.exists()) { assetManager.registerLocator("http://jmonkeyengine.googlecode.com/files/mountains.zip", HttpZipLocator.class); - }else{ + } else { assetManager.registerLocator("mountains.zip", ZipLocator.class); } @@ -89,24 +90,24 @@ public class TerrainGridTest extends SimpleApplication { this.mat_terrain.setTexture("slopeColorMap", rock); this.mat_terrain.setFloat("slopeTileFactor", 32); - this.mat_terrain.setFloat("terrainSize", 513); + this.mat_terrain.setFloat("terrainSize", 129); + + this.terrain = new TerrainGrid("terrain", 65, 257, new ImageBasedHeightMapGrid(assetManager, new Namer() { - this.terrain = new TerrainGrid("terrain", 65, 1025, new ImageBasedHeightMapGrid(assetManager, new Namer() { public String getName(int x, int y) { - return "Scenes/TerrainMountains/mountains_" + (x * 512) + "_" + (y * 512) + ".png"; + return "Scenes/TerrainMountains/terrain_" + x + "_" + y + ".png"; } })); this.terrain.setMaterial(this.mat_terrain); this.terrain.setLocalTranslation(0, 0, 0); this.terrain.setLocalScale(2f, 1f, 2f); - this.terrain.initialize(Vector3f.ZERO); this.rootNode.attachChild(this.terrain); TerrainLodControl control = new TerrainLodControl(this.terrain, getCamera()); this.terrain.addControl(control); - BulletAppState bulletAppState = new BulletAppState(); + final BulletAppState bulletAppState = new BulletAppState(); stateManager.attach(bulletAppState); this.getCamera().setLocation(new Vector3f(0, 256, 0)); @@ -114,19 +115,31 @@ public class TerrainGridTest extends SimpleApplication { this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f)); if (usePhysics) { - RigidBodyControl body = new RigidBodyControl(new HeightfieldCollisionShape(terrain.getHeightMap(), terrain.getLocalScale()), 0); - terrain.addControl(body); - bulletAppState.getPhysicsSpace().add(terrain); - CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(0.5f, 1.8f, 1); - this.player3 = new CharacterControl(capsuleShape, 0.5f); - this.player3.setJumpSpeed(20); - this.player3.setFallSpeed(30); - this.player3.setGravity(30); - - this.player3.setPhysicsLocation(new Vector3f(0, 256, 0)); - - bulletAppState.getPhysicsSpace().add(this.player3); + terrain.addListener("physicsStartListener", new TerrainGridListener() { + + public void gridMoved(Vector3f newCenter) { + terrain.removeListener("physicsStartListener"); + RigidBodyControl body = new RigidBodyControl(new HeightfieldCollisionShape(terrain.getHeightMap(), terrain.getLocalScale()), 0); + terrain.addControl(body); + bulletAppState.getPhysicsSpace().add(terrain); + CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(0.5f, 1.8f, 1); + player3 = new CharacterControl(capsuleShape, 0.5f); + player3.setJumpSpeed(20); + player3.setFallSpeed(30); + player3.setGravity(30); + + player3.setPhysicsLocation(new Vector3f(cam.getLocation().x, 256, cam.getLocation().z)); + + bulletAppState.getPhysicsSpace().add(player3); + physicsAdded = true; + } + + public Material tileLoaded(Material material, Vector3f cell) { + return material; + } + }); } + this.terrain.initialize(cam.getLocation()); this.initKeys(); } @@ -143,7 +156,6 @@ public class TerrainGridTest extends SimpleApplication { this.inputManager.addListener(this.actionListener, "Downs"); this.inputManager.addListener(this.actionListener, "Jumps"); } - private boolean left; private boolean right; private boolean up; @@ -201,7 +213,7 @@ public class TerrainGridTest extends SimpleApplication { this.walkDirection.addLocal(camDir.negate()); } - if (usePhysics) { + if (usePhysics && physicsAdded) { this.player3.setWalkDirection(this.walkDirection); this.cam.setLocation(this.player3.getPhysicsLocation()); }