Browse Source

TerrainGrid added to terrain package, test included

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7483 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
ant..om 14 years ago
parent
commit
34a47debb9
47 changed files with 572 additions and 7 deletions
  1. 216 0
      engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java
  2. 17 0
      engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGridListener.java
  3. 7 7
      engine/src/terrain/com/jme3/terrain/geomipmap/UpdatedTerrainPatch.java
  4. 68 0
      engine/src/terrain/com/jme3/terrain/heightmap/Grayscale16BitHeightMap.java
  5. 19 0
      engine/src/terrain/com/jme3/terrain/heightmap/HeightMapGrid.java
  6. 61 0
      engine/src/terrain/com/jme3/terrain/heightmap/ImageBasedHeightMapGrid.java
  7. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_-512.png
  8. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_0.png
  9. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_1024.png
  10. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_1536.png
  11. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_2048.png
  12. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_2560.png
  13. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_3072.png
  14. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_512.png
  15. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_-512.png
  16. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_0.png
  17. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_1024.png
  18. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_1536.png
  19. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_2048.png
  20. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_2560.png
  21. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_3072.png
  22. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_512.png
  23. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_-512.png
  24. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_0.png
  25. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_1024.png
  26. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_1536.png
  27. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_2048.png
  28. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_2560.png
  29. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_3072.png
  30. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_512.png
  31. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_-512.png
  32. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_0.png
  33. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_1024.png
  34. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_1536.png
  35. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_2048.png
  36. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_2560.png
  37. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_3072.png
  38. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_512.png
  39. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_-512.png
  40. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_0.png
  41. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_1024.png
  42. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_1536.png
  43. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_2048.png
  44. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_2560.png
  45. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_3072.png
  46. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_512.png
  47. 184 0
      engine/src/test/jme3test/terrain/TerrainGridTest.java

+ 216 - 0
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java

