package me.hammerle.snuviengine.api; import java.io.IOException; import java.nio.FloatBuffer; import me.hammerle.snuviengine.util.WrappedInputStream; import me.hammerle.snuviengine.util.WrappedOutputStream; import org.lwjgl.BufferUtils; import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.opengl.GL15.*; import static org.lwjgl.opengl.GL20.*; import static org.lwjgl.opengl.GL30.*; public class Chunk { public final static int CHUNK_SIZE = 8; public final static int TILE_SIZE = 16; public final static int LAYERS = 4; public final static int LAST_BACK_LAYER = 1; private final short[][][] data = new short[LAYERS][CHUNK_SIZE][CHUNK_SIZE]; private final int chunkX; private final int chunkY; private int vao; private int vbo; private final FloatBuffer buffer = BufferUtils.createFloatBuffer(CHUNK_SIZE * CHUNK_SIZE * 24); private boolean[] dirty = new boolean[LAYERS]; public Chunk(int x, int y) { this.chunkX = x; this.chunkY = y; for(int i = 0; i < LAYERS; i++) { dirty[i] = true; } Shader.addTask(() -> { vao = glGenVertexArrays(); vbo = glGenBuffers(); GLHelper.glBindVertexArray(vao); GLHelper.glBindBuffer(vbo); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, false, 16, 0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, false, 16, 8); glBufferData(GL_ARRAY_BUFFER, CHUNK_SIZE * CHUNK_SIZE * 96 * LAYERS, GL_STATIC_DRAW); }); } public void read(WrappedInputStream in) throws IOException { for(int l = 0; l < LAYERS; l++) { for(int x = 0; x < CHUNK_SIZE; x++) { for(int y = 0; y < CHUNK_SIZE; y++) { data[l][x][y] = in.readShort(); } } } } public void write(WrappedOutputStream out) throws IOException { for(int l = 0; l < LAYERS; l++) { for(int x = 0; x < CHUNK_SIZE; x++) { for(int y = 0; y < CHUNK_SIZE; y++) { out.writeShort(data[l][x][y]); } } } } private void rebuild(int layer) { for(int x = 0; x < CHUNK_SIZE; x++) { for(int y = 0; y < CHUNK_SIZE; y++) { short tile = data[layer][x][y]; float minX = x * TILE_SIZE; float minY = y * TILE_SIZE; float maxX = minX + TILE_SIZE; float maxY = minY + TILE_SIZE; float tMinX = (tile % 8) * 0.125f; float tMinY = (tile / 8) * 0.0108695652f; float tMaxX = tMinX + 0.125f; float tMaxY = tMinY + 0.0108695652f; buffer.put(minX); buffer.put(maxY); buffer.put(tMinX); buffer.put(tMaxY); buffer.put(minX); buffer.put(minY); buffer.put(tMinX); buffer.put(tMinY); buffer.put(maxX); buffer.put(maxY); buffer.put(tMaxX); buffer.put(tMaxY); buffer.put(maxX); buffer.put(maxY); buffer.put(tMaxX); buffer.put(tMaxY); buffer.put(minX); buffer.put(minY); buffer.put(tMinX); buffer.put(tMinY); buffer.put(maxX); buffer.put(minY); buffer.put(tMaxX); buffer.put(tMinY); } } buffer.flip(); GLHelper.glBindVertexArray(vao); GLHelper.glBindBuffer(vbo); glBufferSubData(GL_ARRAY_BUFFER, CHUNK_SIZE * CHUNK_SIZE * 96 * layer, buffer); } public void drawBackground() { for(int i = 0; i <= LAST_BACK_LAYER; i++) { if(dirty[i]) { rebuild(i); dirty[i] = false; } } GLHelper.glBindVertexArray(vao); GLHelper.glBindBuffer(vbo); Shader.pushMatrix(); Shader.translate(chunkX * CHUNK_SIZE * TILE_SIZE, chunkY * CHUNK_SIZE * TILE_SIZE); Shader.updateMatrix(); Shader.popMatrix(); glDrawArrays(GL_TRIANGLES, 0, CHUNK_SIZE * CHUNK_SIZE * 6 * (LAST_BACK_LAYER + 1)); } public void drawForeground() { for(int i = LAST_BACK_LAYER + 1; i < LAYERS; i++) { if(dirty[i]) { rebuild(i); dirty[i] = false; } } GLHelper.glBindVertexArray(vao); GLHelper.glBindBuffer(vbo); Shader.pushMatrix(); Shader.translate(chunkX * CHUNK_SIZE * TILE_SIZE, chunkY * CHUNK_SIZE * TILE_SIZE); Shader.updateMatrix(); Shader.popMatrix(); glDrawArrays(GL_TRIANGLES, CHUNK_SIZE * CHUNK_SIZE * 6 * (LAST_BACK_LAYER + 1), CHUNK_SIZE * CHUNK_SIZE * 6 * (LAYERS - LAST_BACK_LAYER - 1)); } }