From fe82cd320a10b6c42075c42fd51a30c9a578d97d Mon Sep 17 00:00:00 2001 From: Eclipse-Sol Date: Sat, 3 Oct 2026 16:19:15 -0400 Subject: [PATCH] Plenty of fixes for GTNH (#2202) --- .../gtnewhorizons/angelica/glsm/StateSet.java | 12 +- .../glsm/ffp/GeometryShaderGenerator.java | 38 +++-- .../angelica/glsm/GLSM_StateSet_GLTest.java | 24 ++- .../angelica/glsm/ffp/WideLineClipGLTest.java | 114 ++++++++++++++ .../client/font/BatchingFontRenderer.java | 53 ++++--- .../angelica/client/font/TextDrawState.java | 95 ++++++++++++ .../angelica/dynamiclights/DynamicLights.java | 7 +- .../angelica/helpers/ItemBlockLight.java | 97 ++++++++++++ .../angelica/render/SelectionBoxRenderer.java | 3 - .../celeritas/CeleritasWorldRenderer.java | 4 + .../rendering/tesr/BakedTransformCapture.java | 17 +- .../rendering/tesr/BatchDrawDefaults.java | 5 + .../java/jss/notfine/gui/GuiCustomMenu.java | 10 +- .../notfine/gui/GuiCustomOptionsRowList.java | 12 +- .../control/element/SliderControlElement.java | 24 +++ .../gui/ReeseSodiumVideoOptionsScreen.java | 13 ++ .../components/SearchTextFieldComponent.java | 5 + .../sodium/client/gui/SodiumOptionsGUI.java | 18 ++- .../element/SodiumControlElementFactory.java | 25 +++ src/main/java/net/coderbot/iris/Iris.java | 4 - .../iris/pipeline/PipelineManager.java | 2 + .../api/v0/item/IrisItemLightProvider.java | 4 +- .../angelica/shaders/selection_box.geom.glsl | 18 ++- .../celeritas/terrain/MixinRenderGlobal.java | 2 + .../early/shaders/MixinRenderGlobal.java | 6 + .../client/font/TextDrawStateGLTest.java | 145 ++++++++++++++++++ 26 files changed, 675 insertions(+), 82 deletions(-) create mode 100644 glsm/src/test/java/com/gtnewhorizons/angelica/glsm/ffp/WideLineClipGLTest.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/client/font/TextDrawState.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/helpers/ItemBlockLight.java create mode 100644 src/test/java/com/gtnewhorizons/angelica/client/font/TextDrawStateGLTest.java diff --git a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/StateSet.java b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/StateSet.java index eee819af5..05910cfb4 100644 --- a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/StateSet.java +++ b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/StateSet.java @@ -107,9 +107,11 @@ public final class StateSet { GLStateManager.getTextures().getTextureUnitBindings(0), GLStateManager.getTextures().getTextureUnitBindings(1), GLStateManager.getActiveTextureUnitStack(), GLStateManager.getProgramStack(), GLStateManager.getBlendMode(), GLStateManager.getAlphaTest(), GLStateManager.getDepthTest(), - GLStateManager.getTextures().getTextureUnitStates(0) + GLStateManager.getTextures().getTextureUnitStates(0), + GLStateManager.getColorMask(), GLStateManager.getCullState(), + GLStateManager.getPolygonState(), GLStateManager.getPolygonOffsetFillState() ), - R_BLEND | R_DEPTH | R_TEXTURE | R_ACTIVE_UNIT | R_PROGRAM, + R_BLEND | R_DEPTH | R_COLOR_MASK | R_TEXTURE | R_ACTIVE_UNIT | R_PROGRAM | R_POLYGON, 0, true); } @@ -121,9 +123,11 @@ public final class StateSet { GLStateManager.getTextures().getTextureUnitBindings(0), GLStateManager.getTextures().getTextureUnitBindings(1), GLStateManager.getActiveTextureUnitStack(), GLStateManager.getBlendMode(), GLStateManager.getAlphaTest(), GLStateManager.getDepthTest(), - GLStateManager.getTextures().getTextureUnitStates(0) + GLStateManager.getTextures().getTextureUnitStates(0), + GLStateManager.getColorMask(), GLStateManager.getCullState(), + GLStateManager.getPolygonState(), GLStateManager.getPolygonOffsetFillState() ), - R_BLEND | R_DEPTH | R_TEXTURE | R_ACTIVE_UNIT, + R_BLEND | R_DEPTH | R_COLOR_MASK | R_TEXTURE | R_ACTIVE_UNIT | R_POLYGON, 0, true); } diff --git a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/ffp/GeometryShaderGenerator.java b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/ffp/GeometryShaderGenerator.java index a64d3e5de..7c41268ce 100644 --- a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/ffp/GeometryShaderGenerator.java +++ b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/ffp/GeometryShaderGenerator.java @@ -54,9 +54,17 @@ public final class GeometryShaderGenerator { sb.append(" vec4 c0 = gl_in[0].gl_Position;\n"); sb.append(" vec4 c1 = gl_in[1].gl_Position;\n\n"); + sb.append(" float d0 = c0.z + c0.w;\n"); + sb.append(" float d1 = c1.z + c1.w;\n"); + sb.append(" if (d0 < 0.0 && d1 < 0.0) return;\n"); + sb.append(" float t0 = d0 < 0.0 ? d0 / (d0 - d1) : 0.0;\n"); + sb.append(" float t1 = d1 < 0.0 ? d0 / (d0 - d1) : 1.0;\n"); + sb.append(" vec4 p0 = mix(c0, c1, t0);\n"); + sb.append(" vec4 p1 = mix(c0, c1, t1);\n\n"); + sb.append(" // NDC positions\n"); - sb.append(" vec2 n0 = c0.xy / c0.w;\n"); - sb.append(" vec2 n1 = c1.xy / c1.w;\n\n"); + sb.append(" vec2 n0 = p0.xy / p0.w;\n"); + sb.append(" vec2 n1 = p1.xy / p1.w;\n\n"); sb.append(" // Screen-space direction and perpendicular\n"); sb.append(" vec2 dir = normalize((n1 - n0) * u_ViewportSize);\n"); @@ -74,22 +82,22 @@ public final class GeometryShaderGenerator { } private static void emitVertex(StringBuilder sb, VertexKey key, int endpointIdx, String offsetExpr) { - final String ci = "c" + endpointIdx; + final String pi = "p" + endpointIdx; final String ni = "n" + endpointIdx; - final String idx = "[" + endpointIdx + "]"; + final String ti = "t" + endpointIdx; sb.append(" // Endpoint ").append(endpointIdx).append(' ').append(offsetExpr).append('\n'); - sb.append(" v_Color = v_Color_gs").append(idx).append(";\n"); + sb.append(" v_Color = ").append(lerp("v_Color_gs", ti)).append(";\n"); if (key.separateSpecular()) { - sb.append(" v_SpecularColor = v_SpecularColor_gs").append(idx).append(";\n"); + sb.append(" v_SpecularColor = ").append(lerp("v_SpecularColor_gs", ti)).append(";\n"); } - if (key.unitTexCoordEnabled(0) || key.texGenEnabled()) sb.append(" v_TexCoord0 = v_TexCoord0_gs").append(idx).append(";\n"); - if (key.lightmapEnabled()) sb.append(" v_TexCoord1 = v_TexCoord1_gs").append(idx).append(";\n"); - if (key.unitTexCoordEnabled(2)) sb.append(" v_TexCoord2 = v_TexCoord2_gs").append(idx).append(";\n"); - if (key.unitTexCoordEnabled(3)) sb.append(" v_TexCoord3 = v_TexCoord3_gs").append(idx).append(";\n"); + if (key.unitTexCoordEnabled(0) || key.texGenEnabled()) sb.append(" v_TexCoord0 = ").append(lerp("v_TexCoord0_gs", ti)).append(";\n"); + if (key.lightmapEnabled()) sb.append(" v_TexCoord1 = ").append(lerp("v_TexCoord1_gs", ti)).append(";\n"); + if (key.unitTexCoordEnabled(2)) sb.append(" v_TexCoord2 = ").append(lerp("v_TexCoord2_gs", ti)).append(";\n"); + if (key.unitTexCoordEnabled(3)) sb.append(" v_TexCoord3 = ").append(lerp("v_TexCoord3_gs", ti)).append(";\n"); if (key.fogEnabled()) { - sb.append(" v_FogCoord = v_FogCoord_gs").append(idx).append(";\n"); + sb.append(" v_FogCoord = ").append(lerp("v_FogCoord_gs", ti)).append(";\n"); } if (key.lineStipple()) { sb.append(" v_LineStart = v_LineStart_gs[0];\n"); @@ -97,11 +105,15 @@ public final class GeometryShaderGenerator { if (key.clipPlanesEnabled()) { for (int i = 0; i < 8; i++) { - sb.append(" gl_ClipDistance[").append(i).append("] = gl_in").append(idx).append(".gl_ClipDistance[").append(i).append("];\n"); + sb.append(" gl_ClipDistance[").append(i).append("] = mix(gl_in[0].gl_ClipDistance[").append(i).append("], gl_in[1].gl_ClipDistance[").append(i).append("], ").append(ti).append(");\n"); } } - sb.append(" gl_Position = vec4((").append(ni).append(' ').append(offsetExpr).append(") * ").append(ci).append(".w, ").append(ci).append(".z, ").append(ci).append(".w);\n"); + sb.append(" gl_Position = vec4((").append(ni).append(' ').append(offsetExpr).append(") * ").append(pi).append(".w, ").append(pi).append(".z, ").append(pi).append(".w);\n"); sb.append(" EmitVertex();\n\n"); } + + private static String lerp(String input, String t) { + return "mix(" + input + "[0], " + input + "[1], " + t + ")"; + } } diff --git a/glsm/src/test/java/com/gtnewhorizons/angelica/glsm/GLSM_StateSet_GLTest.java b/glsm/src/test/java/com/gtnewhorizons/angelica/glsm/GLSM_StateSet_GLTest.java index 3838d8f62..8c28a53dc 100644 --- a/glsm/src/test/java/com/gtnewhorizons/angelica/glsm/GLSM_StateSet_GLTest.java +++ b/glsm/src/test/java/com/gtnewhorizons/angelica/glsm/GLSM_StateSet_GLTest.java @@ -89,33 +89,41 @@ public class GLSM_StateSet_GLTest { } @Test - void fontRestoresDepthAxisAndShadeModelButNotCull() { + void fontRestoresDepthAxisShadeModelAndPolygonOffsetButNotStencil() { try { GLStateManager.enableDepthTest(); GLStateManager.glDepthFunc(GL11.GL_LEQUAL); GLStateManager.glShadeModel(GL11.GL_SMOOTH); - GLStateManager.enableCull(); - GLStateManager.glCullFace(GL11.GL_BACK); + GLStateManager.glDisable(GL11.GL_POLYGON_OFFSET_FILL); + GLStateManager.glPolygonOffset(0.0f, 0.0f); + GLStateManager.glEnable(GL11.GL_STENCIL_TEST); final int d = GLStateManager.pushState(StateSet.FONT); GLStateManager.disableDepthTest(); GLStateManager.glDepthFunc(GL11.GL_ALWAYS); GLStateManager.glShadeModel(GL11.GL_FLAT); - GLStateManager.glCullFace(GL11.GL_FRONT); + GLStateManager.glEnable(GL11.GL_POLYGON_OFFSET_FILL); + GLStateManager.glPolygonOffset(-10.0f, -10.0f); + GLStateManager.glDisable(GL11.GL_STENCIL_TEST); GLStateManager.popStateTo(d); verifyIsEnabled(GL11.GL_DEPTH_TEST, true, "Depth test enable - restored by FONT pop"); assertEquals(GL11.GL_LEQUAL, GLStateManager.getDepthState().getFunc(), "cache depth func"); assertEquals(GL11.GL_LEQUAL, GL11.glGetInteger(GL11.GL_DEPTH_FUNC), "driver depth func"); assertEquals(GL11.GL_SMOOTH, GLStateManager.getShadeModelState().getValue(), "cache shade model"); - assertEquals(GL11.GL_FRONT, GLStateManager.getPolygonState().getCullFaceMode(), "cache cull face mode - not a FONT member, must stay toggled"); - assertEquals(GL11.GL_FRONT, GL11.glGetInteger(GL11.GL_CULL_FACE_MODE), "driver cull face mode - not a FONT member, must stay toggled"); + verifyIsEnabled(GL11.GL_POLYGON_OFFSET_FILL, false, "Polygon offset fill - restored by FONT pop"); + assertEquals(0.0f, GLStateManager.getPolygonState().getOffsetFactor(), "cache polygon offset factor"); + assertEquals(0.0f, GL11.glGetFloat(GL11.GL_POLYGON_OFFSET_FACTOR), "driver polygon offset factor"); + assertEquals(0.0f, GLStateManager.getPolygonState().getOffsetUnits(), "cache polygon offset units"); + assertEquals(0.0f, GL11.glGetFloat(GL11.GL_POLYGON_OFFSET_UNITS), "driver polygon offset units"); + verifyIsEnabled(GL11.GL_STENCIL_TEST, false, "Stencil test - not a FONT member, must stay toggled"); } finally { GLStateManager.disableDepthTest(); GLStateManager.glDepthFunc(GL11.GL_LESS); GLStateManager.glShadeModel(GL11.GL_SMOOTH); - GLStateManager.disableCull(); - GLStateManager.glCullFace(GL11.GL_BACK); + GLStateManager.glDisable(GL11.GL_POLYGON_OFFSET_FILL); + GLStateManager.glPolygonOffset(0.0f, 0.0f); + GLStateManager.glDisable(GL11.GL_STENCIL_TEST); } } diff --git a/glsm/src/test/java/com/gtnewhorizons/angelica/glsm/ffp/WideLineClipGLTest.java b/glsm/src/test/java/com/gtnewhorizons/angelica/glsm/ffp/WideLineClipGLTest.java new file mode 100644 index 000000000..c189730b4 --- /dev/null +++ b/glsm/src/test/java/com/gtnewhorizons/angelica/glsm/ffp/WideLineClipGLTest.java @@ -0,0 +1,114 @@ +package com.gtnewhorizons.angelica.glsm.ffp; + +import com.gtnewhorizons.angelica.glsm.GLCoreTest; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL15; + +import java.nio.FloatBuffer; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +@GLCoreTest +class WideLineClipGLTest { + + private static final int SIZE = 64; + private static final double NEAR = 0.05; + private static final float LINE_WIDTH = 3.0f; + private static final int BACKGROUND = 0xFF000000; + + private static final float[] IN_FRONT = { 0f, -1f, -2f }; + private static final float[] BEHIND = { 0f, 0.8f, 2f }; + + private boolean savedEmulation; + private int vao; + private int vbo; + + @BeforeEach + void setUp() { + assumeTrue(GLStateManager.supportsGeometryShaders()); + savedEmulation = GLStateManager.wideLineEmulationEnabled; + GLStateManager.wideLineEmulationEnabled = true; + + FfpFixture.resetFfpState(); + ShaderManager.enable(); + ShaderManager.getInstance().activate(); + GLStateManager.glViewport(0, 0, SIZE, SIZE); + GLStateManager.glMatrixMode(GL11.GL_PROJECTION); + GLStateManager.glLoadIdentity(); + GLStateManager.glFrustum(-NEAR, NEAR, -NEAR, NEAR, NEAR, 100.0); + GLStateManager.glMatrixMode(GL11.GL_MODELVIEW); + GLStateManager.glLoadIdentity(); + GLStateManager.glDisable(GL11.GL_DEPTH_TEST); + GLStateManager.glLineWidth(LINE_WIDTH); + } + + @AfterEach + void tearDown() { + GLStateManager.wideLineEmulationEnabled = savedEmulation; + GLStateManager.glLineWidth(1.0f); + if (vbo != 0) { GLStateManager.glDeleteBuffers(vbo); vbo = 0; } + if (vao != 0) { GLStateManager.glDeleteVertexArrays(vao); vao = 0; } + GLStateManager.glMatrixMode(GL11.GL_PROJECTION); + GLStateManager.glLoadIdentity(); + GLStateManager.glMatrixMode(GL11.GL_MODELVIEW); + FfpFixture.resetFfpState(); + while (GL11.glGetError() != GL11.GL_NO_ERROR) {} + } + + @Test + void lineEndingBehindTheCameraKeepsItsWidth() { + assertConstantWidth(IN_FRONT, BEHIND); + } + + @Test + void lineStartingBehindTheCameraKeepsItsWidth() { + assertConstantWidth(BEHIND, IN_FRONT); + } + + @Test + void lineFullyBehindTheCameraDrawsNothing() { + final int[] pixels = drawLine(new float[] { 0f, -1f, 2f }, BEHIND); + for (int px : pixels) { + assertEquals(BACKGROUND, px); + } + } + + private void assertConstantWidth(float[] start, float[] end) { + final int[] pixels = drawLine(start, end); + for (int row = 0; row < SIZE / 4; row++) { + int lit = 0; + for (int x = 0; x < SIZE; x++) { + if (pixels[row * SIZE + x] != BACKGROUND) lit++; + } + final int y = row, count = lit; + assertTrue(count > 0 && count <= LINE_WIDTH + 1, () -> "row " + y + " is " + count + " pixels wide"); + } + assertEquals(GL11.GL_NO_ERROR, GL11.glGetError()); + } + + private int[] drawLine(float[] start, float[] end) { + vao = GLStateManager.glGenVertexArrays(); + GLStateManager.glBindVertexArray(vao); + vbo = GLStateManager.glGenBuffers(); + GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo); + final FloatBuffer positions = BufferUtils.createFloatBuffer(6); + positions.put(start).put(end).flip(); + GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, positions, GL15.GL_STATIC_DRAW); + FfpFixture.attrib(0, 3, GL11.GL_FLOAT, false, 12, 0); + GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); + VAOManager.setCurrentVertexFlags(0); + + FfpFixture.clear(); + GLStateManager.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GLStateManager.glDrawArrays(GL11.GL_LINES, 0, 2); + GLStateManager.glBindVertexArray(0); + return FfpFixture.readRegion(SIZE); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java b/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java index e02dad3e6..f7028170b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java @@ -192,6 +192,9 @@ public class BatchingFontRenderer { private int lightmapTextureId = 0; private int lightmapPackedLight = -1; + private final TextDrawState drawState = new TextDrawState(); + private final TextDrawState liveDrawState = new TextDrawState(); + private final Vector3f lightingFactor = new Vector3f(1.0f, 1.0f, 1.0f); private boolean lightingFactorActive = false; @@ -243,6 +246,13 @@ public class BatchingFontRenderer { lightmapPackedLight = packedLight; } + private void captureDrawState() { + liveDrawState.captureLive(); + if (liveDrawState.sameAs(drawState)) return; + sealBatchSegment(); + drawState.set(liveDrawState); + } + private static final class TextSegment { final Matrix4f mvp = new Matrix4f(); final Matrix4f modelView = new Matrix4f(); @@ -256,8 +266,7 @@ public class BatchingFontRenderer { int packedLight; float normalX, normalY, normalZ; int blockEntityId; - boolean depthTest; - boolean depthMask; + final TextDrawState drawState = new TextDrawState(); } // 16-bit EBO index range @@ -543,8 +552,7 @@ public class BatchingFontRenderer { segment.normalY = normal.y; segment.normalZ = normal.z; segment.blockEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedBlockEntity(); - segment.depthTest = GLStateManager.getDepthTest().isEnabled(); - segment.depthMask = GLStateManager.isEffectiveDepthMaskEnabled(); + segment.drawState.set(drawState); batchSegments.add(segment); batchSealedEnd = end; } @@ -576,7 +584,8 @@ public class BatchingFontRenderer { private static boolean shouldDeferNow() { if (!GLStateManager.isMainThread()) return false; - return TesrBatchRenderer.INSTANCE.hasPendingGeometry() || ModelPartBatcher.INSTANCE.isActive(); + return (TesrBatchRenderer.INSTANCE.hasPendingGeometry() || ModelPartBatcher.INSTANCE.isActive()) + && BatchDrawDefaults.drawsToPassFramebuffer(); } public void beginDeferredBatch() { @@ -664,23 +673,13 @@ public class BatchingFontRenderer { GLStateManager.glMatrixMode(GL11.GL_MODELVIEW); GLStateManager.glPushMatrix(); try { - boolean curDepthTest = GLStateManager.getDepthTest().isEnabled(); - boolean curDepthMask = GLStateManager.isEffectiveDepthMaskEnabled(); for (final TextSegment segment : deferredSegments) { final BatchingFontRenderer owner = segment.owner; if (segment.cmdStart == segment.cmdEnd) continue; GLStateManager.setModelViewMatrix(segment.modelView); CapturedRenderingState.INSTANCE.setCurrentBlockEntity(segment.blockEntityId); - - if (segment.depthTest != curDepthTest) { - if (segment.depthTest) GLStateManager.enableDepthTest(); else GLStateManager.disableDepthTest(); - curDepthTest = segment.depthTest; - } - if (segment.depthMask != curDepthMask) { - GLStateManager.glDepthMask(segment.depthMask); - curDepthMask = segment.depthMask; - } + segment.drawState.apply(); final FontDrawCmd[] cmdsData = owner.batchCommands.elements(); Arrays.sort(cmdsData, segment.cmdStart, segment.cmdEnd, FontDrawCmd.DRAW_ORDER_COMPARATOR); @@ -708,22 +707,13 @@ public class BatchingFontRenderer { deferredSegments.get(0).owner.setupFontDrawState(); flushLastTexture = INVALID_TEXTURE; resetFlushLightmap(); - boolean curDepthTest = GLStateManager.getDepthTest().isEnabled(); - boolean curDepthMask = GLStateManager.isEffectiveDepthMaskEnabled(); for (final TextSegment segment : deferredSegments) { FLUSH_MVP.clear(); segment.mvp.get(FLUSH_MVP); GLStateManager.glUniformMatrix4(segment.owner.mvpMatrixLocation, false, FLUSH_MVP); uploadLightmap(segment.owner.lightmapLocation, segment.lightmapActive, segment.lightmapU, segment.lightmapV, segment.lightmapTexture); - if (segment.depthTest != curDepthTest) { - if (segment.depthTest) GLStateManager.enableDepthTest(); else GLStateManager.disableDepthTest(); - curDepthTest = segment.depthTest; - } - if (segment.depthMask != curDepthMask) { - GLStateManager.glDepthMask(segment.depthMask); - curDepthMask = segment.depthMask; - } + segment.owner.applyDrawState(segment.drawState); drawCommands(segment.owner.batchCommands.elements(), segment.cmdStart, segment.cmdEnd, segment.owner); } } finally { @@ -734,6 +724,11 @@ public class BatchingFontRenderer { } } + private void applyDrawState(TextDrawState state) { + state.apply(); + GLStateManager.glUniform1f(alphaTestRefLocation, state.alphaRef); + } + public static void discardDeferredText() { if (deferredSegments.isEmpty()) return; for (int i = 0, n = deferredSegments.size(); i < n; i++) { @@ -841,6 +836,7 @@ public class BatchingFontRenderer { segment.mvp.get(FLUSH_MVP); GLStateManager.glUniformMatrix4(mvpMatrixLocation, false, FLUSH_MVP); uploadLightmap(lightmapLocation, segment.lightmapActive, segment.lightmapU, segment.lightmapV, segment.lightmapTexture); + applyDrawState(segment.drawState); drawCommands(cmds, segment.cmdStart, segment.cmdEnd, this); } if (batchSealedEnd < cmdCount) { @@ -849,6 +845,7 @@ public class BatchingFontRenderer { scratchMvp.get(FLUSH_MVP); GLStateManager.glUniformMatrix4(mvpMatrixLocation, false, FLUSH_MVP); uploadLightmap(lightmapLocation, lightmapActive, lightmapU, lightmapV, lightmapTextureId); + applyDrawState(drawState); drawCommands(cmds, batchSealedEnd, cmdCount, this); } } finally { @@ -882,7 +879,6 @@ public class BatchingFontRenderer { fontBrightnessLast = FontConfig.fontBrightness; GLStateManager.glUniform1f(fontBrightness, 0.625f * FontConfig.fontBrightness + 0.1875f); } - GLStateManager.glUniform1f(alphaTestRefLocation, GLStateManager.getAlphaState().getReference()); if (lightmapSamplerProgram != fontShaderId) { GLStateManager.glUniform1i(lightmapSamplerLocation, LIGHTMAP_TEX_UNIT); lightmapSamplerProgram = fontShaderId; @@ -1011,12 +1007,14 @@ public class BatchingFontRenderer { if (segment.cmdStart == segment.cmdEnd) continue; GLStateManager.setModelViewMatrix(segment.modelView); CapturedRenderingState.INSTANCE.setCurrentBlockEntity(segment.blockEntityId); + segment.drawState.apply(); emitRangeThroughPipeline(this, cmdsData, segment.cmdStart, segment.cmdEnd, segment.packedLight, segment.normalX, segment.normalY, segment.normalZ); } if (batchSealedEnd < cmdCount) { GLStateManager.setModelViewMatrix(scratchModelView); CapturedRenderingState.INSTANCE.setCurrentBlockEntity(prevBlockEntityId); + drawState.apply(); final Vector3f normal = ShaderManager.getCurrentNormal(); emitRangeThroughPipeline(this, cmdsData, batchSealedEnd, cmdCount, lightmapPackedLight, normal.x, normal.y, normal.z); @@ -1241,6 +1239,7 @@ public class BatchingFontRenderer { this.beginBatch(); this.captureLightmapState(); + this.captureDrawState(); this.lightingFactorActive = isWorldSpaceText() && FFPVertexLighting.modulatesVertexColor(this.lightingFactor); float curX = anchorX; try { diff --git a/src/main/java/com/gtnewhorizons/angelica/client/font/TextDrawState.java b/src/main/java/com/gtnewhorizons/angelica/client/font/TextDrawState.java new file mode 100644 index 000000000..cd3ba9652 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/client/font/TextDrawState.java @@ -0,0 +1,95 @@ +package com.gtnewhorizons.angelica.client.font; + +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.glsm.states.ColorMask; +import com.gtnewhorizons.angelica.glsm.states.PolygonState; +import org.lwjgl.opengl.GL11; + +/** + * Drawing text picks up settings from whoever asked for it, such as depth testing, culling, polygon offset and + * alpha cutoff. Text is sometimes drawn later than requested, so these are saved with it to make the late draw + * look the same as an immediate one. + */ +final class TextDrawState { + private final ColorMask colorMaskScratch = new ColorMask(); + + boolean depthTest; + int depthFunc; + boolean depthMask; + boolean colorRed; + boolean colorGreen; + boolean colorBlue; + boolean colorAlpha; + boolean cull; + int cullFace; + int frontFace; + boolean polygonOffset; + float offsetFactor; + float offsetUnits; + float alphaRef; + + void captureLive() { + depthTest = GLStateManager.getDepthTest().isEnabled(); + depthFunc = GLStateManager.getDepthState().getFunc(); + depthMask = GLStateManager.isEffectiveDepthMaskEnabled(); + final ColorMask colorMask = GLStateManager.getEffectiveColorMask(colorMaskScratch); + colorRed = colorMask.red; + colorGreen = colorMask.green; + colorBlue = colorMask.blue; + colorAlpha = colorMask.alpha; + final PolygonState polygon = GLStateManager.getPolygonState(); + cull = GLStateManager.getCullState().isEnabled(); + cullFace = polygon.getCullFaceMode(); + frontFace = polygon.getFrontFace(); + polygonOffset = GLStateManager.getPolygonOffsetFillState().isEnabled(); + offsetFactor = polygon.getOffsetFactor(); + offsetUnits = polygon.getOffsetUnits(); + alphaRef = GLStateManager.getAlphaState().getReference(); + } + + boolean sameAs(TextDrawState other) { + return depthTest == other.depthTest + && depthFunc == other.depthFunc + && depthMask == other.depthMask + && colorRed == other.colorRed + && colorGreen == other.colorGreen + && colorBlue == other.colorBlue + && colorAlpha == other.colorAlpha + && cull == other.cull + && cullFace == other.cullFace + && frontFace == other.frontFace + && polygonOffset == other.polygonOffset + && offsetFactor == other.offsetFactor + && offsetUnits == other.offsetUnits + && alphaRef == other.alphaRef; + } + + void set(TextDrawState other) { + depthTest = other.depthTest; + depthFunc = other.depthFunc; + depthMask = other.depthMask; + colorRed = other.colorRed; + colorGreen = other.colorGreen; + colorBlue = other.colorBlue; + colorAlpha = other.colorAlpha; + cull = other.cull; + cullFace = other.cullFace; + frontFace = other.frontFace; + polygonOffset = other.polygonOffset; + offsetFactor = other.offsetFactor; + offsetUnits = other.offsetUnits; + alphaRef = other.alphaRef; + } + + void apply() { + if (depthTest) GLStateManager.enableDepthTest(); else GLStateManager.disableDepthTest(); + GLStateManager.glDepthFunc(depthFunc); + GLStateManager.glDepthMask(depthMask); + GLStateManager.glColorMask(colorRed, colorGreen, colorBlue, colorAlpha); + if (cull) GLStateManager.enableCull(); else GLStateManager.disableCull(); + GLStateManager.glCullFace(cullFace); + GLStateManager.glFrontFace(frontFace); + if (polygonOffset) GLStateManager.glEnable(GL11.GL_POLYGON_OFFSET_FILL); else GLStateManager.glDisable(GL11.GL_POLYGON_OFFSET_FILL); + GLStateManager.glPolygonOffset(offsetFactor, offsetUnits); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/dynamiclights/DynamicLights.java b/src/main/java/com/gtnewhorizons/angelica/dynamiclights/DynamicLights.java index 8199cf24c..51ad635c6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/dynamiclights/DynamicLights.java +++ b/src/main/java/com/gtnewhorizons/angelica/dynamiclights/DynamicLights.java @@ -12,12 +12,12 @@ import com.gtnewhorizons.angelica.compat.backhand.BackhandReflectionCompat; import com.gtnewhorizons.angelica.compat.battlegear2.Battlegear2Compat; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.dynamiclights.config.EntityLightConfig; +import com.gtnewhorizons.angelica.helpers.ItemBlockLight; import com.gtnewhorizons.angelica.mixins.interfaces.PrimedEntityAccessor; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import mods.battlegear2.api.core.IBattlePlayer; import net.irisshaders.iris.api.v0.IrisApi; -import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -586,10 +586,7 @@ public class DynamicLights { if (item instanceof IDynamicLightProducer lightProducer) { return lightProducer.getLuminance(stack); } else if (item instanceof ItemBlock itemBlock) { - final Block block = itemBlock.field_150939_a; - if (block != null) { - return block.getLightValue(); - } + return ItemBlockLight.getLightValue(itemBlock, stack); } if (item == Items.lava_bucket) return Blocks.lava.getLightValue(); diff --git a/src/main/java/com/gtnewhorizons/angelica/helpers/ItemBlockLight.java b/src/main/java/com/gtnewhorizons/angelica/helpers/ItemBlockLight.java new file mode 100644 index 000000000..d03e236b5 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/helpers/ItemBlockLight.java @@ -0,0 +1,97 @@ +package com.gtnewhorizons.angelica.helpers; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Light value of the block an ItemBlock stack would place. + */ +public final class ItemBlockLight { + + private static final SingleBlockAccess ACCESS = new SingleBlockAccess(); + + private ItemBlockLight() {} + + public static int getLightValue(ItemBlock item, ItemStack stack) { + final Block block = item.field_150939_a; + if (block == null) return 0; + ACCESS.set(block, item.getMetadata(stack.getItemDamage())); + try { + return block.getLightValue(ACCESS, 0, 0, 0); + } catch (RuntimeException e) { + return block.getLightValue(); + } finally { + ACCESS.set(Blocks.air, 0); + } + } + + private static final class SingleBlockAccess implements IBlockAccess { + private Block block = Blocks.air; + private int metadata; + + void set(Block block, int metadata) { + this.block = block; + this.metadata = metadata; + } + + private static boolean isOrigin(int x, int y, int z) { + return x == 0 && y == 0 && z == 0; + } + + @Override + public Block getBlock(int x, int y, int z) { + return isOrigin(x, y, z) ? block : Blocks.air; + } + + @Override + public int getBlockMetadata(int x, int y, int z) { + return isOrigin(x, y, z) ? metadata : 0; + } + + @Override + public TileEntity getTileEntity(int x, int y, int z) { + return null; + } + + @Override + public int getLightBrightnessForSkyBlocks(int x, int y, int z, int min) { + return min << 4; + } + + @Override + public int isBlockProvidingPowerTo(int x, int y, int z, int direction) { + return 0; + } + + @Override + public boolean isAirBlock(int x, int y, int z) { + return !isOrigin(x, y, z) || block == Blocks.air; + } + + @Override + public BiomeGenBase getBiomeGenForCoords(int x, int z) { + return BiomeGenBase.plains; + } + + @Override + public int getHeight() { + return 256; + } + + @Override + public boolean extendedLevelsInChunkCache() { + return false; + } + + @Override + public boolean isSideSolid(int x, int y, int z, ForgeDirection side, boolean _default) { + return false; + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/render/SelectionBoxRenderer.java b/src/main/java/com/gtnewhorizons/angelica/render/SelectionBoxRenderer.java index 5eeac5963..86d781872 100644 --- a/src/main/java/com/gtnewhorizons/angelica/render/SelectionBoxRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/render/SelectionBoxRenderer.java @@ -73,9 +73,6 @@ public final class SelectionBoxRenderer { public static void draw(AxisAlignedBB aabb, int color) { if (program == null || vao == null) return; - GLStateManager.enableDepthTest(); - GLStateManager.glDepthFunc(GL11.GL_LEQUAL); - final float minX = (float) aabb.minX, minY = (float) aabb.minY, minZ = (float) aabb.minZ; final float extX = (float) (aabb.maxX - aabb.minX); final float extY = (float) (aabb.maxY - aabb.minY); diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/CeleritasWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/CeleritasWorldRenderer.java index 7b717d114..2395e2dff 100644 --- a/src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/CeleritasWorldRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/CeleritasWorldRenderer.java @@ -119,6 +119,10 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer= 0 && TesrBatchRenderer.deferredPipeline() == null) { final int framebuffer = GLStateManager.getDrawFramebuffer(); diff --git a/src/main/java/jss/notfine/gui/GuiCustomMenu.java b/src/main/java/jss/notfine/gui/GuiCustomMenu.java index 9d70234d3..4e4f8a25b 100644 --- a/src/main/java/jss/notfine/gui/GuiCustomMenu.java +++ b/src/main/java/jss/notfine/gui/GuiCustomMenu.java @@ -3,7 +3,6 @@ package jss.notfine.gui; import me.jellysquid.mods.sodium.client.gui.options.OptionPage; import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiListExtended; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.resources.I18n; @@ -19,7 +18,7 @@ public class GuiCustomMenu extends GuiScreen { private final OptionPage[] subPages; protected String screenTitle; - private GuiListExtended optionsRowList; + private GuiCustomOptionsRowList optionsRowList; public GuiCustomMenu(GuiScreen parentGuiScreen, OptionPage optionPage, OptionPage... subPages) { this.parentGuiScreen = parentGuiScreen; @@ -30,6 +29,7 @@ public class GuiCustomMenu extends GuiScreen { @Override public void initGui() { + Keyboard.enableRepeatEvents(true); buttonList.clear(); buttonList.add(new GuiButton(200, width / 2 - 110, height - 27, I18n.format("gui.done"))); optionsRowList = new GuiCustomOptionsRowList(mc, width, height, 32, height - 32, 25, optionPage, subPages); @@ -88,9 +88,15 @@ public class GuiCustomMenu extends GuiScreen { if(keyCode == Keyboard.KEY_ESCAPE && !(parentGuiScreen instanceof GuiCustomMenu)) { saveChanges(); } + optionsRowList.keyTyped(keyCode); super.keyTyped(typedChar, keyCode); } + @Override + public void onGuiClosed() { + Keyboard.enableRepeatEvents(false); + } + private void saveChanges() { for(OptionStorage storage : dirtyStorages) { storage.save(); diff --git a/src/main/java/jss/notfine/gui/GuiCustomOptionsRowList.java b/src/main/java/jss/notfine/gui/GuiCustomOptionsRowList.java index 4c7a2b2ae..4ff334a9f 100644 --- a/src/main/java/jss/notfine/gui/GuiCustomOptionsRowList.java +++ b/src/main/java/jss/notfine/gui/GuiCustomOptionsRowList.java @@ -4,6 +4,7 @@ import com.google.common.collect.Lists; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import jss.notfine.gui.options.control.element.NotFineControlElementFactory; +import jss.notfine.gui.options.control.element.SliderControlElement; import me.jellysquid.mods.sodium.client.gui.options.Option; import me.jellysquid.mods.sodium.client.gui.options.OptionGroup; import me.jellysquid.mods.sodium.client.gui.options.OptionPage; @@ -20,6 +21,7 @@ import java.util.List; public class GuiCustomOptionsRowList extends GuiListExtended { private static final NotFineControlElementFactory factory = new NotFineControlElementFactory(); private final List settingsList = Lists.newArrayList(); + private GuiButton focusedButton; public GuiCustomOptionsRowList(Minecraft mc, int width, int height, int top, int bottom, int slotHeight, OptionPage optionPage, OptionPage... subPages) { super(mc, width, height, top, bottom, slotHeight); @@ -64,8 +66,14 @@ public class GuiCustomOptionsRowList extends GuiListExtended { return super.getScrollBarX() + 32; } + public void keyTyped(int keyCode) { + if(focusedButton instanceof SliderControlElement slider) { + slider.keyTyped(keyCode); + } + } + @SideOnly(Side.CLIENT) - public static class Row implements GuiListExtended.IGuiListEntry { + public class Row implements GuiListExtended.IGuiListEntry { private final Minecraft mc = Minecraft.getMinecraft(); private final GuiButton buttonOne, buttonTwo; @@ -93,9 +101,11 @@ public class GuiCustomOptionsRowList extends GuiListExtended { @Override public boolean mousePressed(int index, int x, int y, int mouseEvent, int relativeX, int relativeY) { if(buttonOne.mousePressed(mc, x, y)) { + focusedButton = buttonOne; return true; } if(buttonTwo != null && buttonTwo.mousePressed(mc, x, y)) { + focusedButton = buttonTwo; return true; } return false; diff --git a/src/main/java/jss/notfine/gui/options/control/element/SliderControlElement.java b/src/main/java/jss/notfine/gui/options/control/element/SliderControlElement.java index 22bc4c71d..66ab02a6e 100644 --- a/src/main/java/jss/notfine/gui/options/control/element/SliderControlElement.java +++ b/src/main/java/jss/notfine/gui/options/control/element/SliderControlElement.java @@ -6,6 +6,7 @@ import me.jellysquid.mods.sodium.client.util.Dim2i; import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.minecraft.client.Minecraft; import net.minecraft.util.MathHelper; +import org.lwjgl.input.Keyboard; public class SliderControlElement extends NotFineControlElement { private final ControlValueFormatter formatter; @@ -68,6 +69,29 @@ public class SliderControlElement extends NotFineControlElement { } } + public boolean keyTyped(int keyCode) { + if(!option.isAvailable()) { + return false; + } + + final int step; + if(keyCode == Keyboard.KEY_LEFT) { + step = -interval; + } else if(keyCode == Keyboard.KEY_RIGHT) { + step = interval; + } else { + return false; + } + + final int stepped = MathHelper.clamp_int(option.getValue() + step, min, max); + if(stepped != option.getValue()) { + option.setValue(stepped); + value = MathHelper.clamp_float((float)(stepped - min) / (max - min), 0f, 1f); + onOptionValueChanged(); + } + return true; + } + private void updateSlider(int mouseX) { value = (float)(mouseX - (xPosition + 4)) / (float)(width - 8); //Clamp normalized value diff --git a/src/main/java/me/flashyreese/mods/reeses_sodium_options/client/gui/ReeseSodiumVideoOptionsScreen.java b/src/main/java/me/flashyreese/mods/reeses_sodium_options/client/gui/ReeseSodiumVideoOptionsScreen.java index c98ef0c69..e38e80a1d 100644 --- a/src/main/java/me/flashyreese/mods/reeses_sodium_options/client/gui/ReeseSodiumVideoOptionsScreen.java +++ b/src/main/java/me/flashyreese/mods/reeses_sodium_options/client/gui/ReeseSodiumVideoOptionsScreen.java @@ -78,6 +78,7 @@ public class ReeseSodiumVideoOptionsScreen extends SodiumOptionsGUI { @Override public void initGui() { + Keyboard.enableRepeatEvents(true); this.frame = this.parentFrameBuilder().build(); this.children.add(this.frame); @@ -287,6 +288,18 @@ public class ReeseSodiumVideoOptionsScreen extends SodiumOptionsGUI { } } + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) { + final boolean onSearchField = this.searchTextField.isMouseOver(mouseX, mouseY); + + super.mouseClicked(mouseX, mouseY, mouseButton); + + if (!onSearchField) { + this.searchTextField.setFocused(false); + this.setFocused(this.frame); + } + } + @Override public boolean shouldCloseOnEsc() { return !this.hasPendingChanges; diff --git a/src/main/java/me/flashyreese/mods/reeses_sodium_options/client/gui/frame/components/SearchTextFieldComponent.java b/src/main/java/me/flashyreese/mods/reeses_sodium_options/client/gui/frame/components/SearchTextFieldComponent.java index 4b17926dd..64a33f016 100644 --- a/src/main/java/me/flashyreese/mods/reeses_sodium_options/client/gui/frame/components/SearchTextFieldComponent.java +++ b/src/main/java/me/flashyreese/mods/reeses_sodium_options/client/gui/frame/components/SearchTextFieldComponent.java @@ -154,6 +154,11 @@ public class SearchTextFieldComponent extends AbstractWidget { return this.isFocused(); } + @Override + public boolean isMouseOver(double mouseX, double mouseY) { + return this.dim.containsCursor(mouseX, mouseY); + } + private void drawSelectionHighlight(int x1, int y1, int x2, int y2) { int i; if (x1 < x2) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java index a64072509..980167e96 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java @@ -54,6 +54,7 @@ public class SodiumOptionsGUI extends ScrollableGuiScreen { protected boolean hasPendingChanges; protected ControlElement hoveredElement; + private Element focusedElement; protected OptionPage shaderPacks; @@ -97,13 +98,20 @@ public class SodiumOptionsGUI extends ScrollableGuiScreen { @Override public void initGui() { + Keyboard.enableRepeatEvents(true); this.rebuildGUI(); } + @Override + public void onGuiClosed() { + Keyboard.enableRepeatEvents(false); + } + protected void rebuildGUI() { this.controls.clear(); this.children.clear(); this.drawable.clear(); + this.focusedElement = null; if (this.currentPage == null) { if (this.pages.isEmpty()) { @@ -298,6 +306,10 @@ public class SodiumOptionsGUI extends ScrollableGuiScreen { SodiumGameOptionPages.quality(), SodiumGameOptionPages.advanced(), SodiumGameOptionPages.performance(), SodiumGameOptionPages.appearance())); } + + if (this.focusedElement != null) { + this.focusedElement.keyTyped(typedChar, keyCode); + } } public boolean shouldCloseOnEsc() { @@ -314,7 +326,11 @@ public class SodiumOptionsGUI extends ScrollableGuiScreen { protected void mouseClicked(int mouseX, int mouseY, int mouseButton) { super.mouseClicked(mouseX, mouseY, mouseButton); - this.children.forEach(element -> element.mouseClicked(mouseX, mouseY, mouseButton)); + this.children.forEach(element -> { + if (element.mouseClicked(mouseX, mouseY, mouseButton)) { + this.focusedElement = element; + } + }); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElementFactory.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElementFactory.java index 7e6e7273d..8fe5940db 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElementFactory.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElementFactory.java @@ -7,6 +7,7 @@ import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatte import me.jellysquid.mods.sodium.client.gui.utils.Rect2i; import me.jellysquid.mods.sodium.client.util.Dim2i; import net.minecraft.util.MathHelper; +import org.lwjgl.input.Keyboard; public class SodiumControlElementFactory implements ControlElementFactory { @Override @@ -194,6 +195,30 @@ public class SodiumControlElementFactory implements ControlElementFactory { return false; } + + @Override + public boolean keyTyped(char typedChar, int keyCode) { + if (!this.option.isAvailable()) { + return false; + } + + final int step; + if (keyCode == Keyboard.KEY_LEFT) { + step = -this.interval; + } else if (keyCode == Keyboard.KEY_RIGHT) { + step = this.interval; + } else { + return false; + } + + final int value = MathHelper.clamp_int(this.option.getValue() + step, this.min, this.min + this.range); + + if (this.option.getValue() != value) { + this.option.setValue(value); + } + + return true; + } } private static class TickBoxControlElement extends SodiumControlElement { diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 3cc428cda..a87b97fac 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -320,8 +320,6 @@ public class Iris { // See: https://github.com/IrisShaders/Iris/issues/323 lastDimensionName = "Overworld"; Iris.getPipelineManager().preparePipeline("Overworld"); - - BlockRenderingSettings.INSTANCE.reloadRendererIfRequired(); } public static void toggleShaders(Minecraft minecraft, boolean enabled) throws IOException { @@ -684,8 +682,6 @@ public class Iris { // https://github.com/IrisShaders/Iris/issues/1330 if (Minecraft.getMinecraft().theWorld != null) { Iris.getPipelineManager().preparePipeline(Iris.getCurrentDimensionName()); - - BlockRenderingSettings.INSTANCE.reloadRendererIfRequired(); } if (loadedIncompatiblePack() && Minecraft.getMinecraft().thePlayer != null) { diff --git a/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java b/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java index 32257eb57..3b237fbf9 100644 --- a/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java +++ b/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.glsm.profiling.Tracy; import lombok.Getter; import net.coderbot.iris.Iris; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.coderbot.iris.uniforms.SystemTimeUniforms; import org.jetbrains.annotations.Nullable; import org.lwjgl.opengl.GL11; @@ -43,6 +44,7 @@ public class PipelineManager { Iris.logger.info("Creating pipeline for dimension '{}'", currentDimension); pipeline = pipelineFactory.apply(currentDimension); pipelinesPerDimension.put(currentDimension, pipeline); + BlockRenderingSettings.INSTANCE.reloadRendererIfRequired(); if (Tracy.ENABLED) { shaderSection = Tracy.sectionEnter(Tracy.SECTION_SHADERS, "shaders " + Iris.getCurrentPackName() + " / " + currentDimension); } diff --git a/src/main/java/net/irisshaders/iris/api/v0/item/IrisItemLightProvider.java b/src/main/java/net/irisshaders/iris/api/v0/item/IrisItemLightProvider.java index f697d53b6..91888d246 100644 --- a/src/main/java/net/irisshaders/iris/api/v0/item/IrisItemLightProvider.java +++ b/src/main/java/net/irisshaders/iris/api/v0/item/IrisItemLightProvider.java @@ -1,5 +1,6 @@ package net.irisshaders.iris.api.v0.item; +import com.gtnewhorizons.angelica.helpers.ItemBlockLight; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; @@ -11,8 +12,7 @@ public interface IrisItemLightProvider { default int getLightEmission(EntityPlayer player, ItemStack stack) { if (stack.getItem() instanceof ItemBlock item) { - - return item.field_150939_a.getLightValue(); + return ItemBlockLight.getLightValue(item, stack); } return 0; diff --git a/src/main/resources/assets/angelica/shaders/selection_box.geom.glsl b/src/main/resources/assets/angelica/shaders/selection_box.geom.glsl index f44bd8a51..d052031f0 100644 --- a/src/main/resources/assets/angelica/shaders/selection_box.geom.glsl +++ b/src/main/resources/assets/angelica/shaders/selection_box.geom.glsl @@ -10,19 +10,25 @@ void main() { vec4 c0 = gl_in[0].gl_Position; vec4 c1 = gl_in[1].gl_Position; - vec2 n0 = c0.xy / c0.w; - vec2 n1 = c1.xy / c1.w; + float d0 = c0.z + c0.w; + float d1 = c1.z + c1.w; + if (d0 < 0.0 && d1 < 0.0) return; + vec4 p0 = d0 < 0.0 ? mix(c0, c1, d0 / (d0 - d1)) : c0; + vec4 p1 = d1 < 0.0 ? mix(c0, c1, d0 / (d0 - d1)) : c1; + + vec2 n0 = p0.xy / p0.w; + vec2 n1 = p1.xy / p1.w; vec2 dir = normalize((n1 - n0) * u_ViewportSize); vec2 offset = vec2(-dir.y, dir.x) * u_LineWidth / u_ViewportSize; - gl_Position = vec4((n0 + offset) * c0.w, c0.z, c0.w); + gl_Position = vec4((n0 + offset) * p0.w, p0.z, p0.w); EmitVertex(); - gl_Position = vec4((n0 - offset) * c0.w, c0.z, c0.w); + gl_Position = vec4((n0 - offset) * p0.w, p0.z, p0.w); EmitVertex(); - gl_Position = vec4((n1 + offset) * c1.w, c1.z, c1.w); + gl_Position = vec4((n1 + offset) * p1.w, p1.z, p1.w); EmitVertex(); - gl_Position = vec4((n1 - offset) * c1.w, c1.z, c1.w); + gl_Position = vec4((n1 - offset) * p1.w, p1.z, p1.w); EmitVertex(); EndPrimitive(); } diff --git a/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/celeritas/terrain/MixinRenderGlobal.java b/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/celeritas/terrain/MixinRenderGlobal.java index 2a04ec96b..b997f86ea 100644 --- a/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/celeritas/terrain/MixinRenderGlobal.java +++ b/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/celeritas/terrain/MixinRenderGlobal.java @@ -66,6 +66,7 @@ public class MixinRenderGlobal implements IRenderGlobalExt { @Unique private static final Tracy.ZoneId Z_MT_QUEUE = Tracy.zoneId("mtQueue", Tracy.COLOR_TERRAIN); @Shadow public Minecraft mc; + @Shadow public WorldClient theWorld; @Shadow @Final private TextureManager renderEngine; @Unique private static final String SECTION_SOLID = "draw_chunk_layer_solid"; @@ -264,6 +265,7 @@ public class MixinRenderGlobal implements IRenderGlobalExt { @Inject(method = "loadRenderers", at = @At("RETURN")) private void onReload(CallbackInfo ci) { + if (this.celeritas$renderer.getWorld() != this.theWorld) return; angelica$reload(); } diff --git a/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java b/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java index 2e50f6aa7..485e53d70 100644 --- a/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java +++ b/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java @@ -7,6 +7,7 @@ import net.coderbot.iris.Iris; import net.coderbot.iris.layer.GbufferPrograms; import net.coderbot.iris.pipeline.WorldRenderingPhase; import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.Tessellator; import net.minecraft.entity.player.EntityPlayer; @@ -20,6 +21,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(RenderGlobal.class) public class MixinRenderGlobal { + @Inject(method = "setWorldAndLoadRenderers", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;loadRenderers()V")) + private void iris$preparePipelineForNewWorld(WorldClient world, CallbackInfo ci) { + Iris.getPipelineManager().preparePipeline(Iris.getCurrentDimensionName()); + } + @Inject(method = "renderSky", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;instance:Lnet/minecraft/client/renderer/Tessellator;")) private void iris$renderSky$beginNormalSky(float partialTicks, CallbackInfo ci) { // None of the vanilla sky is rendered until after this call, so if anything is rendered before, it's CUSTOM_SKY. diff --git a/src/test/java/com/gtnewhorizons/angelica/client/font/TextDrawStateGLTest.java b/src/test/java/com/gtnewhorizons/angelica/client/font/TextDrawStateGLTest.java new file mode 100644 index 000000000..4a5a4f1e5 --- /dev/null +++ b/src/test/java/com/gtnewhorizons/angelica/client/font/TextDrawStateGLTest.java @@ -0,0 +1,145 @@ +package com.gtnewhorizons.angelica.client.font; + +import com.gtnewhorizons.angelica.glsm.GLCoreTest; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.glsm.StateSet; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.lwjgl.opengl.GL11; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@GLCoreTest +class TextDrawStateGLTest { + + @AfterEach + void resetState() { + setDefaults(); + } + + private static void setDefaults() { + GLStateManager.disableDepthTest(); + GLStateManager.glDepthFunc(GL11.GL_LESS); + GLStateManager.glDepthMask(true); + GLStateManager.glColorMask(true, true, true, true); + GLStateManager.disableCull(); + GLStateManager.glCullFace(GL11.GL_BACK); + GLStateManager.glFrontFace(GL11.GL_CCW); + GLStateManager.glDisable(GL11.GL_POLYGON_OFFSET_FILL); + GLStateManager.glPolygonOffset(0.0f, 0.0f); + GLStateManager.glAlphaFunc(GL11.GL_ALWAYS, 0.0f); + } + + private static void setNonDefaults() { + GLStateManager.enableDepthTest(); + GLStateManager.glDepthFunc(GL11.GL_GEQUAL); + GLStateManager.glDepthMask(false); + GLStateManager.glColorMask(false, false, false, false); + GLStateManager.enableCull(); + GLStateManager.glCullFace(GL11.GL_FRONT); + GLStateManager.glFrontFace(GL11.GL_CW); + GLStateManager.glEnable(GL11.GL_POLYGON_OFFSET_FILL); + GLStateManager.glPolygonOffset(-10.0f, -10.0f); + GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.5f); + } + + private static TextDrawState capture() { + final TextDrawState state = new TextDrawState(); + state.captureLive(); + return state; + } + + private static List stateFields() { + final List fields = new ArrayList<>(); + for (Field field : TextDrawState.class.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers()) || !field.getType().isPrimitive()) continue; + field.setAccessible(true); + fields.add(field); + } + return fields; + } + + private static boolean isGlState(Field field) { + return !field.getName().equals("alphaRef"); + } + + @Test + void everyFieldIsMovedByTheTestState() throws IllegalAccessException { + setDefaults(); + final TextDrawState defaults = capture(); + setNonDefaults(); + final TextDrawState moved = capture(); + for (Field field : stateFields()) { + assertNotEquals(field.get(defaults), field.get(moved), field.getName() + " - add it to setNonDefaults()"); + } + } + + @Test + void sameAsAndSetCoverEveryField() throws IllegalAccessException { + setNonDefaults(); + final TextDrawState moved = capture(); + setDefaults(); + final TextDrawState defaults = capture(); + for (Field field : stateFields()) { + final TextDrawState copy = new TextDrawState(); + copy.set(moved); + assertEquals(field.get(moved), field.get(copy), field.getName() + " - missing from set()"); + assertTrue(copy.sameAs(moved)); + field.set(copy, field.get(defaults)); + assertFalse(copy.sameAs(moved), field.getName() + " - missing from sameAs()"); + } + } + + @Test + void applyReplaysCapturedState() throws IllegalAccessException { + setNonDefaults(); + final TextDrawState captured = capture(); + setDefaults(); + captured.apply(); + final TextDrawState replayed = capture(); + for (Field field : stateFields()) { + if (!isGlState(field)) continue; + assertEquals(field.get(captured), field.get(replayed), field.getName()); + } + assertEquals(GL11.GL_GEQUAL, GL11.glGetInteger(GL11.GL_DEPTH_FUNC), "driver depth func"); + assertEquals(GL11.GL_FRONT, GL11.glGetInteger(GL11.GL_CULL_FACE_MODE), "driver cull face"); + assertEquals(GL11.GL_CW, GL11.glGetInteger(GL11.GL_FRONT_FACE), "driver front face"); + assertEquals(-10.0f, GL11.glGetFloat(GL11.GL_POLYGON_OFFSET_FACTOR), "driver polygon offset factor"); + assertTrue(GL11.glIsEnabled(GL11.GL_POLYGON_OFFSET_FILL), "driver polygon offset fill"); + } + + @Test + void fontStateSetRestoresEverythingApplyTouches() throws IllegalAccessException { + assertApplyDoesNotLeak(StateSet.FONT); + } + + @Test + void fontPipelineStateSetRestoresEverythingApplyTouches() throws IllegalAccessException { + assertApplyDoesNotLeak(StateSet.FONT_PIPELINE); + } + + private static void assertApplyDoesNotLeak(StateSet set) throws IllegalAccessException { + setNonDefaults(); + final TextDrawState moved = capture(); + setDefaults(); + final TextDrawState before = capture(); + + final int depth = GLStateManager.pushState(set); + moved.apply(); + GLStateManager.popStateTo(depth); + + final TextDrawState after = capture(); + for (Field field : stateFields()) { + if (!isGlState(field)) continue; + assertEquals(field.get(before), field.get(after), field.getName() + " - not restored by the font state set"); + } + } +}