From 2274bfabfd0ea3ca603e17ea7c88d684cf393791 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 14 Jul 2024 23:09:03 -0700 Subject: [PATCH] Beta (#461) * Beta, maybe * Fixes for entityColor uniform in Iris * Handle Iris Texture input hook properly in GLSM * Iris Entity Fixes * Gbuffer progress * Wire up BlockEntity gbuffer * Move Entity gbuffer to a more appropriate place to avoid reentrancy * Wire up ENTITY_EYES and BEACOM_BEAM * Clean up unused RenderStateShard files * This seems marginally more correct? * Fix shadows from showing on sides of blocks * Remove overlay * yeet * More gl debugging * Grr, fix water textures * Add missed enable checks * Workaround for unset depth texture when using apitrace... Use a WrapOperation instead of an Inject with local capture - it wasn't working in dev w/ mixin debug set * update bs * Fix crosshair rendering with shaders * more final * Disable dynamic lights if shaders are in use * No light when in water * Add Void Particle Option + Mixin cleanup * update bs * less false --------- Co-authored-by: Darren Eberly Co-authored-by: Caedis --- dependencies.gradle | 3 + gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 43453 bytes .../angelica/compat/toremove/DrawState.java | 21 ------ .../compat/toremove/OverlayTexture.java | 8 --- .../angelica/compat/toremove/RenderLayer.java | 15 +---- .../angelica/compat/toremove/RenderPhase.java | 23 ------- .../angelica/config/AngelicaConfig.java | 4 +- .../angelica/dynamiclights/DynamicLights.java | 2 +- .../gtnewhorizons/angelica/glsm/GLDebug.java | 28 +++++++- .../angelica/glsm/GLStateManager.java | 24 +++++-- .../angelica/loading/AngelicaTweaker.java | 5 -- .../gtnewhorizons/angelica/mixins/Mixins.java | 7 +- .../early/angelica/MixinEntityRenderer.java | 2 +- .../angelica/archaic/MixinGuiIngameForge.java | 2 +- .../mcpatcherforge/ctm/MixinRenderBlocks.java | 2 +- .../notfine/toggle/MixinEntityRenderer.java | 3 +- .../early/notfine/toggle/MixinGuiIngame.java | 2 +- .../early/shaders/MixinFramebuffer.java | 3 + .../early/shaders/MixinGuiIngameForge.java | 17 +++++ .../early/shaders/MixinRenderDragon.java | 18 ++++++ .../early/shaders/MixinRenderEnderman.java | 19 ++++++ .../early/shaders/MixinRenderManager.java | 30 --------- .../early/shaders/MixinRenderSpider.java | 19 ++++++ .../shaders/MixinRendererLivingEntity.java | 38 +++++++++++ .../MixinTileEntityBeaconRenderer.java | 26 ++++++++ .../early/sodium/MixinRenderGlobal.java | 32 +++++++++- .../transform/RedirectorTransformer.java | 1 + .../sodium/client/gl/shader/GlProgram.java | 10 +-- .../client/gui/SodiumGameOptionPages.java | 1 + .../light/smooth/SmoothLightPipeline.java | 54 ++++++++-------- .../client/render/SodiumWorldRenderer.java | 17 ++++- .../impl/BufferBuilderExt.java | 9 --- .../impl/BufferSegment.java | 5 +- .../matching/InputAvailability.java | 18 +----- .../gbuffer_overrides/state/StateTracker.java | 6 +- .../layer/BlockEntityRenderStateShard.java | 42 ------------ .../iris/layer/EntityRenderStateShard.java | 42 ------------ .../coderbot/iris/layer/GbufferPrograms.java | 8 +-- .../layer/IsBlockEntityRenderStateShard.java | 11 ---- .../iris/layer/IsEntityRenderStateShard.java | 11 ---- .../iris/layer/IsOutlineRenderStateShard.java | 11 ---- .../DeferredWorldRenderingPipeline.java | 12 ++-- .../transform/AttributeTransformer.java | 60 +----------------- .../coderbot/iris/samplers/IrisSamplers.java | 24 ++----- .../EntityVertexBufferWriterNio.java | 3 +- .../EntityVertexBufferWriterUnsafe.java | 3 +- .../GlyphVertexBufferWriterNio.java | 3 +- .../GlyphVertexBufferWriterUnsafe.java | 3 +- .../iris/uniforms/CapturedRenderingState.java | 16 +++++ .../iris/uniforms/CommonUniforms.java | 5 +- .../resources/assets/angelica/lang/en_US.lang | 2 +- 51 files changed, 330 insertions(+), 400 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/DrawState.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/OverlayTexture.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGuiIngameForge.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderDragon.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderEnderman.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderManager.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderSpider.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRendererLivingEntity.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinTileEntityBeaconRenderer.java delete mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java delete mode 100644 src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java delete mode 100644 src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java delete mode 100644 src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java delete mode 100644 src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java delete mode 100644 src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java diff --git a/dependencies.gradle b/dependencies.gradle index 79dc28d2f..ec0f58f45 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -81,6 +81,9 @@ dependencies { compileOnly("com.github.GTNewHorizons:Battlegear2:1.4.0:dev") { transitive = false } compileOnly(rfg.deobf('maven.modrinth:backhand:1.4.1')) { transitive = false } + compileOnly("com.github.GTNewHorizons:Battlegear2:1.4.0:dev") { transitive = false } + compileOnly(rfg.deobf('maven.modrinth:backhand:1.4.1')) { transitive = false } + compileOnly("com.falsepattern:chunkapi-mc1.7.10:0.5.1:api") { transitive = false } compileOnly("com.falsepattern:endlessids-mc1.7.10:1.5-beta0003:dev") { transitive = false } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd4917707c1f8861d8cb53dd15194d4248596..e6441136f3d4ba8a0da8d277868979cfbc8ad796 100644 GIT binary patch delta 34118 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 delta 34176 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 SGW6ptSs!X7{rG*o_g?|vpSEZK diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/DrawState.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/DrawState.java deleted file mode 100644 index 76aa2221e..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/DrawState.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; -import lombok.Getter; - -@Deprecated -public class DrawState { - @Getter - private final VertexFormat format; - @Getter - private final int vertexCount; - @Getter - private final int mode; - - public DrawState(VertexFormat format, int vertexCount, int mode) { - this.format = format; - this.vertexCount = vertexCount; - this.mode = mode; - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/OverlayTexture.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/OverlayTexture.java deleted file mode 100644 index 54a3ab1f1..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/OverlayTexture.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -@Deprecated -public class OverlayTexture { - - // This is definitely wrong - public static final int NO_OVERLAY = 0; -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayer.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayer.java index 690b84662..821051cd4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayer.java @@ -140,7 +140,6 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris private final RenderPhase.DepthTest depthTest; private final RenderPhase.Cull cull; private final RenderPhase.Lightmap lightmap; - private final RenderPhase.Overlay overlay; private final RenderPhase.Fog fog; private final RenderPhase.Layering layering; private final RenderPhase.Target target; @@ -150,7 +149,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris private final OutlineMode outlineMode; private final ImmutableList phases; - private MultiPhaseParameters(RenderPhase.Texture texture, RenderPhase.Transparency transparency, RenderPhase.DiffuseLighting diffuseLighting, RenderPhase.ShadeModel shadeModel, RenderPhase.Alpha alpha, RenderPhase.DepthTest depthTest, RenderPhase.Cull cull, RenderPhase.Lightmap lightmap, RenderPhase.Overlay overlay, RenderPhase.Fog fog, RenderPhase.Layering layering, RenderPhase.Target target, RenderPhase.Texturing texturing, RenderPhase.WriteMaskState writeMaskState, RenderPhase.LineWidth lineWidth, OutlineMode outlineMode) { + private MultiPhaseParameters(RenderPhase.Texture texture, RenderPhase.Transparency transparency, RenderPhase.DiffuseLighting diffuseLighting, RenderPhase.ShadeModel shadeModel, RenderPhase.Alpha alpha, RenderPhase.DepthTest depthTest, RenderPhase.Cull cull, RenderPhase.Lightmap lightmap, RenderPhase.Fog fog, RenderPhase.Layering layering, RenderPhase.Target target, RenderPhase.Texturing texturing, RenderPhase.WriteMaskState writeMaskState, RenderPhase.LineWidth lineWidth, OutlineMode outlineMode) { this.texture = texture; this.transparency = transparency; this.diffuseLighting = diffuseLighting; @@ -159,7 +158,6 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris this.depthTest = depthTest; this.cull = cull; this.lightmap = lightmap; - this.overlay = overlay; this.fog = fog; this.layering = layering; this.target = target; @@ -167,7 +165,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris this.writeMaskState = writeMaskState; this.lineWidth = lineWidth; this.outlineMode = outlineMode; - this.phases = ImmutableList.of(this.texture, this.transparency, this.diffuseLighting, this.shadeModel, this.alpha, this.depthTest, this.cull, this.lightmap, this.overlay, this.fog, this.layering, this.target, new RenderPhase[]{this.texturing, this.writeMaskState, this.lineWidth}); + this.phases = ImmutableList.of(this.texture, this.transparency, this.diffuseLighting, this.shadeModel, this.alpha, this.depthTest, this.cull, this.lightmap, this.fog, this.layering, this.target, this.texturing, this.writeMaskState, this.lineWidth); } public boolean equals(Object object) { @@ -202,7 +200,6 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris private RenderPhase.DepthTest depthTest; private RenderPhase.Cull cull; private RenderPhase.Lightmap lightmap; - private RenderPhase.Overlay overlay; private RenderPhase.Fog fog; private RenderPhase.Layering layering; private RenderPhase.Target target; @@ -219,7 +216,6 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris this.depthTest = RenderPhase.LEQUAL_DEPTH_TEST; this.cull = RenderPhase.ENABLE_CULLING; this.lightmap = RenderPhase.DISABLE_LIGHTMAP; - this.overlay = RenderPhase.DISABLE_OVERLAY_COLOR; this.fog = RenderPhase.FOG; this.layering = RenderPhase.NO_LAYERING; this.target = RenderPhase.MAIN_TARGET; @@ -263,11 +259,6 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris return this; } - public Builder overlay(RenderPhase.Overlay overlay) { - this.overlay = overlay; - return this; - } - public Builder fog(RenderPhase.Fog fog) { this.fog = fog; return this; @@ -288,7 +279,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris } public MultiPhaseParameters build(OutlineMode outlineMode) { - return new MultiPhaseParameters(this.texture, this.transparency, this.diffuseLighting, this.shadeModel, this.alpha, this.depthTest, this.cull, this.lightmap, this.overlay, this.fog, this.layering, this.target, this.texturing, this.writeMaskState, this.lineWidth, outlineMode); + return new MultiPhaseParameters(this.texture, this.transparency, this.diffuseLighting, this.shadeModel, this.alpha, this.depthTest, this.cull, this.lightmap, this.fog, this.layering, this.target, this.texturing, this.writeMaskState, this.lineWidth, outlineMode); } } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderPhase.java index 6ba033e3b..46d9d363a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderPhase.java @@ -69,8 +69,6 @@ public abstract class RenderPhase { protected static final Texturing ENTITY_GLINT_TEXTURING; protected static final Lightmap ENABLE_LIGHTMAP; protected static final Lightmap DISABLE_LIGHTMAP; - protected static final Overlay ENABLE_OVERLAY_COLOR; - protected static final Overlay DISABLE_OVERLAY_COLOR; protected static final DiffuseLighting ENABLE_DIFFUSE_LIGHTING; protected static final DiffuseLighting DISABLE_DIFFUSE_LIGHTING; protected static final Cull ENABLE_CULLING; @@ -177,8 +175,6 @@ public abstract class RenderPhase { }); ENABLE_LIGHTMAP = new Lightmap(true); DISABLE_LIGHTMAP = new Lightmap(false); - ENABLE_OVERLAY_COLOR = new Overlay(true); - DISABLE_OVERLAY_COLOR = new Overlay(false); ENABLE_DIFFUSE_LIGHTING = new DiffuseLighting(true); DISABLE_DIFFUSE_LIGHTING = new DiffuseLighting(false); ENABLE_CULLING = new Cull(true); @@ -505,25 +501,6 @@ public abstract class RenderPhase { } - public static class Overlay extends Toggleable { - public Overlay(boolean overlayColor) { - super("overlay", () -> { - if (overlayColor) { - throw new RuntimeException("Not Implemented Yet"); -// MinecraftClient.getInstance().gameRenderer.getOverlayTexture().setupOverlayColor(); - } - - }, () -> { - if (overlayColor) { - throw new RuntimeException("Not Implemented Yet"); -// MinecraftClient.getInstance().gameRenderer.getOverlayTexture().teardownOverlayColor(); - } - - }, overlayColor); - } - } - - public static class Lightmap extends Toggleable { public Lightmap(boolean lightmap) { super("lightmap", () -> { diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index 176b82c85..6c7301ef9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -35,13 +35,11 @@ public class AngelicaConfig { @Config.Comment("Enable Iris Shaders [Requires Sodium]") @Config.DefaultBoolean(false) @Config.RequiresMcRestart - @Config.Ignore() public static boolean enableIris; @Config.Comment("Enable MCPatcherForge features, still in Alpha. Individual features are toggled in mcpatcher.json") @Config.DefaultBoolean(false) @Config.RequiresMcRestart - @Config.Ignore() public static boolean enableMCPatcherForgeFeatures; @Config.Comment("Replace some vanilla render paths with more optimized versions. Disable if you encounter mixin conflicts.") @@ -86,7 +84,7 @@ public class AngelicaConfig { public static boolean enableFontRenderer; @Config.Comment("Enable Dynamic Lights") - @Config.DefaultBoolean(false) + @Config.DefaultBoolean(true) @Config.RequiresMcRestart public static boolean enableDynamicLights; diff --git a/src/main/java/com/gtnewhorizons/angelica/dynamiclights/DynamicLights.java b/src/main/java/com/gtnewhorizons/angelica/dynamiclights/DynamicLights.java index 2c6404335..34b2fb1e4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/dynamiclights/DynamicLights.java +++ b/src/main/java/com/gtnewhorizons/angelica/dynamiclights/DynamicLights.java @@ -49,7 +49,7 @@ public class DynamicLights { } public static boolean isEnabled() { - return Mode.isEnabled() && AngelicaConfig.enableDynamicLights; + return AngelicaConfig.enableDynamicLights && Mode.isEnabled() && !IrisApi.getInstance().isShaderPackInUse(); } /** diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLDebug.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLDebug.java index 5d5f16de9..8c1de9fb7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLDebug.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLDebug.java @@ -271,17 +271,20 @@ public final class GLDebug { private static DebugState debugState; - private interface DebugState { + private interface DebugState { void nameObject(int id, int object, String name); void pushGroup(String name); void popGroup(); void debugMessage(String name); - } + + String getObjectLabel(int glProgram, int program); + } private static class KHRDebugState implements DebugState { private static final int ID = 0; private int depth = 0; private static final int maxDepth = GL11.glGetInteger(KHRDebug.GL_MAX_DEBUG_GROUP_STACK_DEPTH); + private static final int maxNameLength = GL11.glGetInteger(KHRDebug.GL_MAX_LABEL_LENGTH); @Override public void nameObject(int id, int object, String name) { @@ -310,6 +313,14 @@ public final class GLDebug { public void debugMessage(String message) { KHRDebug.glDebugMessageInsert(KHRDebug.GL_DEBUG_SOURCE_APPLICATION, KHRDebug.GL_DEBUG_TYPE_MARKER, ID, KHRDebug.GL_DEBUG_SEVERITY_NOTIFICATION, message); } + + @Override + public String getObjectLabel(int glProgram, int program) { + if(program == 0) + return ""; + + return KHRDebug.glGetObjectLabel(glProgram, program, maxNameLength); + } } private static class UnsupportedDebugState implements DebugState { @@ -329,6 +340,11 @@ public final class GLDebug { public void debugMessage(String name) { } + + @Override + public String getObjectLabel(int glProgram, int program) { + return ""; + } } public static void initDebugState() { @@ -359,4 +375,12 @@ public final class GLDebug { debugState.debugMessage(message); } } + public static String getObjectLabel(int glProgram, int program) { + if(debugState != null && Thread.currentThread() == GLStateManager.getMainThread()) { + return debugState.getObjectLabel(glProgram, program); + } + return ""; + } + + } diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index ee4c3e0d6..bb0e349bb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -59,6 +59,7 @@ import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL14; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GLContext; +import org.lwjgl.opengl.KHRDebug; import java.lang.Math; import java.nio.ByteBuffer; @@ -134,6 +135,8 @@ public class GLStateManager { @Getter protected static final ViewPortStateStack viewportState = new ViewPortStateStack(); + @Getter protected static int activeProgram = 0; + public static void reset() { runningSplash = true; while(!attribs.isEmpty()) { @@ -399,6 +402,7 @@ public class GLStateManager { case GL14.GL_BLEND_DST_RGB -> blendState.getDstRgb(); case GL14.GL_BLEND_SRC_ALPHA -> blendState.getSrcAlpha(); case GL14.GL_BLEND_SRC_RGB -> blendState.getSrcRgb(); + case GL20.GL_CURRENT_PROGRAM -> activeProgram; default -> GL11.glGetInteger(pname); }; @@ -845,9 +849,6 @@ public class GLStateManager { } else if (textureUnit == IrisSamplers.LIGHTMAP_TEXTURE_UNIT) { StateTracker.INSTANCE.lightmapSampler = true; updatePipeline = true; - } else if (textureUnit == IrisSamplers.OVERLAY_TEXTURE_UNIT) { - StateTracker.INSTANCE.overlaySampler = true; - updatePipeline = true; } if (updatePipeline) { @@ -868,9 +869,6 @@ public class GLStateManager { } else if (textureUnit == IrisSamplers.LIGHTMAP_TEXTURE_UNIT) { StateTracker.INSTANCE.lightmapSampler = false; updatePipeline = true; - } else if (textureUnit == IrisSamplers.OVERLAY_TEXTURE_UNIT) { - StateTracker.INSTANCE.overlaySampler = false; - updatePipeline = true; } if (updatePipeline) { @@ -1569,4 +1567,18 @@ public class GLStateManager { public static void glDepthRange(double near, double far) { GL11.glDepthRange(near, far); } + + public static void glUseProgram(int program) { + if(program != activeProgram || shouldBypassCache()) { + activeProgram = program; + if(AngelicaMod.lwjglDebug) { + final String programName = GLDebug.getObjectLabel(KHRDebug.GL_PROGRAM, program); + GLDebug.debugMessage("Activating Program - " + program + ":" + programName); + } + GL20.glUseProgram(program); + } + } + + + } diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index b665f46a4..af0c54e93 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -48,11 +48,6 @@ public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader { } ctx.updateLoggers(); - // Too many bug reports because people refuse to read or just want to try it - so make these only able - // to be enabled by system properties for now. - AngelicaConfig.enableIris = Boolean.parseBoolean(System.getProperty("angelica.enableShaders", "false")); - AngelicaConfig.enableMCPatcherForgeFeatures = Boolean.parseBoolean(System.getProperty("angelica.enableMCPatcherForgeFeatures", "false")); - // Debug features AngelicaConfig.enableTestBlocks = Boolean.parseBoolean(System.getProperty("angelica.enableTestBlocks", "false")); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index b622271c8..72f1e104d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -140,13 +140,18 @@ public enum Mixins { IRIS_RENDERING(new Builder("Iris Shaders").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses( "shaders.MixinEntityRenderer" + ,"shaders.MixinGuiIngameForge" ,"shaders.MixinFramebuffer" ,"shaders.MixinItem" ,"shaders.MixinLocale" ,"shaders.MixinOpenGlHelper" ,"shaders.MixinRender" + ,"shaders.MixinRenderDragon" + ,"shaders.MixinRenderEnderman" + ,"shaders.MixinRendererLivingEntity" ,"shaders.MixinRenderGlobal" - ,"shaders.MixinRenderManager" + ,"shaders.MixinRenderSpider" + ,"shaders.MixinTileEntityBeaconRenderer" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinEntityRenderer.java index 5ff484814..5d2f8e469 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinEntityRenderer.java @@ -24,7 +24,7 @@ public abstract class MixinEntityRenderer { ); } - @ModifyArg(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", ordinal = 0), index = 0) + @ModifyArg(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", ordinal = 0, remap = false), index = 0) private float captureFov(float fov) { RenderingState.INSTANCE.setFov(fov); return fov; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinGuiIngameForge.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinGuiIngameForge.java index e9fe26039..e8b046dd7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinGuiIngameForge.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinGuiIngameForge.java @@ -8,7 +8,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(GuiIngameForge.class) +@Mixin(value=GuiIngameForge.class, remap = false) public class MixinGuiIngameForge { @Redirect(method = "renderHUDText", at = @At(value = "FIELD", target = "Lnet/minecraft/world/biome/BiomeGenBase;biomeName:Ljava/lang/String;")) private String getModNameWithBiome(BiomeGenBase biome) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/mcpatcherforge/ctm/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/mcpatcherforge/ctm/MixinRenderBlocks.java index c94b31d21..9e1a99dcc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/mcpatcherforge/ctm/MixinRenderBlocks.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/mcpatcherforge/ctm/MixinRenderBlocks.java @@ -510,7 +510,7 @@ public abstract class MixinRenderBlocks { * @author roadhog360 */ @SuppressWarnings("UnreachableCode") - @Inject(method = "renderBlockStainedGlassPane", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockPane;canPaneConnectTo(Lnet/minecraft/world/IBlockAccess;IIILnet/minecraftforge/common/util/ForgeDirection;)Z", ordinal = 3, shift = At.Shift.BY, by = 2), cancellable = true) + @Inject(method = "renderBlockStainedGlassPane", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockPane;canPaneConnectTo(Lnet/minecraft/world/IBlockAccess;IIILnet/minecraftforge/common/util/ForgeDirection;)Z", ordinal = 3, shift = At.Shift.BY, by = 2, remap = false), cancellable = true) private void tweakStainedPaneRenderer(Block block, int x, int y, int z, CallbackInfoReturnable cir, @Local(name = "iicon") IIcon iicon, @Local(name = "d22") double d22, @Local(name = "d0") double d0, @Local(name = "d1") double d1, @Local(name = "d2") double d2, diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinEntityRenderer.java index 8f8f513d8..9f5ce761b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinEntityRenderer.java @@ -52,7 +52,8 @@ abstract public class MixinEntityRenderer { at = @At( value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glFogf(IF)V", - ordinal = 14 + ordinal = 14, + remap = false ) ) private void notFine$nearFogDistance(int mode, float value) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinGuiIngame.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinGuiIngame.java index 04be41fc7..8bd21600b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinGuiIngame.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinGuiIngame.java @@ -17,7 +17,7 @@ public abstract class MixinGuiIngame { target = "Lnet/minecraft/client/Minecraft;isFancyGraphicsEnabled()Z" ) ) - private boolean notFine$toggleVignette(float whyAndHowIsThisAFloat) { + private boolean notFine$toggleVignette() { return SettingsManager.vignette; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java index 5d7027f6d..bba408060 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java @@ -71,6 +71,9 @@ public abstract class MixinFramebuffer implements IRenderTargetExt { @Inject(method="createFramebuffer(II)V", at=@At(value="FIELD", target="Lnet/minecraft/client/shader/Framebuffer;useDepth:Z", shift=At.Shift.BEFORE, ordinal = 1)) private void iris$createDepthTexture(int width, int height, CallbackInfo ci) { if(this.iris$useDepth) { + if(this.iris$depthTextureId == -1) { + this.iris$depthTextureId = GL11.glGenTextures(); + } GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, this.iris$depthTextureId); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGuiIngameForge.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGuiIngameForge.java new file mode 100644 index 000000000..7d2102be1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGuiIngameForge.java @@ -0,0 +1,17 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.minecraftforge.client.GuiIngameForge; +import org.lwjgl.opengl.GL11; +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.CallbackInfo; + +@Mixin(value = GuiIngameForge.class, remap = false) +public class MixinGuiIngameForge { + @Inject(method="renderCrosshairs", at= @At(value = "INVOKE", target = "Lnet/minecraftforge/client/GuiIngameForge;bind(Lnet/minecraft/util/ResourceLocation;)V", shift = At.Shift.AFTER)) + private void renderCrosshairs(CallbackInfo ci) { + // Set the same state as vanilla so we don't break with textures that set a color value on transparent pixels for the crosshairs + GL11.glEnable(GL11.GL_ALPHA_TEST); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderDragon.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderDragon.java new file mode 100644 index 000000000..dc2ed645f --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderDragon.java @@ -0,0 +1,18 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; +import net.coderbot.iris.layer.GbufferPrograms; +import net.minecraft.client.renderer.entity.RenderDragon; +import net.minecraft.entity.boss.EntityDragon; +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; + +@Mixin(RenderDragon.class) +public class MixinRenderDragon { + @Inject(method = "Lnet/minecraft/client/renderer/entity/RenderDragon;shouldRenderPass(Lnet/minecraft/entity/boss/EntityDragon;IF)I", at = @At(value="RETURN", ordinal = 1)) + private void onShouldRenderPass(EntityDragon entity, int pass, float partialTicks, CallbackInfoReturnable cir) { + GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.ENTITY_EYES); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderEnderman.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderEnderman.java new file mode 100644 index 000000000..f1fdca2ad --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderEnderman.java @@ -0,0 +1,19 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; +import net.coderbot.iris.layer.GbufferPrograms; +import net.minecraft.client.renderer.entity.RenderEnderman; +import net.minecraft.entity.monster.EntityEnderman; +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; + +@Mixin(RenderEnderman.class) +public class MixinRenderEnderman { + @Inject(method = "Lnet/minecraft/client/renderer/entity/RenderEnderman;shouldRenderPass(Lnet/minecraft/entity/monster/EntityEnderman;IF)I", at = @At(value="RETURN", ordinal = 1)) + private void onShouldRenderPass(EntityEnderman entity, int pass, float partialTicks, CallbackInfoReturnable cir) { + GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.ENTITY_EYES); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderManager.java deleted file mode 100644 index 377b3383c..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderManager.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shaders; - -import net.coderbot.iris.layer.GbufferPrograms; -import net.coderbot.iris.uniforms.CapturedRenderingState; -import net.minecraft.client.renderer.entity.RenderManager; -import net.minecraft.entity.Entity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(RenderManager.class) -public class MixinRenderManager { - - @Unique - private static final String DO_RENDER = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFF)V"; - - @Inject(method = "func_147939_a", at = @At(value = "INVOKE", target = DO_RENDER)) - private void iris$onRenderEntityPre(Entity entity, double x, double y, double z, float yaw, float partialTicks, boolean rebuild, CallbackInfoReturnable cir) { - CapturedRenderingState.INSTANCE.setCurrentEntity(entity.getEntityId()); - GbufferPrograms.beginEntities(); - } - - @Inject(method = "func_147939_a", at = @At(value = "INVOKE", target = DO_RENDER, shift = At.Shift.AFTER)) - private void iris$onRenderEntityPost(Entity entity, double x, double y, double z, float yaw, float partialTicks, boolean rebuild, CallbackInfoReturnable cir) { - CapturedRenderingState.INSTANCE.setCurrentEntity(-1); - GbufferPrograms.endEntities(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderSpider.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderSpider.java new file mode 100644 index 000000000..a4f9751ef --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderSpider.java @@ -0,0 +1,19 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; +import net.coderbot.iris.layer.GbufferPrograms; +import net.minecraft.client.renderer.entity.RenderSpider; +import net.minecraft.entity.monster.EntitySpider; +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; + +@Mixin(RenderSpider.class) +public class MixinRenderSpider { + @Inject(method = "Lnet/minecraft/client/renderer/entity/RenderSpider;shouldRenderPass(Lnet/minecraft/entity/monster/EntitySpider;IF)I", at = @At(value="RETURN", ordinal = 1)) + private void onShouldRenderPass(EntitySpider entity, int pass, float partialTicks, CallbackInfoReturnable cir) { + GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.ENTITY_EYES); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRendererLivingEntity.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRendererLivingEntity.java new file mode 100644 index 000000000..cf375e851 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRendererLivingEntity.java @@ -0,0 +1,38 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.coderbot.iris.layer.GbufferPrograms; +import net.coderbot.iris.uniforms.CapturedRenderingState; +import net.minecraft.client.renderer.entity.RendererLivingEntity; +import net.minecraft.entity.EntityLivingBase; +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.CallbackInfo; + +@Mixin(RendererLivingEntity.class) +public class MixinRendererLivingEntity { + + @WrapOperation( + method="doRender", + at=@At(value="INVOKE", target="Lnet/minecraft/client/renderer/entity/RendererLivingEntity;getColorMultiplier(Lnet/minecraft/entity/EntityLivingBase;FF)I") + ) + private int iris$setEntityColor(RendererLivingEntity instance, EntityLivingBase elb, float f0, float f1, Operation original) { + final int j = original.call(instance, elb, f0, f1); + final float a = (j >> 24 & 255) / 255.0F; + final float r = (j >> 16 & 255) / 255.0F; + final float g = (j >> 8 & 255) / 255.0F; + final float b = (j & 255) / 255.0F; + CapturedRenderingState.INSTANCE.setCurrentEntityColor(r, g, b, 1.0F - a); + return j; + } + + @Inject( + method="Lnet/minecraft/client/renderer/entity/RendererLivingEntity;doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V", at=@At(value="INVOKE", + target="Lnet/minecraft/client/renderer/entity/RendererLivingEntity;renderEquippedItems(Lnet/minecraft/entity/EntityLivingBase;F)V", shift=At.Shift.BEFORE) + ) + private void iris$teardownSpecialRenderConditions(EntityLivingBase entity, double x, double y, double z, float entityYaw, float partialTicks, CallbackInfo ci) { + GbufferPrograms.teardownSpecialRenderCondition(); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinTileEntityBeaconRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinTileEntityBeaconRenderer.java new file mode 100644 index 000000000..b83b8713b --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinTileEntityBeaconRenderer.java @@ -0,0 +1,26 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; +import net.coderbot.iris.layer.GbufferPrograms; +import net.minecraft.client.renderer.tileentity.TileEntityBeaconRenderer; +import net.minecraft.tileentity.TileEntityBeacon; +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.CallbackInfo; + +@Mixin(TileEntityBeaconRenderer.class) +public class MixinTileEntityBeaconRenderer { + + @Inject(method="Lnet/minecraft/client/renderer/tileentity/TileEntityBeaconRenderer;renderTileEntityAt(Lnet/minecraft/tileentity/TileEntityBeacon;DDDF)V", at=@At("HEAD")) + private void onRenderTileEntityAt(TileEntityBeacon beacon, double x, double y, double z, float partialTicks, CallbackInfo ci) { + GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.BEACON_BEAM); + } + + @Inject(method="Lnet/minecraft/client/renderer/tileentity/TileEntityBeaconRenderer;renderTileEntityAt(Lnet/minecraft/tileentity/TileEntityBeacon;DDDF)V", at=@At("RETURN")) + private void afterRenderTileEntityAt(TileEntityBeacon beacon, double x, double y, double z, float partialTicks, CallbackInfo ci) { + GbufferPrograms.teardownSpecialRenderCondition(); + } + + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 63afccc58..6342609a5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -6,15 +6,19 @@ import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; import com.gtnewhorizons.angelica.rendering.AngelicaRenderQueue; import com.gtnewhorizons.angelica.rendering.RenderingState; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import lombok.Getter; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import net.coderbot.iris.Iris; +import net.coderbot.iris.layer.GbufferPrograms; import net.coderbot.iris.pipeline.HandRenderer; import net.coderbot.iris.pipeline.ShadowRenderer; import net.coderbot.iris.pipeline.WorldRenderingPhase; import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.coderbot.iris.uniforms.CapturedRenderingState; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.client.multiplayer.WorldClient; @@ -23,10 +27,14 @@ import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.client.renderer.culling.ICamera; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Blocks; import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; @@ -49,6 +57,8 @@ public class MixinRenderGlobal implements IRenderGlobalExt { @Shadow public int renderDistanceChunks; @Shadow public WorldRenderer[] worldRenderers; @Shadow public WorldRenderer[] sortedWorldRenderers; + @Shadow @Final private TextureManager renderEngine; + @Getter @Unique private SodiumWorldRenderer renderer; @@ -141,9 +151,10 @@ public class MixinRenderGlobal implements IRenderGlobalExt { pipeline = null; } else { pipeline = Iris.getPipelineManager().getPipelineNullable(); - pipeline.setPhase(WorldRenderingPhase.TERRAIN_CUTOUT); - - if(pass == 1) { + if(pass == 0) { + pipeline.setPhase(WorldRenderingPhase.TERRAIN_CUTOUT); + } else if(pass == 1) { + pipeline.setPhase(WorldRenderingPhase.TERRAIN_TRANSLUCENT); final Camera camera = new Camera(mc.renderViewEntity, (float) partialTicks); // iris$beginTranslucents @@ -151,6 +162,7 @@ public class MixinRenderGlobal implements IRenderGlobalExt { HandRenderer.INSTANCE.renderSolid(null /*poseStack*/, (float) partialTicks, camera, mc.renderGlobal, pipeline); mc.mcProfiler.endStartSection("iris_pre_translucent"); pipeline.beginTranslucents(); + this.renderEngine.bindTexture(TextureMap.locationBlocksTexture); } } // Handle view distance change @@ -172,6 +184,7 @@ public class MixinRenderGlobal implements IRenderGlobalExt { try { final MatrixStack matrixStack = new MatrixStack(ShadowRenderer.ACTIVE ? ShadowRenderer.MODELVIEW : RenderingState.INSTANCE.getModelViewMatrix()); + mc.mcProfiler.endStartSection("draw_chunk_layer_" + pass); this.renderer.drawChunkLayer(BlockRenderPass.VALUES[pass], matrixStack, x, y, z); } finally { RenderDevice.exitManagedCode(); @@ -285,6 +298,19 @@ public class MixinRenderGlobal implements IRenderGlobalExt { this.renderChunksDeep = 0; } + @WrapOperation(method="renderEntities", at=@At(value="INVOKE", target="Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)Z")) + private boolean angelica$renderEntitySimple(RenderManager instance, Entity entity, float partialTicks, Operation original) { + CapturedRenderingState.INSTANCE.setCurrentEntity(entity.getEntityId()); + GbufferPrograms.beginEntities(); + try { + return original.call(instance, entity, partialTicks); + } finally { + CapturedRenderingState.INSTANCE.setCurrentEntity(-1); + GbufferPrograms.endEntities(); + } + } + + @Inject(method="renderEntities", at=@At(value="INVOKE", target="Lnet/minecraft/client/renderer/RenderHelper;enableStandardItemLighting()V", shift = At.Shift.AFTER)) public void sodium$renderTileEntities(EntityLivingBase entity, ICamera camera, float partialTicks, CallbackInfo ci) { this.renderer.renderTileEntities(entity, camera, partialTicks); diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 16405afe6..037f2ec2c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -204,6 +204,7 @@ public class RedirectorTransformer implements IClassTransformer { ); methodRedirects.put(GL20, RedirectMap.newMap() .add("glBlendEquationSeparate") + .add("glUseProgram") ); methodRedirects.put(OpenGlHelper, RedirectMap.newMap() .add("glBlendFunc", "tryBlendFuncSeparate") diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java index c7a8618fb..bc262afe1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.gl.shader; +import com.gtnewhorizons.angelica.glsm.GLDebug; import me.jellysquid.mods.sodium.client.gl.GlObject; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import net.minecraft.util.ResourceLocation; @@ -7,7 +8,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL20; - +import org.lwjgl.opengl.KHRDebug; /** * An OpenGL shader program. @@ -47,7 +48,7 @@ public abstract class GlProgram extends GlObject { * @throws NullPointerException If no uniform exists with the given name */ public int getUniformLocation(String name) { - int index = GL20.glGetUniformLocation(this.handle(), name); + final int index = GL20.glGetUniformLocation(this.handle(), name); if (index < 0) { throw new NullPointerException("No uniform exists with name: " + name); @@ -69,6 +70,7 @@ public abstract class GlProgram extends GlObject { public Builder(ResourceLocation name) { this.name = name; this.program = GL20.glCreateProgram(); + GLDebug.nameObject(KHRDebug.GL_PROGRAM, program, name.toString()); } public Builder attachShader(GlShader shader) { @@ -89,13 +91,13 @@ public abstract class GlProgram extends GlObject { public

    P build(ProgramFactory

    factory) { GL20.glLinkProgram(this.program); - String log = GL20.glGetProgramInfoLog(this.program, GL20.GL_INFO_LOG_LENGTH); + final String log = GL20.glGetProgramInfoLog(this.program, GL20.GL_INFO_LOG_LENGTH); if (!log.isEmpty()) { LOGGER.warn("Program link log for " + this.name + ": " + log); } - int result = GL20.glGetProgrami(this.program, GL20.GL_LINK_STATUS); + final int result = GL20.glGetProgrami(this.program, GL20.GL_LINK_STATUS); if (result != GL11.GL_TRUE) { throw new RuntimeException("Shader program linking failed, see log for details"); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index 745a9cfd1..8475100cf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -187,6 +187,7 @@ public class SodiumGameOptionPages { .setImpact(OptionImpact.LOW) .build()) .add(Settings.PARTICLES_ENC_TABLE.option) + .add(Settings.PARTICLES_VOID.option) .add(OptionImpl.createBuilder(GraphicsQuality.class, sodiumOpts) .setName(I18n.format("sodium.options.grass_quality.name")) .setTooltip(I18n.format("sodium.options.grass_quality.tooltip")) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java index eacc1b449..0981e65fe 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java @@ -72,7 +72,7 @@ public class SmoothLightPipeline implements LightPipeline { public void calculate(ModelQuadView quad, BlockPosImpl pos, QuadLightData out, ForgeDirection cullFace, ForgeDirection face, boolean shade) { this.updateCachedData(pos.asLong()); - int flags = quad.getFlags(); + final int flags = quad.getFlags(); final AoNeighborInfo neighborInfo = AoNeighborInfo.get(face); @@ -102,7 +102,7 @@ public class SmoothLightPipeline implements LightPipeline { * Flags: IS_ALIGNED, !IS_PARTIAL */ private void applyAlignedFullFace(AoNeighborInfo neighborInfo, BlockPosImpl pos, ForgeDirection dir, QuadLightData out) { - AoFaceData faceData = this.getCachedFaceData(pos, dir, true); + final AoFaceData faceData = this.getCachedFaceData(pos, dir, true); neighborInfo.mapCorners(faceData.lm, faceData.ao, out.lm, out.br); } @@ -113,11 +113,11 @@ public class SmoothLightPipeline implements LightPipeline { private void applyAlignedPartialFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPosImpl pos, ForgeDirection dir, QuadLightData out) { for (int i = 0; i < 4; i++) { // Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting - float cx = clamp(quad.getX(i)); - float cy = clamp(quad.getY(i)); - float cz = clamp(quad.getZ(i)); + final float cx = clamp(quad.getX(i)); + final float cy = clamp(quad.getY(i)); + final float cz = clamp(quad.getZ(i)); - float[] weights = this.weights; + final float[] weights = this.weights; neighborInfo.calculateCornerWeights(cx, cy, cz, weights); this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, true); } @@ -133,14 +133,14 @@ public class SmoothLightPipeline implements LightPipeline { private void applyParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPosImpl pos, ForgeDirection dir, QuadLightData out) { for (int i = 0; i < 4; i++) { // Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting - float cx = clamp(quad.getX(i)); - float cy = clamp(quad.getY(i)); - float cz = clamp(quad.getZ(i)); + final float cx = clamp(quad.getX(i)); + final float cy = clamp(quad.getY(i)); + final float cz = clamp(quad.getZ(i)); - float[] weights = this.weights; + final float[] weights = this.weights; neighborInfo.calculateCornerWeights(cx, cy, cz, weights); - float depth = neighborInfo.getDepth(cx, cy, cz); + final float depth = neighborInfo.getDepth(cx, cy, cz); // If the quad is approximately grid-aligned (not inset) to the other side of the block, avoid unnecessary // computation by treating it is as aligned @@ -160,14 +160,14 @@ public class SmoothLightPipeline implements LightPipeline { private void applyNonParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPosImpl pos, ForgeDirection dir, QuadLightData out) { for (int i = 0; i < 4; i++) { // Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting - float cx = clamp(quad.getX(i)); - float cy = clamp(quad.getY(i)); - float cz = clamp(quad.getZ(i)); + final float cx = clamp(quad.getX(i)); + final float cy = clamp(quad.getY(i)); + final float cz = clamp(quad.getZ(i)); - float[] weights = this.weights; + final float[] weights = this.weights; neighborInfo.calculateCornerWeights(cx, cy, cz, weights); - float depth = neighborInfo.getDepth(cx, cy, cz); + final float depth = neighborInfo.getDepth(cx, cy, cz); // If the quad is approximately grid-aligned (not inset), avoid unnecessary computation by treating it is as aligned if (DoubleMath.fuzzyEquals(depth, 0.0F, TOLERANCE)) { @@ -183,22 +183,22 @@ public class SmoothLightPipeline implements LightPipeline { } private void applyAlignedPartialFaceVertex(BlockPosImpl pos, ForgeDirection dir, float[] w, int i, QuadLightData out, boolean offset) { - AoFaceData faceData = this.getCachedFaceData(pos, dir, offset); + final AoFaceData faceData = this.getCachedFaceData(pos, dir, offset); if (!faceData.hasUnpackedLightData()) { faceData.unpackLightData(); } - float sl = faceData.getBlendedSkyLight(w); - float bl = faceData.getBlendedBlockLight(w); - float ao = faceData.getBlendedShade(w); + final float sl = faceData.getBlendedSkyLight(w); + final float bl = faceData.getBlendedBlockLight(w); + final float ao = faceData.getBlendedShade(w); out.br[i] = ao; out.lm[i] = getLightMapCoord(sl, bl); } private void applyInsetPartialFaceVertex(BlockPosImpl pos, ForgeDirection dir, float n1d, float n2d, float[] w, int i, QuadLightData out) { - AoFaceData n1 = this.getCachedFaceData(pos, dir, false); + final AoFaceData n1 = this.getCachedFaceData(pos, dir, false); if (!n1.hasUnpackedLightData()) { n1.unpackLightData(); @@ -211,9 +211,9 @@ public class SmoothLightPipeline implements LightPipeline { } // Blend between the direct neighbors and above based on the passed weights - float ao = (n1.getBlendedShade(w) * n1d) + (n2.getBlendedShade(w) * n2d); - float sl = (n1.getBlendedSkyLight(w) * n1d) + (n2.getBlendedSkyLight(w) * n2d); - float bl = (n1.getBlendedBlockLight(w) * n1d) + (n2.getBlendedBlockLight(w) * n2d); + final float ao = (n1.getBlendedShade(w) * n1d) + (n2.getBlendedShade(w) * n2d); + final float sl = (n1.getBlendedSkyLight(w) * n1d) + (n2.getBlendedSkyLight(w) * n2d); + final float bl = (n1.getBlendedBlockLight(w) * n1d) + (n2.getBlendedBlockLight(w) * n2d); out.br[i] = ao; out.lm[i] = getLightMapCoord(sl, bl); @@ -224,8 +224,8 @@ public class SmoothLightPipeline implements LightPipeline { return; } - float brightness = this.lightCache.getWorld().getBrightness(face, shade); - float[] br = out.br; + final float brightness = this.lightCache.getWorld().getBrightness(face, shade); + final float[] br = out.br; for (int i = 0; i < br.length; i++) { br[i] *= brightness; @@ -236,7 +236,7 @@ public class SmoothLightPipeline implements LightPipeline { * Returns the cached data for a given facing or calculates it if it hasn't been cached. */ private AoFaceData getCachedFaceData(BlockPosImpl pos, ForgeDirection face, boolean offset) { - AoFaceData data = this.cachedFaceData[offset ? face.ordinal() : face.ordinal() + 6]; + final AoFaceData data = this.cachedFaceData[offset ? face.ordinal() : face.ordinal() + 6]; if (!data.hasLightData()) { data.initLightData(this.lightCache, pos, face, offset); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 927854899..e2e35d613 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -30,10 +30,13 @@ import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; import me.jellysquid.mods.sodium.common.util.ListUtil; import net.coderbot.iris.block_rendering.BlockRenderingSettings; +import net.coderbot.iris.layer.GbufferPrograms; import net.coderbot.iris.pipeline.ShadowRenderer; import net.coderbot.iris.shadows.ShadowRenderingState; import net.coderbot.iris.sodium.shadow_map.SwappableChunkRenderManager; import net.coderbot.iris.sodium.vertex_format.IrisModelVertexFormats; +import net.coderbot.iris.uniforms.CapturedRenderingState; +import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.WorldRenderer; @@ -339,7 +342,13 @@ public class SodiumWorldRenderer implements ChunkStatusListener { return; try { + if(AngelicaConfig.enableIris) { + final Block block = tileEntity.getWorldObj().getBlock(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); + CapturedRenderingState.INSTANCE.setCurrentBlockEntity(Block.getIdFromBlock(block)); + GbufferPrograms.beginBlockEntities(); + } TileEntityRendererDispatcher.instance.renderTileEntity(tileEntity, partialTicks); + } catch(RuntimeException e) { if(tileEntity.isInvalid()) { SodiumClientMod.logger().error("Suppressing crash from invalid tile entity", e); @@ -347,10 +356,16 @@ public class SodiumWorldRenderer implements ChunkStatusListener { throw e; } } + finally { + if(AngelicaConfig.enableIris) { + CapturedRenderingState.INSTANCE.setCurrentBlockEntity(-1); + GbufferPrograms.endBlockEntities(); + } + } } public void renderTileEntities(EntityLivingBase entity, ICamera camera, float partialTicks) { - int pass = MinecraftForgeClient.getRenderPass(); + final int pass = MinecraftForgeClient.getRenderPass(); for (TileEntity tileEntity : this.chunkRenderManager.getVisibleTileEntities()) { renderTE(tileEntity, pass, partialTicks); } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java deleted file mode 100644 index cc0a98ae1..000000000 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java +++ /dev/null @@ -1,9 +0,0 @@ -package net.coderbot.batchedentityrendering.impl; - -import com.gtnewhorizons.angelica.compat.toremove.DrawState; - -import java.nio.ByteBuffer; - -public interface BufferBuilderExt { - -} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java index 237aa54f4..f46bbe951 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java @@ -1,6 +1,5 @@ package net.coderbot.batchedentityrendering.impl; -import com.gtnewhorizons.angelica.compat.toremove.DrawState; import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import lombok.Getter; @@ -9,12 +8,10 @@ import java.nio.ByteBuffer; public class BufferSegment { private final ByteBuffer slice; @Getter - private final DrawState drawState; private final RenderLayer type; - public BufferSegment(ByteBuffer slice, DrawState drawState, RenderLayer type) { + public BufferSegment(ByteBuffer slice, RenderLayer type) { this.slice = slice; - this.drawState = drawState; this.type = type; } diff --git a/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/InputAvailability.java b/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/InputAvailability.java index cf0899196..bdd9e729f 100644 --- a/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/InputAvailability.java +++ b/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/InputAvailability.java @@ -5,29 +5,19 @@ public class InputAvailability { public final boolean texture; public final boolean lightmap; - public final boolean overlay; - public InputAvailability(boolean texture, boolean lightmap, boolean overlay) { + public InputAvailability(boolean texture, boolean lightmap) { this.texture = texture; this.lightmap = lightmap; - this.overlay = overlay; - } - - public InputAvailability withoutOverlay() { - return new InputAvailability(texture, lightmap, false); } public static InputAvailability unpack(int packed) { - return new InputAvailability((packed & 1) == 1, (packed & 2) == 2, (packed & 4) == 4); + return new InputAvailability((packed & 1) == 1, (packed & 2) == 2); } public int pack() { int packed = 0; - if (overlay) { - packed |= 4; - } - if (lightmap) { packed |= 2; } @@ -44,7 +34,6 @@ public class InputAvailability { return "InputAvailability{" + "texture=" + texture + ", lightmap=" + lightmap + - ", overlay=" + overlay + '}'; } @@ -53,7 +42,6 @@ public class InputAvailability { final int prime = 31; int result = 1; result = prime * result + (lightmap ? 1231 : 1237); - result = prime * result + (overlay ? 1231 : 1237); result = prime * result + (texture ? 1231 : 1237); return result; } @@ -69,8 +57,6 @@ public class InputAvailability { InputAvailability other = (InputAvailability) obj; if (lightmap != other.lightmap) return false; - if (overlay != other.overlay) - return false; if (texture != other.texture) return false; return true; diff --git a/src/main/java/net/coderbot/iris/gbuffer_overrides/state/StateTracker.java b/src/main/java/net/coderbot/iris/gbuffer_overrides/state/StateTracker.java index bf6c6e982..46f38a6fc 100644 --- a/src/main/java/net/coderbot/iris/gbuffer_overrides/state/StateTracker.java +++ b/src/main/java/net/coderbot/iris/gbuffer_overrides/state/StateTracker.java @@ -11,12 +11,8 @@ public class StateTracker { public boolean albedoSampler; // LightmapStateShard / TextureUnit.LIGHTMAP public boolean lightmapSampler; - // OverlayStateShard / TextureUnit.OVERLAY - public boolean overlaySampler; public InputAvailability getInputs() { - return new InputAvailability(albedoSampler, - lightmapSampler, - overlaySampler); + return new InputAvailability(albedoSampler, lightmapSampler); } } diff --git a/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java deleted file mode 100644 index 67d8ea954..000000000 --- a/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.coderbot.iris.layer; - -import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; -import net.coderbot.iris.uniforms.CapturedRenderingState; - -public final class BlockEntityRenderStateShard extends RenderPhase { - private static final BlockEntityRenderStateShard UNIDENTIFIED = new BlockEntityRenderStateShard(-1); - - private final int entityId; - - private BlockEntityRenderStateShard(int entityId) { - super("iris:is_block_entity", () -> { - CapturedRenderingState.INSTANCE.setCurrentBlockEntity(entityId); - GbufferPrograms.beginBlockEntities(); - }, () -> { - CapturedRenderingState.INSTANCE.setCurrentBlockEntity(-1); - GbufferPrograms.endBlockEntities(); - }); - - this.entityId = entityId; - } - - public static BlockEntityRenderStateShard forId(int entityId) { - if (entityId == -1) { - return UNIDENTIFIED; - } else { - // TODO: Cache all created render phases to avoid allocations? - return new BlockEntityRenderStateShard(entityId); - } - } - - @Override - public boolean equals(Object object) { - if (object == null || object.getClass() != this.getClass()) { - return false; - } - - BlockEntityRenderStateShard other = (BlockEntityRenderStateShard) object; - - return this.entityId == other.entityId; - } -} diff --git a/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java deleted file mode 100644 index d47d627cb..000000000 --- a/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.coderbot.iris.layer; - -import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; -import net.coderbot.iris.uniforms.CapturedRenderingState; - -public final class EntityRenderStateShard extends RenderPhase { - private static final EntityRenderStateShard UNIDENTIFIED = new EntityRenderStateShard(-1); - - private final int entityId; - - private EntityRenderStateShard(int entityId) { - super("iris:is_entity", () -> { - CapturedRenderingState.INSTANCE.setCurrentEntity(entityId); - GbufferPrograms.beginEntities(); - }, () -> { - CapturedRenderingState.INSTANCE.setCurrentEntity(-1); - GbufferPrograms.endEntities(); - }); - - this.entityId = entityId; - } - - public static EntityRenderStateShard forId(int entityId) { - if (entityId == -1) { - return UNIDENTIFIED; - } else { - // TODO: Cache all created render phases to avoid allocations? - return new EntityRenderStateShard(entityId); - } - } - - @Override - public boolean equals(Object object) { - if (object == null || object.getClass() != this.getClass()) { - return false; - } - - EntityRenderStateShard other = (EntityRenderStateShard) object; - - return this.entityId == other.entityId; - } -} diff --git a/src/main/java/net/coderbot/iris/layer/GbufferPrograms.java b/src/main/java/net/coderbot/iris/layer/GbufferPrograms.java index 42f048099..fdde3525d 100644 --- a/src/main/java/net/coderbot/iris/layer/GbufferPrograms.java +++ b/src/main/java/net/coderbot/iris/layer/GbufferPrograms.java @@ -65,7 +65,7 @@ public class GbufferPrograms { } public static WorldRenderingPhase getCurrentPhase() { - WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); + final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); if (pipeline != null) { return pipeline.getPhase(); @@ -75,7 +75,7 @@ public class GbufferPrograms { } private static void setPhase(WorldRenderingPhase phase) { - WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); + final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); if (pipeline != null) { pipeline.setPhase(phase); @@ -83,7 +83,7 @@ public class GbufferPrograms { } public static void setOverridePhase(WorldRenderingPhase phase) { - WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); + final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); if (pipeline != null) { pipeline.setOverridePhase(phase); @@ -100,7 +100,7 @@ public class GbufferPrograms { Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setSpecialCondition(override)); } - public static void teardownSpecialRenderCondition(SpecialCondition override) { + public static void teardownSpecialRenderCondition() { Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setSpecialCondition(null)); } diff --git a/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java deleted file mode 100644 index f18af5669..000000000 --- a/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.coderbot.iris.layer; - -import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; - -public class IsBlockEntityRenderStateShard extends RenderPhase { - public static final IsBlockEntityRenderStateShard INSTANCE = new IsBlockEntityRenderStateShard(); - - private IsBlockEntityRenderStateShard() { - super("iris:is_block_entity", GbufferPrograms::beginBlockEntities, GbufferPrograms::endBlockEntities); - } -} diff --git a/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java deleted file mode 100644 index a3daa0920..000000000 --- a/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.coderbot.iris.layer; - -import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; - -public class IsEntityRenderStateShard extends RenderPhase { - public static final IsEntityRenderStateShard INSTANCE = new IsEntityRenderStateShard(); - - private IsEntityRenderStateShard() { - super("iris:is_entity", GbufferPrograms::beginEntities, GbufferPrograms::endEntities); - } -} diff --git a/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java deleted file mode 100644 index 2c2edc836..000000000 --- a/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.coderbot.iris.layer; - -import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; - -public class IsOutlineRenderStateShard extends RenderPhase { - public static final IsOutlineRenderStateShard INSTANCE = new IsOutlineRenderStateShard(); - - private IsOutlineRenderStateShard() { - super("iris:is_outline", GbufferPrograms::beginOutline, GbufferPrograms::endOutline); - } -} diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 570cd98f9..440ea7dea 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -145,7 +145,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R private WorldRenderingPhase phase = WorldRenderingPhase.NONE; private boolean isBeforeTranslucent; private boolean isRenderingShadow = false; - private InputAvailability inputs = new InputAvailability(false, false, false); + private InputAvailability inputs = new InputAvailability(false, false); private SpecialCondition special = null; private boolean shouldBindPBR; @@ -344,7 +344,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R if (programs.getPackDirectives().getShadowDirectives().isShadowEnabled().orElse(true)) { this.shadowRenderer = new ShadowRenderer(programs.getShadow().orElse(null), programs.getPackDirectives(), shadowRenderTargets); - Program shadowProgram = table.match(RenderCondition.SHADOW, new InputAvailability(true, true, true)).getProgram(); + Program shadowProgram = table.match(RenderCondition.SHADOW, new InputAvailability(true, true)).getProgram(); shadowRenderer.setUsesImages(shadowProgram != null && shadowProgram.getActiveImages() > 0); } else { shadowRenderer = null; @@ -367,7 +367,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureManager.getCustomTextureIdMap(TextureStage.GBUFFERS_AND_SHADOW)); IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false); - IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true, false)); + IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true)); IrisSamplers.addWorldDepthSamplers(customTextureSamplerInterceptor, renderTargets); IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture()); @@ -395,7 +395,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureManager.getCustomTextureIdMap(TextureStage.GBUFFERS_AND_SHADOW)); IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flippedAfterPrepare, renderTargets, false); - IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true, false)); + IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true)); IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture()); // Only initialize these samplers if the shadow map renderer exists. Otherwise, this program shouldn't be used at all? @@ -548,7 +548,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R } if (sodiumTerrainRendering) { - beginPass(table.match(getCondition(getPhase()), new InputAvailability(true, true, false))); + beginPass(table.match(getCondition(getPhase()), new InputAvailability(true, true))); return; } @@ -967,7 +967,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false); IrisImages.addRenderTargetImages(builder, flipped, renderTargets); - IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true, false)); + IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true)); IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture()); diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/AttributeTransformer.java b/src/main/java/net/coderbot/iris/pipeline/transform/AttributeTransformer.java index bf0c333cd..805951b70 100644 --- a/src/main/java/net/coderbot/iris/pipeline/transform/AttributeTransformer.java +++ b/src/main/java/net/coderbot/iris/pipeline/transform/AttributeTransformer.java @@ -36,7 +36,7 @@ class AttributeTransformer { // lightmap texture coordinate. // See https://github.com/IrisShaders/Iris/issues/1149 if (parameters.inputs.lightmap) { - root.rename("gl_MultiTexCoord1", "gl_MultiTexCoord2"); + root.rename("gl_MultiTexCoord2", "gl_MultiTexCoord1"); } Stream stream = Stream.empty(); @@ -59,10 +59,6 @@ class AttributeTransformer { patchTextureMatrices(t, tree, root, parameters.inputs.lightmap); - if (parameters.inputs.overlay) { - patchOverlayColor(t, tree, root, parameters); - } - if (parameters.type.glShaderType == ShaderType.VERTEX && root.identifierIndex.has("gl_MultiTexCoord3") && !root.identifierIndex.has("mc_midTexCoord")) { @@ -91,7 +87,7 @@ class AttributeTransformer { "const float iris_ONE_OVER_32 = iris_ONE_OVER_256 * 8;"); if (hasLightmap) { tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_FUNCTIONS, - "mat4 iris_LightmapTextureMatrix = gl_TextureMatrix[2];"); + "mat4 iris_LightmapTextureMatrix = gl_TextureMatrix[1];"); } else { tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_FUNCTIONS, "mat4 iris_LightmapTextureMatrix =" + "mat4(iris_ONE_OVER_256, 0.0, 0.0, 0.0," + @@ -112,56 +108,4 @@ class AttributeTransformer { "mat4(1.0)" + ");"); } - - private static final AutoHintedMatcher uniformVec4EntityColor = new AutoHintedMatcher<>( - "uniform vec4 entityColor;", Matcher.externalDeclarationPattern); - - // Add entity color -> overlay color attribute support. - private static void patchOverlayColor( - ASTParser t, - TranslationUnit tree, - Root root, - AttributeParameters parameters) { - // delete original declaration - root.processMatches(t, uniformVec4EntityColor, ASTNode::detachAndDelete); - - if (parameters.type.glShaderType == ShaderType.VERTEX) { - // add our own declarations - // TODO: We're exposing entityColor to this stage even if it isn't declared in - // this stage. But this is needed for the pass-through behavior. - tree.parseAndInjectNodes(t, ASTInjectionPoint.BEFORE_FUNCTIONS, - "uniform sampler2D iris_overlay;", - "varying vec4 entityColor;"); - - // this is so we can pass through the overlay color at the end to the geometry - // or fragment stage. - tree.prependMain(t, - "vec4 overlayColor = texture2D(iris_overlay, (gl_TextureMatrix[1] * gl_MultiTexCoord1).xy);", - "entityColor = vec4(overlayColor.rgb, 1.0 - overlayColor.a);", - // Workaround for a shader pack bug: - // https://github.com/IrisShaders/Iris/issues/1549 - // Some shader packs incorrectly ignore the alpha value, and assume that rgb - // will be - // zero if there is no hit flash, we try to emulate that here - "entityColor.rgb *= float(entityColor.a != 0.0);"); - } else if (parameters.type.glShaderType == ShaderType.GEOMETRY) { - // replace read references to grab the color from the first vertex. - root.replaceReferenceExpressions(t, "entityColor", "entityColor[0]"); - - // TODO: this is passthrough behavior - tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_FUNCTIONS, - "out vec4 entityColorGS;"); - tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_FUNCTIONS, - "in vec4 entityColor[];"); - tree.prependMain(t, "entityColorGS = entityColor[0];"); - } else if (parameters.type.glShaderType == ShaderType.FRAGMENT) { - tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_DECLARATIONS, - "varying vec4 entityColor;"); - - // Different output name to avoid a name collision in the geometry shader. - if (parameters.hasGeometry) { - root.rename("entityColor", "entityColorGS"); - } - } - } } diff --git a/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java b/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java index 4ffef547d..bc0a52953 100644 --- a/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java +++ b/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java @@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableSet; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gl.sampler.SamplerHolder; import net.coderbot.iris.gl.state.StateUpdateNotifiers; +import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline; import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.coderbot.iris.rendertarget.RenderTarget; import net.coderbot.iris.rendertarget.RenderTargets; @@ -18,15 +19,13 @@ import java.util.function.Supplier; public class IrisSamplers { public static final int ALBEDO_TEXTURE_UNIT = 0; - // TODO: Find equivalent in 1.7.10 - public static final int OVERLAY_TEXTURE_UNIT = 1; public static final int LIGHTMAP_TEXTURE_UNIT = 1; - public static final ImmutableSet WORLD_RESERVED_TEXTURE_UNITS = ImmutableSet.of(0, 1, 2); + public static final ImmutableSet WORLD_RESERVED_TEXTURE_UNITS = ImmutableSet.of(0, 1); // TODO: In composite programs, there shouldn't be any reserved textures. // We need a way to restore these texture bindings. - public static final ImmutableSet COMPOSITE_RESERVED_TEXTURE_UNITS = ImmutableSet.of(1, 2); + public static final ImmutableSet COMPOSITE_RESERVED_TEXTURE_UNITS = ImmutableSet.of(1); private IrisSamplers() { // no construction allowed @@ -139,14 +138,6 @@ public class IrisSamplers { samplers.addDynamicSampler(whitePixel::getGlTextureId, "lightmap"); } - if (availability.overlay) { - // TODO: Overlay equivalent in 1.7.10? -// samplers.addExternalSampler(OVERLAY_TEXTURE_UNIT, "iris_overlay"); - samplers.addDynamicSampler(whitePixel::getGlTextureId, "iris_overlay"); - } else { - samplers.addDynamicSampler(whitePixel::getGlTextureId, "iris_overlay"); - } - samplers.addDynamicSampler(pipeline::getCurrentNormalTexture, StateUpdateNotifiers.normalTextureChangeNotifier, "normals"); samplers.addDynamicSampler(pipeline::getCurrentSpecularTexture, StateUpdateNotifiers.specularTextureChangeNotifier, "specular"); } @@ -158,11 +149,8 @@ public class IrisSamplers { } public static void addCompositeSamplers(SamplerHolder samplers, RenderTargets renderTargets) { - samplers.addDynamicSampler(renderTargets::getDepthTexture, - "gdepthtex", "depthtex0"); - samplers.addDynamicSampler(renderTargets.getDepthTextureNoTranslucents()::getTextureId, - "depthtex1"); - samplers.addDynamicSampler(renderTargets.getDepthTextureNoHand()::getTextureId, - "depthtex2"); + samplers.addDynamicSampler(renderTargets::getDepthTexture, "gdepthtex", "depthtex0"); + samplers.addDynamicSampler(renderTargets.getDepthTextureNoTranslucents()::getTextureId, "depthtex1"); + samplers.addDynamicSampler(renderTargets.getDepthTextureNoHand()::getTextureId, "depthtex2"); } } diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java index a649ff0be..c5bdcd882 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java @@ -1,6 +1,5 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; -import com.gtnewhorizons.angelica.compat.toremove.OverlayTexture; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; @@ -53,7 +52,7 @@ public class EntityVertexBufferWriterNio extends VertexBufferWriterNio implement @Override public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) { - writeQuad(x, y, z, color, u, v, light, OverlayTexture.NO_OVERLAY, 0); + writeQuad(x, y, z, color, u, v, light, 0, 0); } private void endQuad(int normal) { diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java index bbb0e3913..c697bec3b 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java @@ -1,7 +1,6 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; -import com.gtnewhorizons.angelica.compat.toremove.OverlayTexture; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; @@ -51,7 +50,7 @@ public class EntityVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe imp @Override public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) { - writeQuad(x, y, z, color, u, v, light, OverlayTexture.NO_OVERLAY, 0); + writeQuad(x, y, z, color, u, v, light, 0, 0); } private void endQuad(int normal) { diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java index e2b0d4bce..fb7a45074 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java @@ -1,6 +1,5 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; -import com.gtnewhorizons.angelica.compat.toremove.OverlayTexture; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; @@ -52,7 +51,7 @@ public class GlyphVertexBufferWriterNio extends VertexBufferWriterNio implements @Override public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) { - writeQuad(x, y, z, color, u, v, light, OverlayTexture.NO_OVERLAY, 0); + writeQuad(x, y, z, color, u, v, light, 0, 0); } private void endQuad(int normal) { diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java index 66e087d61..70d4d719b 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java @@ -1,7 +1,6 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; -import com.gtnewhorizons.angelica.compat.toremove.OverlayTexture; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; @@ -50,7 +49,7 @@ public class GlyphVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe impl @Override public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) { - writeQuad(x, y, z, color, u, v, light, OverlayTexture.NO_OVERLAY, 0); + writeQuad(x, y, z, color, u, v, light, 0, 0); } private void endQuad(int normal) { diff --git a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java index dd9699e3b..92ad32267 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java +++ b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java @@ -3,6 +3,8 @@ package net.coderbot.iris.uniforms; import lombok.Getter; import net.coderbot.iris.gl.state.ValueUpdateNotifier; +import org.joml.Vector4f; + public class CapturedRenderingState { public static final CapturedRenderingState INSTANCE = new CapturedRenderingState(); @@ -16,6 +18,10 @@ public class CapturedRenderingState { private int currentRenderedEntity = -1; private Runnable entityIdListener = null; + @Getter + private final Vector4f currentEntityColor = new Vector4f(); + private Runnable entityColorListener = null; + private CapturedRenderingState() { } @@ -39,6 +45,14 @@ public class CapturedRenderingState { } } + public void setCurrentEntityColor(float r, float g, float b, float a) { + this.currentEntityColor.set(r, g, b, a); + + if (this.entityColorListener != null) { + this.entityColorListener.run(); + } + } + public ValueUpdateNotifier getEntityIdNotifier() { return listener -> this.entityIdListener = listener; } @@ -46,4 +60,6 @@ public class CapturedRenderingState { public ValueUpdateNotifier getBlockEntityIdNotifier() { return listener -> this.blockEntityIdListener = listener; } + + public ValueUpdateNotifier getEntityColorNotifier() { return listener -> this.entityColorListener = listener; } } diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index 4dde1fb34..dcec1b6fe 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -91,6 +91,8 @@ public final class CommonUniforms { uniforms.uniform1i("renderStage", () -> GbufferPrograms.getCurrentPhase().ordinal(), StateUpdateNotifiers.phaseChangeNotifier); + uniforms.uniform4f("entityColor", CapturedRenderingState.INSTANCE::getCurrentEntityColor, CapturedRenderingState.INSTANCE.getEntityColorNotifier()); + CommonUniforms.generalCommonUniforms(uniforms, updateNotifier, directives); } @@ -115,8 +117,7 @@ public final class CommonUniforms { .uniform1f(PER_FRAME, "screenBrightness", () -> client.gameSettings.gammaSetting) // just a dummy value for shaders where entityColor isn't supplied through a vertex attribute (and thus is // not available) - suppresses warnings. See AttributeShaderTransformer for the actual entityColor code. - .uniform4f(ONCE, "entityColor", Vector4f::new) - .uniform1f(PER_TICK, "playerMood", CommonUniforms::getPlayerMood) + .uniform1f(PER_TICK, "playerMood", CommonUniforms::getPlayerMood) .uniform2i(PER_FRAME, "eyeBrightness", CommonUniforms::getEyeBrightness) .uniform2i(PER_FRAME, "eyeBrightnessSmooth", () -> { final Vector2f smoothed = eyeBrightnessSmooth.get(); diff --git a/src/main/resources/assets/angelica/lang/en_US.lang b/src/main/resources/assets/angelica/lang/en_US.lang index 529535131..9257fb6ab 100644 --- a/src/main/resources/assets/angelica/lang/en_US.lang +++ b/src/main/resources/assets/angelica/lang/en_US.lang @@ -127,7 +127,7 @@ options.iris.shadowDistance.disabled=Your current shader pack has already set a options.iris.gui.hide=Hide GUI options.iris.gui.show=Show GUI options.dynamic_lights=Dynamic Lights -options.dynamic_lights.tooltip=Enables dynamic lights. Modes: OFF - off, FASTEST - 500ms delay, FAST - 250ms delay, FANCY - no delay +options.dynamic_lights.tooltip=Enables dynamic lights. Modes: OFF - off, FASTEST - 500ms delay, FAST - 250ms delay, FANCY - no delay. Disabled if shaders are in use. pack.iris.select.title=Select pack.iris.configure.title=Configure label.iris.true=On