Terrain.java 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. package eu.tankernn.gameEngine.terrains;
  2. import java.awt.image.BufferedImage;
  3. import java.io.File;
  4. import java.io.IOException;
  5. import javax.imageio.ImageIO;
  6. import org.lwjgl.util.vector.Vector2f;
  7. import org.lwjgl.util.vector.Vector3f;
  8. import eu.tankernn.gameEngine.loader.models.RawModel;
  9. import eu.tankernn.gameEngine.loader.textures.TerrainTexture;
  10. import eu.tankernn.gameEngine.loader.textures.TerrainTexturePack;
  11. import eu.tankernn.gameEngine.renderEngine.Loader;
  12. import eu.tankernn.gameEngine.util.Maths;
  13. public class Terrain {
  14. private static final float SIZE = 800;
  15. private static final float MAX_HEIGHT = 40;
  16. private static final float MAX_PIXEL_COLOR = 256 * 256 * 256;
  17. private float x, z;
  18. private int gridX, gridZ;
  19. private RawModel model;
  20. private TerrainTexturePack texturePack;
  21. private TerrainTexture blendMap;
  22. private float[][] heights;
  23. public Terrain(int gridX, int gridZ, Loader loader, TerrainTexturePack texturePack, TerrainTexture blendMap, String heightMap) {
  24. this.texturePack = texturePack;
  25. this.blendMap = blendMap;
  26. this.gridX = gridX;
  27. this.gridZ = gridZ;
  28. this.x = gridX * SIZE;
  29. this.z = gridZ * SIZE;
  30. this.model = generateTerrain(loader, heightMap);
  31. }
  32. public Terrain(int gridX, int gridZ, Loader loader, TerrainTexturePack texturePack, TerrainTexture blendMap, int seed) {
  33. this.texturePack = texturePack;
  34. this.blendMap = blendMap;
  35. this.gridX = gridX;
  36. this.gridZ = gridZ;
  37. this.x = gridX * SIZE;
  38. this.z = gridZ * SIZE;
  39. this.model = generateTerrain(loader, seed);
  40. }
  41. private RawModel generateTerrain(Loader loader, String heightMap) {
  42. BufferedImage image = null;
  43. try {
  44. image = ImageIO.read(new File("res/" + heightMap + ".png"));
  45. } catch (IOException e) {
  46. e.printStackTrace();
  47. }
  48. int vertexCount = image.getHeight();
  49. heights = new float[vertexCount][vertexCount];
  50. int count = vertexCount * vertexCount;
  51. float[] vertices = new float[count * 3];
  52. float[] normals = new float[count * 3];
  53. float[] textureCoords = new float[count * 2];
  54. int[] indices = new int[6 * (vertexCount - 1) * (vertexCount - 1)];
  55. int vertexPointer = 0;
  56. for (int i = 0; i < vertexCount; i++) {
  57. for (int j = 0; j < vertexCount; j++) {
  58. vertices[vertexPointer * 3] = (float) j / ((float) vertexCount - 1) * SIZE;
  59. float height = getHeight(j, i, image);
  60. heights[j][i] = height;
  61. vertices[vertexPointer * 3 + 1] = height;
  62. vertices[vertexPointer * 3 + 2] = (float) i / ((float) vertexCount - 1) * SIZE;
  63. Vector3f normal = calculateNormal(j, i, image);
  64. normals[vertexPointer * 3] = normal.x;
  65. normals[vertexPointer * 3 + 1] = normal.y;
  66. normals[vertexPointer * 3 + 2] = normal.z;
  67. textureCoords[vertexPointer * 2] = (float) j / ((float) vertexCount - 1);
  68. textureCoords[vertexPointer * 2 + 1] = (float) i / ((float) vertexCount - 1);
  69. vertexPointer++;
  70. }
  71. }
  72. int pointer = 0;
  73. for (int gz = 0; gz < vertexCount - 1; gz++) {
  74. for (int gx = 0; gx < vertexCount - 1; gx++) {
  75. int topLeft = (gz * vertexCount) + gx;
  76. int topRight = topLeft + 1;
  77. int bottomLeft = ((gz + 1) * vertexCount) + gx;
  78. int bottomRight = bottomLeft + 1;
  79. indices[pointer++] = topLeft;
  80. indices[pointer++] = bottomLeft;
  81. indices[pointer++] = topRight;
  82. indices[pointer++] = topRight;
  83. indices[pointer++] = bottomLeft;
  84. indices[pointer++] = bottomRight;
  85. }
  86. }
  87. return loader.loadToVAO(vertices, textureCoords, normals, indices);
  88. }
  89. private RawModel generateTerrain(Loader loader, int seed) {
  90. int vertexCount = 128;
  91. HeightsGenerator generator = new HeightsGenerator(this.gridX, this.gridZ, vertexCount, seed);
  92. heights = new float[vertexCount][vertexCount];
  93. int count = vertexCount * vertexCount;
  94. float[] vertices = new float[count * 3];
  95. float[] normals = new float[count * 3];
  96. float[] textureCoords = new float[count * 2];
  97. int[] indices = new int[6 * (vertexCount - 1) * (vertexCount - 1)];
  98. int vertexPointer = 0;
  99. for (int i = 0; i < vertexCount; i++) {
  100. for (int j = 0; j < vertexCount; j++) {
  101. vertices[vertexPointer * 3] = (float) j / ((float) vertexCount - 1) * SIZE;
  102. float height = getHeight(j, i, generator);
  103. heights[j][i] = height;
  104. vertices[vertexPointer * 3 + 1] = height;
  105. vertices[vertexPointer * 3 + 2] = (float) i / ((float) vertexCount - 1) * SIZE;
  106. Vector3f normal = calculateNormal(j, i, generator);
  107. normals[vertexPointer * 3] = normal.x;
  108. normals[vertexPointer * 3 + 1] = normal.y;
  109. normals[vertexPointer * 3 + 2] = normal.z;
  110. textureCoords[vertexPointer * 2] = (float) j / ((float) vertexCount - 1);
  111. textureCoords[vertexPointer * 2 + 1] = (float) i / ((float) vertexCount - 1);
  112. vertexPointer++;
  113. }
  114. }
  115. int pointer = 0;
  116. for (int gz = 0; gz < vertexCount - 1; gz++) {
  117. for (int gx = 0; gx < vertexCount - 1; gx++) {
  118. int topLeft = (gz * vertexCount) + gx;
  119. int topRight = topLeft + 1;
  120. int bottomLeft = ((gz + 1) * vertexCount) + gx;
  121. int bottomRight = bottomLeft + 1;
  122. indices[pointer++] = topLeft;
  123. indices[pointer++] = bottomLeft;
  124. indices[pointer++] = topRight;
  125. indices[pointer++] = topRight;
  126. indices[pointer++] = bottomLeft;
  127. indices[pointer++] = bottomRight;
  128. }
  129. }
  130. return loader.loadToVAO(vertices, textureCoords, normals, indices);
  131. }
  132. private Vector3f calculateNormal(int x, int z, BufferedImage image) {
  133. float heightL = getHeight(x - 1, z, image);
  134. float heightR = getHeight(x + 1, z, image);
  135. float heightD = getHeight(x, z - 1, image);
  136. float heightU = getHeight(x, z + 1, image);
  137. Vector3f normal = new Vector3f(heightL - heightR, 2f, heightD - heightU);
  138. normal.normalise();
  139. return normal;
  140. }
  141. private Vector3f calculateNormal(int x, int z, HeightsGenerator generator) {
  142. float heightL = getHeight(x - 1, z, generator);
  143. float heightR = getHeight(x + 1, z, generator);
  144. float heightD = getHeight(x, z - 1, generator);
  145. float heightU = getHeight(x, z + 1, generator);
  146. Vector3f normal = new Vector3f(heightL - heightR, 2f, heightD - heightU);
  147. normal.normalise();
  148. return normal;
  149. }
  150. private float getHeight(int x, int z, BufferedImage image) {
  151. if (x < 0 || x >= image.getHeight() || z < 0 || z >= image.getHeight()) {
  152. return 0;
  153. }
  154. float height = image.getRGB(x, z);
  155. height += MAX_PIXEL_COLOR / 2f;
  156. height /= MAX_PIXEL_COLOR / 2f;
  157. height *= MAX_HEIGHT;
  158. return height;
  159. }
  160. private float getHeight(int x, int z, HeightsGenerator generator) {
  161. return generator.generateHeight(x, z);
  162. }
  163. public float getX() {
  164. return x;
  165. }
  166. public float getZ() {
  167. return z;
  168. }
  169. float getSize() {
  170. return SIZE;
  171. }
  172. public RawModel getModel() {
  173. return model;
  174. }
  175. public TerrainTexturePack getTexturePack() {
  176. return texturePack;
  177. }
  178. public TerrainTexture getBlendMap() {
  179. return blendMap;
  180. }
  181. public float getHeightOfTerrain(float worldX, float worldZ) {
  182. float terrainX = worldX - this.x;
  183. float terrainZ = worldZ - this.z;
  184. float gridSquareSize = SIZE / ((float) heights.length - 1);
  185. int gridX = (int) Math.floor(terrainX / gridSquareSize);
  186. int gridZ = (int) Math.floor(terrainZ / gridSquareSize);
  187. if (gridX >= heights.length - 1 || gridZ >= heights.length - 1 || gridX < 0 || gridZ < 0) {
  188. return 0;
  189. }
  190. float xCoord = (terrainX % gridSquareSize) / gridSquareSize;
  191. float zCoord = (terrainZ % gridSquareSize) / gridSquareSize;
  192. float answer;
  193. if (xCoord <= (1 - zCoord)) {
  194. answer = Maths
  195. .barryCentric(new Vector3f(0, heights[gridX][gridZ], 0), new Vector3f(1,
  196. heights[gridX + 1][gridZ], 0), new Vector3f(0,
  197. heights[gridX][gridZ + 1], 1), new Vector2f(xCoord, zCoord));
  198. } else {
  199. answer = Maths
  200. .barryCentric(new Vector3f(1, heights[gridX + 1][gridZ], 0), new Vector3f(1,
  201. heights[gridX + 1][gridZ + 1], 1), new Vector3f(0,
  202. heights[gridX][gridZ + 1], 1), new Vector2f(xCoord, zCoord));
  203. }
  204. return answer;
  205. }
  206. }