aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/makamys/lodmod/renderer/ChunkMesh.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/makamys/lodmod/renderer/ChunkMesh.java')
-rw-r--r--src/main/java/makamys/lodmod/renderer/ChunkMesh.java352
1 files changed, 352 insertions, 0 deletions
diff --git a/src/main/java/makamys/lodmod/renderer/ChunkMesh.java b/src/main/java/makamys/lodmod/renderer/ChunkMesh.java
new file mode 100644
index 0000000..4175b9f
--- /dev/null
+++ b/src/main/java/makamys/lodmod/renderer/ChunkMesh.java
@@ -0,0 +1,352 @@
+package makamys.lodmod.renderer;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.lwjgl.BufferUtils;
+
+import makamys.lodmod.ducks.IWorldRenderer;
+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.tileentity.TileEntity;
+
+public class ChunkMesh extends Mesh {
+
+ int x;
+ int y;
+ int z;
+ Flags flags;
+
+ private ChunkMesh(int x, int y, int z, Flags flags, int quadCount, byte[] data, List<String> stringTable) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.flags = flags;
+ this.quadCount = quadCount;
+
+ this.buffer = createBuffer(data, stringTable);
+ }
+
+ public ChunkMesh(int x, int y, int z, Flags flags, int quadCount, List<MeshQuad> quads) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.flags = flags;
+ this.quadCount = quadCount;
+
+ this.buffer = createBuffer(quads);
+ }
+
+ private ByteBuffer createBuffer(List<MeshQuad> quads) {
+ 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;
+ }
+
+ ByteBuffer buffer = BufferUtils.createByteBuffer(quadCount * 6 * getStride());
+ FloatBuffer floatBuffer = buffer.asFloatBuffer();
+ ShortBuffer shortBuffer = buffer.asShortBuffer();
+ IntBuffer intBuffer = buffer.asIntBuffer();
+
+ try {
+ for(MeshQuad quad : quads) {
+ if(quad.deleted) {
+ continue;
+ }
+ String spriteName = quad.spriteName;
+
+ 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 simpleX = quad.xs[vi];
+ if(simpleX == 255) simpleX = 256;
+ int simpleY = quad.ys[vi];
+ if(simpleY == 255) simpleY = 256;
+ int simpleZ = quad.zs[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
+
+ int relU = quad.relUs[vi];
+ int relV = quad.relVs[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)quad.bUs[vi]); // bU
+ shortBuffer.put((short)quad.bVs[vi]); // bV
+
+ intBuffer.position(shortBuffer.position() / 2);
+
+ intBuffer.put(quad.cs[vi]); // c
+
+ floatBuffer.position(intBuffer.position());
+ }
+ }
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+
+ buffer.position(floatBuffer.position() * 4);
+ buffer.flip();
+
+ return buffer;
+ }
+
+ 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);
+
+ DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
+
+ 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(in, 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);
+
+ intBuffer.put(readIntAt(in, colorOffset + 4 * 4 * quadI + 4 * vi)); // c
+
+ floatBuffer.position(intBuffer.position());
+ }
+ }
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+
+ buffer.position(floatBuffer.position() * 4);
+ buffer.flip();
+
+ return buffer;
+ }
+
+ // 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 int readIntAt(DataInputStream in, int offset) {
+ try {
+ in.reset();
+ in.skip(offset);
+ return in.readInt();
+ } catch(IOException e) {
+ return -1;
+ }
+ }
+
+ public int getStride() {
+ return (3 * 4 + (flags.hasTexture ? 8 : 0) + (flags.hasBrightness ? 4 : 0) + (flags.hasColor ? 4 : 0) + (flags.hasNormals ? 4 : 0));
+ }
+
+ static ChunkMesh loadChunkMesh(int x, int y, int z) {
+ try(DataInputStream in = new DataInputStream(new FileInputStream("tessellator_dump.dat"))){
+ List<String> stringTable = Files.readAllLines(Paths.get("tessellator_strings.txt"));
+
+ while(true) {
+ int xOffset = in.readInt();
+ int yOffset = in.readInt();
+ int zOffset = in.readInt();
+ Flags flags = new Flags(in.readByte());
+
+ int quadSize = 2 + 4 * (3 + (flags.hasTexture ? 2 : 0) + (flags.hasBrightness ? 2 : 0)
+ + (flags.hasColor ? 4 : 0) + (flags.hasNormals ? 4 : 0));
+
+
+ int quadCount = in.readInt();
+
+ if(xOffset == x && yOffset == y && zOffset == z) {
+ byte[] data = new byte[quadSize * quadCount];
+ in.read(data, 0, data.length);
+
+ return new ChunkMesh(x, y, z, flags, quadCount, data, stringTable);
+ } else {
+ in.skip(quadSize * quadCount);
+ }
+ }
+ } catch(EOFException eof) {
+ System.out.println("end??");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ // TODO don't repeat yourself
+ static List<ChunkMesh> loadAll(){
+ List<ChunkMesh> list = new ArrayList<ChunkMesh>();
+ try(DataInputStream in = new DataInputStream(new FileInputStream("tessellator_dump.dat"))){
+ List<String> stringTable = Files.readAllLines(Paths.get("tessellator_strings.txt"));
+
+ while(true) {
+ int xOffset = in.readInt();
+ int yOffset = in.readInt();
+ int zOffset = in.readInt();
+ Flags flags = new Flags(in.readByte());
+
+ int quadSize = 2 + 4 * (3 + (flags.hasTexture ? 2 : 0) + (flags.hasBrightness ? 2 : 0)
+ + (flags.hasColor ? 4 : 0) + (flags.hasNormals ? 4 : 0));
+
+
+ int quadCount = in.readInt();
+
+ if(quadCount > 0) {
+ byte[] data = new byte[quadSize * quadCount];
+ in.read(data, 0, data.length);
+
+ list.add(new ChunkMesh(xOffset, yOffset, zOffset, flags, quadCount, data, stringTable));
+ }
+ }
+ } catch(EOFException eof) {
+ System.out.println("end??");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return list;
+ }
+
+ 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 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;
+ }
+ }
+
+}
+