@@ -0,0 +1,216 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.terrain.geomipmap;
+
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.terrain.heightmap.HeightMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import com.jme3.material.Material;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.terrain.geomipmap.lodcalc.LodCalculatorFactory;
+import com.jme3.terrain.geomipmap.lodcalc.LodDistanceCalculatorFactory;
+import com.jme3.terrain.heightmap.HeightMapGrid;
+
+/**
+ * @author Anthyon
+ */
+public class TerrainGrid extends TerrainQuad {
+
+    private static Logger log = Logger.getLogger(TerrainGrid.class.getCanonicalName());
+    private Vector3f currentCell;
+    private int quarterSize;
+    private int quadSize;
+    private HeightMapGrid heightMapGrid;
+    private Vector3f[] quadOrigins;
+    private Vector3f[] quadIndex;
+    private Map<String, TerrainGridListener> listeners = new HashMap<String, TerrainGridListener>();
+    private Material material;
+
+    public TerrainGrid(String name, int patchSize, int size, Vector3f stepScale, HeightMapGrid heightMapGrid, int totalSize,
+            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.heightMapGrid = heightMapGrid;
+        heightMapGrid.setSize(this.quadSize);
+        this.totalSize = totalSize;
+        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.quadIndex = new Vector3f[]{new Vector3f(0, 0, 0), new Vector3f(0, 0, 1), new Vector3f(1, 0, 0), new Vector3f(1, 0, 1)};
+
+        updateChildrens(Vector3f.ZERO);
+    }
+
+    public TerrainGrid(String name, int patchSize, int size, Vector3f scale, HeightMapGrid heightMapGrid,
+            LodCalculatorFactory lodCalculatorFactory) {
+        this(name, patchSize, size, scale, heightMapGrid, size, 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 totalSize, HeightMapGrid heightMapGrid) {
+        this(name, patchSize, totalSize, heightMapGrid, null);
+    }
+
+    public TerrainGrid() {
+    }
+
+    @Override
+    public void update(List<Vector3f> locations) {
+        // for now, only the first camera is handled.
+        // to accept more, there are two ways:
+        // 1: every camera has an associated grid, then the location is not enough to identify which camera location has changed
+        // 2: grids are associated with locations, and no incremental update is done, we load new grids for new locations, and unload those that are not needed anymore
+        Vector3f cam = locations.get(0);
+        Vector3f camCell = this.getCell(cam);
+        if (!camCell.equals(this.currentCell)) {
+            this.updateChildrens(camCell);
+            for (TerrainGridListener l : this.listeners.values()) {
+                l.gridMoved(camCell);
+            }
+        }
+
+        super.update(locations);
+    }
+
+    public Vector3f getCell(Vector3f location) {
+        final Vector3f v = location.clone().divideLocal(this.getLocalScale().mult(this.quadSize)).add(0.5f, 0, 0.5f);
+        return new Vector3f(FastMath.floor(v.x), FastMath.floor(v.y), FastMath.floor(v.z));
+    }
+
+    protected void removeQuad(int idx) {
+        this.detachChild(this.getQuad(idx));
+    }
+
+    protected void moveQuad(int from, int to) {
+        this.removeQuad(to);
+        TerrainQuad fq = this.getQuad(from);
+        fq.setQuadrant((short) to);
+        fq.setLocalTranslation(this.quadOrigins[to - 1]);
+    }
+
+    protected TerrainQuad createQuadAt(Vector3f location, int quadrant) {
+        final HeightMap heightMapAt = this.heightMapGrid.getHeightMapAt(location);
+        TerrainQuad q = new TerrainQuad(this.getName() + "Quad" + location, this.patchSize, this.quadSize, heightMapAt == null ? null : heightMapAt.getHeightMap(), this.lodCalculatorFactory);
+        q.setLocalTranslation(this.quadOrigins[quadrant - 1]);
+        q.setMaterial(this.material);
+        q.setQuadrant((short) quadrant);
+        return q;
+    }
+
+    private void updateChildrens(Vector3f cam) {
+        RigidBodyControl control = getControl(RigidBodyControl.class);
+        PhysicsSpace space = null;
+        if (control != null) {
+            space = control.getPhysicsSpace();
+            space.remove(this);
+            this.removeControl(control);
+        }
+        int dx = (int) cam.x;
+        int dz = (int) cam.z;
+        if (this.currentCell != null) {
+            dx -= (int) (this.currentCell.x);
+            dz -= (int) (this.currentCell.z);
+        }
+        if (this.currentCell == null || FastMath.abs(dx) > 1 || FastMath.abs(dz) > 1 || (dx != 0 && dz != 0)) {
+            if (this.currentCell != null) {
+                // in case of teleport, otherwise the FastMath.abs(delta) should
+                // never be greater than 1
+                this.removeQuad(1);
+                this.removeQuad(2);
+                this.removeQuad(3);
+                this.removeQuad(4);
+            }
+            this.attachChild(this.createQuadAt(cam.add(this.quadIndex[0]).mult(this.quadSize - 1), 1));
+            this.attachChild(this.createQuadAt(cam.add(this.quadIndex[1]).mult(this.quadSize - 1), 2));
+            this.attachChild(this.createQuadAt(cam.add(this.quadIndex[2]).mult(this.quadSize - 1), 3));
+            this.attachChild(this.createQuadAt(cam.add(this.quadIndex[3]).mult(this.quadSize - 1), 4));
+        } else if (dx == 0) {
+            if (dz < 0) {
+                // move north
+                this.moveQuad(1, 2);
+                this.moveQuad(3, 4);
+                this.attachChild(this.createQuadAt(cam.add(this.quadIndex[0]).mult(this.quadSize - 1), 1));
+                this.attachChild(this.createQuadAt(cam.add(this.quadIndex[2]).mult(this.quadSize - 1), 3));
+            } else {
+                // move south
+                this.moveQuad(2, 1);
+                this.moveQuad(4, 3);
+                this.attachChild(this.createQuadAt(cam.add(this.quadIndex[1]).mult(this.quadSize - 1), 2));
+                this.attachChild(this.createQuadAt(cam.add(this.quadIndex[3]).mult(this.quadSize - 1), 4));
+            }
+        } else if (dz == 0) {
+            if (dx < 0) {
+                // move west
+                this.moveQuad(1, 3);
+                this.moveQuad(2, 4);
+                this.attachChild(this.createQuadAt(cam.add(this.quadIndex[0]).mult(this.quadSize - 1), 1));
+                this.attachChild(this.createQuadAt(cam.add(this.quadIndex[1]).mult(this.quadSize - 1), 2));
+            } else {
+                // move east
+                this.moveQuad(3, 1);
+                this.moveQuad(4, 2);
+                this.attachChild(this.createQuadAt(cam.add(this.quadIndex[2]).mult(this.quadSize - 1), 3));
+                this.attachChild(this.createQuadAt(cam.add(this.quadIndex[3]).mult(this.quadSize - 1), 4));
+            }
+        } else {
+            // rare situation to enter into a diagonally placed cell
+            // could not get into this part while testing, as it is handled by moving first
+            // in either horizontally or vertically than the other way
+            // I handle it in the first IF
+        }
+        this.currentCell = cam;
+        this.setLocalTranslation(cam.mult(2 * this.quadSize));
+
+        if (control != null) {
+            control = new RigidBodyControl(new HeightfieldCollisionShape(getHeightMap(), getLocalScale()), 0);
+            this.addControl(control);
+            space.add(this);
+        }
+    }
+
+    public void addListener(String id, TerrainGridListener listener) {
+        this.listeners.put(id, listener);
+    }
+
+    public Vector3f getCurrentCell() {
+        return this.currentCell;
+    }
+
+    public void removeListener(String id) {
+        this.listeners.remove(id);
+    }
+
+    @Override
+    public void setMaterial(Material mat) {
+        this.material = mat;
+        super.setMaterial(mat);
+    }
+
+    public void setQuadSize(int quadSize) {
+        this.quadSize = quadSize;
+    }
+}

+ 17 - 0
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGridListener.java

@@ -0,0 +1,17 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.terrain.geomipmap;
+
+import com.jme3.math.Vector3f;
+
+/**
+ *
+ * @author Anthyon
+ */
+public interface TerrainGridListener {
+
+    public void gridMoved(Vector3f newCenter);
+
+}

+ 7 - 7
engine/src/terrain/com/jme3/terrain/geomipmap/UpdatedTerrainPatch.java

@@ -39,12 +39,12 @@ import com.jme3.scene.VertexBuffer.Type;
 /**
  * Stores a terrain patch's details so the LOD background thread can update
  * the actual terrain patch back on the ogl thread.
- * 
+ *
  * @author Brent Owens
  *
  */
 public class UpdatedTerrainPatch {
-	
+
 	private TerrainPatch updatedPatch;
 	private int newLod;
 	private int previousLod;
@@ -52,12 +52,12 @@ public class UpdatedTerrainPatch {
 	private IntBuffer newIndexBuffer;
 	private boolean reIndexNeeded = false;
 	private boolean fixEdges = false;
-	
+
 	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;
@@ -70,14 +70,14 @@ public class UpdatedTerrainPatch {
 	public String getName() {
 		return updatedPatch.getName();
 	}
-	
+
 	protected boolean lodChanged() {
 		if (reIndexNeeded && previousLod != newLod)
 			return true;
 		else
 			return false;
 	}
-	
+
 	protected TerrainPatch getUpdatedPatch() {
 		return updatedPatch;
 	}
@@ -174,7 +174,7 @@ public class UpdatedTerrainPatch {
 		updatedPatch.setLodTop(topLod);
 		updatedPatch.setLodLeft(leftLod);
 		updatedPatch.setLodBottom(bottomLod);
-		if (reIndexNeeded || fixEdges) {
+		if (newIndexBuffer != null && (reIndexNeeded || fixEdges)) {
 			updatedPatch.setPreviousLod(previousLod);
 			updatedPatch.getMesh().clearBuffer(Type.Index);
 			updatedPatch.getMesh().setBuffer(Type.Index, 3, newIndexBuffer);

+ 68 - 0
engine/src/terrain/com/jme3/terrain/heightmap/Grayscale16BitHeightMap.java

@@ -0,0 +1,68 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.terrain.heightmap;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.imageio.ImageIO;
+
+/**
+ *
+ * @author Anthyon
+ */
+public class Grayscale16BitHeightMap extends AbstractHeightMap {
+
+    private BufferedImage image;
+
+    public Grayscale16BitHeightMap() {
+    }
+
+    public Grayscale16BitHeightMap(BufferedImage image) {
+        this.image = image;
+    }
+
+    public Grayscale16BitHeightMap(String filename) {
+        this(new File(filename));
+    }
+
+    public Grayscale16BitHeightMap(File file) {
+        try {
+            this.image = ImageIO.read(file);
+        } catch (IOException ex) {
+            Logger.getLogger(Grayscale16BitHeightMap.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+
+    @Override
+    public boolean load() {
+        return load(false, false);
+    }
+
+    public boolean load(boolean flipX, boolean flipY) {
+        int imageWidth = image.getWidth();
+        int imageHeight = image.getHeight();
+
+        if (imageWidth != imageHeight) {
+            throw new RuntimeException("imageWidth: " + imageWidth
+                    + " != imageHeight: " + imageHeight);
+        }
+
+        Object out = new short[imageWidth * imageHeight];
+        out = image.getData().getDataElements(0, 0, imageWidth, imageHeight, out);
+        short[] values = (short[]) out;
+        heightData = new float[imageWidth * imageHeight];
+        int i = 0;
+        for (int y = 0; y < imageHeight; y++) {
+            for (int x = 0; x < imageWidth; x++, i++) {
+                heightData[i] = heightScale * (values[i] & 0x0000FFFF) / 65536f;
+            }
+        }
+
+        return true;
+    }
+}

+ 19 - 0
engine/src/terrain/com/jme3/terrain/heightmap/HeightMapGrid.java

@@ -0,0 +1,19 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.terrain.heightmap;
+
+import com.jme3.math.Vector3f;
+
+/**
+ *
+ * @author Anthyon
+ */
+public interface HeightMapGrid {
+
+    public HeightMap getHeightMapAt(Vector3f location);
+
+    public void setSize(int size);
+
+}

+ 61 - 0
engine/src/terrain/com/jme3/terrain/heightmap/ImageBasedHeightMapGrid.java

@@ -0,0 +1,61 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.terrain.heightmap;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.asset.AssetNotFoundException;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.texture.Texture;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.imageio.ImageIO;
+import jme3tools.converters.ImageToAwt;
+
+/**
+ *
+ * @author Anthyon
+ */
+public class ImageBasedHeightMapGrid implements HeightMapGrid {
+
+    private final String textureBase;
+    private final String textureExt;
+    private final AssetManager assetManager;
+    private int size;
+
+    public ImageBasedHeightMapGrid(String textureBase, String textureExt, AssetManager assetManager) {
+        this.textureBase = textureBase;
+        this.textureExt = textureExt;
+        this.assetManager = assetManager;
+    }
+
+    public HeightMap getHeightMapAt(Vector3f location) {
+        // HEIGHTMAP image (for the terrain heightmap)
+        int x = (int) (FastMath.floor(location.x / this.size) * this.size);
+        int z = (int) (FastMath.floor(location.z / this.size) * this.size);
+        AbstractHeightMap heightmap = null;
+        try {
+            final InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(textureBase + "_" + x + "_" + z + "." + textureExt);
+            BufferedImage im = null;
+            if (stream != null) {
+                im = ImageIO.read(stream);
+            } else {
+                im = new BufferedImage(size, size, BufferedImage.TYPE_USHORT_GRAY);
+            }
+            // CREATE HEIGHTMAP
+            heightmap = new Grayscale16BitHeightMap(im);
+            heightmap.setHeightScale(256);
+            heightmap.load();
+        } catch (IOException e) {
+        } catch (AssetNotFoundException e) {
+        }
+        return heightmap;
+    }
+
+    public void setSize(int size) {
+        this.size = size - 1;
+    }
+}

BIN
engine/src/test-data/Textures/Terrain/grid/mountains_0_-512.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_0_0.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_0_1024.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_0_1536.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_0_2048.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_0_2560.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_0_3072.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_0_512.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1024_-512.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1024_0.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1024_1024.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1024_1536.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1024_2048.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1024_2560.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1024_3072.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1024_512.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1536_-512.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1536_0.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1536_1024.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1536_1536.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1536_2048.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1536_2560.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1536_3072.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_1536_512.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_2048_-512.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_2048_0.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_2048_1024.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_2048_1536.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_2048_2048.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_2048_2560.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_2048_3072.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_2048_512.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_512_-512.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_512_0.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_512_1024.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_512_1536.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_512_2048.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_512_2560.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_512_3072.png


BIN
engine/src/test-data/Textures/Terrain/grid/mountains_512_512.png


+ 184 - 0
engine/src/test/jme3test/terrain/TerrainGridTest.java

@@ -0,0 +1,184 @@
+package jme3test.terrain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.app.state.ScreenshotAppState;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
+import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape;
+import com.jme3.bullet.control.CharacterControl;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.input.KeyInput;
+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.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.ImageBasedHeightMapGrid;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+
+public class TerrainGridTest extends SimpleApplication {
+
+    private Material mat_terrain;
+    private TerrainQuad terrain;
+    private float grassScale = 64;
+    private float dirtScale = 16;
+    private float rockScale = 128;
+
+    public static void main(final String[] args) {
+        TerrainGridTest app = new TerrainGridTest();
+        app.start();
+    }
+    private CharacterControl player3;
+
+    @Override
+    public void simpleInitApp() {
+        this.flyCam.setMoveSpeed(100f);
+        ScreenshotAppState state = new ScreenshotAppState();
+        this.stateManager.attach(state);
+
+        // TERRAIN TEXTURE material
+        mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");
+        mat_terrain.setBoolean("useTriPlanarMapping", false);
+
+        // ALPHA map (for splat textures)
+        mat_terrain.setTexture("Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));
+
+        // GRASS texture
+        Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
+        grass.setWrap(WrapMode.Repeat);
+        mat_terrain.setTexture("Tex1", grass);
+        mat_terrain.setFloat("Tex1Scale", grassScale);
+
+        // DIRT texture
+        Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
+        dirt.setWrap(WrapMode.Repeat);
+        mat_terrain.setTexture("Tex2", dirt);
+        mat_terrain.setFloat("Tex2Scale", dirtScale);
+
+        // ROCK texture
+        Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
+        rock.setWrap(WrapMode.Repeat);
+        mat_terrain.setTexture("Tex3", rock);
+        mat_terrain.setFloat("Tex3Scale", rockScale);
+
+        this.terrain = new TerrainGrid("terrain", 65, 1025, new ImageBasedHeightMapGrid("Textures/Terrain/grid/mountains", "png",
+                this.assetManager));
+
+        this.terrain.setMaterial(this.mat_terrain);
+        this.terrain.setLocalTranslation(0, 0, 0);
+        this.terrain.setLocalScale(2f, 1f, 2f);
+        this.rootNode.attachChild(this.terrain);
+
+        List<Camera> cameras = new ArrayList<Camera>();
+        cameras.add(this.getCamera());
+        TerrainLodControl control = new TerrainLodControl(this.terrain, cameras);
+        this.terrain.addControl(control);
+
+        BulletAppState bulletAppState = new BulletAppState();
+        stateManager.attach(bulletAppState);
+
+        RigidBodyControl body = new RigidBodyControl(new HeightfieldCollisionShape(terrain.getHeightMap(), terrain.getLocalScale()), 0);
+        terrain.addControl(body);
+        bulletAppState.getPhysicsSpace().add(terrain);
+
+        this.getCamera().setLocation(new Vector3f(0, 256, 0));
+
+        this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
+
+        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);
+
+        this.initKeys();
+    }
+
+    private void initKeys() {
+        // You can map one or several inputs to one named action
+        this.inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A));
+        this.inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D));
+        this.inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_W));
+        this.inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_S));
+        this.inputManager.addMapping("Jumps", new KeyTrigger(KeyInput.KEY_SPACE));
+        this.inputManager.addMapping("Gravity", new KeyTrigger(KeyInput.KEY_G));
+        this.inputManager.addListener(this.actionListener, "Lefts");
+        this.inputManager.addListener(this.actionListener, "Rights");
+        this.inputManager.addListener(this.actionListener, "Ups");
+        this.inputManager.addListener(this.actionListener, "Downs");
+        this.inputManager.addListener(this.actionListener, "Jumps");
+        this.inputManager.addListener(this.actionListener, "Gravity");
+    }
+    private boolean left;
+    private boolean right;
+    private boolean up;
+    private boolean down;
+    private final ActionListener actionListener = new ActionListener() {
+
+        @Override
+        public void onAction(final String name, final boolean keyPressed, final float tpf) {
+            if (name.equals("Lefts")) {
+                if (keyPressed) {
+                    TerrainGridTest.this.left = true;
+                } else {
+                    TerrainGridTest.this.left = false;
+                }
+            } else if (name.equals("Rights")) {
+                if (keyPressed) {
+                    TerrainGridTest.this.right = true;
+                } else {
+                    TerrainGridTest.this.right = false;
+                }
+            } else if (name.equals("Ups")) {
+                if (keyPressed) {
+                    TerrainGridTest.this.up = true;
+                } else {
+                    TerrainGridTest.this.up = false;
+                }
+            } else if (name.equals("Downs")) {
+                if (keyPressed) {
+                    TerrainGridTest.this.down = true;
+                } else {
+                    TerrainGridTest.this.down = false;
+                }
+            } else if (name.equals("Jumps")) {
+                TerrainGridTest.this.player3.jump();
+            }
+        }
+    };
+    private final Vector3f walkDirection = new Vector3f();
+
+    @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());
+        }
+
+        this.player3.setWalkDirection(this.walkDirection);
+        this.cam.setLocation(this.player3.getPhysicsLocation());
+    }
+}