160 lines
5.0 KiB
Java
160 lines
5.0 KiB
Java
package io.github.hydos.ginger.engine.terrain;
|
|
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.IOException;
|
|
|
|
import javax.imageio.ImageIO;
|
|
|
|
import io.github.hydos.ginger.engine.mathEngine.Maths;
|
|
import io.github.hydos.ginger.engine.mathEngine.vectors.Vector2f;
|
|
import io.github.hydos.ginger.engine.mathEngine.vectors.Vector3f;
|
|
import io.github.hydos.ginger.engine.renderEngine.models.RawModel;
|
|
import io.github.hydos.ginger.engine.utils.Loader;
|
|
import io.github.hydos.ginger.main.settings.Constants;
|
|
|
|
public class Terrain
|
|
{
|
|
private static final float MAX_PIXEL_COLOUR = 256 * 256 * 256;
|
|
private float[][] heights;
|
|
private float x, z;
|
|
private RawModel model;
|
|
private TerrainTexturePack texturePack;
|
|
private TerrainTexture blendMap;
|
|
|
|
public Terrain(float gridX, float gridZ, TerrainTexturePack texturePack, TerrainTexture blendMap, String heightMapLocation)
|
|
{
|
|
this.texturePack = texturePack;
|
|
this.blendMap = blendMap;
|
|
this.x = gridX * Constants.terrainSize;
|
|
this.z = gridZ * Constants.terrainSize;
|
|
this.model = generateTerrain(heightMapLocation);
|
|
}
|
|
|
|
public float getHeightOfTerrain(float worldX, float worldZ)
|
|
{
|
|
float terrainX = worldX - this.x;
|
|
float terrainZ = worldZ - this.z;
|
|
float gridSquareSize = Constants.terrainSize / ((float) heights.length - 1);
|
|
int gridX = (int) Math.floor(terrainX / gridSquareSize);
|
|
int gridZ = (int) Math.floor(terrainZ / gridSquareSize);
|
|
if (gridX >= heights.length - 1 || gridZ >= heights.length - 1 || gridX < 0 || gridZ < 0)
|
|
{ return 0; }
|
|
float xCoord = (terrainX % gridSquareSize) / gridSquareSize;
|
|
float zCoord = (terrainZ % gridSquareSize) / gridSquareSize;
|
|
float answer;
|
|
if (xCoord <= (1 - zCoord))
|
|
{
|
|
answer = Maths
|
|
.barryCentric(new Vector3f(0, heights[gridX][gridZ], 0), new Vector3f(1,
|
|
heights[gridX + 1][gridZ], 0),
|
|
new Vector3f(0,
|
|
heights[gridX][gridZ + 1], 1),
|
|
new Vector2f(xCoord, zCoord));
|
|
}
|
|
else
|
|
{
|
|
answer = Maths
|
|
.barryCentric(new Vector3f(1, heights[gridX + 1][gridZ], 0), new Vector3f(1,
|
|
heights[gridX + 1][gridZ + 1], 1),
|
|
new Vector3f(0,
|
|
heights[gridX][gridZ + 1], 1),
|
|
new Vector2f(xCoord, zCoord));
|
|
}
|
|
return answer;
|
|
}
|
|
|
|
public float getX()
|
|
{ return x; }
|
|
|
|
public float getZ()
|
|
{ return z; }
|
|
|
|
public RawModel getModel()
|
|
{ return model; }
|
|
|
|
public TerrainTexturePack getTexturePack()
|
|
{ return texturePack; }
|
|
|
|
public TerrainTexture getBlendMap()
|
|
{ return blendMap; }
|
|
|
|
private RawModel generateTerrain(String heightMap)
|
|
{
|
|
BufferedImage image = null;
|
|
try
|
|
{
|
|
image = ImageIO.read(Class.class.getResourceAsStream("/textures/terrain/" + heightMap));
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
e.printStackTrace();
|
|
}
|
|
int VERTEX_COUNT = image.getHeight();
|
|
heights = new float[VERTEX_COUNT][VERTEX_COUNT];
|
|
int count = VERTEX_COUNT * VERTEX_COUNT;
|
|
float[] vertices = new float[count * 3];
|
|
float[] normals = new float[count * 3];
|
|
float[] textureCoords = new float[count * 2];
|
|
int[] indices = new int[6 * (VERTEX_COUNT - 1) * (VERTEX_COUNT - 1)];
|
|
int vertexPointer = 0;
|
|
for (int i = 0; i < VERTEX_COUNT; i++)
|
|
{
|
|
for (int j = 0; j < VERTEX_COUNT; j++)
|
|
{
|
|
vertices[vertexPointer * 3] = j / ((float) VERTEX_COUNT - 1) * Constants.terrainSize;
|
|
float height = getHeight(j, i, image);
|
|
heights[j][i] = height;
|
|
vertices[vertexPointer * 3 + 1] = height;
|
|
vertices[vertexPointer * 3 + 2] = i / ((float) VERTEX_COUNT - 1) * Constants.terrainSize;
|
|
Vector3f normal = calculateNormal(j, i, image);
|
|
normals[vertexPointer * 3] = normal.x;
|
|
normals[vertexPointer * 3 + 1] = normal.y;
|
|
normals[vertexPointer * 3 + 2] = normal.z;
|
|
textureCoords[vertexPointer * 2] = j / ((float) VERTEX_COUNT - 1);
|
|
textureCoords[vertexPointer * 2 + 1] = i / ((float) VERTEX_COUNT - 1);
|
|
vertexPointer++;
|
|
}
|
|
}
|
|
int pointer = 0;
|
|
for (int gz = 0; gz < VERTEX_COUNT - 1; gz++)
|
|
{
|
|
for (int gx = 0; gx < VERTEX_COUNT - 1; gx++)
|
|
{
|
|
int topLeft = (gz * VERTEX_COUNT) + gx;
|
|
int topRight = topLeft + 1;
|
|
int bottomLeft = ((gz + 1) * VERTEX_COUNT) + gx;
|
|
int bottomRight = bottomLeft + 1;
|
|
indices[pointer++] = topLeft;
|
|
indices[pointer++] = bottomLeft;
|
|
indices[pointer++] = topRight;
|
|
indices[pointer++] = topRight;
|
|
indices[pointer++] = bottomLeft;
|
|
indices[pointer++] = bottomRight;
|
|
}
|
|
}
|
|
return Loader.loadToVAO(vertices, indices, normals, textureCoords);
|
|
}
|
|
|
|
private float getHeight(int x, int z, BufferedImage image)
|
|
{
|
|
if (x < 0 || x >= image.getHeight() || z < 0 || z >= image.getHeight())
|
|
{ return 0; }
|
|
float height = image.getRGB(x, z);
|
|
height += MAX_PIXEL_COLOUR / 2f;
|
|
height /= MAX_PIXEL_COLOUR / 2f;
|
|
height *= Constants.terrainMaxHeight;
|
|
return height;
|
|
}
|
|
|
|
private Vector3f calculateNormal(int x, int z, BufferedImage image)
|
|
{
|
|
float heightL = getHeight(x - 1, z, image);
|
|
float heightR = getHeight(x + 1, z, image);
|
|
float heightD = getHeight(x, z - 1, image);
|
|
float heightU = getHeight(x, z + 1, image);
|
|
Vector3f normal = new Vector3f(heightL - heightR, 2f, heightD - heightU);
|
|
normal.normalise();
|
|
return normal;
|
|
}
|
|
}
|