LiteCraft/src/main/java/io/github/hydos/ginger/engine/terrain/Terrain.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;
}
}