aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/makamys/neodymium
diff options
context:
space:
mode:
authormakamys <makamys@outlook.com>2022-07-11 22:55:20 +0200
committermakamys <makamys@outlook.com>2022-07-11 22:56:53 +0200
commitacdc0adecd3c8d649cad97c6932fb7ba418721e6 (patch)
tree9606d944818016067c1709825c92977323b6bb48 /src/main/java/makamys/neodymium
parentf26762ca0c6b7c1977f71ae24b3b011a658d7e53 (diff)
downloadNeodymium-acdc0adecd3c8d649cad97c6932fb7ba418721e6.tar.gz
Neodymium-acdc0adecd3c8d649cad97c6932fb7ba418721e6.tar.bz2
Neodymium-acdc0adecd3c8d649cad97c6932fb7ba418721e6.zip
Be able to capture chunk meshes consisting of multiple tessellations
Start of fix for #5
Diffstat (limited to 'src/main/java/makamys/neodymium')
-rw-r--r--src/main/java/makamys/neodymium/MixinConfigPlugin.java3
-rw-r--r--src/main/java/makamys/neodymium/ducks/ITessellator.java7
-rw-r--r--src/main/java/makamys/neodymium/mixin/MixinTessellator.java29
-rw-r--r--src/main/java/makamys/neodymium/mixin/MixinWorldRenderer.java27
-rw-r--r--src/main/java/makamys/neodymium/renderer/ChunkMesh.java74
5 files changed, 109 insertions, 31 deletions
diff --git a/src/main/java/makamys/neodymium/MixinConfigPlugin.java b/src/main/java/makamys/neodymium/MixinConfigPlugin.java
index a572d3c..6624a49 100644
--- a/src/main/java/makamys/neodymium/MixinConfigPlugin.java
+++ b/src/main/java/makamys/neodymium/MixinConfigPlugin.java
@@ -37,7 +37,8 @@ public class MixinConfigPlugin implements IMixinConfigPlugin {
List<String> mixins = new ArrayList<>();
mixins.addAll(Arrays.asList(
"MixinRenderGlobal",
- "MixinWorldRenderer"));
+ "MixinWorldRenderer",
+ "MixinTessellator"));
if (OFUtil.isOptiFinePresent()) {
System.out.println("Detected OptiFine");
diff --git a/src/main/java/makamys/neodymium/ducks/ITessellator.java b/src/main/java/makamys/neodymium/ducks/ITessellator.java
new file mode 100644
index 0000000..1e2598f
--- /dev/null
+++ b/src/main/java/makamys/neodymium/ducks/ITessellator.java
@@ -0,0 +1,7 @@
+package makamys.neodymium.ducks;
+
+public interface ITessellator {
+
+ public void enableMeshCapturing(boolean enable);
+
+}
diff --git a/src/main/java/makamys/neodymium/mixin/MixinTessellator.java b/src/main/java/makamys/neodymium/mixin/MixinTessellator.java
new file mode 100644
index 0000000..15f71da
--- /dev/null
+++ b/src/main/java/makamys/neodymium/mixin/MixinTessellator.java
@@ -0,0 +1,29 @@
+package makamys.neodymium.mixin;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+import makamys.neodymium.ducks.ITessellator;
+import makamys.neodymium.renderer.ChunkMesh;
+import net.minecraft.client.renderer.Tessellator;
+
+@Mixin(Tessellator.class)
+abstract class MixinTessellator implements ITessellator {
+
+ private boolean nd$captureMeshes;
+
+ @Inject(method = "draw", at = @At(value = "HEAD"))
+ private void preDraw(CallbackInfoReturnable<Integer> cir) {
+ if(nd$captureMeshes) {
+ ChunkMesh.preTessellatorDraw((Tessellator)(Object)this);
+ }
+ }
+
+ @Override
+ public void enableMeshCapturing(boolean enable) {
+ nd$captureMeshes = enable;
+ }
+
+}
diff --git a/src/main/java/makamys/neodymium/mixin/MixinWorldRenderer.java b/src/main/java/makamys/neodymium/mixin/MixinWorldRenderer.java
index 32b27a9..a794931 100644
--- a/src/main/java/makamys/neodymium/mixin/MixinWorldRenderer.java
+++ b/src/main/java/makamys/neodymium/mixin/MixinWorldRenderer.java
@@ -13,6 +13,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.google.common.collect.Lists;
import makamys.neodymium.Neodymium;
+import makamys.neodymium.ducks.ITessellator;
import makamys.neodymium.ducks.IWorldRenderer;
import makamys.neodymium.renderer.ChunkMesh;
import makamys.neodymium.renderer.NeoRenderer;
@@ -81,12 +82,34 @@ abstract class MixinWorldRenderer implements IWorldRenderer {
}
}
+ @Inject(method = "preRenderBlocks", at = @At("HEAD"))
+ private void prePreRenderBlocks(int pass, CallbackInfo ci) {
+ if(Neodymium.isActive()) {
+ ((ITessellator)Tessellator.instance).enableMeshCapturing(true);
+ ChunkMesh cm = new ChunkMesh((WorldRenderer)(Object)this, pass);
+ nd$chunkMeshes.set(pass, cm);
+ ChunkMesh.setCaptureTarget(cm);
+ }
+ }
+
@Inject(method = "postRenderBlocks", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Tessellator;draw()I"))
private void prePostRenderBlocks(int pass, EntityLivingBase entity, CallbackInfo ci) {
- if(Neodymium.isActive()) {
+ /*if(Neodymium.isActive()) {
if(nd$chunkMeshes != null) {
- nd$chunkMeshes.set(pass, ChunkMesh.fromTessellator(pass, WorldRenderer.class.cast(this), Tessellator.instance));
+ if(nd$chunkMeshes.get(pass) == null) {
+ nd$chunkMeshes.set(pass, ChunkMesh.fromTessellator(pass, WorldRenderer.class.cast(this)));
+ }
+ nd$chunkMeshes.get(pass).addTessellatorData(Tessellator.instance);
}
+ }*/
+ }
+
+ @Inject(method = "postRenderBlocks", at = @At("RETURN"))
+ private void postPostRenderBlocks(int pass, EntityLivingBase entity, CallbackInfo ci) {
+ if(Neodymium.isActive()) {
+ nd$chunkMeshes.get(pass).finishConstruction();
+ ((ITessellator)Tessellator.instance).enableMeshCapturing(false);
+ ChunkMesh.setCaptureTarget(null);
}
}
diff --git a/src/main/java/makamys/neodymium/renderer/ChunkMesh.java b/src/main/java/makamys/neodymium/renderer/ChunkMesh.java
index c4956eb..a574765 100644
--- a/src/main/java/makamys/neodymium/renderer/ChunkMesh.java
+++ b/src/main/java/makamys/neodymium/renderer/ChunkMesh.java
@@ -1,5 +1,7 @@
package makamys.neodymium.renderer;
+import static makamys.neodymium.Neodymium.LOGGER;
+
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
@@ -8,6 +10,7 @@ import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.lwjgl.BufferUtils;
+import org.lwjgl.opengl.GL11;
import makamys.neodymium.config.Config;
import makamys.neodymium.ducks.IWorldRenderer;
@@ -22,7 +25,6 @@ import net.minecraft.tileentity.TileEntity;
/** A mesh for a 16x16x16 region of the world. */
public class ChunkMesh extends Mesh {
- Flags flags;
WorldRenderer wr;
private int[] subMeshStart = new int[NORMAL_ORDER.length];
@@ -32,10 +34,14 @@ public class ChunkMesh extends Mesh {
private static RecyclingList<MeshQuad> quadBuf = new RecyclingList<>(() -> new MeshQuad());
+ private static ChunkMesh meshCaptureTarget;
+
private static final QuadNormal[] NORMAL_ORDER = new QuadNormal[] {QuadNormal.NONE, QuadNormal.POSITIVE_Y, QuadNormal.POSITIVE_X, QuadNormal.POSITIVE_Z, QuadNormal.NEGATIVE_X, QuadNormal.NEGATIVE_Z, QuadNormal.NEGATIVE_Y};
private static final Comparator<MeshQuad> MESH_QUAD_RENDER_COMPARATOR = new MeshQuadRenderOrderComparator();
private static final int[] QUAD_NORMAL_TO_NORMAL_ORDER;
+ private static final Flags FLAGS = new Flags(true, true, true, false);
+
static {
QUAD_NORMAL_TO_NORMAL_ORDER = new int[QuadNormal.values().length];
for(int i = 0; i < QuadNormal.values().length; i++) {
@@ -47,39 +53,52 @@ public class ChunkMesh extends Mesh {
}
}
- public ChunkMesh(WorldRenderer wr, Flags flags, int quadCount, List<MeshQuad> quads, int pass) {
+ public ChunkMesh(WorldRenderer wr, int pass) {
this.x = wr.posX / 16;
this.y = wr.posY / 16;
this.z = wr.posZ / 16;
this.wr = wr;
- this.flags = flags;
- this.quadCount = quadCount;
this.pass = pass;
Arrays.fill(subMeshStart, -1);
- buffer = createBuffer(quads, quadCount);
- usedRAM += buffer.limit();
instances++;
+
+ if(!quadBuf.getAsList().isEmpty()) {
+ LOGGER.error("Invalid state: tried to construct a chunk mesh before the previous one has finished constructing!");
+ }
}
- 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;
+ public static void preTessellatorDraw(Tessellator t) {
+ if(meshCaptureTarget != null) {
+ meshCaptureTarget.addTessellatorData(t);
}
+ }
+
+ private void addTessellatorData(Tessellator t) {
+ // TODO triangle support
- int xOffset = wr.posX;
- int yOffset = wr.posY;
- int zOffset = wr.posZ;
-
- ChunkMesh.Flags flags = new ChunkMesh.Flags(t.hasTexture, t.hasBrightness, t.hasColor, t.hasNormals);
-
- quadBuf.reset();
+ if(t.vertexCount == 0) {
+ // Sometimes the tessellator has no vertices and weird flags. Don't warn in this case, just silently return.
+ return;
+ }
+ if(t.vertexCount % 4 != 0) {
+ LOGGER.error("Error: Vertex count is not a multiple of 4");
+ return;
+ }
+ if(t.drawMode != GL11.GL_QUADS) {
+ LOGGER.error("Error: Unsupported draw mode: " + t.drawMode);
+ }
+ if(!t.hasTexture || !t.hasBrightness || !t.hasColor || t.hasNormals) {
+ LOGGER.error("Error: Unsupported tessellator flags");
+ return;
+ }
for(int quadI = 0; quadI < t.vertexCount / 4; quadI++) {
- quadBuf.next().setState(t.rawBuffer, quadI * 32, flags, (float)-t.xOffset, (float)-t.yOffset, (float)-t.zOffset);
+ quadBuf.next().setState(t.rawBuffer, quadI * 32, FLAGS, (float)-t.xOffset, (float)-t.yOffset, (float)-t.zOffset);
}
-
+ }
+
+ public void finishConstruction() {
List<MeshQuad> quads = quadBuf.getAsList();
if(Config.simplifyChunkMeshes) {
@@ -110,16 +129,11 @@ public class ChunkMesh extends Mesh {
}
}
- int quadCount = countValidQuads(quads);
+ quadCount = countValidQuads(quads);
+ buffer = createBuffer(quads, quadCount);
+ usedRAM += buffer.limit();
- if(quadCount > 0) {
- return new ChunkMesh(
- wr,
- new ChunkMesh.Flags(t.hasTexture, t.hasBrightness, t.hasColor, t.hasNormals),
- quadCount, quads, pass);
- } else {
- return null;
- }
+ quadBuf.reset();
}
private static void simplifyPlane(List<MeshQuad> planeQuads) {
@@ -300,6 +314,10 @@ public class ChunkMesh extends Mesh {
return player.getDistanceSq(centerX, centerY, centerZ);
}
+ public static void setCaptureTarget(ChunkMesh cm) {
+ meshCaptureTarget = cm;
+ }
+
public static class Flags {
boolean hasTexture;
boolean hasBrightness;