diff --git a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java index 584df0bba..04e28b76c 100644 --- a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java +++ b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java @@ -1,9 +1,38 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.jme3.terrain.geomipmap; +import com.jme3.scene.control.UpdateControl; +import com.jme3.app.Application; import com.jme3.bullet.PhysicsSpace; import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape; import com.jme3.bullet.control.RigidBodyControl; @@ -19,10 +48,11 @@ import com.jme3.material.Material; import com.jme3.math.FastMath; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; import com.jme3.terrain.geomipmap.lodcalc.LodCalculatorFactory; import com.jme3.terrain.geomipmap.lodcalc.LodDistanceCalculatorFactory; import com.jme3.terrain.heightmap.HeightMapGrid; -import com.jme3.terrain.heightmap.RawHeightMap; +import java.util.concurrent.Callable; /** * @author Anthyon @@ -34,7 +64,7 @@ public class TerrainGrid extends TerrainQuad { private int quarterSize; private int quadSize; private HeightMapGrid heightMapGrid; - private Vector3f[] quadOrigins; + //private Vector3f[] quadOrigins; private Vector3f[] quadIndex; private Map listeners = new HashMap(); private Material material; @@ -45,77 +75,107 @@ public class TerrainGrid extends TerrainQuad { private class UpdateQuadCache implements Runnable { private final Vector3f location; - private final boolean centerOnly; public UpdateQuadCache(Vector3f location) { this.location = location; - this.centerOnly = false; - } - - public UpdateQuadCache(Vector3f location, boolean centerOnly) { - this.location = location; - this.centerOnly = centerOnly; } public void run() { - for (int i = centerOnly ? 1 : 0; i < (centerOnly ? 3 : 4); i++) { - for (int j = centerOnly ? 1 : 0; j < (centerOnly ? 3 : 4); j++) { - Vector3f temp = location.add(quadIndex[i * 4 + j]); - if (cache.get(temp) == null) { + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + int quadIdx = i * 4 + j; + final Vector3f temp = location.add(quadIndex[quadIdx]); + TerrainQuad q = cache.get(temp); + if (q == null) { + // create the new Quad since it doesn't exist HeightMap heightMapAt = heightMapGrid.getHeightMapAt(temp); - TerrainQuad q = new TerrainQuad(getName() + "Quad" + temp, patchSize, quadSize, heightMapAt == null ? null : heightMapAt.getHeightMap(), lodCalculatorFactory); + q = new TerrainQuad(getName() + "Quad" + temp, patchSize, quadSize, totalSize, heightMapAt == null ? null : heightMapAt.getHeightMap(), lodCalculatorFactory); Material mat = material.clone(); for (TerrainGridListener l : listeners.values()) { mat = l.tileLoaded(mat, temp); } q.setMaterial(mat); - cache.put(temp, q); + 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; + } + }); } } } } } + + private boolean isCenter(int quadIndex) { + return quadIndex == 9 || quadIndex == 5 || quadIndex == 10 || quadIndex == 6; + } + + private int getQuadrant(int quadIndex) { + if (quadIndex == 9) + return 1; + else if (quadIndex == 5) + return 2; + else if (quadIndex == 10) + return 3; + else if (quadIndex == 6) + return 4; + return 0; // error + } - public TerrainGrid(String name, int patchSize, int size, Vector3f stepScale, HeightMapGrid heightMapGrid, int totalSize, + public TerrainGrid(String name, int patchSize, int maxVisibleSize, Vector3f scale, HeightMapGrid heightMapGrid, Vector2f offset, float offsetAmount, LodCalculatorFactory lodCalculatorFactory) { this.name = name; this.patchSize = patchSize; - this.size = size; - this.quarterSize = size >> 2; - this.quadSize = (size + 1) >> 1; - this.stepScale = stepScale; + this.size = maxVisibleSize; + this.quarterSize = maxVisibleSize >> 2; + this.quadSize = (maxVisibleSize + 1) >> 1; + this.stepScale = scale; this.heightMapGrid = heightMapGrid; heightMapGrid.setSize(this.quadSize); - this.totalSize = totalSize; + this.totalSize = maxVisibleSize; this.offset = offset; this.offsetAmount = offsetAmount; this.lodCalculatorFactory = lodCalculatorFactory; if (lodCalculatorFactory == null) { lodCalculatorFactory = new LodDistanceCalculatorFactory(); } - this.quadOrigins = new Vector3f[]{new Vector3f(-this.quarterSize, 0, -this.quarterSize).mult(this.stepScale), - new Vector3f(-this.quarterSize, 0, this.quarterSize).mult(this.stepScale), - new Vector3f(this.quarterSize, 0, -this.quarterSize).mult(this.stepScale), - new Vector3f(this.quarterSize, 0, this.quarterSize).mult(this.stepScale)}; +// this.quadOrigins = new Vector3f[]{ +// new Vector3f(-this.quarterSize, 0, -this.quarterSize).mult(this.stepScale), +// new Vector3f(-this.quarterSize, 0, this.quarterSize).mult(this.stepScale), +// new Vector3f(this.quarterSize, 0, -this.quarterSize).mult(this.stepScale), +// new Vector3f(this.quarterSize, 0, this.quarterSize).mult(this.stepScale)}; this.quadIndex = new Vector3f[]{ - new Vector3f(-1, 0, -1), new Vector3f(-1, 0, 0), new Vector3f(-1, 0, 1), new Vector3f(-1, 0, 2), - new Vector3f(0, 0, -1), new Vector3f(0, 0, 0), new Vector3f(0, 0, 1), new Vector3f(0, 0, 2), - new Vector3f(1, 0, -1), new Vector3f(1, 0, 0), new Vector3f(1, 0, 1), new Vector3f(1, 0, 2), - new Vector3f(2, 0, -1), new Vector3f(2, 0, 0), new Vector3f(2, 0, 1), new Vector3f(2, 0, 2)}; + new Vector3f(-1, 0, 2), new Vector3f(0, 0, 2), new Vector3f(1, 0, 2), new Vector3f(2, 0, 2), + 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()); } - public TerrainGrid(String name, int patchSize, int size, Vector3f scale, HeightMapGrid heightMapGrid, + public TerrainGrid(String name, int patchSize, int maxVisibleSize, Vector3f scale, HeightMapGrid heightMapGrid, LodCalculatorFactory lodCalculatorFactory) { - this(name, patchSize, size, scale, heightMapGrid, size, new Vector2f(), 0, lodCalculatorFactory); + this(name, patchSize, maxVisibleSize, scale, heightMapGrid, new Vector2f(), 0, lodCalculatorFactory); } - public TerrainGrid(String name, int patchSize, int totalSize, HeightMapGrid heightMapGrid, LodCalculatorFactory lodCalculatorFactory) { - this(name, patchSize, totalSize, Vector3f.UNIT_XYZ, heightMapGrid, lodCalculatorFactory); + public TerrainGrid(String name, int patchSize, int maxVisibleSize, HeightMapGrid heightMapGrid, LodCalculatorFactory lodCalculatorFactory) { + this(name, patchSize, maxVisibleSize, Vector3f.UNIT_XYZ, heightMapGrid, lodCalculatorFactory); } - public TerrainGrid(String name, int patchSize, int totalSize, HeightMapGrid heightMapGrid) { - this(name, patchSize, totalSize, heightMapGrid, null); + public TerrainGrid(String name, int patchSize, int maxVisibleSize, HeightMapGrid heightMapGrid) { + this(name, patchSize, maxVisibleSize, heightMapGrid, null); } public TerrainGrid() { @@ -164,13 +224,18 @@ public class TerrainGrid extends TerrainQuad { } } + /** + * Runs on the rendering thread + */ protected void attachQuadAt(TerrainQuad q, int quadrant, Vector3f cam) { + this.removeQuad(quadrant); //q.setMaterial(this.material); //q.setLocalTranslation(quadOrigins[quadrant - 1]); q.setQuadrant((short) quadrant); this.attachChild(q); - q.setLocalTranslation(cam.mult(this.quadSize).add(quadOrigins[quadrant-1])); + 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); @@ -181,6 +246,8 @@ public class TerrainGrid extends TerrainQuad { //quadControls[quadrant - 1].setPhysicsLocation(cam.add(this.quadOrigins[quadrant - 1])); } else { } + + updateModelBound(); } private void updateChildrens(Vector3f cam) { @@ -203,11 +270,14 @@ public class TerrainGrid extends TerrainQuad { } } - TerrainQuad q1 = cache.get(cam.add(quadIndex[5])); - TerrainQuad q2 = cache.get(cam.add(quadIndex[6])); - TerrainQuad q3 = cache.get(cam.add(quadIndex[9])); - TerrainQuad q4 = cache.get(cam.add(quadIndex[10])); + //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? + // --------------------------------------------------- int dx = 0; int dy = 0; if (currentCell != null) { @@ -236,16 +306,21 @@ public class TerrainGrid extends TerrainQuad { cache.get(cam.add(quadIndex[i * 4 + j])); } } - - if (q1 == null || q2 == null || q3 == null || q4 == null) { + // --------------------------------------------------- + // --------------------------------------------------- + + if (executor == null) + executor = createExecutorService(); + + executor.submit(new UpdateQuadCache(cam)); + +/* if (q1 == null || q2 == null || q3 == null || q4 == null) { try { - if (executor == null) - executor = createExecutorService(); - executor.submit(new UpdateQuadCache(cam, true)).get(); - q1 = cache.get(cam.add(quadIndex[5])); - q2 = cache.get(cam.add(quadIndex[6])); - q3 = cache.get(cam.add(quadIndex[9])); - q4 = cache.get(cam.add(quadIndex[10])); + 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; @@ -263,15 +338,15 @@ public class TerrainGrid extends TerrainQuad { this.removeQuad(3); this.removeQuad(4); - attachQuadAt(q1, 1, cam); - attachQuadAt(q2, 2, cam); - attachQuadAt(q3, 3, cam); - attachQuadAt(q4, 4, cam); - + attachQuadAt(q1, 1, cam); // quadIndex[9] + attachQuadAt(q2, 2, cam); // quadIndex[5] + attachQuadAt(q3, 3, cam); // quadIndex[10] + attachQuadAt(q4, 4, cam); // quadIndex[6] +*/ this.currentCell = cam; - this.updateModelBound(); +// this.updateModelBound(); } - + public void addListener(String id, TerrainGridListener listener) { this.listeners.put(id, listener); } @@ -293,4 +368,15 @@ 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 ) + { + vect.x -= currentGridLocation.x; + vect.y -= currentGridLocation.z; + } + super.adjustHeight( xz, height ); + } } diff --git a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGridListener.java b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGridListener.java index e11577386..64544c97a 100644 --- a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGridListener.java +++ b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGridListener.java @@ -1,6 +1,33 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.jme3.terrain.geomipmap; diff --git a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java index caa1bb56c..26ad92ca4 100644 --- a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java +++ b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java @@ -32,6 +32,8 @@ package com.jme3.terrain.geomipmap; +import com.jme3.scene.control.UpdateControl; +import com.jme3.app.AppTask; import com.jme3.material.Material; import java.io.IOException; import java.util.HashMap; @@ -67,6 +69,9 @@ import com.jme3.util.TangentBinormalGenerator; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Future; /** * A terrain quad is a node in the quad tree of the terrain system. @@ -94,8 +99,7 @@ public class TerrainQuad extends Node implements Terrain { protected int quadrant = 1; // 1=upper left, 2=lower left, 3=upper right, 4=lower right protected LodCalculatorFactory lodCalculatorFactory; - - + protected List lastCameraLocations; // used for LOD calc private boolean lodCalcRunning = false; private int maxLod = -1; @@ -129,14 +133,19 @@ public class TerrainQuad extends Node implements Terrain { public TerrainQuad(String name, int patchSize, int totalSize, float[] heightMap, LodCalculatorFactory lodCalculatorFactory) { this(name, patchSize, totalSize, Vector3f.UNIT_XYZ, heightMap, lodCalculatorFactory); } - - public TerrainQuad(String name, int patchSize, int size, Vector3f scale, float[] heightMap, LodCalculatorFactory lodCalculatorFactory) { - this(name, patchSize, size, scale, heightMap, size, new Vector2f(), 0, lodCalculatorFactory); + + public TerrainQuad(String name, int patchSize, int size, int totalSize, float[] heightMap, LodCalculatorFactory lodCalculatorFactory) { + this(name, patchSize, size, Vector3f.UNIT_XYZ, heightMap, totalSize, new Vector2f(), 0, lodCalculatorFactory); affectedAreaBBox = new BoundingBox(new Vector3f(0,0,0), size, Float.MAX_VALUE, size); fixNormalEdges(affectedAreaBBox); addControl(new NormalRecalcControl(this)); } + public TerrainQuad(String name, int patchSize, int size, Vector3f scale, float[] heightMap, LodCalculatorFactory lodCalculatorFactory) { + this(name, patchSize, size, scale, heightMap, size, new Vector2f(), 0, lodCalculatorFactory); + + } + protected TerrainQuad(String name, int patchSize, int size, Vector3f scale, float[] heightMap, int totalSize, Vector2f offset, float offsetAmount, @@ -1580,7 +1589,7 @@ public class TerrainQuad extends Node implements Terrain { int area = size*size; hm = new float[area]; - if (getChildren() != null) { + if (getChildren() != null && !getChildren().isEmpty()) { float[] ul=null, ur=null, bl=null, br=null; // get the child heightmaps if (getChild(0) instanceof TerrainPatch) { diff --git a/engine/src/terrain/com/jme3/terrain/heightmap/FractalHeightMapGrid.java b/engine/src/terrain/com/jme3/terrain/heightmap/FractalHeightMapGrid.java index ce35c1b4c..9aa72ff03 100644 --- a/engine/src/terrain/com/jme3/terrain/heightmap/FractalHeightMapGrid.java +++ b/engine/src/terrain/com/jme3/terrain/heightmap/FractalHeightMapGrid.java @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.terrain.heightmap; import java.awt.image.BufferedImage; diff --git a/engine/src/terrain/com/jme3/terrain/heightmap/Grayscale16BitHeightMap.java b/engine/src/terrain/com/jme3/terrain/heightmap/Grayscale16BitHeightMap.java index ed93af890..29e307d4e 100644 --- a/engine/src/terrain/com/jme3/terrain/heightmap/Grayscale16BitHeightMap.java +++ b/engine/src/terrain/com/jme3/terrain/heightmap/Grayscale16BitHeightMap.java @@ -1,6 +1,33 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.jme3.terrain.heightmap; diff --git a/engine/src/test/jme3test/terrain/TerrainFractalGridTest.java b/engine/src/test/jme3test/terrain/TerrainFractalGridTest.java index 8bb5e9311..84ed5ad20 100644 --- a/engine/src/test/jme3test/terrain/TerrainFractalGridTest.java +++ b/engine/src/test/jme3test/terrain/TerrainFractalGridTest.java @@ -19,10 +19,7 @@ import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; import com.jme3.terrain.geomipmap.TerrainGrid; import com.jme3.terrain.geomipmap.TerrainLodControl; -import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.heightmap.FractalHeightMapGrid; -import com.jme3.terrain.heightmap.ImageBasedHeightMapGrid; -import com.jme3.terrain.heightmap.Namer; import com.jme3.texture.Texture; import com.jme3.texture.Texture.WrapMode; import org.novyon.noise.ShaderUtils; diff --git a/engine/src/test/jme3test/terrain/TerrainTestModifyHeight.java b/engine/src/test/jme3test/terrain/TerrainTestModifyHeight.java index 69e9c65bf..77b303c6d 100644 --- a/engine/src/test/jme3test/terrain/TerrainTestModifyHeight.java +++ b/engine/src/test/jme3test/terrain/TerrainTestModifyHeight.java @@ -47,12 +47,22 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.Ray; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; +import com.jme3.terrain.geomipmap.TerrainGrid; import com.jme3.terrain.geomipmap.TerrainLodControl; import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.heightmap.FractalHeightMapGrid; import com.jme3.texture.Texture; import com.jme3.texture.Texture.WrapMode; import java.util.ArrayList; import java.util.List; +import org.novyon.noise.ShaderUtils; +import org.novyon.noise.basis.FilteredBasis; +import org.novyon.noise.filter.IterativeFilter; +import org.novyon.noise.filter.OptimizedErode; +import org.novyon.noise.filter.PerturbFilter; +import org.novyon.noise.filter.SmoothFilter; +import org.novyon.noise.fractal.FractalSum; +import org.novyon.noise.modulator.NoiseModulator; /** * @@ -82,15 +92,15 @@ public class TerrainTestModifyHeight extends SimpleApplication { @Override public void simpleUpdate(float tpf){ - updateHintText(); + Vector3f intersection = getWorldIntersection(); + updateHintText(intersection); if (raiseTerrain){ - Vector3f intersection = getWorldIntersection(); + if (intersection != null) { adjustHeight(intersection, 64, tpf * 60); } }else if (lowerTerrain){ - Vector3f intersection = getWorldIntersection(); if (intersection != null) { adjustHeight(intersection, 64, -tpf * 60); } @@ -103,47 +113,13 @@ public class TerrainTestModifyHeight extends SimpleApplication { initCrossHairs(); setupKeys(); - // First, we load up our textures and the heightmap texture for the terrain - - // TERRAIN TEXTURE material - matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); - matTerrain.setBoolean("useTriPlanarMapping", false); - matTerrain.setBoolean("WardIso", true); - - // ALPHA map (for splat textures) - matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); - - // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); - grass.setWrap(WrapMode.Repeat); - matTerrain.setTexture("DiffuseMap", grass); - matTerrain.setFloat("DiffuseMap_0_scale", grassScale); - - // DIRT texture - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); - dirt.setWrap(WrapMode.Repeat); - matTerrain.setTexture("DiffuseMap_1", dirt); - matTerrain.setFloat("DiffuseMap_1_scale", dirtScale); - - // ROCK texture - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); - rock.setWrap(WrapMode.Repeat); - matTerrain.setTexture("DiffuseMap_2", rock); - matTerrain.setFloat("DiffuseMap_2_scale", rockScale); - // WIREFRAME material matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); matWire.getAdditionalRenderState().setWireframe(true); matWire.setColor("Color", ColorRGBA.Green); - - // CREATE THE TERRAIN - terrain = new TerrainQuad("terrain", 65, 513, null); - TerrainLodControl control = new TerrainLodControl(terrain, getCamera()); - terrain.addControl(control); - terrain.setMaterial(matTerrain); - terrain.setLocalTranslation(0, -100, 0); - terrain.setLocalScale(2f, 1f, 2f); - rootNode.attachChild(terrain); + + //createTerrain(); + createTerrainGrid(); DirectionalLight light = new DirectionalLight(); light.setDirection((new Vector3f(-0.5f, -1f, -0.5f)).normalize()); @@ -153,7 +129,7 @@ public class TerrainTestModifyHeight extends SimpleApplication { ambLight.setColor(new ColorRGBA(1f, 1f, 0.8f, 0.2f)); rootNode.addLight(ambLight); - cam.setLocation(new Vector3f(0, 10, -10)); + cam.setLocation(new Vector3f(0, 256, 0)); cam.lookAtDirection(new Vector3f(0, -1.5f, -1).normalizeLocal(), Vector3f.UNIT_Y); } @@ -164,11 +140,14 @@ public class TerrainTestModifyHeight extends SimpleApplication { guiNode.attachChild(hintText); } - public void updateHintText() { + public void updateHintText(Vector3f target) { int x = (int) getCamera().getLocation().x; int y = (int) getCamera().getLocation().y; int z = (int) getCamera().getLocation().z; - hintText.setText("Press left mouse button to raise terrain, press right mouse button to lower terrain. " + x + "," + y + "," + z); + String targetText = ""; + if (target!= null) + targetText = " intersect: "+target.toString(); + hintText.setText("Press left mouse button to raise terrain, press right mouse button to lower terrain. " + x + "," + y + "," + z+targetText); } protected void initCrossHairs() { @@ -272,4 +251,132 @@ public class TerrainTestModifyHeight extends SimpleApplication { } return null; } + + private void createTerrain() { + // First, we load up our textures and the heightmap texture for the terrain + + // TERRAIN TEXTURE material + matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matTerrain.setBoolean("useTriPlanarMapping", false); + matTerrain.setBoolean("WardIso", true); + + // ALPHA map (for splat textures) + matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); + + // GRASS texture + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap", grass); + matTerrain.setFloat("DiffuseMap_0_scale", grassScale); + + // DIRT texture + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap_1", dirt); + matTerrain.setFloat("DiffuseMap_1_scale", dirtScale); + + // ROCK texture + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap_2", rock); + matTerrain.setFloat("DiffuseMap_2_scale", rockScale); + + // CREATE THE TERRAIN + terrain = new TerrainQuad("terrain", 65, 513, null); + TerrainLodControl control = new TerrainLodControl(terrain, getCamera()); + terrain.addControl(control); + terrain.setMaterial(matTerrain); + terrain.setLocalTranslation(0, -100, 0); + terrain.setLocalScale(2f, 1f, 2f); + rootNode.attachChild(terrain); + } + + private void createTerrainGrid() { + + // TERRAIN TEXTURE material + matTerrain = new Material(this.assetManager, "Common/MatDefs/Terrain/HeightBasedTerrain.j3md"); + + // Parameters to material: + // regionXColorMap: X = 1..4 the texture that should be appliad to state X + // regionX: a Vector3f containing the following information: + // regionX.x: the start height of the region + // regionX.y: the end height of the region + // regionX.z: the texture scale for the region + // it might not be the most elegant way for storing these 3 values, but it packs the data nicely :) + // slopeColorMap: the texture to be used for cliffs, and steep mountain sites + // slopeTileFactor: the texture scale for slopes + // terrainSize: the total size of the terrain (used for scaling the texture) + // GRASS texture + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matTerrain.setTexture("region1ColorMap", grass); + matTerrain.setVector3("region1", new Vector3f(88, 200, this.grassScale)); + + // DIRT texture + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matTerrain.setTexture("region2ColorMap", dirt); + matTerrain.setVector3("region2", new Vector3f(0, 90, this.dirtScale)); + + // ROCK texture + Texture rock = assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); + rock.setWrap(WrapMode.Repeat); + matTerrain.setTexture("region3ColorMap", rock); + matTerrain.setVector3("region3", new Vector3f(198, 260, this.rockScale)); + + matTerrain.setTexture("region4ColorMap", rock); + matTerrain.setVector3("region4", new Vector3f(198, 260, this.rockScale)); + + matTerrain.setTexture("slopeColorMap", rock); + matTerrain.setFloat("slopeTileFactor", 32); + + matTerrain.setFloat("terrainSize", 513); + + FractalSum base = new FractalSum(); + base.setRoughness(0.7f); + base.setFrequency(1.0f); + base.setAmplitude(1.0f); + base.setLacunarity(2.12f); + base.setOctaves(8); + base.setScale(0.02125f); + base.addModulator(new NoiseModulator() { + @Override + public float value(float... in) { + return ShaderUtils.clamp(in[0] * 0.5f + 0.5f, 0, 1); + } + }); + + FilteredBasis ground = new FilteredBasis(base); + + PerturbFilter perturb = new PerturbFilter(); + perturb.setMagnitude(0.119f); + + OptimizedErode therm = new OptimizedErode(); + therm.setRadius(5); + therm.setTalus(0.011f); + + SmoothFilter smooth = new SmoothFilter(); + smooth.setRadius(1); + smooth.setEffect(0.7f); + + IterativeFilter iterate = new IterativeFilter(); + iterate.addPreFilter(perturb); + iterate.addPostFilter(smooth); + iterate.setFilter(therm); + iterate.setIterations(1); + + ground.addPreFilter(iterate); + + this.terrain = new TerrainGrid("terrain", 65, 257, new FractalHeightMapGrid(ground, null, 256f)); + + + terrain.setMaterial(matWire); + terrain.setLocalTranslation(0, 0, 0); + terrain.setLocalScale(2f, 1f, 2f); + ((TerrainGrid)terrain).initialize(Vector3f.ZERO); + rootNode.attachChild(this.terrain); + + TerrainLodControl control = new TerrainLodControl(this.terrain, getCamera()); + this.terrain.addControl(control); + } }