From 20110c2b18c50cc1a322cc3aba86799d8aece6c1 Mon Sep 17 00:00:00 2001 From: danyadev Date: Thu, 20 Nov 2025 20:29:46 +0300 Subject: [PATCH] patch CTM renderer to allow rendering an overrided block texture as if it were a CTM texture --- .../client/render/SubmapManagerVoidstone.java | 85 ------------------ .../team/chisel/ctmlib/RenderBlocksCTM.java | 90 +++++++++++++------ 2 files changed, 65 insertions(+), 110 deletions(-) diff --git a/src/main/java/team/chisel/client/render/SubmapManagerVoidstone.java b/src/main/java/team/chisel/client/render/SubmapManagerVoidstone.java index aadd2a59..49d2d4b5 100644 --- a/src/main/java/team/chisel/client/render/SubmapManagerVoidstone.java +++ b/src/main/java/team/chisel/client/render/SubmapManagerVoidstone.java @@ -25,66 +25,54 @@ public class SubmapManagerVoidstone extends SubmapManagerBase { @Override public void renderFaceXNeg(Block block, double x, double y, double z, IIcon icon) { - shiftBoundary(ForgeDirection.WEST); setOverrideBlockTexture(getBase(x, y, z, ForgeDirection.WEST.ordinal())); super.renderFaceXNeg(block, x, y, z, null); clearOverrideBlockTexture(); - resetBoundary(ForgeDirection.WEST); super.renderFaceXNeg(block, x, y, z, icon); } @Override public void renderFaceXPos(Block block, double x, double y, double z, IIcon icon) { - shiftBoundary(ForgeDirection.EAST); setOverrideBlockTexture(getBase(x, y, z, ForgeDirection.EAST.ordinal())); super.renderFaceXPos(block, x, y, z, null); clearOverrideBlockTexture(); - resetBoundary(ForgeDirection.EAST); super.renderFaceXPos(block, x, y, z, icon); } @Override public void renderFaceYNeg(Block block, double x, double y, double z, IIcon icon) { - shiftBoundary(ForgeDirection.DOWN); setOverrideBlockTexture(getBase(x, y, z, ForgeDirection.DOWN.ordinal())); super.renderFaceYNeg(block, x, y, z, null); clearOverrideBlockTexture(); - resetBoundary(ForgeDirection.DOWN); super.renderFaceYNeg(block, x, y, z, icon); } @Override public void renderFaceYPos(Block block, double x, double y, double z, IIcon icon) { - shiftBoundary(ForgeDirection.UP); setOverrideBlockTexture(getBase(x, y, z, ForgeDirection.UP.ordinal())); super.renderFaceYPos(block, x, y, z, null); clearOverrideBlockTexture(); - resetBoundary(ForgeDirection.UP); super.renderFaceYPos(block, x, y, z, icon); } @Override public void renderFaceZNeg(Block block, double x, double y, double z, IIcon icon) { - shiftBoundary(ForgeDirection.NORTH); setOverrideBlockTexture(getBase(x, y, z, ForgeDirection.NORTH.ordinal())); super.renderFaceZNeg(block, x, y, z, null); clearOverrideBlockTexture(); - resetBoundary(ForgeDirection.NORTH); super.renderFaceZNeg(block, x, y, z, icon); } @Override public void renderFaceZPos(Block block, double x, double y, double z, IIcon icon) { - shiftBoundary(ForgeDirection.SOUTH); setOverrideBlockTexture(getBase(x, y, z, ForgeDirection.SOUTH.ordinal())); super.renderFaceZPos(block, x, y, z, null); clearOverrideBlockTexture(); - resetBoundary(ForgeDirection.SOUTH); super.renderFaceZPos(block, x, y, z, icon); } @@ -98,79 +86,6 @@ public class SubmapManagerVoidstone extends SubmapManagerBase { MathHelper.floor_double(z), side); } - - private void shiftBoundary(ForgeDirection direction) { - // When rendering a CTM overlay texture over a base block texture the base texture starts to z-fight. - // This method makes the base texture render slightly below the overlay. - // This submap check makes sure that we only apply this hack for blocks with CTM overlays - if (submap == null) { - return; - } - - float epsilon = 0.0005F; - - switch (direction) { - case WEST -> { - renderMinX += epsilon; - renderMinX += epsilon; - } - case EAST -> { - renderMinX -= epsilon; - renderMaxX -= epsilon; - } - case DOWN -> { - renderMinY += epsilon; - renderMaxY += epsilon; - } - case UP -> { - renderMinY -= epsilon; - renderMaxY -= epsilon; - } - case NORTH -> { - renderMinZ += epsilon; - renderMaxZ += epsilon; - } - case SOUTH -> { - renderMinZ -= epsilon; - renderMaxZ -= epsilon; - } - } - } - - private void resetBoundary(ForgeDirection direction) { - if (submap == null) { - return; - } - - float epsilon = 0.0005F; - - switch (direction) { - case WEST -> { - renderMinX -= epsilon; - renderMaxX -= epsilon; - } - case EAST -> { - renderMinX += epsilon; - renderMaxX += epsilon; - } - case DOWN -> { - renderMinY -= epsilon; - renderMaxY -= epsilon; - } - case UP -> { - renderMinY += epsilon; - renderMaxY += epsilon; - } - case NORTH -> { - renderMinZ -= epsilon; - renderMaxZ -= epsilon; - } - case SOUTH -> { - renderMinZ += epsilon; - renderMaxZ += epsilon; - } - } - } } @SideOnly(Side.CLIENT) diff --git a/src/main/java/team/chisel/ctmlib/RenderBlocksCTM.java b/src/main/java/team/chisel/ctmlib/RenderBlocksCTM.java index 29a73ed6..c2f7b9d1 100644 --- a/src/main/java/team/chisel/ctmlib/RenderBlocksCTM.java +++ b/src/main/java/team/chisel/ctmlib/RenderBlocksCTM.java @@ -361,6 +361,61 @@ public class RenderBlocksCTM extends RenderBlocks { protected void side(Block block, SubSide side, int iconIndex) { + // If we have an overridden texture when we're supposed to render a CTM texture, + // we'll treat it as a normal block texture but still render it the CTM way: quarter of a texture at a time. + // This way has one benefit: if an overridden texture is a base block texture and a CTM texture (that is being + // rendered next) is an overlay texture above the base, we're avoiding any z-fighting issues because we + // create identical vertices and now only order of rendering dictates which texture will be rendered above + if (hasOverrideBlockTexture()) { + IIcon icon = overrideBlockTexture; + + double u0 = icon.getMinU(); + double u1 = icon.getMaxU(); + double v0 = icon.getMinV(); + double v1 = icon.getMaxV(); + + double uMid = (u0 + u1) / 2; + double vMid = (v0 + v1) / 2; + + // Map all LB-style subsides to bottom-left quarter, RB to bottom-right, RT to top-right, LT to top-left + switch (side) { + // bottom-left quarter + case XNEG_LB, XPOS_LB, YNEG_LB, YPOS_LB, ZNEG_LB, ZPOS_LB -> { + minU = u0; + maxU = uMid; + minV = vMid; + maxV = v1; + } + + // bottom-right quarter + case XNEG_RB, XPOS_RB, YNEG_RB, YPOS_RB, ZNEG_RB, ZPOS_RB -> { + minU = uMid; + maxU = u1; + minV = vMid; + maxV = v1; + } + + // top-right quarter + case XNEG_RT, XPOS_RT, YNEG_RT, YPOS_RT, ZNEG_RT, ZPOS_RT -> { + minU = uMid; + maxU = u1; + minV = v0; + maxV = vMid; + } + + // top-left quarter + case XNEG_LT, XPOS_LT, YNEG_LT, YPOS_LT, ZNEG_LT, ZPOS_LT -> { + minU = u0; + maxU = uMid; + minV = v0; + maxV = vMid; + } + } + + side.render(this); + return; + } + IIcon icon; TextureSubmap map; if (iconIndex >= 16) { @@ -378,25 +433,10 @@ public class RenderBlocksCTM extends RenderBlocks { icon = map.getSubIcon(x, y); } - double umax = icon.getMaxU(); - double umin = icon.getMinU(); - double vmax = icon.getMaxV(); - double vmin = icon.getMinV(); - - minU = umin; - maxU = umax; - minV = vmin; - maxV = vmax; - - // uCache[0] = umin; - // uCache[1] = umax; - // uCache[2] = umax; - // uCache[3] = umin; - // - // vCache[0] = vmax; - // vCache[1] = vmax; - // vCache[2] = vmin; - // vCache[3] = vmin; + minU = icon.getMinU(); + maxU = icon.getMaxU(); + minV = icon.getMinV(); + maxV = icon.getMaxV(); side.render(this); } @@ -404,7 +444,7 @@ public class RenderBlocksCTM extends RenderBlocks { @Override public void renderFaceXNeg(Block block, double x, double y, double z, IIcon icon) { pre(ForgeDirection.WEST); - if (!inWorld || hasOverrideBlockTexture() || submap == null) { + if (!inWorld || submap == null) { super.renderFaceXNeg(block, 0, 0, 0, icon); } else { int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 4); @@ -429,7 +469,7 @@ public class RenderBlocksCTM extends RenderBlocks { @Override public void renderFaceXPos(Block block, double x, double y, double z, IIcon icon) { pre(ForgeDirection.EAST); - if (!inWorld || hasOverrideBlockTexture() || submap == null) { + if (!inWorld || submap == null) { super.renderFaceXPos(block, 0, 0, 0, icon); } else { int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 5); @@ -454,7 +494,7 @@ public class RenderBlocksCTM extends RenderBlocks { @Override public void renderFaceZNeg(Block block, double x, double y, double z, IIcon icon) { pre(ForgeDirection.NORTH); - if (!inWorld || hasOverrideBlockTexture() || submap == null) { + if (!inWorld || submap == null) { super.renderFaceZNeg(block, 0, 0, 0, icon); } else { int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 2); @@ -479,7 +519,7 @@ public class RenderBlocksCTM extends RenderBlocks { @Override public void renderFaceZPos(Block block, double x, double y, double z, IIcon icon) { pre(ForgeDirection.SOUTH); - if (!inWorld || hasOverrideBlockTexture() || submap == null) { + if (!inWorld || submap == null) { super.renderFaceZPos(block, 0, 0, 0, icon); } else { int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 3); @@ -504,7 +544,7 @@ public class RenderBlocksCTM extends RenderBlocks { @Override public void renderFaceYNeg(Block block, double x, double y, double z, IIcon icon) { pre(ForgeDirection.DOWN); - if (!inWorld || hasOverrideBlockTexture() || submap == null) { + if (!inWorld || submap == null) { super.renderFaceYNeg(block, 0, 0, 0, icon); } else { int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 0); @@ -529,7 +569,7 @@ public class RenderBlocksCTM extends RenderBlocks { @Override public void renderFaceYPos(Block block, double x, double y, double z, IIcon icon) { pre(ForgeDirection.UP); - if (!inWorld || hasOverrideBlockTexture() || submap == null) { + if (!inWorld || submap == null) { super.renderFaceYPos(block, 0, 0, 0, icon); } else { int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 1);