diff options
Diffstat (limited to 'src/main/java/makamys/lodmod/renderer')
-rw-r--r-- | src/main/java/makamys/lodmod/renderer/ChunkMesh.java | 455 | ||||
-rw-r--r-- | src/main/java/makamys/lodmod/renderer/FarChunkCache.java | 12 | ||||
-rw-r--r-- | src/main/java/makamys/lodmod/renderer/FarWorldRenderer.java | 14 | ||||
-rw-r--r-- | src/main/java/makamys/lodmod/renderer/GPUMemoryManager.java | 215 | ||||
-rw-r--r-- | src/main/java/makamys/lodmod/renderer/LODChunk.java | 184 | ||||
-rw-r--r-- | src/main/java/makamys/lodmod/renderer/LODRegion.java | 195 | ||||
-rw-r--r-- | src/main/java/makamys/lodmod/renderer/LODRenderer.java | 730 | ||||
-rw-r--r-- | src/main/java/makamys/lodmod/renderer/Mesh.java | 44 | ||||
-rw-r--r-- | src/main/java/makamys/lodmod/renderer/MeshQuad.java | 426 | ||||
-rw-r--r-- | src/main/java/makamys/lodmod/renderer/SimpleChunkMesh.java | 350 |
10 files changed, 0 insertions, 2625 deletions
diff --git a/src/main/java/makamys/lodmod/renderer/ChunkMesh.java b/src/main/java/makamys/lodmod/renderer/ChunkMesh.java deleted file mode 100644 index f07a908..0000000 --- a/src/main/java/makamys/lodmod/renderer/ChunkMesh.java +++ /dev/null @@ -1,455 +0,0 @@ -package makamys.lodmod.renderer; - -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import org.lwjgl.BufferUtils; - -import makamys.lodmod.LODMod; -import makamys.lodmod.MixinConfigPlugin; -import makamys.lodmod.ducks.IWorldRenderer; -import makamys.lodmod.util.BufferWriter; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureMap; -import net.minecraft.entity.Entity; -import net.minecraft.nbt.NBTBase; -import net.minecraft.nbt.NBTTagByteArray; -import net.minecraft.tileentity.TileEntity; - -public class ChunkMesh extends Mesh { - - Flags flags; - - // TODO move this somewhere else - List<String> nameList = (List<String>) ((TextureMap)Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture)).mapUploadedSprites.keySet().stream().collect(Collectors.toList()); - - public static int usedRAM = 0; - public static int instances = 0; - - public ChunkMesh(int x, int y, int z, Flags flags, int quadCount, ByteBuffer buffer, int pass) { - this.x = x; - this.y = y; - this.z = z; - this.flags = flags; - this.quadCount = quadCount; - this.pass = pass; - - this.buffer = buffer; - usedRAM += buffer.limit(); - instances++; - } - - public ChunkMesh(int x, int y, int z, Flags flags, int quadCount, List<MeshQuad> quads, int pass) { - this.x = x; - this.y = y; - this.z = z; - this.flags = flags; - this.quadCount = quadCount; - this.pass = pass; - - NBTBase nbtData = toNBT(quads, quadCount); - buffer = createBuffer(((NBTTagByteArray)nbtData).func_150292_c(), nameList); - usedRAM += buffer.limit(); - instances++; - } - - private static int totalOriginalQuadCount = 0; - private static int totalSimplifiedQuadCount = 0; - - public static ChunkMesh fromTessellator(int pass, WorldRenderer wr, Tessellator t) { - if(t.vertexCount % 4 != 0) { - System.out.println("Error: Vertex count is not a multiple of 4"); - return null; - } - - int xOffset = wr.posX; - int yOffset = wr.posY; - int zOffset = wr.posZ; - - boolean fr = MixinConfigPlugin.isOptiFinePresent() && LODMod.ofFastRender; - int tessellatorXOffset = fr ? xOffset : 0; - int tessellatorYOffset = fr ? yOffset : 0; - int tessellatorZOffset = fr ? zOffset : 0; - - boolean optimize = LODMod.optimizeChunkMeshes; - - ChunkMesh.Flags flags = new ChunkMesh.Flags(t.hasTexture, t.hasBrightness, t.hasColor, t.hasNormals); - - if(optimize) { - List<MeshQuad> quads = new ArrayList<>(); - - for(int quadI = 0; quadI < t.vertexCount / 4; quadI++) { - MeshQuad quad = new MeshQuad(t.rawBuffer, quadI * 32, flags, tessellatorXOffset, tessellatorYOffset, tessellatorZOffset); - //if(quad.bUs[0] == quad.bUs[1] && quad.bUs[1] == quad.bUs[2] && quad.bUs[2] == quad.bUs[3] && quad.bUs[3] == quad.bVs[0] && quad.bVs[0] == quad.bVs[1] && quad.bVs[1] == quad.bVs[2] && quad.bVs[2] == quad.bVs[3] && quad.bVs[3] == 0) { - // quad.deleted = true; - //} - if(quad.plane == quad.PLANE_XZ && !quad.isClockwiseXZ()) { - // water hack - quad.deleted = true; - } - quads.add(quad); - } - - ArrayList<ArrayList<MeshQuad>> quadsByPlaneDir = new ArrayList<>(); // XY, XZ, YZ - for(int i = 0; i < 3; i++) { - quadsByPlaneDir.add(new ArrayList<MeshQuad>()); - } - for(MeshQuad quad : quads) { - if(quad.plane != MeshQuad.PLANE_NONE) { - quadsByPlaneDir.get(quad.plane).add(quad); - } - } - for(int plane = 0; plane < 3; plane++) { - quadsByPlaneDir.get(plane).sort(MeshQuad.QuadPlaneComparator.quadPlaneComparators[plane]); - } - - for(int plane = 0; plane < 3; plane++) { - List<MeshQuad> planeDirQuads = quadsByPlaneDir.get(plane); - int planeStart = 0; - for(int quadI = 0; quadI < planeDirQuads.size(); quadI++) { - MeshQuad quad = planeDirQuads.get(quadI); - MeshQuad nextQuad = quadI == planeDirQuads.size() - 1 ? null : planeDirQuads.get(quadI + 1); - if(!quad.onSamePlaneAs(nextQuad)) { - simplifyPlane(planeDirQuads.subList(planeStart, quadI)); - planeStart = quadI + 1; - } - } - } - - int quadCount = countValidQuads(quads); - - totalOriginalQuadCount += quads.size(); - totalSimplifiedQuadCount += quadCount; - //System.out.println("simplified quads " + totalOriginalQuadCount + " -> " + totalSimplifiedQuadCount + " (ratio: " + ((float)totalSimplifiedQuadCount / (float)totalOriginalQuadCount) + ") totalMergeCountByPlane: " + Arrays.toString(totalMergeCountByPlane)); - - if(quadCount > 0) { - return new ChunkMesh( - (int)(xOffset / 16), (int)(yOffset / 16), (int)(zOffset / 16), - new ChunkMesh.Flags(t.hasTexture, t.hasBrightness, t.hasColor, t.hasNormals), - quadCount, quads, pass); - } else { - return null; - } - } else { - int quadCount = t.vertexCount / 4; - ByteBuffer buffer = BufferUtils.createByteBuffer(quadCount * 6 * 7 * 4); - BufferWriter out = new BufferWriter(buffer); - - try { - for(int i = 0; i < quadCount; i++) { - writeBufferQuad(t, i * 32, out, -tessellatorXOffset + xOffset, -tessellatorYOffset + yOffset, -tessellatorZOffset + zOffset); - } - } catch(IOException e) { - e.printStackTrace(); - } - buffer.flip(); - - if(quadCount > 0) { - return new ChunkMesh( - (int)(xOffset / 16), (int)(yOffset / 16), (int)(zOffset / 16), - flags, - quadCount, buffer, pass); - } else { - return null; - } - } - } - - private static void writeBufferQuad(Tessellator t, int offset, BufferWriter out, float offsetX, float offsetY, float offsetZ) throws IOException { - for(int vertexI = 0; vertexI < 6; vertexI++) { - - int vi = new int[]{0, 1, 2, 0, 2, 3}[vertexI]; - - int i = offset + vi * 8; - - float x = Float.intBitsToFloat(t.rawBuffer[i + 0]) + offsetX; - float y = Float.intBitsToFloat(t.rawBuffer[i + 1]) + offsetY; - float z = Float.intBitsToFloat(t.rawBuffer[i + 2]) + offsetZ; - - out.writeFloat(x); - out.writeFloat(y); - out.writeFloat(z); - - float u = Float.intBitsToFloat(t.rawBuffer[i + 3]); - float v = Float.intBitsToFloat(t.rawBuffer[i + 4]); - - out.writeFloat(u); - out.writeFloat(v); - - int brightness = t.rawBuffer[i + 7]; - out.writeInt(brightness); - - int color = t.rawBuffer[i + 5]; - out.writeInt(color); - - i += 8; - } - } - - private static void simplifyPlane(List<MeshQuad> planeQuads) { - MeshQuad lastQuad = null; - // Pass 1: merge quads to create rows - for(MeshQuad quad : planeQuads) { - if(lastQuad != null) { - lastQuad.tryToMerge(quad); - } - if(quad.isValid(quad)) { - lastQuad = quad; - } - } - - // Pass 2: merge rows to create rectangles - // TODO optimize? - for(int i = 0; i < planeQuads.size(); i++) { - for(int j = i + 1; j < planeQuads.size(); j++) { - planeQuads.get(i).tryToMerge(planeQuads.get(j)); - } - } - } - - private static int countValidQuads(List<MeshQuad> quads) { - int quadCount = 0; - for(MeshQuad quad : quads) { - if(!quad.deleted) { - quadCount++; - } - } - return quadCount; - } - - private NBTBase toNBT(List<? extends MeshQuad> quads, int quadCount) { - ByteArrayOutputStream byteOut = new ByteArrayOutputStream(quadCount * (2 + 4 * (3 + 2 + 2 + 4))); - DataOutputStream out = new DataOutputStream(byteOut); - try { - for(int pass = 0; pass <= 9; pass++){ - for(MeshQuad quad : quads) { - quad.writeToDisk(out, pass); - } - } - } catch(IOException e) {} - - NBTTagByteArray arr = new NBTTagByteArray(byteOut.toByteArray()); - usedRAM += arr.func_150292_c().length; - return arr; - } - - void destroy() { - if(buffer != null) { - usedRAM -= buffer.limit(); - instances--; - buffer = null; - - if(gpuStatus == Mesh.GPUStatus.SENT) { - gpuStatus = Mesh.GPUStatus.PENDING_DELETE; - } - } - } - - @Override - public void destroyBuffer() { - destroy(); - } - - private ByteBuffer createBuffer(byte[] data, List<String> stringTable) { - if(!(flags.hasTexture && flags.hasColor && flags.hasBrightness && !flags.hasNormals)) { - // for simplicity's sake we just assume this setup - System.out.println("invalid mesh properties, expected a chunk"); - return null; - } - int coordsOffset = quadCount * 2; - int textureOffset = quadCount * (2 + 4 + 4 + 4); - int brightnessOffset = quadCount * (2 + 4 + 4 + 4 + 4 + 4); - int colorOffset = quadCount * (2 + 4 + 4 + 4 + 4 + 4 + 4 + 4); - - ByteBuffer buffer = BufferUtils.createByteBuffer(quadCount * 6 * getStride()); - FloatBuffer floatBuffer = buffer.asFloatBuffer(); - ShortBuffer shortBuffer = buffer.asShortBuffer(); - IntBuffer intBuffer = buffer.asIntBuffer(); - - try { - for(int quadI = 0; quadI < quadCount; quadI++) { - short spriteIndex = readShortAt(data, quadI * 2); - String spriteName = stringTable.get(spriteIndex); - - TextureAtlasSprite tas = ((TextureMap)Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture)).getAtlasSprite(spriteName); - - for (int vertexNum = 0; vertexNum < 6; vertexNum++) { - int vi = new int[]{0, 1, 3, 1, 2, 3}[vertexNum]; - int vertexI = 4 * quadI + vi; - int offset = vertexI * getStride(); - int simpleX = Byte.toUnsignedInt(data[coordsOffset + 0 * 4 * quadCount + 4 * quadI + vi]); - if(simpleX == 255) simpleX = 256; - int simpleY = Byte.toUnsignedInt(data[coordsOffset + 1 * 4 * quadCount + 4 * quadI + vi]); - if(simpleY == 255) simpleY = 256; - int simpleZ = Byte.toUnsignedInt(data[coordsOffset + 2 * 4 * quadCount + 4 * quadI + vi]); - if(simpleZ == 255) simpleZ = 256; - floatBuffer.put(x * 16 + simpleX / 16f); // x - floatBuffer.put(y * 16 + simpleY / 16f); // y - floatBuffer.put(z * 16 + simpleZ / 16f); // z - - byte relU = data[textureOffset + 0 * 4 * quadCount + 4 * quadI + vi]; - byte relV = data[textureOffset + 1 * 4 * quadCount + 4 * quadI + vi]; - - floatBuffer.put(tas.getMinU() + (tas.getMaxU() - tas.getMinU()) * (relU / 16f)); // u - floatBuffer.put(tas.getMinV() + (tas.getMaxV() - tas.getMinV()) * (relV / 16f)); // v - - shortBuffer.position(floatBuffer.position() * 2); - - shortBuffer.put((short)Byte.toUnsignedInt(data[brightnessOffset + 0 * 4 * quadCount + 4 * quadI + vi])); // bU - shortBuffer.put((short)Byte.toUnsignedInt(data[brightnessOffset + 1 * 4 * quadCount + 4 * quadI + vi])); // bV - - intBuffer.position(shortBuffer.position() / 2); - - int integet = readIntAt(data, colorOffset + 4 * 4 * quadI + 4 * vi); - intBuffer.put(integet); // c - - floatBuffer.position(intBuffer.position()); - } - } - } catch(Exception e) { - e.printStackTrace(); - } - - buffer.position(floatBuffer.position() * 4); - buffer.flip(); - - usedRAM += buffer.limit(); - - return buffer; - } - - public void update() { - } - - // Java is weird. - public static short readShortAt(DataInputStream in, int offset) { - try { - in.reset(); - in.skip(offset); - return in.readShort(); - } catch(IOException e) { - return -1; - } - } - - public static short readShortAt(byte[] data, int offset) { - return (short)(Byte.toUnsignedInt(data[offset]) << 8 | Byte.toUnsignedInt(data[offset + 1])); - } - - public static int readIntAt(DataInputStream in, int offset) { - try { - in.reset(); - in.skip(offset); - return in.readInt(); - } catch(IOException e) { - return -1; - } - } - - public static int readIntAt(byte[] data, int offset) { - return (int)(Byte.toUnsignedLong(data[offset]) << 24 | Byte.toUnsignedLong(data[offset + 1]) << 16 | Byte.toUnsignedLong(data[offset + 2]) << 8 | Byte.toUnsignedLong(data[offset + 3])); - } - - public int getStride() { - return (3 * 4 + (flags.hasTexture ? 8 : 0) + (flags.hasBrightness ? 4 : 0) + (flags.hasColor ? 4 : 0) + (flags.hasNormals ? 4 : 0)); - } - - static void saveChunks(List<Integer> coords) { - System.out.println("saving " + (coords.size() / 3) + " cchunks"); - for(int i = 0; i < coords.size(); i += 3) { - if(i % 300 == 0) { - System.out.println((i / 3) + " / " + (coords.size() / 3)); - } - int theX = coords.get(i); - int theY = coords.get(i + 1); - int theZ = coords.get(i + 2); - - WorldRenderer wr = new WorldRenderer(Minecraft.getMinecraft().theWorld, new ArrayList<TileEntity>(), theX * 16, theY * 16, theZ * 16, 100000); - /* - if (this.occlusionEnabled) - { - this.worldRenderers[(var6 * this.renderChunksTall + var5) * this.renderChunksWide + var4].glOcclusionQuery = this.glOcclusionQueryBase.get(var3); - }*/ - - wr.isWaitingOnOcclusionQuery = false; - wr.isVisible = true; - wr.isInFrustum = true; - wr.chunkIndex = 0; - wr.markDirty(); - wr.updateRenderer(Minecraft.getMinecraft().thePlayer); - } - //Tessellator.endSave(); - } - - static List<ChunkMesh> getChunkMesh(int theX, int theY, int theZ) { - WorldRenderer wr = new WorldRenderer(Minecraft.getMinecraft().theWorld, new ArrayList<TileEntity>(), theX * 16, theY * 16, theZ * 16, 100000); - - wr.isWaitingOnOcclusionQuery = false; - wr.isVisible = true; - wr.isInFrustum = true; - wr.chunkIndex = 0; - wr.markDirty(); - wr.updateRenderer(Minecraft.getMinecraft().thePlayer); - return ((IWorldRenderer)wr).getChunkMeshes(); - } - - public double distSq(Entity player) { - int centerX = x * 16 + 8; - int centerY = y * 16 + 8; - int centerZ = z * 16 + 8; - - return player.getDistanceSq(centerX, centerY, centerZ); - } - - public static class Flags { - boolean hasTexture; - boolean hasBrightness; - boolean hasColor; - boolean hasNormals; - - public Flags(byte flags) { - hasTexture = (flags & 1) != 0; - hasBrightness = (flags & 2) != 0; - hasColor = (flags & 4) != 0; - hasNormals = (flags & 8) != 0; - } - - public Flags(boolean hasTexture, boolean hasBrightness, boolean hasColor, boolean hasNormals) { - this.hasTexture = hasTexture; - this.hasBrightness = hasBrightness; - this.hasColor = hasColor; - this.hasNormals = hasNormals; - } - - public byte toByte() { - byte flags = 0; - if(hasTexture) { - flags |= 1; - } - if(hasBrightness) { - flags |= 2; - } - if(hasColor) { - flags |= 4; - } - if(hasNormals) { - flags |= 8; - } - return flags; - } - } - -} - diff --git a/src/main/java/makamys/lodmod/renderer/FarChunkCache.java b/src/main/java/makamys/lodmod/renderer/FarChunkCache.java deleted file mode 100644 index f4e3cca..0000000 --- a/src/main/java/makamys/lodmod/renderer/FarChunkCache.java +++ /dev/null @@ -1,12 +0,0 @@ -package makamys.lodmod.renderer; - -import net.minecraft.world.ChunkCache; -import net.minecraft.world.World; - -public class FarChunkCache extends ChunkCache { - - public FarChunkCache(World p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) { - super(p1, p2, p3, p4, p5, p6, p7, p8); - } - -} diff --git a/src/main/java/makamys/lodmod/renderer/FarWorldRenderer.java b/src/main/java/makamys/lodmod/renderer/FarWorldRenderer.java deleted file mode 100644 index 72eb4fd..0000000 --- a/src/main/java/makamys/lodmod/renderer/FarWorldRenderer.java +++ /dev/null @@ -1,14 +0,0 @@ -package makamys.lodmod.renderer; - -import java.util.List; - -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.world.World; - -public class FarWorldRenderer extends WorldRenderer { - - public FarWorldRenderer(World p1, List p2, int p3, int p4, int p5, int p6) { - super(p1, p2, p3, p4, p5, p6); - } - -} diff --git a/src/main/java/makamys/lodmod/renderer/GPUMemoryManager.java b/src/main/java/makamys/lodmod/renderer/GPUMemoryManager.java deleted file mode 100644 index 19d4dbe..0000000 --- a/src/main/java/makamys/lodmod/renderer/GPUMemoryManager.java +++ /dev/null @@ -1,215 +0,0 @@ -package makamys.lodmod.renderer; - -import static org.lwjgl.opengl.GL15.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -import makamys.lodmod.LODMod; -import makamys.lodmod.renderer.Mesh.GPUStatus; -import makamys.lodmod.util.GuiHelper; - -public class GPUMemoryManager { - - private int bufferSize; - - public int VBO; - - private int nextMesh; - - private List<Mesh> sentMeshes = new ArrayList<>(); - - public GPUMemoryManager() { - VBO = glGenBuffers(); - - bufferSize = LODMod.VRAMSize * 1024 * 1024; - - glBindBuffer(GL_ARRAY_BUFFER, VBO); - - glBufferData(GL_ARRAY_BUFFER, bufferSize, GL_DYNAMIC_DRAW); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - public void runGC(boolean full) { - glBindBuffer(GL_ARRAY_BUFFER, VBO); - - int moved = 0; - int timesReachedEnd = 0; - int checksLeft = sentMeshes.size(); - - while((!full && (moved < 4 && checksLeft-- > 0)) || (full && timesReachedEnd < 2) && !sentMeshes.isEmpty()) { - nextMesh++; - if(nextMesh >= sentMeshes.size()) { - nextMesh = 0; - timesReachedEnd++; - } - Mesh mesh = sentMeshes.get(nextMesh); - - if(mesh.gpuStatus == GPUStatus.SENT) { - int offset = nextMesh == 0 ? 0 : sentMeshes.get(nextMesh - 1).getEnd(); - if(mesh.offset != offset) { - glBufferSubData(GL_ARRAY_BUFFER, offset, mesh.buffer); - moved++; - } - mesh.iFirst = offset / mesh.getStride(); - mesh.offset = offset; - } else if(mesh.gpuStatus == GPUStatus.PENDING_DELETE) { - mesh.iFirst = mesh.offset = -1; - mesh.visible = false; - mesh.gpuStatus = GPUStatus.UNSENT; - - sentMeshes.remove(nextMesh); - - mesh.destroyBuffer(); - - if(nextMesh > 0) { - nextMesh--; - } - } - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - private int malloc(int size) { - int nextBase = 0; - if(!sentMeshes.isEmpty()) { - if(nextMesh < sentMeshes.size() - 1) { - Mesh next = sentMeshes.get(nextMesh); - Mesh nextnext = sentMeshes.get(nextMesh + 1); - if(nextnext.offset - next.getEnd() >= size) { - return next.getEnd(); - } - } - - nextBase = sentMeshes.get(sentMeshes.size() - 1).getEnd(); - } - - if(nextBase + size >= bufferSize) { - return -1; - } else { - return nextBase; - } - } - - private int end() { - return (sentMeshes.isEmpty() ? 0 : sentMeshes.get(sentMeshes.size() - 1).getEnd()); - } - - public void sendMeshToGPU(Mesh mesh) { - if(mesh == null || mesh.buffer == null) { - return; - } - - if(end() + mesh.bufferSize() >= bufferSize) { - runGC(true); - } - - if(end() + mesh.bufferSize() >= bufferSize) { - System.out.println("VRAM is full! Try increasing the allocated VRAM in the config, if possible. Reverting to vanilla renderer."); - LODMod.renderer.destroyPending = true; - // TODO restart renderer with more VRAM allocated when this happens. - return; - } - - int size = mesh.bufferSize(); - int insertIndex = -1; - - int nextBase = -1; - if(!sentMeshes.isEmpty()) { - if(nextMesh < sentMeshes.size() - 1) { - Mesh next = sentMeshes.get(nextMesh); - Mesh nextnext = null; - for(int i = nextMesh + 1; i < sentMeshes.size(); i++) { - Mesh m = sentMeshes.get(i); - if(m.gpuStatus == Mesh.GPUStatus.SENT) { - nextnext = m; - break; - } - } - if(nextnext != null && nextnext.offset - next.getEnd() >= size) { - nextBase = next.getEnd(); - insertIndex = nextMesh + 1; - } - } - - if(nextBase == -1) { - nextBase = sentMeshes.get(sentMeshes.size() - 1).getEnd(); - } - } - if(nextBase == -1) nextBase = 0; - - - if(mesh.gpuStatus == GPUStatus.UNSENT) { - mesh.prepareBuffer(); - - glBindBuffer(GL_ARRAY_BUFFER, VBO); - - glBufferSubData(GL_ARRAY_BUFFER, nextBase, mesh.buffer); - mesh.iFirst = nextBase / mesh.getStride(); - mesh.iCount = mesh.quadCount * 6; - mesh.offset = nextBase; - - if(insertIndex == -1) { - sentMeshes.add(mesh); - } else { - sentMeshes.add(insertIndex, mesh); - nextMesh = insertIndex; - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - mesh.gpuStatus = GPUStatus.SENT; - } - - public void deleteMeshFromGPU(Mesh mesh) { - if(mesh == null || mesh.gpuStatus == GPUStatus.UNSENT) { - return; - } - mesh.gpuStatus = GPUStatus.PENDING_DELETE; - } - - public void destroy() { - glDeleteBuffers(VBO); - } - - public List<String> getDebugText() { - return Arrays.asList("VRAM: " + (end() / 1024 / 1024) + "MB / " + (bufferSize / 1024 / 1024) + "MB"); - } - - public void drawInfo() { - int scale = 10000; - int rowLength = 512; - int yOff = 20; - - int height = (bufferSize / scale) / rowLength; - GuiHelper.drawRectangle(0, yOff, rowLength, height, 0x000000, 50); - - int meshI = 0; - for(Mesh mesh : sentMeshes) { - - int o = mesh.offset / 10000; - int o2 = (mesh.offset + mesh.bufferSize()) / 10000; - if(o / rowLength == o2 / rowLength) { - if(mesh.gpuStatus != Mesh.GPUStatus.PENDING_DELETE) { - GuiHelper.drawRectangle(o % rowLength, o / rowLength + yOff, mesh.buffer.limit() / scale + 1, 1, meshI == nextMesh ? 0x00FF00 : 0xFFFFFF); - } - } else { - for(int i = o; i < o2; i++) { - int x = i % rowLength; - int y = i / rowLength; - if(mesh.gpuStatus != Mesh.GPUStatus.PENDING_DELETE) { - GuiHelper.drawRectangle(x, y + yOff, 1, 1, 0xFFFFFF); - } - } - } - meshI++; - } - GuiHelper.drawRectangle(0 % rowLength, 0 + yOff, 4, 4, 0x00FF00); - GuiHelper.drawRectangle((bufferSize / scale) % rowLength, (bufferSize / scale) / rowLength + yOff, 4, 4, 0xFF0000); - } - -} diff --git a/src/main/java/makamys/lodmod/renderer/LODChunk.java b/src/main/java/makamys/lodmod/renderer/LODChunk.java deleted file mode 100644 index 2c5d61c..0000000 --- a/src/main/java/makamys/lodmod/renderer/LODChunk.java +++ /dev/null @@ -1,184 +0,0 @@ -package makamys.lodmod.renderer; - -import java.util.List; - -import makamys.lodmod.LODMod; -import net.minecraft.entity.Entity; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagEnd; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.world.chunk.Chunk; - -public class LODChunk { - - int x, z; - public boolean needsChunk = true; - int lod = 0; - boolean visible; - boolean dirty; - boolean discardedMesh; - - SimpleChunkMesh[] simpleMeshes = new SimpleChunkMesh[2]; - ChunkMesh[] chunkMeshes = new ChunkMesh[32]; - - public boolean[] isSectionVisible = new boolean[16]; - - LODRenderer renderer = LODMod.renderer; - - public LODChunk(int x, int z) { - this.x = x; - this.z = z; - } - /* - public LODChunk(NBTTagCompound nbt, List<String> spriteList) { - this.x = nbt.getInteger("x"); - this.z = nbt.getInteger("z"); - - loadChunkMeshesNBT(nbt.getCompoundTag("chunkMeshes"), spriteList); - } - - private void loadChunkMeshesNBT(NBTTagCompound chunkMeshesCompound, List<String> spriteList) { - for(Object o : chunkMeshesCompound.func_150296_c()) { - String key = (String)o; - int keyInt = Integer.parseInt(key); - - byte[] data = chunkMeshesCompound.getByteArray(key); - - chunkMeshes[keyInt] = new ChunkMesh(x, keyInt / 2, z, new ChunkMesh.Flags(true, true, true, false), data.length / (2 + 4 * (3 + 2 + 2 + 4)), data, spriteList, keyInt % 2); - } - } - */ - @Override - public String toString() { - return "LODChunk(" + x + ", " + z + ")"; - } - - public double distSq(Entity entity) { - return Math.pow(entity.posX - x * 16, 2) + Math.pow(entity.posZ - z * 16, 2); - } - - public void putChunkMeshes(int cy, List<ChunkMesh> newChunkMeshes) { - for(int i = 0; i < 2; i++) { - ChunkMesh newChunkMesh = newChunkMeshes.size() > i ? newChunkMeshes.get(i) : null; - if(chunkMeshes[cy * 2 + i] != null) { - if(newChunkMesh != null) { - newChunkMesh.pass = i; - } - - renderer.removeMesh(chunkMeshes[cy * 2 + i]); - chunkMeshes[cy * 2 + i].destroy(); - } - chunkMeshes[cy * 2 + i] = newChunkMesh; - } - LODMod.renderer.lodChunkChanged(this); - dirty = true; - discardedMesh = false; - } - - // nice copypasta - public void putSimpleMeshes(List<SimpleChunkMesh> newSimpleMeshes) { - for(int i = 0; i < 2; i++) { - SimpleChunkMesh newSimpleMesh = newSimpleMeshes.size() > i ? newSimpleMeshes.get(i) : null; - if(simpleMeshes[i] != null) { - if(newSimpleMesh != null) { - newSimpleMesh.pass = i; - } - - renderer.setMeshVisible(simpleMeshes[i], false); - simpleMeshes[i].destroy(); - } - simpleMeshes[i] = newSimpleMesh; - } - LODMod.renderer.lodChunkChanged(this); - } - - public boolean hasChunkMeshes() { - for(ChunkMesh cm : chunkMeshes) { - if(cm != null) { - return true; - } - } - return false; - } - - public void tick(Entity player) { - double distSq = distSq(player); - if(LODMod.disableSimpleMeshes || distSq < Math.pow((LODMod.renderer.renderRange / 2) * 16, 2)) { - setLOD(2); - } else if(distSq < Math.pow((LODMod.renderer.renderRange) * 16, 2)) { - setLOD(1); - } else { - setLOD(0); - } - } - - public void setLOD(int lod) { - if(lod == this.lod) return; - - this.lod = lod; - LODMod.renderer.lodChunkChanged(this); - if(!dirty) { - if(lod < 2) { - for(int i = 0; i < chunkMeshes.length; i++) { - if(chunkMeshes[i] != null) { - chunkMeshes[i].destroy(); - chunkMeshes[i] = null; - discardedMesh = true; - } - } - } - } - } - /* - public NBTTagCompound saveToNBT(NBTTagCompound oldNbt, List<String> oldStringTable) { - NBTTagCompound nbt = new NBTTagCompound(); - nbt.setInteger("x", x); - nbt.setInteger("z", z); - - NBTTagCompound chunkMeshesCompound = oldNbt == null ? new NBTTagCompound() : oldNbt.getCompoundTag("chunkMeshes"); - if(!discardedMesh) { - for(int i = 0; i < chunkMeshes.length; i++) { - if(chunkMeshes[i] != null) { - chunkMeshesCompound.setTag(String.valueOf(i), chunkMeshes[i].nbtData); - } - } - } else if(oldNbt != null && discardedMesh && lod == 2) { - loadChunkMeshesNBT(chunkMeshesCompound, oldStringTable); - LODMod.renderer.lodChunkChanged(this); - } - nbt.setTag("chunkMeshes", chunkMeshesCompound); - dirty = false; - return nbt; - } - */ - public void destroy() { - for(SimpleChunkMesh scm: simpleMeshes) { - if(scm != null) { - scm.destroy(); - } - } - for(ChunkMesh cm: chunkMeshes) { - if(cm != null) { - cm.destroy(); - } - } - LODMod.renderer.setVisible(this, false); - } - - public void receiveChunk(Chunk chunk) { - if(!LODMod.disableSimpleMeshes) { - putSimpleMeshes(SimpleChunkMesh.generateSimpleMeshes(chunk)); - } - } - - public boolean isFullyVisible() { - if(!visible) return false; - for(boolean b : isSectionVisible) { - if(!b) { - return false; - } - } - return true; - } - -} diff --git a/src/main/java/makamys/lodmod/renderer/LODRegion.java b/src/main/java/makamys/lodmod/renderer/LODRegion.java deleted file mode 100644 index 9fdaa89..0000000 --- a/src/main/java/makamys/lodmod/renderer/LODRegion.java +++ /dev/null @@ -1,195 +0,0 @@ -package makamys.lodmod.renderer; - -import java.io.BufferedOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import makamys.lodmod.LODMod; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.TextureMap; -import net.minecraft.entity.Entity; -import net.minecraft.nbt.CompressedStreamTools; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.world.chunk.Chunk; -import net.minecraftforge.common.util.Constants.NBT; - -public class LODRegion { - - private LODChunk[][] data = new LODChunk[32][32]; - - int regionX, regionZ; - - public LODRegion(int regionX, int regionZ) { - this.regionX = regionX; - this.regionZ = regionZ; - - for(int i = 0; i < 32; i++) { - for(int j = 0; j < 32; j++) { - data[i][j] = new LODChunk(regionX * 32 + i, regionZ * 32 + j); - } - } - } - /* - public LODRegion(int regionX, int regionZ, NBTTagCompound nbt) { - this.regionX = regionX; - this.regionZ = regionZ; - - NBTTagList list = nbt.getTagList("chunks", NBT.TAG_COMPOUND); - List<String> stringTable = Arrays.asList(nbt.getString("stringTable").split("\\n")); - - int idx = 0; - for(int i = 0; i < 32; i++) { - for(int j = 0; j < 32; j++) { - data[i][j] = new LODChunk(list.getCompoundTagAt(idx++), stringTable); - if(data[i][j].hasChunkMeshes()) { - LODMod.renderer.setVisible(data[i][j], true); - } - } - } - } - */ - public static LODRegion load(Path saveDir, int regionX, int regionZ) { - /*if(!(LODMod.disableChunkMeshes || !LODMod.saveMeshes)) { - File saveFile = getSavePath(saveDir, regionX, regionZ).toFile(); - if(saveFile.exists()) { - try { - NBTTagCompound nbt = CompressedStreamTools.readCompressed(new FileInputStream(saveFile)); - return new LODRegion(regionX, regionZ, nbt); - } catch (Exception e) { - e.printStackTrace(); - } - } - }*/ - return new LODRegion(regionX, regionZ); - } - /* - private static Path getSavePath(Path saveDir, int regionX, int regionZ) { - return saveDir.resolve("lod").resolve(regionX + "," + regionZ + ".lod"); - } - - public void save(Path saveDir) { - if(LODMod.disableChunkMeshes || !LODMod.saveMeshes) return; - - try { - File saveFile = getSavePath(saveDir, regionX, regionZ).toFile(); - saveFile.getParentFile().mkdirs(); - - NBTTagCompound oldNbt = null; - NBTTagList oldList = null; - List<String> oldStringTable = null; - if(saveFile.exists()) { - oldNbt = CompressedStreamTools.readCompressed(new FileInputStream(saveFile)); - oldList = oldNbt.getTagList("chunks", NBT.TAG_COMPOUND);; - oldStringTable = Arrays.asList(oldNbt.getString("stringTable").split("\\n")); - } - - NBTTagCompound nbt = new NBTTagCompound(); - nbt.setByte("V", (byte)0); - nbt.setString("stringTable", String.join("\n", (List<String>) ((TextureMap)Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture)).mapUploadedSprites.keySet().stream().collect(Collectors.toList()))); - - NBTTagList list = new NBTTagList(); - - int idx = 0; - for(int i = 0; i < 32; i++) { - for(int j = 0; j < 32; j++) { - list.appendTag(data[i][j].saveToNBT(oldNbt == null ? null : oldList.getCompoundTagAt(idx++), - oldNbt == null? null : oldStringTable)); - } - } - nbt.setTag("chunks", list); - - new Thread( - new Runnable() { - - @Override - public void run() { - try { - CompressedStreamTools.writeCompressed(nbt, new FileOutputStream(saveFile)); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - }).start(); - - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - */ - public LODChunk getChunkAbsolute(int chunkXAbs, int chunkZAbs) { - return getChunk(chunkXAbs - regionX * 32, chunkZAbs - regionZ * 32); - } - - public LODChunk getChunk(int x, int z) { - if(x >= 0 && x < 32 && z >= 0 && z < 32) { - return data[x][z]; - } else { - return null; - } - } - - public LODChunk putChunk(Chunk chunk) { - int relX = chunk.xPosition - regionX * 32; - int relZ = chunk.zPosition - regionZ * 32; - - if(relX >= 0 && relX < 32 && relZ >= 0 && relZ < 32) { - data[relX][relZ].receiveChunk(chunk); - return data[relX][relZ]; - } - return null; - } - - public boolean tick(Entity player) { - int visibleChunks = 0; - for(int i = 0; i < 32; i++) { - for(int j = 0; j < 32; j++) { - LODChunk chunk = data[i][j]; - if(chunk != null) { - chunk.tick(player); - if(chunk.visible) { - visibleChunks++; - } - } - } - } - return visibleChunks > 0; - } - - public void destroy(Path saveDir) { - //save(saveDir); - for(int i = 0; i < 32; i++) { - for(int j = 0; j < 32; j++) { - LODChunk chunk = data[i][j]; - if(chunk != null) { - chunk.destroy(); - } - } - } - } - - public double distanceTaxicab(Entity entity) { - double centerX = ((regionX * 32) + 16) * 16; - double centerZ = ((regionZ * 32) + 16) * 16; - - return Math.max(Math.abs(centerX - entity.posX), Math.abs(centerZ - entity.posZ)); - - } - - @Override - public String toString() { - return "LODRegion(" + regionX + ", " + regionZ + ")"; - } - -} diff --git a/src/main/java/makamys/lodmod/renderer/LODRenderer.java b/src/main/java/makamys/lodmod/renderer/LODRenderer.java deleted file mode 100644 index 3420c34..0000000 --- a/src/main/java/makamys/lodmod/renderer/LODRenderer.java +++ /dev/null @@ -1,730 +0,0 @@ -package makamys.lodmod.renderer; - -import net.minecraft.block.Block; -import net.minecraft.block.material.Material; -import net.minecraft.client.Minecraft; -import net.minecraft.client.particle.EntityFX; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureMap; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.util.EnumFacing; -import net.minecraft.world.ChunkCoordIntPair; -import net.minecraft.world.IBlockAccess; -import net.minecraft.world.World; -import net.minecraft.world.biome.BiomeGenBase; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.gen.ChunkProviderServer; -import net.minecraftforge.event.world.ChunkEvent; - -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; - -import org.apache.commons.lang3.ArrayUtils; -import org.lwjgl.BufferUtils; -import org.lwjgl.input.Keyboard; -import org.lwjgl.opengl.GL11; -import org.lwjgl.util.vector.Matrix4f; - -import makamys.lodmod.LODMod; -import makamys.lodmod.ducks.IWorldRenderer; -import makamys.lodmod.renderer.Mesh.GPUStatus; -import makamys.lodmod.util.GuiHelper; -import makamys.lodmod.util.Util; - -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.opengl.GL14.*; -import static org.lwjgl.opengl.GL15.*; -import static org.lwjgl.opengl.GL20.*; -import static org.lwjgl.opengl.GL30.*; - -public class LODRenderer { - - public boolean hasInited = false; - public boolean destroyPending; - - private boolean[] wasDown = new boolean[256]; - private int renderQuads = 0; - - public boolean renderWorld; - public boolean rendererActive; - private boolean showMemoryDebugger; - - private static int MAX_MESHES = 100000; - - private int VAO, shaderProgram; - private IntBuffer[] piFirst = new IntBuffer[2]; - private IntBuffer[] piCount = new IntBuffer[2]; - private List<Mesh>[] sentMeshes = (List<Mesh>[])new ArrayList[] {new ArrayList<Mesh>(), new ArrayList<Mesh>()}; - GPUMemoryManager mem; - - List<Chunk> myChunks = new ArrayList<Chunk>(); - List<LODChunk> pendingLODChunks = new ArrayList<>(); - - private boolean hasServerInited = false; - private Map<ChunkCoordIntPair, LODRegion> loadedRegionsMap = new HashMap<>(); - - public World world; - - // TODO make these packets to make this work on dedicated servers - Queue<Chunk> farChunks = new ConcurrentLinkedQueue<>(); - - List<ChunkCoordIntPair> serverChunkLoadQueue = new ArrayList<>(); - - private double lastSortX = Double.NaN; - private double lastSortY = Double.NaN; - private double lastSortZ = Double.NaN; - - private long lastGCTime = -1; - private long lastSaveTime = -1; - private long gcInterval = 10 * 1000; - private long saveInterval = 60 * 1000; - - private int renderedMeshes; - private int frameCount; - - public int renderRange = 48; - - private boolean freezeMeshes; - - public LODRenderer(World world){ - this.world = world; - if(shouldRenderInWorld(world)) { - hasInited = init(); - } - - renderWorld = true; - rendererActive = true; - } - - public void preRenderSortedRenderers(int renderPass, double alpha, WorldRenderer[] sortedWorldRenderers) { - if(renderPass != 0) return; - - LODMod.fogEventWasPosted = false; - - renderedMeshes = 0; - - Minecraft.getMinecraft().entityRenderer.enableLightmap((double)alpha); - - if(hasInited) { - mainLoop(); - if(Minecraft.getMinecraft().currentScreen == null) { - handleKeyboard(); - } - if(frameCount % 2 == 0) { - mem.runGC(false); - } - lastGCTime = System.currentTimeMillis(); - if(lastSaveTime == -1 || (System.currentTimeMillis() - lastSaveTime) > saveInterval && LODMod.saveMeshes) { - onSave(); - lastSaveTime = System.currentTimeMillis(); - } - - if(rendererActive && renderWorld) { - if(frameCount % LODMod.sortFrequency == 0) { - sort(); - } - - updateMeshes(); - initIndexBuffers(); - render(alpha); - } - } - - frameCount++; - - Minecraft.getMinecraft().entityRenderer.disableLightmap((double)alpha); - } - - public void onRenderTickEnd() { - if(destroyPending) { - LODMod.renderer = null; - return; - } - if(showMemoryDebugger && mem != null) { - GuiHelper.begin(); - mem.drawInfo(); - GuiHelper.end(); - } - } - - private void sort() { - Entity player = Minecraft.getMinecraft().renderViewEntity; - for(List<Mesh> list : sentMeshes) { - list.sort(new MeshDistanceComparator(player.posX / 16, player.posY / 16, player.posZ / 16)); - } - } - - private void updateMeshes() { - for(List<Mesh> list : sentMeshes) { - for(Mesh mesh : list) { - mesh.update(); - } - } - } - - private void initIndexBuffers() { - for(int i = 0; i < 2; i++) { - piFirst[i].limit(sentMeshes[i].size()); - piCount[i].limit(sentMeshes[i].size()); - for(Mesh mesh : sentMeshes[i]) { - if(mesh.visible && (LODMod.maxMeshesPerFrame == -1 || renderedMeshes < LODMod.maxMeshesPerFrame)) { - renderedMeshes++; - piFirst[i].put(mesh.iFirst); - piCount[i].put(mesh.iCount); - } - } - piFirst[i].flip(); - piCount[i].flip(); - } - } - - private void mainLoop() { - while(!farChunks.isEmpty()) { - LODChunk lodChunk = receiveFarChunk(farChunks.remove()); - sendChunkToGPU(lodChunk); - } - - if(Minecraft.getMinecraft().playerController.netClientHandler.doneLoadingTerrain) { - Entity player = Minecraft.getMinecraft().renderViewEntity; - - List<ChunkCoordIntPair> newServerChunkLoadQueue = new ArrayList<>(); - - if(Double.isNaN(lastSortX) || getLastSortDistanceSq(player) > 16 * 16) { - int centerX = (int)Math.floor(player.posX / 16.0); - int centerZ = (int)Math.floor(player.posZ / 16.0); - - for(int x = -renderRange; x <= renderRange; x++) { - for(int z = -renderRange; z <= renderRange; z++) { - if(x * x + z * z < renderRange * renderRange) { - int chunkX = centerX + x; - int chunkZ = centerZ + z; - - if(getLODChunk(chunkX, chunkZ).needsChunk) { - newServerChunkLoadQueue.add(new ChunkCoordIntPair(chunkX, chunkZ)); - getLODChunk(chunkX, chunkZ).needsChunk = false; - } - } - } - } - Collections.sort(newServerChunkLoadQueue, new ChunkCoordDistanceComparator(player.posX, player.posY, player.posZ)); - addToServerChunkLoadQueue(newServerChunkLoadQueue); - - lastSortX = player.posX; - lastSortY = player.posY; - lastSortZ = player.posZ; - for(Iterator<ChunkCoordIntPair> it = loadedRegionsMap.keySet().iterator(); it.hasNext();) { - ChunkCoordIntPair k = it.next(); - LODRegion v = loadedRegionsMap.get(k); - - if(v.distanceTaxicab(player) > renderRange * 16 + 16 * 16) { - System.out.println("unloading " + v); - v.destroy(getSaveDir()); - it.remove(); - } else { - v.tick(player); - } - } - } - } - } - - public float getFarPlaneDistanceMultiplier() { - return (float)LODMod.farPlaneDistanceMultiplier; - } - - public void afterSetupFog(int mode, float alpha, float farPlaneDistance) { - EntityLivingBase entity = Minecraft.getMinecraft().renderViewEntity; - if(LODMod.fogEventWasPosted && !Minecraft.getMinecraft().theWorld.provider.doesXZShowFog((int)entity.posX, (int)entity.posZ)) { - GL11.glFogf(GL11.GL_FOG_START, mode < 0 ? 0 : farPlaneDistance * (float)LODMod.fogStart); - GL11.glFogf(GL11.GL_FOG_END, mode < 0 ? farPlaneDistance/4 : farPlaneDistance * (float)LODMod.fogEnd); - } - } - - private void handleKeyboard() { - if(LODMod.debugPrefix == 0 || (LODMod.debugPrefix != -1 && Keyboard.isKeyDown(LODMod.debugPrefix))) { - if(Keyboard.isKeyDown(Keyboard.KEY_F) && !wasDown[Keyboard.KEY_F]) { - rendererActive = !rendererActive; - } - if(Keyboard.isKeyDown(Keyboard.KEY_V) && !wasDown[Keyboard.KEY_V]) { - renderWorld = !renderWorld; - } - if(Keyboard.isKeyDown(Keyboard.KEY_R) && !wasDown[Keyboard.KEY_R]) { - loadShader(); - } - if(Keyboard.isKeyDown(Keyboard.KEY_M) && !wasDown[Keyboard.KEY_M]) { - showMemoryDebugger = !showMemoryDebugger; - //LODChunk chunk = getLODChunk(9, -18); - //setMeshVisible(chunk.chunkMeshes[7], false, true); - //freezeMeshes = false; - //chunk.chunkMeshes[7].quadCount = 256; - //setMeshVisible(chunk.chunkMeshes[7], true, true); - } - } - for(int i = 0; i < 256; i++) { - wasDown[i] = Keyboard.isKeyDown(i); - } - } - - FloatBuffer modelView = BufferUtils.createFloatBuffer(16); - FloatBuffer projBuf = BufferUtils.createFloatBuffer(16); - IntBuffer viewportBuf = BufferUtils.createIntBuffer(16); - FloatBuffer projInvBuf = BufferUtils.createFloatBuffer(16); - FloatBuffer fogColorBuf = BufferUtils.createFloatBuffer(16); - FloatBuffer fogStartEnd = BufferUtils.createFloatBuffer(2); - Matrix4f projMatrix = new Matrix4f(); - - private void render(double alpha) { - GL11.glPushAttrib(GL11.GL_ENABLE_BIT); - GL11.glDisable(GL11.GL_TEXTURE_2D); - - glUseProgram(shaderProgram); - - int u_modelView = glGetUniformLocation(shaderProgram, "modelView"); - int u_proj = glGetUniformLocation(shaderProgram, "proj"); - int u_playerPos = glGetUniformLocation(shaderProgram, "playerPos"); - int u_light = glGetUniformLocation(shaderProgram, "lightTex"); - int u_viewport = glGetUniformLocation(shaderProgram, "viewport"); - int u_projInv = glGetUniformLocation(shaderProgram, "projInv"); - int u_fogColor = glGetUniformLocation(shaderProgram, "fogColor"); - int u_fogStartEnd = glGetUniformLocation(shaderProgram, "fogStartEnd"); - - if(false && (u_modelView == -1 || u_proj == -1 || u_playerPos == -1 || u_light == -1 || u_viewport == -1 || u_projInv == -1 || u_fogColor == -1 || u_fogStartEnd == -1)) { - System.out.println("failed to get the uniform"); - } else { - glGetFloat(GL_MODELVIEW_MATRIX, modelView); - - glGetFloat(GL_PROJECTION_MATRIX, projBuf); - - glGetInteger(GL_VIEWPORT, viewportBuf); - - projMatrix.load(projBuf); - projBuf.flip(); - projMatrix.invert(); - projMatrix.store(projInvBuf); - projInvBuf.flip(); - - fogColorBuf.limit(16); - glGetFloat(GL_FOG_COLOR, fogColorBuf); - fogColorBuf.limit(4); - - fogStartEnd.put(glGetFloat(GL_FOG_START)); - fogStartEnd.put(glGetFloat(GL_FOG_END)); - fogStartEnd.flip(); - - glUniformMatrix4(u_modelView, false, modelView); - glUniformMatrix4(u_proj, false, projBuf); - glUniformMatrix4(u_projInv, false, projInvBuf); - glUniform4f(u_viewport, viewportBuf.get(0),viewportBuf.get(1),viewportBuf.get(2),viewportBuf.get(3)); - glUniform4(u_fogColor, fogColorBuf); - glUniform2(u_fogStartEnd, fogStartEnd); - - float originX = 0; - float originY = 0; - float originZ = 0; - - Entity rve = Minecraft.getMinecraft().renderViewEntity; - double interpX = rve.lastTickPosX + (rve.posX - rve.lastTickPosX) * alpha; - double interpY = rve.lastTickPosY + (rve.posY - rve.lastTickPosY) * alpha + rve.getEyeHeight(); - double interpZ = rve.lastTickPosZ + (rve.posZ - rve.lastTickPosZ) * alpha; - - glUniform3f(u_playerPos, (float)interpX - originX, (float)interpY - originY, (float)interpZ - originZ); - - glUniform1i(u_light, 1); - - modelView.position(0); - projBuf.position(0); - viewportBuf.position(0); - projInvBuf.position(0); - fogColorBuf.position(0); - fogStartEnd.position(0); - } - - glBindVertexArray(VAO); - GL11.glDisable(GL11.GL_BLEND); - glMultiDrawArrays(GL_TRIANGLES, piFirst[0], piCount[0]); - GL11.glEnable(GL11.GL_BLEND); - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - glMultiDrawArrays(GL_TRIANGLES, piFirst[1], piCount[1]); - - glBindVertexArray(0); - glUseProgram(0); - - GL11.glDepthMask(true); - GL11.glPopAttrib(); - - - } - - public boolean init() { - Map<String, TextureAtlasSprite> uploadedSprites = ((TextureMap)Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture)).mapUploadedSprites; - - loadShader(); - - VAO = glGenVertexArrays(); - glBindVertexArray(VAO); - - mem = new GPUMemoryManager(); - - glBindBuffer(GL_ARRAY_BUFFER, mem.VBO); - - int stride = 7 * 4; - - glVertexAttribPointer(0, 3, GL_FLOAT, false, stride, 0); - glVertexAttribPointer(1, 2, GL_FLOAT, false, stride, 3 * 4); - glVertexAttribPointer(2, 2, GL_SHORT, false, stride, 5 * 4); - glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, false, stride, 6 * 4); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glEnableVertexAttribArray(3); - - for(int i = 0; i < 2; i++) { - piFirst[i] = BufferUtils.createIntBuffer(MAX_MESHES); - piFirst[i].flip(); - piCount[i] = BufferUtils.createIntBuffer(MAX_MESHES); - piCount[i].flip(); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - return true; - } - - private void loadShader() { - int vertexShader; - vertexShader = glCreateShader(GL_VERTEX_SHADER); - - glShaderSource(vertexShader, Util.readFile("shaders/chunk.vert")); - glCompileShader(vertexShader); - - if(glGetShaderi(vertexShader, GL_COMPILE_STATUS) == 0) { - System.out.println("Error compiling vertex shader: " + glGetShaderInfoLog(vertexShader, 256)); - } - - int fragmentShader; - fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - glShaderSource(fragmentShader, Util.readFile(LODMod.enableFog ? "shaders/chunk_fog.frag" : "shaders/chunk.frag")); - glCompileShader(fragmentShader); - - if(glGetShaderi(fragmentShader, GL_COMPILE_STATUS) == 0) { - System.out.println("Error compiling fragment shader: " + glGetShaderInfoLog(fragmentShader, 256)); - } - - shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, vertexShader); - glAttachShader(shaderProgram, fragmentShader); - glLinkProgram(shaderProgram); - - if(glGetProgrami(shaderProgram, GL_LINK_STATUS) == 0) { - System.out.println("Error linking shader: " + glGetShaderInfoLog(shaderProgram, 256)); - } - - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - } - - public void destroy() { - onSave(); - - glDeleteProgram(shaderProgram); - glDeleteVertexArrays(VAO); - mem.destroy(); - - SimpleChunkMesh.instances = 0; - SimpleChunkMesh.usedRAM = 0; - ChunkMesh.instances = 0; - ChunkMesh.usedRAM = 0; - } - - public void onWorldRendererChanged(WorldRenderer wr, WorldRendererChange change) { - int x = Math.floorDiv(wr.posX, 16); - int y = Math.floorDiv(wr.posY, 16); - int z = Math.floorDiv(wr.posZ, 16); - LODChunk lodChunk = getLODChunk(x, z); - - lodChunk.isSectionVisible[y] = change == WorldRendererChange.VISIBLE; - if(change == WorldRendererChange.DELETED) { - removeMesh(lodChunk.chunkMeshes[y]); - } - lodChunkChanged(lodChunk); - } - - public void onWorldRendererPost(WorldRenderer wr) { - if(LODMod.disableChunkMeshes) return; - - int x = Math.floorDiv(wr.posX, 16); - int y = Math.floorDiv(wr.posY, 16); - int z = Math.floorDiv(wr.posZ, 16); - - if(Minecraft.getMinecraft().theWorld.getChunkFromChunkCoords(x, z).isChunkLoaded) { - LODChunk lodChunk = getLODChunk(x, z); - lodChunk.isSectionVisible[y] = ((IWorldRenderer)wr).isDrawn(); - lodChunk.putChunkMeshes(y, ((IWorldRenderer)wr).getChunkMeshes()); - } - } - - private double getLastSortDistanceSq(Entity player) { - return Math.pow(lastSortX - player.posX, 2) + Math.pow(lastSortZ - player.posZ, 2); - } - - private synchronized void addToServerChunkLoadQueue(List<ChunkCoordIntPair> coords) { - serverChunkLoadQueue.addAll(coords); - } - - private LODChunk receiveFarChunk(Chunk chunk) { - LODRegion region = getRegionContaining(chunk.xPosition, chunk.zPosition); - return region.putChunk(chunk); - } - - private LODChunk getLODChunk(int chunkX, int chunkZ) { - return getRegionContaining(chunkX, chunkZ).getChunkAbsolute(chunkX, chunkZ); - } - - public void onStopServer() { - - } - - public synchronized void serverTick() { - int chunkLoadsRemaining = LODMod.chunkLoadsPerTick; - while(!serverChunkLoadQueue.isEmpty() && chunkLoadsRemaining-- > 0) { - ChunkCoordIntPair coords = serverChunkLoadQueue.remove(0); - ChunkProviderServer chunkProviderServer = Minecraft.getMinecraft().getIntegratedServer().worldServerForDimension(world.provider.dimensionId).theChunkProviderServer; - Chunk chunk = chunkProviderServer.currentChunkProvider.provideChunk(coords.chunkXPos, coords.chunkZPos); - SimpleChunkMesh.prepareFarChunkOnServer(chunk); - farChunks.add(chunk); - } - } - - private LODRegion getRegionContaining(int chunkX, int chunkZ) { - ChunkCoordIntPair key = new ChunkCoordIntPair(Math.floorDiv(chunkX , 32), Math.floorDiv(chunkZ, 32)); - LODRegion region = loadedRegionsMap.get(key); - if(region == null) { - region = LODRegion.load(getSaveDir(), Math.floorDiv(chunkX , 32), Math.floorDiv(chunkZ , 32)); - loadedRegionsMap.put(key, region); - } - return region; - } - - private void sendChunkToGPU(LODChunk lodChunk) { - Entity player = Minecraft.getMinecraft().renderViewEntity; - - lodChunk.tick(player); - setVisible(lodChunk, true, true); - } - - public void setVisible(LODChunk chunk, boolean visible) { - setVisible(chunk, visible, false); - } - - public void setVisible(LODChunk lodChunk, boolean visible, boolean forceCheck) { - if(!forceCheck && visible == lodChunk.visible) return; - - lodChunk.visible = visible; - lodChunkChanged(lodChunk); - } - - public void lodChunkChanged(LODChunk lodChunk) { - int newLOD = (!lodChunk.hasChunkMeshes() && lodChunk.lod == 2) ? (LODMod.disableSimpleMeshes ? 0 : 1) : lodChunk.lod; - for(SimpleChunkMesh sm : lodChunk.simpleMeshes) { - if(sm != null) { - if(lodChunk.isFullyVisible() && newLOD == 1) { - if(!sm.visible) { - setMeshVisible(sm, true); - } - } else { - if(sm.visible) { - setMeshVisible(sm, false); - } - } - } - } - for(int y = 0; y < 16; y++) { - for(int pass = 0; pass < 2; pass++) { - ChunkMesh cm = lodChunk.chunkMeshes[y * 2 + pass]; - if(cm != null) { - if(lodChunk.isSectionVisible[y] && newLOD == 2) { - if(!cm.visible) { - setMeshVisible(cm, true); - } - } else { - if(cm.visible) { - setMeshVisible(cm, false); - } - } - } - } - } - } - - protected void setMeshVisible(Mesh mesh, boolean visible) { - setMeshVisible(mesh, visible, false); - } - - protected void setMeshVisible(Mesh mesh, boolean visible, boolean force) { - if((!force && freezeMeshes) || mesh == null) return; - - if(mesh.visible != visible) { - mesh.visible = visible; - - if(mesh.gpuStatus == GPUStatus.UNSENT) { - mem.sendMeshToGPU(mesh); - sentMeshes[mesh.pass].add(mesh); - } - } - } - - public void removeMesh(Mesh mesh) { - if(mesh == null) return; - - mem.deleteMeshFromGPU(mesh); - sentMeshes[mesh.pass].remove(mesh); - setMeshVisible(mesh, false); - } - - public Chunk getChunkFromChunkCoords(int x, int z) { - for(Chunk chunk : myChunks) { - if(chunk.xPosition == x && chunk.zPosition == z) { - return chunk; - } - } - return null; - } - - public boolean shouldSideBeRendered(Block block, IBlockAccess ba, int x, int y, int z, int w) { - EnumFacing facing = EnumFacing.values()[w]; - if(block.getMaterial() == Material.water && facing != EnumFacing.UP && facing != EnumFacing.DOWN && !Minecraft.getMinecraft().theWorld.getChunkFromBlockCoords(x, z).isChunkLoaded) { - return false; - } else { - return block.shouldSideBeRendered(ba, x, y, z, w); - } - } - - public List<String> getDebugText() { - List<String> text = new ArrayList<>(); - text.addAll(mem.getDebugText()); - text.addAll(Arrays.asList( - "Simple meshes: " + SimpleChunkMesh.instances + " (" + SimpleChunkMesh.usedRAM / 1024 / 1024 + "MB)", - "Full meshes: " + ChunkMesh.instances + " (" + ChunkMesh.usedRAM / 1024 / 1024 + "MB)", - "Total RAM used: " + ((SimpleChunkMesh.usedRAM + ChunkMesh.usedRAM) / 1024 / 1024) + " MB", - "Rendered: " + renderedMeshes - )); - return text; - } - - public void onSave() { - System.out.println("Saving LOD regions..."); - long t0 = System.currentTimeMillis(); - //loadedRegionsMap.forEach((k, v) -> v.save(getSaveDir())); - System.out.println("Finished saving LOD regions in " + ((System.currentTimeMillis() - t0) / 1000.0) + "s"); - } - - public void onChunkLoad(ChunkEvent.Load event) { - farChunks.add(event.getChunk()); - } - - private Path getSaveDir(){ - return Minecraft.getMinecraft().mcDataDir.toPath().resolve("lodmod").resolve(Minecraft.getMinecraft().getIntegratedServer().getFolderName()); - } - - private boolean shouldRenderInWorld(World world) { - return world != null && !world.provider.isHellWorld; - } - - public static class LODChunkComparator implements Comparator<LODChunk> { - Entity player; - - public LODChunkComparator(Entity player) { - this.player = player; - } - - @Override - public int compare(LODChunk p1, LODChunk p2) { - int distSq1 = distSq(p1); - int distSq2 = distSq(p2); - return distSq1 < distSq2 ? -1 : distSq1 > distSq2 ? 1 : 0; - } - - int distSq(LODChunk p) { - return (int)( - Math.pow(((p.x * 16) - player.chunkCoordX), 2) + - Math.pow(((p.z * 16) - player.chunkCoordZ), 2) - ); - } - } - - public static class ChunkCoordDistanceComparator implements Comparator<ChunkCoordIntPair> { - double x, y, z; - - public ChunkCoordDistanceComparator(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; - } - - @Override - public int compare(ChunkCoordIntPair p1, ChunkCoordIntPair p2) { - int distSq1 = distSq(p1); - int distSq2 = distSq(p2); - return distSq1 < distSq2 ? -1 : distSq1 > distSq2 ? 1 : 0; - } - - int distSq(ChunkCoordIntPair p) { - return (int)( - Math.pow(((p.chunkXPos * 16) - x), 2) + - Math.pow(((p.chunkZPos * 16) - z), 2) - ); - } - } - - public static class MeshDistanceComparator implements Comparator<Mesh> { - double x, y, z; - - MeshDistanceComparator(double x, double y, double z){ - this.x = x; - this.y = y; - this.z = z; - } - - @Override - public int compare(Mesh a, Mesh b) { - if(a.pass < b.pass) { - return -1; - } else if(a.pass > b.pass) { - return 1; - } else { - double distSqA = a.distSq(x, y, z); - double distSqB = b.distSq(x, y, z); - if(distSqA > distSqB) { - return 1; - } else if(distSqA < distSqB) { - return -1; - } else { - return 0; - } - } - } - - } - - public static enum WorldRendererChange { - VISIBLE, INVISIBLE, DELETED - } -}
\ No newline at end of file diff --git a/src/main/java/makamys/lodmod/renderer/Mesh.java b/src/main/java/makamys/lodmod/renderer/Mesh.java deleted file mode 100644 index fb1b8f1..0000000 --- a/src/main/java/makamys/lodmod/renderer/Mesh.java +++ /dev/null @@ -1,44 +0,0 @@ -package makamys.lodmod.renderer; - -import java.nio.ByteBuffer; -import java.nio.IntBuffer; - -import makamys.lodmod.util.Util; -import net.minecraft.entity.Entity; -import net.minecraft.nbt.NBTBase; - -public abstract class Mesh { - - /** Can be null, unless gpuStatus is SENT */ - public ByteBuffer buffer; - public int quadCount; - public boolean visible; - public GPUStatus gpuStatus = GPUStatus.UNSENT; - public int iFirst = -1, iCount = -1; - public int offset = -1; - public int pass; - int x, y, z; - - public abstract int getStride(); - - public double distSq(double x2, double y2, double z2) { - return Util.distSq(x, y, z, x2, y2, z2); - } - - public int bufferSize() { - return buffer == null ? 0 : buffer.limit(); - } - - public int getEnd() { - return offset + bufferSize(); - } - - public void prepareBuffer() {} - public void destroyBuffer() {} - - public void update() {} - - public static enum GPUStatus { - UNSENT, SENT, PENDING_DELETE - } -} diff --git a/src/main/java/makamys/lodmod/renderer/MeshQuad.java b/src/main/java/makamys/lodmod/renderer/MeshQuad.java deleted file mode 100644 index 48f0a12..0000000 --- a/src/main/java/makamys/lodmod/renderer/MeshQuad.java +++ /dev/null @@ -1,426 +0,0 @@ -package makamys.lodmod.renderer; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Comparator; -import java.util.Locale; -import java.util.Map; - -import makamys.lodmod.renderer.MeshQuad.QuadPlaneComparator; -import makamys.lodmod.util.SpriteUtil; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureMap; -import net.minecraft.util.EnumFacing; - -public class MeshQuad { - public int spriteIndex; - public String spriteName; - public int[] xs = new int[4]; - public int[] ys = new int[4]; - public int[] zs = new int[4]; - public int baseX = -1, baseY, baseZ; - public int minX = Integer.MAX_VALUE; - public int minY = Integer.MAX_VALUE; - public int minZ = Integer.MAX_VALUE; - public int maxX = Integer.MIN_VALUE; - public int maxY = Integer.MIN_VALUE; - public int maxZ = Integer.MIN_VALUE; - public int[] relUs = new int[4]; - public int[] relVs = new int[4]; - public int[] bUs = new int[4]; - public int[] bVs = new int[4]; - public int[] cs = new int[4]; - public int[] normals = new int[4]; - public boolean deleted; - public boolean isFullQuad; - - public static final int PLANE_NONE = -1, PLANE_XY = 0, PLANE_XZ = 1, PLANE_YZ = 2; - public int plane = PLANE_NONE; - public int offset; - public ChunkMesh.Flags flags; - - public static int[] totalMergeCountByPlane = new int[3]; - - private int minPositive(int a, int b) { - if(a == -1) { - return b; - } else { - return a < b ? a : b; - } - } - private int maxPositive(int a, int b) { - if(a == -1) { - return b; - } else { - return a > b ? a : b; - } - } - - public MeshQuad(int[] rawBuffer, int offset, ChunkMesh.Flags flags, int offsetX, int offsetY, int offsetZ) { - this.offset = offset; - this.flags = flags; - int i = offset; - float[] us = new float[4]; - float uSum = 0; - float[] vs = new float[4]; - float vSum = 0; - for(int vertexI = 0; vertexI < 4; vertexI++) { - float u = Float.intBitsToFloat(rawBuffer[vertexI * 8 + i + 3]); - float v = Float.intBitsToFloat(rawBuffer[vertexI * 8 + i + 4]); - - us[vertexI] = u; - vs[vertexI] = v; - - uSum += u; - vSum += v; - } - - float avgU = uSum / 4f; - float avgV = vSum / 4f; - - TextureAtlasSprite sprite = null; - Map<String, TextureAtlasSprite> uploadedSprites = ((TextureMap)Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture)).mapUploadedSprites; - - spriteIndex = SpriteUtil.getSpriteIndexForUV(avgU, avgV); - sprite = SpriteUtil.getSprite(spriteIndex); - - if(sprite == null) { - System.out.println("Error: couldn't find sprite"); - } else { - spriteName = sprite.getIconName(); - for(int vertexI = 0; vertexI < 4; vertexI++) { - float x = Float.intBitsToFloat(rawBuffer[i + 0]) - offsetX; - float y = Float.intBitsToFloat(rawBuffer[i + 1]) - offsetY; - float z = Float.intBitsToFloat(rawBuffer[i + 2]) - offsetZ; - - int simpleX = (int)(x * 16); - //if(simpleX == 256) simpleX = 255; - int simpleY = (int)(y * 16); - //if(simpleY == 256) simpleY = 255; - int simpleZ = (int)(z * 16); - //if(simpleZ == 256) simpleZ = 255; - - xs[vertexI] = simpleX; - ys[vertexI] = simpleY; - zs[vertexI] = simpleZ; - - // hasTexture - float u = us[vertexI]; - float v = vs[vertexI]; - - int simpleRelU = (int)((u - sprite.getMinU()) / (sprite.getMaxU() - sprite.getMinU()) * 16); - int simpleRelV = (int)((v - sprite.getMinV()) / (sprite.getMaxV() - sprite.getMinV()) * 16); - if(flags.hasTexture) { - relUs[vertexI] = simpleRelU; - relVs[vertexI] = simpleRelV; - } - - // hasBrightness - int brightness = rawBuffer[i + 7]; - int brightnessU = brightness & 0xFFFF; - int brightnessV = (brightness >> 16) & 0xFFFF; - if(flags.hasBrightness) { - bUs[vertexI] = (int)brightnessU; - bVs[vertexI] = (int)brightnessV; - } - - // hasColor - int color = rawBuffer[i + 5]; - if(flags.hasColor) { - cs[vertexI] = color; - } - - // hasNormals - int normal = rawBuffer[i + 6]; - if(flags.hasNormals) { - normals[vertexI] = normal; - } - - i += 8; - } - } - - updateMinMaxXYZ(); - - if(ys[0] == ys[1] && ys[1] == ys[2] && ys[2] == ys[3]) { - plane = PLANE_XZ; - } else if(xs[0] == xs[1] && xs[1] == xs[2] && xs[2] == xs[3]) { - plane = PLANE_YZ; - } else if(zs[0] == zs[1] && zs[1] == zs[2] && zs[2] == zs[3]) { - plane = PLANE_XY; - } else { - plane = PLANE_NONE; - } - - boolean equalToAABB = true; - for(int minOrMaxX = 0; minOrMaxX < 2; minOrMaxX++) { - for(int minOrMaxY = 0; minOrMaxY < 2; minOrMaxY++) { - for(int minOrMaxZ = 0; minOrMaxZ < 2; minOrMaxZ++) { - if(getCornerVertex(minOrMaxX == 1, minOrMaxY == 1, minOrMaxZ == 1) == -1) { - equalToAABB = false; - break; - } - } - } - } - - switch(plane) { - case PLANE_XY: - isFullQuad = equalToAABB && (maxX - minX) == 16 && (maxY - minY) == 16; - break; - case PLANE_XZ: - isFullQuad = equalToAABB && (maxX - minX) == 16 && (maxZ - minZ) == 16; - break; - case PLANE_YZ: - isFullQuad = equalToAABB && (maxY - minY) == 16 && (maxZ - minZ) == 16; - break; - default: - isFullQuad = false; - } - - for(int c = 0; c < 3; c++) { - if(getMin(c) < 0 || getMax(c) < 0 || getMax(c) - getMin(c) > 16 || getMin(c) > 256 || getMax(c) > 256) { - this.deleted = true; - // TODO handle weirdness more gracefully - } - } - } - - // yeah this is kinda unoptimal - private int getCornerVertex(boolean minOrMaxX, boolean minOrMaxY, boolean minOrMaxZ) { - int aabbCornerX = !minOrMaxX ? minX : maxX; - int aabbCornerY = !minOrMaxY ? minY : maxY; - int aabbCornerZ = !minOrMaxZ ? minZ : maxZ; - - for(int vi = 0; vi < 4; vi++) { - if(xs[vi] == aabbCornerX && ys[vi] == aabbCornerY && zs[vi] == aabbCornerZ) { - return vi; - } - } - return -1; - } - - public void tryToMerge(MeshQuad o) { - if(isValid(this) && isValid(o) && plane == o.plane - && spriteIndex == o.spriteIndex && isFullQuad && o.isFullQuad) { - int numVerticesTouching = 0; - for(int i = 0; i < 4; i++) { - for(int j = 0; j < 4; j++) { - if(xs[i] == o.xs[j] && ys[i] == o.ys[j] && zs[i] == o.zs[j]) { - numVerticesTouching++; - } - } - } - if(numVerticesTouching == 2) { - mergeWithQuad(o); - - totalMergeCountByPlane[plane]++; - - o.deleted = true; - } - } - } - - private void mergeWithQuad(MeshQuad o) { - if(minX < o.minX) { - copyEdgeFrom(o, EnumFacing.EAST); - } else if(minX > o.minX) { - copyEdgeFrom(o, EnumFacing.WEST); - } else if(minY < o.minY) { - copyEdgeFrom(o, EnumFacing.UP); - } else if(minY > o.minY) { - copyEdgeFrom(o, EnumFacing.DOWN); - } else if(minZ < o.minZ) { - copyEdgeFrom(o, EnumFacing.NORTH); - } else if(minX > o.minX) { - copyEdgeFrom(o, EnumFacing.SOUTH); - } - } - - private void copyEdgeFrom(MeshQuad o, EnumFacing side) { - int whichX, whichY, whichZ; - whichX = whichY = whichZ = -1; - - switch(plane) { - case PLANE_XY: - whichZ = 0; - break; - case PLANE_XZ: - whichY = 0; - break; - case PLANE_YZ: - whichX = 0; - break; - } - - switch(side) { - case EAST: - copyCornerVertexFrom(o, 1, whichY, whichZ); - break; - case WEST: - copyCornerVertexFrom(o, 0, whichY, whichZ); - break; - case UP: - copyCornerVertexFrom(o, whichX, 1, whichZ); - break; - case DOWN: - copyCornerVertexFrom(o, whichX, 0, whichZ); - break; - case NORTH: - copyCornerVertexFrom(o, whichX, whichY, 1); - break; - case SOUTH: - copyCornerVertexFrom(o, whichX, whichY, 0); - break; - } - - updateMinMaxXYZ(); - } - - private void updateMinMaxXYZ() { - for(int i = 0; i < 4; i++) { - minX = Math.min(minX, xs[i]); - minY = Math.min(minY, ys[i]); - minZ = Math.min(minZ, zs[i]); - maxX = Math.max(maxX, xs[i]); - maxY = Math.max(maxY, ys[i]); - maxZ = Math.max(maxZ, zs[i]); - } - } - - private void copyCornerVertexFrom(MeshQuad o, int whichX, int whichY, int whichZ) { - int whichXMin, whichXMax, whichYMin, whichYMax, whichZMin, whichZMax; - whichXMin = whichYMin = whichZMin = 0; - whichXMax = whichYMax = whichZMax = 1; - - if(whichX != -1) whichXMin = whichXMax = whichX; - if(whichY != -1) whichYMin = whichYMax = whichY; - if(whichZ != -1) whichZMin = whichZMax = whichZ; - - for(int minOrMaxX = whichXMin; minOrMaxX <= whichXMax; minOrMaxX++) { - for(int minOrMaxY = whichYMin; minOrMaxY <= whichYMax; minOrMaxY++) { - for(int minOrMaxZ = whichZMin; minOrMaxZ <= whichZMax; minOrMaxZ++) { - copyVertexFrom(o, - o.getCornerVertex(minOrMaxX == 1, minOrMaxY == 1, minOrMaxZ == 1), - getCornerVertex(minOrMaxX == 1, minOrMaxY == 1, minOrMaxZ == 1)); - } - } - } - } - - private void copyVertexFrom(MeshQuad o, int src, int dest) { - xs[dest] = o.xs[src]; - ys[dest] = o.ys[src]; - zs[dest] = o.zs[src]; - relUs[dest] = o.relUs[src]; - relVs[dest] = o.relVs[src]; - bUs[dest] = o.bUs[src]; - bVs[dest] = o.bVs[src]; - cs[dest] = o.cs[src]; - normals[dest] = o.normals[src]; - } - - public void writeToDisk(DataOutputStream out, int pass) throws IOException { - if(deleted) { - return; - } - - if(flags.hasTexture) { - if(pass == 0) out.writeShort(spriteIndex); - } - for (int vertexI = 0; vertexI < 4; vertexI++) { - if(pass == 1) out.writeByte(xs[vertexI] == 256 ? 255 : xs[vertexI]); - if(pass == 2) out.writeByte(ys[vertexI] == 256 ? 255 : ys[vertexI]); - if(pass == 3) out.writeByte(zs[vertexI] == 256 ? 255 : zs[vertexI]); - - if (flags.hasTexture) { - if(pass == 4) out.writeByte(relUs[vertexI]); - if(pass == 5) out.writeByte(relVs[vertexI]); - } - - if (flags.hasBrightness) { - if(pass == 6) out.writeByte(bUs[vertexI]); - if(pass == 7) out.writeByte(bVs[vertexI]); - } - - if (flags.hasColor) { - if(pass == 8) out.writeInt(cs[vertexI]); - } - - if (flags.hasNormals) { - if(pass == 9) out.writeInt(normals[vertexI]); - } - } - } - - // maybe minXYZ and maxXYZ should be arrays instead - public int getMin(int coord) { - return coord == 0 ? minX : coord == 1 ? minY : coord == 2 ? minZ : -1; - } - - public int getMax(int coord) { - return coord == 0 ? maxX : coord == 1 ? maxY : coord == 2 ? maxZ : -1; - } - - public boolean onSamePlaneAs(MeshQuad o) { - return isValid(this) && isValid(o) && plane == o.plane && - ((plane == PLANE_XY && minZ == o.minZ) || - (plane == PLANE_XZ && minY == o.minY) || - (plane == PLANE_YZ && minX == o.minX)); - } - - // this should be static.. - public boolean isValid(MeshQuad q) { - return q != null && !q.deleted; - } - - public boolean isClockwiseXZ() { - return (xs[1] - xs[0]) * (zs[2] - zs[0]) - (xs[2] - xs[0]) * (zs[1] - zs[0]) < 0; - } - - @Override - public String toString() { - return String.format(Locale.ENGLISH, "%s(%.1f, %.1f, %.1f -- %.1f, %.1f, %.1f) %s", deleted ? "XXX " : "", minX/16f, minY/16f, minZ/16f, maxX/16f, maxY/16f, maxZ/16f, spriteName); - } - - public static class QuadPlaneComparator implements Comparator<MeshQuad> { - - public static final QuadPlaneComparator[] quadPlaneComparators = new QuadPlaneComparator[]{ - new QuadPlaneComparator(2, 1, 0), // PLANE_XY -> ZYX - new QuadPlaneComparator(1, 2, 0), // PLANE_XZ -> YZX - new QuadPlaneComparator(0, 2, 1) // PLANE_YZ -> XZY - }; - - private int c0, c1, c2; - - public QuadPlaneComparator(int firstCoordToCompare, int secondCoordToCompare, int thirdCoordToCompare) { - this.c0 = firstCoordToCompare; - this.c1 = secondCoordToCompare; - this.c2 = thirdCoordToCompare; - } - - @Override - public int compare(MeshQuad a, MeshQuad b) { - if(a.getMin(c0) < b.getMin(c0)) { - return -1; - } else if(a.getMin(c0) > b.getMin(c0)) { - return 1; - } else { - if(a.getMin(c1) < b.getMin(c1)) { - return -1; - } else if(a.getMin(c1) > b.getMin(c1)) { - return 1; - } else { - if(a.getMin(c2) < b.getMin(c2)) { - return -1; - } else if(a.getMin(c2) > b.getMin(c2)) { - return 1; - } else { - return (int)Math.signum(a.offset - b.offset); - } - } - } - } - } -} diff --git a/src/main/java/makamys/lodmod/renderer/SimpleChunkMesh.java b/src/main/java/makamys/lodmod/renderer/SimpleChunkMesh.java deleted file mode 100644 index 4065b6c..0000000 --- a/src/main/java/makamys/lodmod/renderer/SimpleChunkMesh.java +++ /dev/null @@ -1,350 +0,0 @@ -package makamys.lodmod.renderer; - -import static org.lwjgl.opengl.GL11.GL_FLOAT; -import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER; -import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER; -import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW; -import static org.lwjgl.opengl.GL15.glBufferData; -import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray; -import static org.lwjgl.opengl.GL20.glVertexAttribPointer; - -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.util.Arrays; -import java.util.List; - -import org.lwjgl.BufferUtils; - -import makamys.lodmod.LODMod; -import makamys.lodmod.util.MCUtil; -import net.minecraft.block.Block; -import net.minecraft.block.BlockGrass; -import net.minecraft.block.BlockLeaves; -import net.minecraft.block.material.Material; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureMap; -import net.minecraft.entity.Entity; -import net.minecraft.init.Blocks; -import net.minecraft.nbt.NBTTagString; -import net.minecraft.util.IIcon; -import net.minecraft.world.biome.BiomeGenBase; -import net.minecraft.world.chunk.Chunk; - -public class SimpleChunkMesh extends Mesh { - - private FloatBuffer vertices; - - public static int usedRAM; - public static int instances; - public static int divisions = 4; - - private static boolean isSolid(Block block) { - return block.isBlockNormalCube() && block.isOpaqueCube() && block.renderAsNormalBlock(); - } - - private static boolean isBad(Block block) { - for(Class clazz : LODMod.blockClassBlacklist) { - if(clazz.isInstance(block)) { - return true; - } - } - return false; - } - - public static List<SimpleChunkMesh> generateSimpleMeshes(Chunk target){ - SimpleChunkMesh pass1 = new SimpleChunkMesh(target.xPosition, target.zPosition, divisions * divisions * 25, 0); - SimpleChunkMesh pass2 = new SimpleChunkMesh(target.xPosition, target.zPosition, divisions * divisions * 25, 1); - - SimpleChunkMeshBuilder builder = new SimpleChunkMeshBuilder(); - - for(int divX = 0; divX < divisions; divX++) { - for(int divZ = 0; divZ < divisions; divZ++) { - IIcon icon = null; - int color = 0xFFFFFFFF; - int size = 16 / divisions; - int y = 255; - boolean foundWater = false; - - int xOff = divX * size; - int zOff = divZ * size; - - int biomeId = target.getBiomeArray()[xOff << 4 | zOff] & 255; - if(biomeId == 255) { - System.out.println("Missing biome data for chunk " + target.xPosition + ", " + target.zPosition); - } - BiomeGenBase biome = BiomeGenBase.getBiome(biomeId) == null ? BiomeGenBase.plains : BiomeGenBase.getBiome(biomeId); - - for(y = 255; y > 0; y--) { - Block block = target.getBlock(xOff, y, zOff); - - int worldX = target.xPosition * 16 + divX * size; - int worldY = y; - int worldZ = target.zPosition * 16 + divZ * size; - - if(!foundWater && block.getMaterial() == Material.water) { - foundWater = true; - int meta = target.getBlockMetadata(xOff, y, zOff); - IIcon waterIcon = block.getIcon(1, meta); - - int waterColor = biome.getWaterColorMultiplier(); - waterColor |= 0xFF000000; - pass2.addFaceYPos(worldX, worldY, worldZ, size, size, waterIcon, waterColor, 1); - } - - if(isSolid(block) && isBad(block)) { - for(int dx = -1; dx <= 1; dx++) { - for(int dz = -1; dz <= 1; dz++) { - int newX = xOff + dx; - int newZ = zOff + dz; - if(newX >= 0 && newX < 16 && newZ >= 0 && newZ < 16) { - Block newBlock = target.getBlock(newX, y, newZ); - if(!isBad(newBlock)) { - xOff += dx; - zOff += dz; - worldX += dx; - worldZ += dz; - block = newBlock; - } - } - } - } - } - if(isSolid(block)) { - - float brightnessMult = foundWater ? 0.2f : 1f; - int meta = target.getBlockMetadata(xOff, y, zOff); - icon = block.getIcon(1, meta); - - if(block instanceof BlockGrass) { - color = biome.getBiomeGrassColor(worldX, y, worldZ); - } else if(block instanceof BlockLeaves) { - color = biome.getBiomeFoliageColor(worldX, y, worldZ); - } else { - color = block.colorMultiplier(Minecraft.getMinecraft().theWorld, worldX, y, worldZ); - } - color = (0xFF << 24) | ((color >> 16 & 0xFF) << 0) | ((color >> 8 & 0xFF) << 8) | ((color >> 0 & 0xFF) << 16); - - if((LODMod.forceVanillaBiomeTemperature ? MCUtil.getBiomeTemperatureVanilla(biome, worldX, y, worldZ) - : biome.getFloatTemperature(worldX, y, worldZ)) < 0.15f) { - - builder.addCube(divX, divZ, worldY + 0.2f, 1f, Blocks.snow_layer.getIcon(1, 0), 0xFFFFFFFF, brightnessMult); - builder.addCube(divX, divZ, worldY - 0.8f, -1, icon, color, brightnessMult); - } else { - builder.addCube(divX, divZ, worldY, -1, icon, color, brightnessMult); - } - - - break; - } - } - } - } - - builder.render(pass1, target.xPosition, target.zPosition); - - pass1.finish(); - pass2.finish(); - - return Arrays.asList(new SimpleChunkMesh[] {pass1.quadCount != 0 ? pass1 : null, pass2.quadCount != 0 ? pass2 : null}); - } - - private static class SimpleChunkMeshBuilder { - int maxIconsPerColumn = 2; - float[][][] heights = new float[divisions][divisions][maxIconsPerColumn]; - float[][][] depths = new float[divisions][divisions][maxIconsPerColumn]; - IIcon[][][] icons = new IIcon[divisions][divisions][maxIconsPerColumn]; - int[][][] colors = new int[divisions][divisions][maxIconsPerColumn]; - float[][][] brightnessMults = new float[divisions][divisions][maxIconsPerColumn]; - - public void addCube(int x, int z, float height, float depth, IIcon icon, int color, float brightnessMult) { - IIcon[] iconz = icons[x][z]; - int i = iconz[0] == null ? 0 : 1; - if(iconz[0] != null && iconz[1] != null) { - throw new IllegalStateException("Too many icons in column"); - } - - heights[x][z][i] = height; - depths[x][z][i] = depth; - icons[x][z][i] = icon; - colors[x][z][i] = color; - brightnessMults[x][z][i] = brightnessMult; - } - - public void render(SimpleChunkMesh mesh, int chunkX, int chunkZ) { - float size = 16 / divisions; - - for(int x = 0; x < divisions; x++) { - for(int z = 0; z < divisions; z++) { - float worldX = chunkX * 16 + x * size; - float worldZ = chunkZ * 16 + z * size; - for(int i = 0; i < maxIconsPerColumn; i++) { - IIcon icon = icons[x][z][i]; - if(icon != null) { - float height = heights[x][z][i]; - float depthValue = depths[x][z][i]; - float depth = depthValue == -1 ? height : depthValue; - int color = colors[x][z][i]; - float brightnessMult = brightnessMults[x][z][i]; - - if(i == 0) { - mesh.addFaceYPos(worldX, height, worldZ, size, size, icon, color, brightnessMult); - } - float heightX0 = x > 0 ? heights[x - 1][z][0] : 0; - if(heightX0 < height) { - mesh.addFaceX2(worldX, height, worldZ, Math.min(depth, height - heightX0), size, icon, color, brightnessMult); - } - - float heightX1 = x < divisions - 1 ? heights[x + 1][z][0] : 0; - if(heightX1 < height) { - mesh.addFaceX1(worldX + size, height, worldZ, Math.min(depth, height - heightX1), size, icon, color, brightnessMult); - } - - float heightZ0 = z > 0 ? heights[x][z - 1][0] : 0; - if(heightZ0 < height) { - mesh.addFaceZ1(worldX, height, worldZ, size, Math.min(depth, height - heightZ0), icon, color, brightnessMult); - } - - float heightZ1 = z < divisions - 1 ? heights[x][z + 1][0] : 0; - if(heightZ1 < height) { - mesh.addFaceZ2(worldX, height, worldZ + size, size, Math.min(depth, height - heightZ1), icon, color, brightnessMult); - } - } - } - } - } - } - } - - public SimpleChunkMesh(int x, int z, int maxQuads, int pass) { - this.x = x; - this.y = 64; - this.z = z; - this.pass = pass; - - buffer = BufferUtils.createByteBuffer(4 * 6 * 7 * maxQuads); - vertices = buffer.asFloatBuffer(); - } - - public void finish() { - vertices.flip(); - buffer.limit(vertices.limit() * 4); - - // may want to shrink the buffers to actual size to not waste memory - - usedRAM += buffer.limit(); - instances++; - } - - private void addCube(float x, float y, float z, float sizeX, float sizeZ, float sizeY, IIcon icon, int color, float brightnessMult) { - addFaceYPos(x, y, z, sizeX, sizeZ, icon, color, brightnessMult); - addFaceZ1(x, y, z, sizeX, sizeY, icon, color, brightnessMult); - addFaceZ2(x, y, z + sizeZ, sizeX, sizeY, icon, color, brightnessMult); - addFaceX1(x + sizeX, y, z, sizeX, sizeY, icon, color, brightnessMult); - addFaceX2(x, y, z, sizeX, sizeY, icon, color, brightnessMult); - } - - private void addFaceZ1(float x, float y, float z, float sizeX, float sizeY, IIcon icon, int color, float brightnessMult) { - addFace( - x + 0, y - sizeY, z + 0, - x + 0, y + 0, z + 0, - x + sizeX, y + 0, z + 0, - x + sizeX, y - sizeY, z + 0, - icon, color, (int)(200 * brightnessMult) - ); - } - - private void addFaceZ2(float x, float y, float z, float sizeX, float sizeY, IIcon icon, int color, float brightnessMult) { - addFace( - x + sizeX, y - sizeY, z, - x + sizeX, y + 0, z, - x + 0, y + 0, z, - x + 0, y - sizeY, z, - icon, color, (int)(200 * brightnessMult) - ); - } - - private void addFaceX1(float x, float y, float z, float sizeY, float sizeZ, IIcon icon, int color, float brightnessMult) { - addFace( - x, y - sizeY, z + 0, - x, y + 0, z + 0, - x, y + 0, z + sizeZ, - x, y - sizeY, z + sizeZ, - icon, color, (int)(160 * brightnessMult) - ); - } - - private void addFaceX2(float x, float y, float z, float sizeY, float sizeZ, IIcon icon, int color, float brightnessMult) { - addFace( - x + 0, y - sizeY, z + sizeZ, - x + 0, y + 0, z + sizeZ, - x + 0, y + 0, z + 0, - x + 0, y - sizeY, z + 0, - icon, color, (int)(160 * brightnessMult) - ); - } - - private void addFaceYPos(float x, float y, float z, float sizeX, float sizeZ, IIcon icon, int color, float brightnessMult) { - addFace( - x + 0, y + 0, z + 0, - x + 0, y + 0, z + sizeZ, - x + sizeX, y + 0, z + sizeZ, - x + sizeX, y + 0, z + 0, - icon, color, (int)(240 * brightnessMult) - ); - } - - private void addFace(float p1x, float p1y, float p1z, - float p2x, float p2y, float p2z, - float p3x, float p3y, float p3z, - float p4x, float p4y, float p4z, - IIcon icon, int color, int brightness) { - int off = vertices.position() * 4; - vertices.put(new float[] { - p1x, p1y, p1z, icon.getMinU(), icon.getMaxV(), 0, 0, - p2x, p2y, p2z, icon.getMinU(), icon.getMinV(), 0, 0, - p4x, p4y, p4z, icon.getMaxU(), icon.getMaxV(), 0, 0, - p2x, p2y, p2z, icon.getMinU(), icon.getMinV(), 0, 0, - p3x, p3y, p3z, icon.getMaxU(), icon.getMinV(), 0, 0, - p4x, p4y, p4z, icon.getMaxU(), icon.getMaxV(), 0, 0 - }); - buffer.putInt(off + 0 * getStride() + 6 * 4, color); - buffer.putShort(off + 0 * getStride() + 5 * 4 + 2, (short)brightness); - buffer.putInt(off + 1 * getStride() + 6 * 4, color); - buffer.putShort(off + 1 * getStride() + 5 * 4 + 2, (short)brightness); - buffer.putInt(off + 2 * getStride() + 6 * 4, color); - buffer.putShort(off + 2 * getStride() + 5 * 4 + 2, (short)brightness); - buffer.putInt(off + 3 * getStride() + 6 * 4, color); - buffer.putShort(off + 3 * getStride() + 5 * 4 + 2, (short)brightness); - buffer.putInt(off + 4 * getStride() + 6 * 4, color); - buffer.putShort(off + 4 * getStride() + 5 * 4 + 2, (short)brightness); - buffer.putInt(off + 5 * getStride() + 6 * 4, color); - buffer.putShort(off + 5 * getStride() + 5 * 4 + 2, (short)brightness); - - quadCount++; - } - - public int getStride() { - return (3 * 4 + 8 + 4 + 4); - } - - public void destroy() { - usedRAM -= buffer.limit(); - instances--; - } - - public static void prepareFarChunkOnServer(Chunk chunk) { - for(int divX = 0; divX < divisions; divX++) { - for(int divZ = 0; divZ < divisions; divZ++) { - int size = 16 / divisions; - - int xOff = divX * size; - int zOff = divZ * size; - - chunk.getBiomeGenForWorldCoords(xOff, zOff, chunk.worldObj.getWorldChunkManager()); - } - } - } - -} |