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);
|
// cam.lookAt(new Vector3f(0f,0f,0f), Vector3f.UNIT_Z);
|
||||||
|
|
||||||
flyCam.setEnabled(false);
|
flyCam.setEnabled(false);
|
||||||
// stateManager.detach(stateManager.getState(FlyCamAppState.class));
|
|
||||||
ChaseCamera chaseCam = new ChaseCamera(cam, player.getGfxNode(), inputManager);
|
ChaseCamera chaseCam = new ChaseCamera(cam, player.getGfxNode(), inputManager);
|
||||||
chaseCam.setDefaultDistance(10);
|
chaseCam.setDefaultDistance(10);
|
||||||
chaseCam.setRotationSpeed(2);
|
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 {
|
public class TerrainMesh extends Mesh {
|
||||||
|
|
||||||
private float width;
|
private float squareWidth;
|
||||||
private float height;
|
private float squareHeight;
|
||||||
private int widthCount;
|
private int squareCountWidth;
|
||||||
private int heightCount;
|
private int squareCountHeight;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created a terrain Mesh with the given sizes.
|
* Created a terrain Mesh with the given sizes.
|
||||||
*
|
*
|
||||||
* @param width is the width of a single square
|
* @param squareWidth is the width of a single square
|
||||||
* @param height is the height of a single square
|
* @param squareHeight is the height of a single square
|
||||||
* @param widthCount the number of squares that make up the whole terrain
|
* @param squareCountWidth the number of squares that make up the whole terrain
|
||||||
* @param heightCount 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){
|
public TerrainMesh(float squareWidth, float squareHeight, int squareCountWidth, int squareCountHeight){
|
||||||
this.width = width;
|
this.squareWidth = squareWidth;
|
||||||
this.height = height;
|
this.squareHeight = squareHeight;
|
||||||
this.widthCount = widthCount;
|
this.squareCountWidth = squareCountWidth;
|
||||||
this.heightCount = heightCount;
|
this.squareCountHeight = squareCountHeight;
|
||||||
|
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|
@ -45,16 +46,16 @@ public class TerrainMesh extends Mesh {
|
||||||
* Generates a vertex buffer containing vertex xyz coordinates.
|
* Generates a vertex buffer containing vertex xyz coordinates.
|
||||||
*/
|
*/
|
||||||
protected float[] generateVertexBuffer() {
|
protected float[] generateVertexBuffer() {
|
||||||
int vertexCountWidth = widthCount + 1;
|
int vertexCountWidth = squareCountWidth + 1;
|
||||||
int vertexCountHeight = heightCount + 1;
|
int vertexCountHeight = squareCountHeight + 1;
|
||||||
float[] vertexBuf = new float[3 * vertexCountWidth * vertexCountHeight];
|
float[] vertexBuf = new float[3 * vertexCountWidth * vertexCountHeight];
|
||||||
|
|
||||||
for (int row=0; row<vertexCountHeight; row++) {
|
for (int row=0; row<vertexCountHeight; row++) {
|
||||||
for (int col=0; col<vertexCountWidth; col++) {
|
for (int col=0; col<vertexCountWidth; col++) {
|
||||||
int vertexIndex = (3 * vertexCountWidth * row) + (3 * 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 + 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.
|
* Generates a index buffer containing planes for the mesh.
|
||||||
*/
|
*/
|
||||||
protected short[] generateIndexBuffer() {
|
protected short[] generateIndexBuffer() {
|
||||||
int vertexCountWidth = widthCount + 1;
|
int vertexCountWidth = squareCountWidth + 1;
|
||||||
int triangleCount = widthCount * heightCount * 2;
|
int triangleCount = squareCountWidth * squareCountHeight * 2;
|
||||||
short[] indexBuf = new short[3 * triangleCount];
|
short[] indexBuf = new short[3 * triangleCount];
|
||||||
|
|
||||||
for (int row=0; row<heightCount; row++) {
|
for (int row = 0; row< squareCountHeight; row++) {
|
||||||
for (int col = 0; col<widthCount; col++) {
|
for (int col = 0; col< squareCountWidth; col++) {
|
||||||
int vertexTopLeft = (row * vertexCountWidth) + col;
|
int vertexTopLeft = (row * vertexCountWidth) + col;
|
||||||
int vertexTopRight = vertexTopLeft + 1;
|
int vertexTopRight = vertexTopLeft + 1;
|
||||||
int vertexBottomLeft = ((row + 1) * vertexCountWidth) + col;
|
int vertexBottomLeft = ((row + 1) * vertexCountWidth) + col;
|
||||||
int vertexBottomRight = vertexBottomLeft + 1;
|
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 + 0] = (short) vertexTopLeft;
|
||||||
indexBuf[indexOffset + 1] = (short) vertexBottomLeft;
|
indexBuf[indexOffset + 1] = (short) vertexBottomLeft;
|
||||||
|
|
@ -114,4 +115,21 @@ public class TerrainMesh extends Mesh {
|
||||||
0, 0, 1
|
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