New TerrainManager class implemented
This commit is contained in:
parent
7966d86a2d
commit
33258c7820
5 changed files with 211 additions and 23 deletions
|
|
@ -47,7 +47,6 @@ public class CookeryClient extends SimpleApplication {
|
|||
// cam.lookAt(new Vector3f(0f,0f,0f), Vector3f.UNIT_Z);
|
||||
|
||||
flyCam.setEnabled(false);
|
||||
// stateManager.detach(stateManager.getState(FlyCamAppState.class));
|
||||
ChaseCamera chaseCam = new ChaseCamera(cam, player.getGfxNode(), inputManager);
|
||||
chaseCam.setDefaultDistance(10);
|
||||
chaseCam.setRotationSpeed(2);
|
||||
|
|
|
|||
15
core/src/se/cookery/gfx/terrain/TerrainHeightMap.java
Normal file
15
core/src/se/cookery/gfx/terrain/TerrainHeightMap.java
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package se.cookery.gfx.terrain;
|
||||
|
||||
public interface TerrainHeightMap {
|
||||
|
||||
|
||||
/**
|
||||
* @return the number of squares on the width that make a single TerrainMesh instance.
|
||||
*/
|
||||
int getSquareCountWidth();
|
||||
|
||||
/**
|
||||
* @return the number of squares on the height that make a single TerrainMesh instance.
|
||||
*/
|
||||
int getSquareCountHeight();
|
||||
}
|
||||
81
core/src/se/cookery/gfx/terrain/TerrainManager.java
Normal file
81
core/src/se/cookery/gfx/terrain/TerrainManager.java
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package se.cookery.gfx.terrain;
|
||||
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.Node;
|
||||
import se.cookery.gfx.util.MaterialUtil;
|
||||
|
||||
/**
|
||||
* This class represents a infinite terrain object (using multiple buffered TerrainMesh objects)
|
||||
*/
|
||||
public class TerrainManager {
|
||||
protected static final int BUFFER_SIZE = 3;
|
||||
|
||||
private float squareWidth;
|
||||
private float squareHeight;
|
||||
private TerrainHeightMap heightMap;
|
||||
|
||||
private Geometry[][] terrainBuffer;
|
||||
private Vector3f terrainZero; // The top-left coordinate for the center square
|
||||
private Node node = new Node("Terrain Node");
|
||||
|
||||
/**
|
||||
* Create a new instance of TerrainManager
|
||||
*
|
||||
* @param squareWidth is the width of a single square
|
||||
* @param squareHeight is the height of a single square
|
||||
* @param heightMap is the height map for the terrain
|
||||
*/
|
||||
public TerrainManager(float squareWidth, float squareHeight, TerrainHeightMap heightMap, Material material) {
|
||||
this.squareWidth = squareWidth;
|
||||
this.squareHeight = squareHeight;
|
||||
this.heightMap = heightMap;
|
||||
this.terrainBuffer = new Geometry[BUFFER_SIZE][BUFFER_SIZE];
|
||||
|
||||
for (int x=0; x<BUFFER_SIZE; x++) {
|
||||
for (int z=0; z<BUFFER_SIZE; z++) {
|
||||
TerrainMesh terrainMesh = new TerrainMesh(squareWidth, squareHeight, heightMap.getSquareCountWidth(), heightMap.getSquareCountHeight());
|
||||
terrainBuffer[x][z] = new Geometry("TerrainMesh " + x + "x" + z, terrainMesh);
|
||||
terrainBuffer[x][z].setMaterial(material);
|
||||
node.attachChild(terrainBuffer[x][z]);
|
||||
}
|
||||
}
|
||||
|
||||
setTerrainCenter(Vector3f.ZERO);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method will move the terrain center by reorganizing the buffer
|
||||
* by deallocating out of scope terrain and allocating new terrain that is in scope.
|
||||
*/
|
||||
protected void setTerrainCenter(Vector3f newCenter) {
|
||||
Vector3f newTerrainZero = new Vector3f(
|
||||
(int) newCenter.getX()/(squareWidth*heightMap.getSquareCountWidth()),
|
||||
0,
|
||||
(int) newCenter.getZ()/(squareHeight*heightMap.getSquareCountHeight()));
|
||||
|
||||
if (newTerrainZero.equals(terrainZero))
|
||||
return;
|
||||
|
||||
terrainZero = newTerrainZero;
|
||||
int centerIndex = BUFFER_SIZE/2;
|
||||
|
||||
for (int x=0; x<BUFFER_SIZE; x++) {
|
||||
for (int z=0; z<BUFFER_SIZE; z++) {
|
||||
TerrainMesh terrainMesh = (TerrainMesh) terrainBuffer[x][z].getMesh();
|
||||
terrainBuffer[x][z].setLocalTranslation(
|
||||
terrainZero.getX() + (x - centerIndex) * terrainMesh.getWidth(),
|
||||
0 ,
|
||||
terrainZero.getZ() + (z - centerIndex) * terrainMesh.getHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Node getNode() {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,24 +9,25 @@ import com.jme3.scene.VertexBuffer;
|
|||
*/
|
||||
public class TerrainMesh extends Mesh {
|
||||
|
||||
private float width;
|
||||
private float height;
|
||||
private int widthCount;
|
||||
private int heightCount;
|
||||
private float squareWidth;
|
||||
private float squareHeight;
|
||||
private int squareCountWidth;
|
||||
private int squareCountHeight;
|
||||
|
||||
|
||||
/**
|
||||
* Created a terrain Mesh with the given sizes.
|
||||
*
|
||||
* @param width is the width of a single square
|
||||
* @param height is the height of a single square
|
||||
* @param widthCount the number of squares that make up the whole terrain
|
||||
* @param heightCount the number of squares that make up the whole terrain
|
||||
* @param squareWidth is the width of a single square
|
||||
* @param squareHeight is the height of a single square
|
||||
* @param squareCountWidth the number of squares that make up the whole terrain
|
||||
* @param squareCountHeight the number of squares that make up the whole terrain
|
||||
*/
|
||||
public TerrainMesh(float width, float height, int widthCount, int heightCount){
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.widthCount = widthCount;
|
||||
this.heightCount = heightCount;
|
||||
public TerrainMesh(float squareWidth, float squareHeight, int squareCountWidth, int squareCountHeight){
|
||||
this.squareWidth = squareWidth;
|
||||
this.squareHeight = squareHeight;
|
||||
this.squareCountWidth = squareCountWidth;
|
||||
this.squareCountHeight = squareCountHeight;
|
||||
|
||||
updateGeometry();
|
||||
}
|
||||
|
|
@ -45,16 +46,16 @@ public class TerrainMesh extends Mesh {
|
|||
* Generates a vertex buffer containing vertex xyz coordinates.
|
||||
*/
|
||||
protected float[] generateVertexBuffer() {
|
||||
int vertexCountWidth = widthCount + 1;
|
||||
int vertexCountHeight = heightCount + 1;
|
||||
int vertexCountWidth = squareCountWidth + 1;
|
||||
int vertexCountHeight = squareCountHeight + 1;
|
||||
float[] vertexBuf = new float[3 * vertexCountWidth * vertexCountHeight];
|
||||
|
||||
for (int row=0; row<vertexCountHeight; row++) {
|
||||
for (int col=0; col<vertexCountWidth; col++) {
|
||||
int vertexIndex = (3 * vertexCountWidth * row) + (3 * col);
|
||||
vertexBuf[vertexIndex + 0] = width * col; // X
|
||||
vertexBuf[vertexIndex + 0] = squareWidth * col; // X
|
||||
vertexBuf[vertexIndex + 1] = 0; // Y
|
||||
vertexBuf[vertexIndex + 2] = height * row; // Z
|
||||
vertexBuf[vertexIndex + 2] = squareHeight * row; // Z
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,17 +66,17 @@ public class TerrainMesh extends Mesh {
|
|||
* Generates a index buffer containing planes for the mesh.
|
||||
*/
|
||||
protected short[] generateIndexBuffer() {
|
||||
int vertexCountWidth = widthCount + 1;
|
||||
int triangleCount = widthCount * heightCount * 2;
|
||||
int vertexCountWidth = squareCountWidth + 1;
|
||||
int triangleCount = squareCountWidth * squareCountHeight * 2;
|
||||
short[] indexBuf = new short[3 * triangleCount];
|
||||
|
||||
for (int row=0; row<heightCount; row++) {
|
||||
for (int col = 0; col<widthCount; col++) {
|
||||
for (int row = 0; row< squareCountHeight; row++) {
|
||||
for (int col = 0; col< squareCountWidth; col++) {
|
||||
int vertexTopLeft = (row * vertexCountWidth) + col;
|
||||
int vertexTopRight = vertexTopLeft + 1;
|
||||
int vertexBottomLeft = ((row + 1) * vertexCountWidth) + col;
|
||||
int vertexBottomRight = vertexBottomLeft + 1;
|
||||
int indexOffset = 3 * 2 * ((row * widthCount) + col);
|
||||
int indexOffset = 3 * 2 * ((row * squareCountWidth) + col);
|
||||
|
||||
indexBuf[indexOffset + 0] = (short) vertexTopLeft;
|
||||
indexBuf[indexOffset + 1] = (short) vertexBottomLeft;
|
||||
|
|
@ -114,4 +115,21 @@ public class TerrainMesh extends Mesh {
|
|||
0, 0, 1
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public float getWidth() {
|
||||
return squareWidth * squareCountWidth;
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return squareHeight * squareCountHeight;
|
||||
}
|
||||
|
||||
public float getSquareWidth() {
|
||||
return squareWidth;
|
||||
}
|
||||
|
||||
public float getSquareHeight() {
|
||||
return squareHeight;
|
||||
}
|
||||
}
|
||||
75
core/test/se/cookery/gfx/terrain/TerrainManagerTest.java
Normal file
75
core/test/se/cookery/gfx/terrain/TerrainManagerTest.java
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
package se.cookery.gfx.terrain;
|
||||
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.Spatial;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class TerrainManagerTest {
|
||||
|
||||
private static class TerrainHeightMapImpl implements TerrainHeightMap {
|
||||
public int getSquareCountWidth() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int getSquareCountHeight() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void initialization() {
|
||||
TerrainManager manager = new TerrainManager(1, 1, new TerrainHeightMapImpl(), null);
|
||||
Node node = manager.getNode();
|
||||
|
||||
assertEquals(TerrainManager.BUFFER_SIZE*TerrainManager.BUFFER_SIZE, node.getChildren().size());
|
||||
|
||||
for (int x=0; x<TerrainManager.BUFFER_SIZE; x++) {
|
||||
for (int y=0; y<TerrainManager.BUFFER_SIZE; y++) {
|
||||
assertNotNull(node.getChild("TerrainMesh " + x + "x" + y), "TerrainMesh missing: TerrainMesh " + x + "x" + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void setTerrainCenter() {
|
||||
TerrainManager manager = new TerrainManager(1, 1, new TerrainHeightMapImpl(), null);
|
||||
Node node = manager.getNode();
|
||||
|
||||
assertEquals(new Vector3f(-1, 0, -1), node.getChild("TerrainMesh 0x0").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 0, 0, -1), node.getChild("TerrainMesh 1x0").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 1, 0, -1), node.getChild("TerrainMesh 2x0").getLocalTranslation());
|
||||
assertEquals(new Vector3f(-1, 0, 0), node.getChild("TerrainMesh 0x1").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 0, 0, 0), node.getChild("TerrainMesh 1x1").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 1, 0, 0), node.getChild("TerrainMesh 2x1").getLocalTranslation());
|
||||
assertEquals(new Vector3f(-1, 0, 1), node.getChild("TerrainMesh 0x2").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 0, 0, 1), node.getChild("TerrainMesh 1x2").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 1, 0, 1), node.getChild("TerrainMesh 2x2").getLocalTranslation());
|
||||
|
||||
manager.setTerrainCenter(new Vector3f(10, 0, 10));
|
||||
|
||||
assertEquals(new Vector3f( 9, 0, 9), node.getChild("TerrainMesh 0x0").getLocalTranslation());
|
||||
assertEquals(new Vector3f(10, 0, 9), node.getChild("TerrainMesh 1x0").getLocalTranslation());
|
||||
assertEquals(new Vector3f(11, 0, 9), node.getChild("TerrainMesh 2x0").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 9, 0, 10), node.getChild("TerrainMesh 0x1").getLocalTranslation());
|
||||
assertEquals(new Vector3f(10, 0, 10), node.getChild("TerrainMesh 1x1").getLocalTranslation());
|
||||
assertEquals(new Vector3f(11, 0, 10), node.getChild("TerrainMesh 2x1").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 9, 0, 11), node.getChild("TerrainMesh 0x2").getLocalTranslation());
|
||||
assertEquals(new Vector3f(10, 0, 11), node.getChild("TerrainMesh 1x2").getLocalTranslation());
|
||||
assertEquals(new Vector3f(11, 0, 11), node.getChild("TerrainMesh 2x2").getLocalTranslation());
|
||||
|
||||
manager.setTerrainCenter(new Vector3f(0.1f, 0, 0.1f));
|
||||
|
||||
assertEquals(new Vector3f(-1, 0, -1), node.getChild("TerrainMesh 0x0").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 0, 0, -1), node.getChild("TerrainMesh 1x0").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 1, 0, -1), node.getChild("TerrainMesh 2x0").getLocalTranslation());
|
||||
assertEquals(new Vector3f(-1, 0, 0), node.getChild("TerrainMesh 0x1").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 0, 0, 0), node.getChild("TerrainMesh 1x1").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 1, 0, 0), node.getChild("TerrainMesh 2x1").getLocalTranslation());
|
||||
assertEquals(new Vector3f(-1, 0, 1), node.getChild("TerrainMesh 0x2").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 0, 0, 1), node.getChild("TerrainMesh 1x2").getLocalTranslation());
|
||||
assertEquals(new Vector3f( 1, 0, 1), node.getChild("TerrainMesh 2x2").getLocalTranslation());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue