diff --git a/dependencies.gradle b/dependencies.gradle index 04923996a..9ca52ac84 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -136,6 +136,9 @@ dependencies { // Better Crashes compileOnly("com.github.GTNewHorizons:BetterCrashes:1.4.1-GTNH:dev") + // Distant Horizons + compileOnly("maven.modrinth:DistantHorizonsApi:5.1.0") + afterEvaluate { dependencies { testImplementation(platform('org.junit:junit-bom:5.14.1')) diff --git a/src/main/java/com/gtnewhorizons/angelica/iris/IrisGLSMBridge.java b/src/main/java/com/gtnewhorizons/angelica/iris/IrisGLSMBridge.java index beca86b2d..f017a790b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/iris/IrisGLSMBridge.java +++ b/src/main/java/com/gtnewhorizons/angelica/iris/IrisGLSMBridge.java @@ -14,6 +14,7 @@ import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline; import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.coderbot.iris.samplers.IrisSamplers; import net.coderbot.iris.texture.pbr.PBRTextureManager; +import net.coderbot.iris.vertices.ImmediateState; public class IrisGLSMBridge { @@ -114,7 +115,7 @@ public class IrisGLSMBridge { if (!drp.shouldOverrideShaders()) return; if (drp.getActivePassProgramId() == -1) return; - if (DepthColorStorage.isOwnedProgram(event.newProgram)) { + if (!ImmediateState.isRenderingLevel || DepthColorStorage.isOwnedProgram(event.newProgram)) { DepthColorStorage.unlockDepthColor(); } else { drp.onModProgramOverride(); diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 2131738c5..a5405a803 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -7,6 +7,7 @@ import com.gtnewhorizons.angelica.AngelicaMod; import com.gtnewhorizons.angelica.Tags; import com.gtnewhorizons.angelica.config.AngelicaConfig; import cpw.mods.fml.client.registry.ClientRegistry; +import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.gameevent.InputEvent; import it.unimi.dsi.fastutil.ints.Int2IntMap; @@ -17,6 +18,7 @@ import net.coderbot.iris.block_rendering.BlockRenderingSettings; import com.gtnewhorizons.angelica.config.AngelicaConfig; import net.coderbot.iris.celeritas.IrisCeleritasShaderProvider; import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProviderHolder; +import net.coderbot.iris.compat.dh.DHCompat; import net.coderbot.iris.config.IrisConfig; import net.coderbot.iris.gl.shader.StandardMacros; import net.coderbot.iris.gui.screen.ShaderPackScreen; @@ -113,11 +115,31 @@ public class Iris { // Used in favor of queueDefaultShaderPackOptionValues() for resetting as the // behavior is more concrete and therefore is more likely to repair a user's issues private static boolean resetShaderPackOptions = false; + private static boolean loadShaderPackWhenPossible = false; private static String IRIS_VERSION; @Getter private static boolean fallback; + public static boolean loadedIncompatiblePack() { + return DHCompat.lastPackIncompatible(); + } + + public static void loadShaderpackWhenPossible() { + loadShaderPackWhenPossible = true; + } + + public static void tryLoadShaderpackWhenPossible() { + if (loadShaderPackWhenPossible) { + loadShaderPackWhenPossible = false; + try { + reload(); + } catch (IOException e) { + logger.error("Error during deferred shader reload", e); + } + } + } + /** * Lazy executor for parallelizing shader transformations during shader pack loading. * Creates threads on demand and shuts down after a period of inactivity. @@ -350,6 +372,7 @@ public class Iris { *

This is called right before options are loaded, so we can add key bindings here.

*/ public void onEarlyInitialize() { + DHCompat.run(); try { if (!Files.exists(getShaderpacksDirectory())) { Files.createDirectories(getShaderpacksDirectory()); @@ -395,8 +418,19 @@ public class Iris { PBRTextureManager.INSTANCE.init(); - // Only load the shader pack when we can access OpenGL - loadShaderpack(); + boolean isDHLoaded; + try { + Class.forName("com.seibel.distanthorizons.DistantHorizonsTweaker"); + isDHLoaded = true; + } + catch (Exception e) { + isDHLoaded = false; + } + + // When DH is present, defer shaderpack loading until its init callback has run. + if (!isDHLoaded) { + loadShaderpack(); + } } /** @@ -721,6 +755,12 @@ public class Iris { BlockRenderingSettings.INSTANCE.reloadRendererIfRequired(); } + + if (loadedIncompatiblePack() && Minecraft.getMinecraft().thePlayer != null) { + Iris.logger.warn("Incompatible pack for DH!"); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.BOLD.toString() + EnumChatFormatting.RED + "This pack doesn't have DH support.")); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "Distant Horizons (DH) chunks won't show up. This isn't a bug, get another shader.")); + } } /** diff --git a/src/main/java/net/coderbot/iris/compat/dh/DHCompat.java b/src/main/java/net/coderbot/iris/compat/dh/DHCompat.java index 64f820012..f215514e2 100644 --- a/src/main/java/net/coderbot/iris/compat/dh/DHCompat.java +++ b/src/main/java/net/coderbot/iris/compat/dh/DHCompat.java @@ -1,14 +1,129 @@ package net.coderbot.iris.compat.dh; -/** - * Stub implementation of Distant Horizons compatibility. - */ -public class DHCompat { - public int getDepthTex() { - return 0; - } +import com.gtnewhorizons.angelica.rendering.RenderingState; +import net.coderbot.iris.Iris; +import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline; +import net.minecraft.client.Minecraft; +import org.joml.Matrix4f; +import org.joml.Matrix4fc; - public int getDepthTexNoTranslucent() { - return 0; - } +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationTargetException; + +public class DHCompat { + private static boolean dhPresent; + private static boolean lastIncompatible; + private DHCompatInternal compatInternalInstance; + private final static Matrix4f tempProj = new Matrix4f(); + + public DHCompat(DeferredWorldRenderingPipeline pipeline, boolean renderDHShadow) { + if (pipeline == null) { + return; + } + try { + if (dhPresent) { + compatInternalInstance = new DHCompatInternal(pipeline, renderDHShadow); + lastIncompatible = compatInternalInstance.incompatiblePack(); + } + } catch (Throwable e) { + lastIncompatible = false; + if (e instanceof InvocationTargetException ite) { + throw new RuntimeException("Unknown error loading Distant Horizons compatibility.", ite.getCause()); + } else { + throw new RuntimeException("Unknown error loading Distant Horizons compatibility.", e); + } + } + + } + + public static Matrix4fc getProjection() { + Matrix4f projection = RenderingState.INSTANCE.getProjectionMatrix(); + if (!dhPresent) { + return projection; + } + + return tempProj.setPerspective(projection.perspectiveFov(), projection.m11() / projection.m00(), DHCompat.getNearPlane(), DHCompat.getFarPlane()); + } + + public static void run() { + try { + Class.forName("com.seibel.distanthorizons.DistantHorizonsTweaker"); + dhPresent = true; + } + catch (Exception e) { + dhPresent = false; + } + try { + if (dhPresent) { + LodRendererEvents.setupEventHandlers(); + } + } catch (Throwable e) { + dhPresent = false; + if (e instanceof ExceptionInInitializerError eiie) { + throw new RuntimeException("Failure loading DH compat.", eiie.getCause()); + } else { + throw new RuntimeException("DH found, but one or more API methods are missing. Iris requires DH [2.0.4] or DH API version [1.1.0] or newer. Please make sure you are on the latest version of DH and Iris.", e); + } + } + } + + public static boolean lastPackIncompatible() { + return dhPresent && hasRenderingEnabled() && lastIncompatible; + } + + public static float getFarPlane() { + if (!dhPresent) return 0.01f; + return DHCompatInternal.getFarPlane(); + } + + public static float getNearPlane() { + if (!dhPresent) return 0.01f; + return DHCompatInternal.getNearPlane(); + } + + public static int getRenderDistance() { + if (!dhPresent) return Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16; + + return DHCompatInternal.getRenderDistance(); + } + + public static boolean checkFrame() { + if (!dhPresent) { + return false; + } + + return DHCompatInternal.checkFrame(); + } + + public static boolean hasRenderingEnabled() { + if (!dhPresent) { + return false; + } + + return checkFrame(); + } + + public void clearPipeline() { + if (compatInternalInstance == null) return; + + compatInternalInstance.clear(); + } + + public int getDepthTex() { + if (compatInternalInstance == null) return -1; + + return compatInternalInstance.getStoredDepthTex(); + } + + public int getDepthTexNoTranslucent() { + if (compatInternalInstance == null) return -1; + + return compatInternalInstance.getDepthTexNoTranslucent(); + } + + public DHCompatInternal getInstance() { + return compatInternalInstance; + } } diff --git a/src/main/java/net/coderbot/iris/compat/dh/DHCompatInternal.java b/src/main/java/net/coderbot/iris/compat/dh/DHCompatInternal.java new file mode 100644 index 000000000..116ba4c09 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/dh/DHCompatInternal.java @@ -0,0 +1,291 @@ +package net.coderbot.iris.compat.dh; + +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.seibel.distanthorizons.api.DhApi; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram; +import com.seibel.distanthorizons.api.objects.math.DhApiVec3f; +import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.framebuffer.GlFramebuffer; +import net.coderbot.iris.gl.texture.DepthBufferFormat; +import net.coderbot.iris.gl.texture.DepthCopyStrategy; +import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline; +import net.coderbot.iris.rendertarget.DepthTexture; +import net.coderbot.iris.rendertarget.IRenderTargetExt; +import net.coderbot.iris.shaderpack.CloudSetting; +import net.coderbot.iris.shaderpack.ProgramSource; +import net.coderbot.iris.uniforms.CapturedRenderingState; +import net.irisshaders.iris.api.v0.IrisApi; +import net.minecraft.client.Minecraft; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; + +public class DHCompatInternal { + public static final DHCompatInternal SHADERLESS = new DHCompatInternal(null, false); + static boolean dhEnabled; + private static int guiScale = -1; + private final DeferredWorldRenderingPipeline pipeline; + public boolean shouldOverrideShadow; + public boolean shouldOverride; + private GlFramebuffer dhGenericFramebuffer; + private IrisLodRenderProgram solidProgram; + private IrisGenericRenderProgram genericShader; + private IrisLodRenderProgram translucentProgram; + private IrisLodRenderProgram shadowProgram; + private GlFramebuffer dhTerrainFramebuffer; + private DhFrameBufferWrapper dhTerrainFramebufferWrapper; + private GlFramebuffer dhWaterFramebuffer; + private GlFramebuffer dhShadowFramebuffer; + private DhFrameBufferWrapper dhShadowFramebufferWrapper; + private DepthTexture depthTexNoTranslucent; + private boolean translucentDepthDirty; + private int storedDepthTex = -1; + private boolean incompatible = false; + private int cachedVersion; + + public DHCompatInternal(DeferredWorldRenderingPipeline pipeline, boolean dhShadowEnabled) { + this.pipeline = pipeline; + + if (pipeline == null || !DhApi.Delayed.configs.graphics().renderingEnabled().getValue()) { + return; + } + + if (pipeline.getDHTerrainShader().isEmpty() && pipeline.getDHWaterShader().isEmpty()) { + Iris.logger.warn("No DH shader found in this pack."); + incompatible = true; + return; + } + + cachedVersion = ((IRenderTargetExt) Minecraft.getMinecraft().getFramebuffer()).iris$getDepthBufferVersion(); + + createDepthTex(Minecraft.getMinecraft().getFramebuffer().framebufferWidth, Minecraft.getMinecraft().getFramebuffer().framebufferHeight); + translucentDepthDirty = true; + + ProgramSource terrain = pipeline.getDHTerrainShader().get(); + solidProgram = IrisLodRenderProgram.createProgram(terrain.getName(), false, false, terrain, pipeline.getCustomUniforms(), pipeline); + + ProgramSource generic = pipeline.getDHGenericShader().get(); + genericShader = IrisGenericRenderProgram.createProgram(generic.getName() + "_g", false, false, generic, pipeline.getCustomUniforms(), pipeline); + dhGenericFramebuffer = pipeline.createDHFramebuffer(generic, false); + + if (pipeline.getDHWaterShader().isPresent()) { + ProgramSource water = pipeline.getDHWaterShader().get(); + translucentProgram = IrisLodRenderProgram.createProgram(water.getName(), false, true, water, pipeline.getCustomUniforms(), pipeline); + dhWaterFramebuffer = pipeline.createDHFramebuffer(water, true); + } + + if (pipeline.getDHShadowShader().isPresent() && dhShadowEnabled) { + ProgramSource shadow = pipeline.getDHShadowShader().get(); + shadowProgram = IrisLodRenderProgram.createProgram(shadow.getName(), true, false, shadow, pipeline.getCustomUniforms(), pipeline); + if (pipeline.hasShadowRenderTargets()) { + dhShadowFramebuffer = pipeline.createDHFramebufferShadow(shadow); + dhShadowFramebufferWrapper = new DhFrameBufferWrapper(dhShadowFramebuffer); + } + shouldOverrideShadow = true; + } else { + shouldOverrideShadow = false; + } + + dhTerrainFramebuffer = pipeline.createDHFramebuffer(terrain, false); + dhTerrainFramebufferWrapper = new DhFrameBufferWrapper(dhTerrainFramebuffer); + + if (translucentProgram == null) { + translucentProgram = solidProgram; + } + + shouldOverride = true; + } + + public static int getDhBlockRenderDistance() { + if (DhApi.Delayed.configs == null || !dhEnabled) { + // Called before DH has finished setup + return Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16; + } + + return DhApi.Delayed.configs.graphics().chunkRenderDistance().getValue() * 16; + } + + public static int getRenderDistance() { + return getDhBlockRenderDistance(); + } + + public static float getFarPlane() { + if (DhApi.Delayed.configs == null) { + // Called before DH has finished setup + return 0; + } + + int lodChunkDist = DhApi.Delayed.configs.graphics().chunkRenderDistance().getValue(); + int lodBlockDist = lodChunkDist * 16; + // sqrt 2 to prevent the corners from being cut off + return (float) ((lodBlockDist + 512) * Math.sqrt(2)); + } + + public static float getNearPlane() { + if (DhApi.Delayed.renderProxy == null) { + // Called before DH has finished setup + return 0; + } + + return DhApi.Delayed.renderProxy.getNearClipPlaneDistanceInBlocks(CapturedRenderingState.INSTANCE.getTickDelta()); + } + + public static boolean checkFrame() { + if (guiScale == -1) { + guiScale = Minecraft.getMinecraft().gameSettings.guiScale; + } + + if (DhApi.Delayed.configs == null) return dhEnabled; + + if ((dhEnabled != DhApi.Delayed.configs.graphics().renderingEnabled().getValue() || guiScale != Minecraft.getMinecraft().gameSettings.guiScale) + && IrisApi.getInstance().isShaderPackInUse()) { + guiScale = Minecraft.getMinecraft().gameSettings.guiScale; + dhEnabled = DhApi.Delayed.configs.graphics().renderingEnabled().getValue(); + try { + Iris.reload(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + return dhEnabled; + } + + public boolean incompatiblePack() { + return incompatible; + } + + public void reconnectDHTextures(int depthTex) { + if (((IRenderTargetExt) Minecraft.getMinecraft().getFramebuffer()).iris$getDepthBufferVersion() != cachedVersion) { + cachedVersion = ((IRenderTargetExt) Minecraft.getMinecraft().getFramebuffer()).iris$getDepthBufferVersion(); + createDepthTex(Minecraft.getMinecraft().getFramebuffer().framebufferWidth, Minecraft.getMinecraft().getFramebuffer().framebufferHeight); + } + if (storedDepthTex != depthTex && dhTerrainFramebuffer != null) { + storedDepthTex = depthTex; + dhTerrainFramebuffer.addDepthAttachmentBypass(depthTex); + if (dhWaterFramebuffer != null) { + dhWaterFramebuffer.addDepthAttachmentBypass(depthTex); + } + if (dhGenericFramebuffer != null) { + dhGenericFramebuffer.addDepthAttachmentBypass(depthTex); + } + } + } + + public void createDepthTex(int width, int height) { + if (depthTexNoTranslucent != null) { + depthTexNoTranslucent.destroy(); + depthTexNoTranslucent = null; + } + + translucentDepthDirty = true; + + depthTexNoTranslucent = new DepthTexture(width, height, DepthBufferFormat.DEPTH32F); + } + + public void clear() { + if (solidProgram != null) { + solidProgram.free(); + solidProgram = null; + } + if (translucentProgram != null) { + translucentProgram.free(); + translucentProgram = null; + } + if (shadowProgram != null) { + shadowProgram.free(); + shadowProgram = null; + } + shouldOverrideShadow = false; + shouldOverride = false; + dhTerrainFramebuffer = null; + dhWaterFramebuffer = null; + dhShadowFramebuffer = null; + storedDepthTex = -1; + translucentDepthDirty = true; + + OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, dhTerrainFramebufferWrapper); + OverrideInjector.INSTANCE.unbind(IDhApiGenericObjectShaderProgram.class, genericShader); + OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, dhShadowFramebufferWrapper); + dhTerrainFramebufferWrapper = null; + dhShadowFramebufferWrapper = null; + } + + public void setModelPos(DhApiVec3f modelPos) { + solidProgram.bind(); + solidProgram.setModelPos(modelPos); + translucentProgram.bind(); + translucentProgram.setModelPos(modelPos); + solidProgram.bind(); + } + + public IrisLodRenderProgram getSolidShader() { + return solidProgram; + } + + public GlFramebuffer getSolidFB() { + return dhTerrainFramebuffer; + } + + public DhFrameBufferWrapper getSolidFBWrapper() { + return dhTerrainFramebufferWrapper; + } + + public IrisLodRenderProgram getShadowShader() { + return shadowProgram; + } + + public GlFramebuffer getShadowFB() { + return dhShadowFramebuffer; + } + + public DhFrameBufferWrapper getShadowFBWrapper() { + return dhShadowFramebufferWrapper; + } + + public IrisLodRenderProgram getTranslucentShader() { + if (translucentProgram == null) { + return solidProgram; + } + return translucentProgram; + } + + public int getStoredDepthTex() { + return storedDepthTex; + } + + public void copyTranslucents(int width, int height) { + if (translucentDepthDirty) { + translucentDepthDirty = false; + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, depthTexNoTranslucent.getTextureId()); + dhTerrainFramebuffer.bindAsReadBuffer(); + GLStateManager.glCopyTexImage2D(GL11.GL_TEXTURE_2D, 0, DepthBufferFormat.DEPTH32F.getGlInternalFormat(), 0, 0, width, height, 0); + } else { + DepthCopyStrategy.fastest(false).copy(dhTerrainFramebuffer, storedDepthTex, null, depthTexNoTranslucent.getTextureId(), width, height); + } + } + + public GlFramebuffer getTranslucentFB() { + return dhWaterFramebuffer; + } + + public GlFramebuffer getGenericFB() { + return dhGenericFramebuffer; + } + + public int getDepthTexNoTranslucent() { + if (depthTexNoTranslucent == null) return 0; + + return depthTexNoTranslucent.getTextureId(); + } + + public IDhApiGenericObjectShaderProgram getGenericShader() { + return genericShader; + } + + public boolean avoidRenderingClouds() { + return pipeline != null && (pipeline.getDHCloudSetting() == CloudSetting.OFF || (pipeline.getDHCloudSetting() == CloudSetting.DEFAULT && pipeline.getCloudSetting() == CloudSetting.OFF)); + } +} diff --git a/src/main/java/net/coderbot/iris/compat/dh/DhFrameBufferWrapper.java b/src/main/java/net/coderbot/iris/compat/dh/DhFrameBufferWrapper.java new file mode 100644 index 000000000..1d4a68cb4 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/dh/DhFrameBufferWrapper.java @@ -0,0 +1,55 @@ +package net.coderbot.iris.compat.dh; + +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer; +import net.coderbot.iris.gl.framebuffer.GlFramebuffer; +import org.lwjgl.opengl.GL30; + +public class DhFrameBufferWrapper implements IDhApiFramebuffer { + private final GlFramebuffer framebuffer; + + + public DhFrameBufferWrapper(GlFramebuffer framebuffer) { + this.framebuffer = framebuffer; + } + + + @Override + public boolean overrideThisFrame() { + return true; + } + + @Override + public void bind() { + this.framebuffer.bind(); + } + + @Override + public void addDepthAttachment(int i, boolean b) { + // ignore + } + + @Override + public int getId() { + return this.framebuffer.getId(); + } + + @Override + public int getStatus() { + this.bind(); + int status = GLStateManager.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER); + return status; + } + + @Override + public void addColorAttachment(int i, int i1) { + // ignore + } + + @Override + public void destroy() { + // ignore + //this.framebuffer.destroy(); + } + +} diff --git a/src/main/java/net/coderbot/iris/compat/dh/IrisGenericRenderProgram.java b/src/main/java/net/coderbot/iris/compat/dh/IrisGenericRenderProgram.java new file mode 100644 index 000000000..626fae2be --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/dh/IrisGenericRenderProgram.java @@ -0,0 +1,351 @@ +package net.coderbot.iris.compat.dh; + +import com.google.common.primitives.Ints; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor; +import com.mitchej123.lwjgl.MemoryStack; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup; +import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; +import com.seibel.distanthorizons.api.objects.math.DhApiMat4f; +import com.seibel.distanthorizons.api.objects.math.DhApiVec3d; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading; +import net.coderbot.iris.gl.blending.BlendModeOverride; +import net.coderbot.iris.gl.blending.BufferBlendOverride; +import net.coderbot.iris.gl.program.ProgramImages; +import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.program.ProgramUniforms; +import net.coderbot.iris.gl.shader.GlShader; +import net.coderbot.iris.gl.shader.ShaderType; +import net.coderbot.iris.gl.state.FogMode; +import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline; +import net.coderbot.iris.pipeline.PatchedShaderPrinter; +import net.coderbot.iris.pipeline.transform.PatchShaderType; +import net.coderbot.iris.pipeline.transform.TransformPatcher; +import net.coderbot.iris.samplers.IrisSamplers; +import net.coderbot.iris.shaderpack.ProgramSource; +import net.coderbot.iris.uniforms.CommonUniforms; +import net.coderbot.iris.uniforms.builtin.BuiltinReplacementUniforms; +import net.coderbot.iris.uniforms.custom.CustomUniforms; +import net.irisshaders.iris.api.v0.IrisApi; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.DynamicTexture; +import org.joml.Matrix3f; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL30; + +import java.nio.FloatBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class IrisGenericRenderProgram implements IDhApiGenericObjectShaderProgram { + // Uniforms + public final int modelViewUniform; + public final int modelViewInverseUniform; + public final int projectionUniform; + public final int projectionInverseUniform; + public final int normalMatrix3fUniform; + // Fog/Clip Uniforms + private final int id; + private final ProgramUniforms uniforms; + private final CustomUniforms customUniforms; + private final ProgramSamplers samplers; + private final ProgramImages images; + private final BlendModeOverride blend; + private final BufferBlendOverride[] bufferBlendOverrides; + private final Matrix4f tempModel = new Matrix4f(); + private final Matrix4f tempProj = new Matrix4f(); + private final Matrix4f tempMat4 = new Matrix4f(); + private final Matrix3f tempMat3 = new Matrix3f(); + + private final int instancedShaderOffsetChunkUniform; + private final int instancedShaderOffsetSubChunkUniform; + private final int instancedShaderCameraChunkPosUniform; + private final int instancedShaderCameraSubChunkPosUniform; + private final int instancedShaderProjectionModelViewMatrixUniform; + private final int va; + private final int uBlockLight; + private final int uSkyLight; + + // This will bind AbstractVertexAttribute + private IrisGenericRenderProgram(String name, boolean isShadowPass, boolean translucent, BlendModeOverride override, BufferBlendOverride[] bufferBlendOverrides, String vertex, String tessControl, String tessEval, String geometry, String fragment, CustomUniforms customUniforms, DeferredWorldRenderingPipeline pipeline) { + id = GLStateManager.glCreateProgram(); + + GLStateManager.glBindAttribLocation(this.id, 0, "vPosition"); + + this.bufferBlendOverrides = bufferBlendOverrides; + + GlShader vert = new GlShader(ShaderType.VERTEX, name + ".vsh", vertex); + GLStateManager.glAttachShader(id, vert.getHandle()); + + GlShader tessCont = null; + if (tessControl != null) { + tessCont = new GlShader(ShaderType.TESSELATION_CONTROL, name + ".tcs", tessControl); + GLStateManager.glAttachShader(id, tessCont.getHandle()); + } + + GlShader tessE = null; + if (tessEval != null) { + tessE = new GlShader(ShaderType.TESSELATION_EVAL, name + ".tes", tessEval); + GLStateManager.glAttachShader(id, tessE.getHandle()); + } + + GlShader geom = null; + if (geometry != null) { + geom = new GlShader(ShaderType.GEOMETRY, name + ".gsh", geometry); + GLStateManager.glAttachShader(id, geom.getHandle()); + } + + GlShader frag = new GlShader(ShaderType.FRAGMENT, name + ".fsh", fragment); + GLStateManager.glAttachShader(id, frag.getHandle()); + + GLStateManager.glLinkProgram(this.id); + int status = GLStateManager.glGetProgrami(this.id, GL20.GL_LINK_STATUS); + if (status != 1) { + String message = "Shader link error in Iris DH program! Details: " + GLStateManager.glGetProgramInfoLog(this.id, 9999); + this.free(); + throw new RuntimeException(message); + } else { + GLStateManager.glUseProgram(this.id); + } + + vert.destroy(); + frag.destroy(); + + if (tessCont != null) tessCont.destroy(); + if (tessE != null) tessE.destroy(); + if (geom != null) geom.destroy(); + + blend = override; + ProgramUniforms.Builder uniformBuilder = ProgramUniforms.builder(name, id); + ProgramSamplers.Builder samplerBuilder = ProgramSamplers.builder(id, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS); + CommonUniforms.addDynamicUniforms(uniformBuilder, FogMode.PER_VERTEX); + customUniforms.assignTo(uniformBuilder); + BuiltinReplacementUniforms.addBuiltinReplacementUniforms(uniformBuilder); + ProgramImages.Builder builder = ProgramImages.builder(id); + pipeline.addGbufferOrShadowSamplers(samplerBuilder, builder, + isShadowPass ? pipeline::getFlippedBeforeShadow : () -> translucent ? pipeline.getFlippedAfterTranslucent() : pipeline.getFlippedAfterPrepare(), + isShadowPass, true, true, false); + customUniforms.mapholderToPass(uniformBuilder, this); + this.uniforms = uniformBuilder.buildUniforms(); + this.customUniforms = customUniforms; + samplers = samplerBuilder.build(); + images = builder.build(); + + this.va = GLStateManager.glGenVertexArrays(); + GLStateManager.glBindVertexArray(va); + GLStateManager.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0); + GLStateManager.glEnableVertexAttribArray(0); + + projectionUniform = tryGetUniformLocation2("iris_ProjectionMatrix"); + projectionInverseUniform = tryGetUniformLocation2("iris_ProjectionMatrixInverse"); + modelViewUniform = tryGetUniformLocation2("iris_ModelViewMatrix"); + modelViewInverseUniform = tryGetUniformLocation2("iris_ModelViewMatrixInverse"); + normalMatrix3fUniform = tryGetUniformLocation2("iris_NormalMatrix"); + + this.instancedShaderOffsetChunkUniform = this.tryGetUniformLocation2("uOffsetChunk"); + this.instancedShaderOffsetSubChunkUniform = this.tryGetUniformLocation2("uOffsetSubChunk"); + this.instancedShaderCameraChunkPosUniform = this.tryGetUniformLocation2("uCameraPosChunk"); + this.instancedShaderCameraSubChunkPosUniform = this.tryGetUniformLocation2("uCameraPosSubChunk"); + this.instancedShaderProjectionModelViewMatrixUniform = this.tryGetUniformLocation2("uProjectionMvm"); + this.uBlockLight = this.tryGetUniformLocation2("uBlockLight"); + this.uSkyLight = this.tryGetUniformLocation2("uSkyLight"); + } + + public static IrisGenericRenderProgram createProgram(String name, boolean isShadowPass, boolean translucent, ProgramSource source, CustomUniforms uniforms, DeferredWorldRenderingPipeline pipeline) { + Map transformed = TransformPatcher.patchDHGeneric( + name, + source.getVertexSource().orElseThrow(RuntimeException::new), + source.getTessControlSource().orElse(null), + source.getTessEvalSource().orElse(null), + source.getGeometrySource().orElse(null), + source.getFragmentSource().orElseThrow(RuntimeException::new), + pipeline.getTextureMap()); + String vertex = transformed.get(PatchShaderType.VERTEX); + String tessControl = transformed.get(PatchShaderType.TESS_CONTROL); + String tessEval = transformed.get(PatchShaderType.TESS_EVAL); + String geometry = transformed.get(PatchShaderType.GEOMETRY); + String fragment = transformed.get(PatchShaderType.FRAGMENT); + PatchedShaderPrinter.debugPatchedShaders(source.getName() + "_g", vertex, geometry, tessControl, tessEval, fragment); + + List bufferOverrides = new ArrayList<>(); + + source.getDirectives().getBufferBlendOverrides().forEach(information -> { + int index = Ints.indexOf(source.getDirectives().getDrawBuffers(), information.getIndex()); + if (index > -1) { + bufferOverrides.add(new BufferBlendOverride(index, information.getBlendMode())); + } + }); + + return new IrisGenericRenderProgram(name, isShadowPass, translucent, source.getDirectives().getBlendModeOverride().orElse(null), bufferOverrides.toArray(BufferBlendOverride[]::new), vertex, tessControl, tessEval, geometry, fragment, uniforms, pipeline); + } + + // Noise Uniforms + + private static int getChunkPosFromDouble(double value) { + return (int) Math.floor(value / 16); + } + + private static float getSubChunkPosFromDouble(double value) { + double chunkPos = Math.floor(value / 16); + return (float) (value - chunkPos * 16); + } + + public int tryGetUniformLocation2(CharSequence name) { + return GLStateManager.glGetUniformLocation(this.id, name); + } + + public void setUniform(int index, Matrix4f matrix) { + if (index == -1 || matrix == null) return; + + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer buffer = stack.callocFloat(16); + matrix.get(buffer); + buffer.rewind(); + + GLStateManager.glUniformMatrix4(index, false, buffer); + } + } + + public void setUniform(int index, Matrix3f matrix) { + if (index == -1) return; + + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer buffer = stack.callocFloat(9); + matrix.get(buffer); + buffer.rewind(); + + GLStateManager.glUniformMatrix3(index, false, buffer); + } + } + + // Override ShaderProgram.bind() + public void bind(DhApiRenderParam renderParam) { + GLStateManager.glBindVertexArray(va); + GLStateManager.glUseProgram(id); + if (blend != null) blend.apply(); + + for (BufferBlendOverride override : bufferBlendOverrides) { + override.apply(); + } + + toJOML(tempModel, renderParam.dhModelViewMatrix); + toJOML(tempProj, renderParam.dhProjectionMatrix); + + setUniform(modelViewUniform, tempModel); + setUniform(projectionUniform, tempProj); + this.setUniform(this.instancedShaderProjectionModelViewMatrixUniform, tempMat4.set(tempProj).mul(tempModel)); + tempModel.invert(); + tempProj.invert(); + setUniform(modelViewInverseUniform, tempModel); + setUniform(projectionInverseUniform, tempProj); + setUniform(normalMatrix3fUniform, tempModel.transpose3x3(tempMat3)); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + IrisSamplers.LIGHTMAP_TEXTURE_UNIT); + DynamicTexture lightmapTexture = ((EntityRendererAccessor) Minecraft.getMinecraft().entityRenderer).getLightmapTexture(); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, lightmapTexture.getGlTextureId()); + + samplers.update(); + uniforms.update(); + + customUniforms.push(this); + + images.update(); + } + + public void unbind() { + GLStateManager.glBindVertexArray(0); + GLStateManager.glUseProgram(0); + ProgramUniforms.clearActiveUniforms(); + ProgramSamplers.clearActiveSamplers(); + BlendModeOverride.restore(); + } + + @Override + public void bindVertexBuffer(int i) { + GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, i); + GLStateManager.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 12, 0); + } + + @Override + public boolean overrideThisFrame() { + return IrisApi.getInstance().isShaderPackInUse(); + } + + @Override + public int getId() { + return id; + } + + public void free() { + GLStateManager.glDeleteProgram(id); + } + + public void fillIndirectUniformData(DhApiRenderParam dhApiRenderParam, DhApiRenderableBoxGroupShading dhApiRenderableBoxGroupShading, IDhApiRenderableBoxGroup boxGroup, DhApiVec3d camPos) { + bind(dhApiRenderParam); + GLStateManager.enableDepthTest(); + GLStateManager.glDepthFunc(GL11.GL_LEQUAL); + this.setUniform(this.instancedShaderOffsetChunkUniform, + getChunkPosFromDouble(boxGroup.getOriginBlockPos().x), + getChunkPosFromDouble(boxGroup.getOriginBlockPos().y), + getChunkPosFromDouble(boxGroup.getOriginBlockPos().z) + ); + this.setUniform(this.instancedShaderOffsetSubChunkUniform, + getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x), + getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y), + getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z) + ); + + this.setUniform(this.instancedShaderCameraChunkPosUniform, + getChunkPosFromDouble(camPos.x), + getChunkPosFromDouble(camPos.y), + getChunkPosFromDouble(camPos.z) + ); + this.setUniform(this.instancedShaderCameraSubChunkPosUniform, + getSubChunkPosFromDouble(camPos.x), + getSubChunkPosFromDouble(camPos.y), + getSubChunkPosFromDouble(camPos.z) + ); + this.setUniform(this.uBlockLight, + boxGroup.getBlockLight()); + this.setUniform(this.uSkyLight, + boxGroup.getSkyLight()); + + } + + @Override + public void fillSharedDirectUniformData(DhApiRenderParam dhApiRenderParam, DhApiRenderableBoxGroupShading dhApiRenderableBoxGroupShading, IDhApiRenderableBoxGroup iDhApiRenderableBoxGroup, DhApiVec3d dhApiVec3d) { + throw new IllegalStateException("Only indirect is supported with Iris."); + } + + @Override + public void fillDirectUniformData(DhApiRenderParam dhApiRenderParam, IDhApiRenderableBoxGroup iDhApiRenderableBoxGroup, DhApiRenderableBox dhApiRenderableBox, DhApiVec3d dhApiVec3d) { + throw new IllegalStateException("Only indirect is supported with Iris."); + } + + private void toJOML(Matrix4f target, DhApiMat4f mat4f) { + target.setTransposed(mat4f.getValuesAsArray()); + } + + private void setUniform(int index, int value) { + GLStateManager.glUniform1i(index, value); + } + + private void setUniform(int index, float value) { + GLStateManager.glUniform1f(index, value); + } + + private void setUniform(int index, float x, float y, float z) { + GLStateManager.glUniform3f(index, x, y, z); + } + + private void setUniform(int index, int x, int y, int z) { + GLStateManager.glUniform3i(index, x, y, z); + } + +} diff --git a/src/main/java/net/coderbot/iris/compat/dh/IrisLodRenderProgram.java b/src/main/java/net/coderbot/iris/compat/dh/IrisLodRenderProgram.java new file mode 100644 index 000000000..659b198cb --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/dh/IrisLodRenderProgram.java @@ -0,0 +1,266 @@ +package net.coderbot.iris.compat.dh; + +import com.google.common.primitives.Ints; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor; +import com.mitchej123.lwjgl.MemoryStack; +import com.seibel.distanthorizons.api.DhApi; +import com.seibel.distanthorizons.api.objects.math.DhApiVec3f; +import net.coderbot.iris.gl.blending.BlendModeOverride; +import net.coderbot.iris.gl.blending.BufferBlendOverride; +import net.coderbot.iris.gl.program.ProgramImages; +import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.program.ProgramUniforms; +import net.coderbot.iris.gl.shader.GlShader; +import net.coderbot.iris.gl.shader.ShaderType; +import net.coderbot.iris.gl.state.FogMode; +import net.coderbot.iris.gl.texture.TextureType; +import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline; +import net.coderbot.iris.pipeline.PatchedShaderPrinter; +import net.coderbot.iris.pipeline.transform.PatchShaderType; +import net.coderbot.iris.pipeline.transform.TransformPatcher; +import net.coderbot.iris.samplers.IrisSamplers; +import net.coderbot.iris.shaderpack.ProgramSource; +import net.coderbot.iris.uniforms.CommonUniforms; +import net.coderbot.iris.uniforms.builtin.BuiltinReplacementUniforms; +import net.coderbot.iris.uniforms.custom.CustomUniforms; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.DynamicTexture; +import org.joml.Matrix3f; +import org.joml.Matrix4f; +import org.joml.Matrix4fc; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL32; + +import java.nio.FloatBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class IrisLodRenderProgram { + // Uniforms + public final int modelOffsetUniform; + public final int worldYOffsetUniform; + public final int mircoOffsetUniform; + public final int modelViewUniform; + public final int modelViewInverseUniform; + public final int projectionUniform; + public final int projectionInverseUniform; + public final int normalMatrix3fUniform; + // Fog/Clip Uniforms + public final int clipDistanceUniform; + private final int id; + private final ProgramUniforms uniforms; + private final CustomUniforms customUniforms; + private final ProgramSamplers samplers; + private final ProgramImages images; + private final BlendModeOverride blend; + private final BufferBlendOverride[] bufferBlendOverrides; + private final Matrix4f tempMat4a = new Matrix4f(); + private final Matrix4f tempMat4b = new Matrix4f(); + private final Matrix3f tempMat3 = new Matrix3f(); + + // This will bind AbstractVertexAttribute + private IrisLodRenderProgram(String name, boolean isShadowPass, boolean translucent, BlendModeOverride override, BufferBlendOverride[] bufferBlendOverrides, String vertex, String tessControl, String tessEval, String geometry, String fragment, CustomUniforms customUniforms, DeferredWorldRenderingPipeline pipeline) { + id = GLStateManager.glCreateProgram(); + + GLStateManager.glBindAttribLocation(this.id, 0, "vPosition"); + GLStateManager.glBindAttribLocation(this.id, 1, "iris_color"); + GLStateManager.glBindAttribLocation(this.id, 2, "irisExtra"); + + this.bufferBlendOverrides = bufferBlendOverrides; + + GlShader vert = new GlShader(ShaderType.VERTEX, name + ".vsh", vertex); + GLStateManager.glAttachShader(id, vert.getHandle()); + + GlShader tessCont = null; + if (tessControl != null) { + tessCont = new GlShader(ShaderType.TESSELATION_CONTROL, name + ".tcs", tessControl); + GLStateManager.glAttachShader(id, tessCont.getHandle()); + } + + GlShader tessE = null; + if (tessEval != null) { + tessE = new GlShader(ShaderType.TESSELATION_EVAL, name + ".tes", tessEval); + GLStateManager.glAttachShader(id, tessE.getHandle()); + } + + GlShader geom = null; + if (geometry != null) { + geom = new GlShader(ShaderType.GEOMETRY, name + ".gsh", geometry); + GLStateManager.glAttachShader(id, geom.getHandle()); + } + + GlShader frag = new GlShader(ShaderType.FRAGMENT, name + ".fsh", fragment); + GLStateManager.glAttachShader(id, frag.getHandle()); + + GLStateManager.glLinkProgram(this.id); + int status = GLStateManager.glGetProgrami(this.id, GL20.GL_LINK_STATUS); + if (status != 1) { + String message = "Shader link error in Iris DH program! Details: " + GLStateManager.glGetProgramInfoLog(this.id, 9999); + this.free(); + throw new RuntimeException(message); + } else { + GLStateManager.glUseProgram(this.id); + } + + vert.destroy(); + frag.destroy(); + + if (tessCont != null) tessCont.destroy(); + if (tessE != null) tessE.destroy(); + if (geom != null) geom.destroy(); + + blend = override; + ProgramUniforms.Builder uniformBuilder = ProgramUniforms.builder(name, id); + ProgramSamplers.Builder samplerBuilder = ProgramSamplers.builder(id, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS); + CommonUniforms.addDynamicUniforms(uniformBuilder, FogMode.PER_VERTEX); + customUniforms.assignTo(uniformBuilder); + BuiltinReplacementUniforms.addBuiltinReplacementUniforms(uniformBuilder); + ProgramImages.Builder builder = ProgramImages.builder(id); + pipeline.addGbufferOrShadowSamplers(samplerBuilder, builder, + isShadowPass ? pipeline::getFlippedBeforeShadow : () -> translucent ? pipeline.getFlippedAfterTranslucent() : pipeline.getFlippedAfterPrepare(), + isShadowPass, true, true, false); + customUniforms.mapholderToPass(uniformBuilder, this); + this.uniforms = uniformBuilder.buildUniforms(); + this.customUniforms = customUniforms; + samplers = samplerBuilder.build(); + images = builder.build(); + + modelOffsetUniform = tryGetUniformLocation2("modelOffset"); + worldYOffsetUniform = tryGetUniformLocation2("worldYOffset"); + mircoOffsetUniform = tryGetUniformLocation2("mircoOffset"); + projectionUniform = tryGetUniformLocation2("iris_ProjectionMatrix"); + projectionInverseUniform = tryGetUniformLocation2("iris_ProjectionMatrixInverse"); + modelViewUniform = tryGetUniformLocation2("iris_ModelViewMatrix"); + modelViewInverseUniform = tryGetUniformLocation2("iris_ModelViewMatrixInverse"); + normalMatrix3fUniform = tryGetUniformLocation2("iris_NormalMatrix"); + + // Fog/Clip Uniforms + clipDistanceUniform = tryGetUniformLocation2("clipDistance"); + } + + public static IrisLodRenderProgram createProgram(String name, boolean isShadowPass, boolean translucent, ProgramSource source, CustomUniforms uniforms, DeferredWorldRenderingPipeline pipeline) { + Map transformed = TransformPatcher.patchDHTerrain( + name, + source.getVertexSource().orElseThrow(RuntimeException::new), + source.getTessControlSource().orElse(null), + source.getTessEvalSource().orElse(null), + source.getGeometrySource().orElse(null), + source.getFragmentSource().orElseThrow(RuntimeException::new), + pipeline.getTextureMap()); + String vertex = transformed.get(PatchShaderType.VERTEX); + String tessControl = transformed.get(PatchShaderType.TESS_CONTROL); + String tessEval = transformed.get(PatchShaderType.TESS_EVAL); + String geometry = transformed.get(PatchShaderType.GEOMETRY); + String fragment = transformed.get(PatchShaderType.FRAGMENT); + PatchedShaderPrinter.debugPatchedShaders(source.getName(), vertex, geometry, tessControl, tessEval, fragment); + + List bufferOverrides = new ArrayList<>(); + + source.getDirectives().getBufferBlendOverrides().forEach(information -> { + int index = Ints.indexOf(source.getDirectives().getDrawBuffers(), information.getIndex()); + if (index > -1) { + bufferOverrides.add(new BufferBlendOverride(index, information.getBlendMode())); + } + }); + + return new IrisLodRenderProgram(name, isShadowPass, translucent, source.getDirectives().getBlendModeOverride().orElse(null), bufferOverrides.toArray(BufferBlendOverride[]::new), vertex, tessControl, tessEval, geometry, fragment, uniforms, pipeline); + } + + // Noise Uniforms + + public int tryGetUniformLocation2(CharSequence name) { + return GLStateManager.glGetUniformLocation(this.id, name); + } + + public void setUniform(int index, Matrix4fc matrix) { + if (index == -1 || matrix == null) return; + + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer buffer = stack.callocFloat(16); + matrix.get(buffer); + buffer.rewind(); + + GLStateManager.glUniformMatrix4(index, false, buffer); + } + } + + public void setUniform(int index, Matrix3f matrix) { + if (index == -1) return; + + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer buffer = stack.callocFloat(9); + matrix.get(buffer); + buffer.rewind(); + + GLStateManager.glUniformMatrix3(index, false, buffer); + } + } + + // Override ShaderProgram.bind() + public void bind() { + GLStateManager.glUseProgram(id); + if (blend != null) blend.apply(); + + for (BufferBlendOverride override : bufferBlendOverrides) { + override.apply(); + } + } + + public void unbind() { + GLStateManager.glUseProgram(0); + ProgramUniforms.clearActiveUniforms(); + ProgramSamplers.clearActiveSamplers(); + BlendModeOverride.restore(); + } + + public void free() { + GLStateManager.glDeleteProgram(id); + } + + public void fillUniformData(Matrix4fc projection, Matrix4fc modelView, int worldYOffset, float partialTicks) { + GLStateManager.glUseProgram(id); + + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + IrisSamplers.LIGHTMAP_TEXTURE_UNIT); + DynamicTexture lightmapTexture = ((EntityRendererAccessor) Minecraft.getMinecraft().entityRenderer).getLightmapTexture(); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, lightmapTexture.getGlTextureId()); + setUniform(modelViewUniform, modelView); + setUniform(modelViewInverseUniform, modelView.invert(tempMat4a)); + setUniform(projectionUniform, projection); + setUniform(projectionInverseUniform, projection.invert(tempMat4b)); + setUniform(normalMatrix3fUniform, tempMat4a.set(modelView).invert().transpose3x3(tempMat3)); + + setUniform(mircoOffsetUniform, 0.01f); // 0.01 block offset + + // setUniform(skyLightUniform, skyLight); + + if (worldYOffsetUniform != -1) setUniform(worldYOffsetUniform, (float) worldYOffset); + + // Fog/Clip Uniforms + float dhNearClipDistance = DhApi.Delayed.renderProxy.getNearClipPlaneDistanceInBlocks(partialTicks); + setUniform(clipDistanceUniform, dhNearClipDistance); + + samplers.update(); + uniforms.update(); + + customUniforms.push(this); + + images.update(); + } + + private void setUniform(int index, float value) { + GLStateManager.glUniform1f(index, value); + } + + public void setModelPos(DhApiVec3f modelPos) { + setUniform(modelOffsetUniform, modelPos); + } + + private void setUniform(int index, DhApiVec3f pos) { + GLStateManager.glUniform3f(index, pos.x, pos.y, pos.z); + } + +} diff --git a/src/main/java/net/coderbot/iris/compat/dh/LodRendererEvents.java b/src/main/java/net/coderbot/iris/compat/dh/LodRendererEvents.java new file mode 100644 index 000000000..76651e487 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/dh/LodRendererEvents.java @@ -0,0 +1,383 @@ +package net.coderbot.iris.compat.dh; + +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.rendering.RenderingState; +import com.seibel.distanthorizons.api.DhApi; +import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogDrawMode; +import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass; +import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeApplyShaderRenderEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeBufferRenderEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDeferredRenderEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericObjectRenderEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderSetupEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderCleanupEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderPassEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderSetupEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeTextureClearEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiColorDepthTextureCreatedEvent; +import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiCancelableEventParam; +import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam; +import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; +import com.seibel.distanthorizons.api.objects.math.DhApiVec3f; +import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector; +import net.coderbot.iris.Iris; +import net.coderbot.iris.pipeline.ShadowRenderer; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.coderbot.iris.shadows.ShadowRenderingState; +import net.coderbot.iris.uniforms.CapturedRenderingState; +import net.irisshaders.iris.api.v0.IrisApi; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11; + +public class LodRendererEvents { + // TODO: Query actual world min height for Cubic Chunks compatibility + private static final int WORLD_MIN_Y = 0; + + private static boolean eventHandlersBound = false; + + private static boolean atTranslucent = false; + private static int textureWidth; + private static int textureHeight; + private static final Matrix4f tempMat4 = new Matrix4f(); + + + // constructor // + + public static void setupEventHandlers() { + if (!eventHandlersBound) { + eventHandlersBound = true; + Iris.logger.info("Queuing DH event binding..."); + + DhApiAfterDhInitEvent beforeCleanupEvent = new DhApiAfterDhInitEvent() { + @Override + public void afterDistantHorizonsInit(DhApiEventParam event) { + Iris.logger.info("DH Ready, binding Iris event handlers..."); + + Iris.loadShaderpackWhenPossible(); + + setupSetDeferredBeforeRenderingEvent(); + setupReconnectDepthTextureEvent(); + setupGenericEvent(); + setupCreateDepthTextureEvent(); + setupTransparentRendererEventCancling(); + setupBeforeBufferClearEvent(); + setupBeforeRenderCleanupEvent(); + beforeBufferRenderEvent(); + setupBeforeRenderFrameBufferBinding(); + setupBeforeRenderPassEvent(); + setupBeforeApplyShaderEvent(); + DHCompatInternal.dhEnabled = DhApi.Delayed.configs.graphics().renderingEnabled().getValue(); + Iris.logger.info("DH Iris events bound."); + } + }; + DhApi.events.bind(DhApiAfterDhInitEvent.class, beforeCleanupEvent); + } + } + + + // setup event handlers // + + + private static void setupSetDeferredBeforeRenderingEvent() { + DhApiBeforeRenderEvent beforeRenderEvent = new DhApiBeforeRenderEvent() { + // this event is called before DH starts any rendering prep + // canceling it will prevent DH from rendering for that frame + @Override + public void beforeRender(DhApiCancelableEventParam event) { + + DhApi.Delayed.renderProxy.setDeferTransparentRendering(IrisApi.getInstance().isShaderPackInUse() && getInstance().shouldOverride); + DhApi.Delayed.configs.graphics().fog().drawMode().setValue(getInstance().shouldOverride ? EDhApiFogDrawMode.FOG_DISABLED : EDhApiFogDrawMode.FOG_ENABLED); + } + }; + + DhApi.events.bind(DhApiBeforeRenderEvent.class, beforeRenderEvent); + } + + private static void setupReconnectDepthTextureEvent() { + DhApiBeforeTextureClearEvent beforeRenderEvent = new DhApiBeforeTextureClearEvent() { + @Override + public void beforeClear(DhApiCancelableEventParam event) { + var getResult = DhApi.Delayed.renderProxy.getDhDepthTextureId(); + if (getResult.success) { + int depthTextureId = getResult.payload; + getInstance().reconnectDHTextures(depthTextureId); + } + } + }; + + DhApi.events.bind(DhApiBeforeTextureClearEvent.class, beforeRenderEvent); + } + + private static void setupGenericEvent() { + DhApiBeforeGenericRenderSetupEvent beforeRenderEvent = new DhApiBeforeGenericRenderSetupEvent() { + @Override + public void beforeSetup(DhApiEventParam dhApiEventParam) { + if (getInstance().getGenericFB() != null) { + getInstance().getGenericFB().bind(); + } + } + }; + + DhApiBeforeGenericObjectRenderEvent beforeDrawEvent = new DhApiBeforeGenericObjectRenderEvent() { + @Override + public void beforeRender(DhApiCancelableEventParam dhApiCancelableEventParam) { + if (dhApiCancelableEventParam.value.resourceLocationPath.equalsIgnoreCase("Clouds")) { + if (getInstance().avoidRenderingClouds()) { + dhApiCancelableEventParam.cancelEvent(); + } + } + } + }; + + DhApi.events.bind(DhApiBeforeGenericRenderSetupEvent.class, beforeRenderEvent); + DhApi.events.bind(DhApiBeforeGenericObjectRenderEvent.class, beforeDrawEvent); + } + + private static DHCompatInternal getInstance() { + return Iris.getPipelineManager().getPipeline().map(WorldRenderingPipeline::getDHCompat).map(DHCompat::getInstance).orElse(DHCompatInternal.SHADERLESS); + } + + private static void setupCreateDepthTextureEvent() { + DhApiColorDepthTextureCreatedEvent beforeRenderEvent = new DhApiColorDepthTextureCreatedEvent() { + @Override + public void onResize(DhApiEventParam input) { + textureWidth = input.value.newWidth; + textureHeight = input.value.newHeight; + } + }; + + DhApi.events.bind(DhApiColorDepthTextureCreatedEvent.class, beforeRenderEvent); + } + + private static void setupTransparentRendererEventCancling() { + DhApiBeforeRenderEvent beforeRenderEvent = new DhApiBeforeRenderEvent() { + @Override + public void beforeRender(DhApiCancelableEventParam event) { + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered() && (!getInstance().shouldOverrideShadow)) { + event.cancelEvent(); + } + } + }; + DhApiBeforeDeferredRenderEvent beforeRenderEvent2 = new DhApiBeforeDeferredRenderEvent() { + @Override + public void beforeRender(DhApiCancelableEventParam event) { + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered() && (!getInstance().shouldOverrideShadow)) { + event.cancelEvent(); + } + } + }; + + DhApi.events.bind(DhApiBeforeRenderEvent.class, beforeRenderEvent); + DhApi.events.bind(DhApiBeforeDeferredRenderEvent.class, beforeRenderEvent2); + } + + private static void setupBeforeRenderCleanupEvent() { + DhApiBeforeRenderCleanupEvent beforeCleanupEvent = new DhApiBeforeRenderCleanupEvent() { + @Override + public void beforeCleanup(DhApiEventParam event) { + if (getInstance().shouldOverride) { + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + getInstance().getShadowShader().unbind(); + } else { + getInstance().getSolidShader().unbind(); + if (atTranslucent) { + GLStateManager.enableCull(); + } + } + } + } + }; + + DhApi.events.bind(DhApiBeforeRenderCleanupEvent.class, beforeCleanupEvent); + } + + private static void setupBeforeBufferClearEvent() { + DhApiBeforeTextureClearEvent beforeCleanupEvent = new DhApiBeforeTextureClearEvent() { + @Override + public void beforeClear(DhApiCancelableEventParam event) { + if (event.value.renderPass == EDhApiRenderPass.OPAQUE) { + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + event.cancelEvent(); + } else if (getInstance().shouldOverride) { + GLStateManager.glClear(GL11.GL_DEPTH_BUFFER_BIT); + event.cancelEvent(); + } + } + } + }; + + DhApi.events.bind(DhApiBeforeTextureClearEvent.class, beforeCleanupEvent); + } + + private static void beforeBufferRenderEvent() { + DhApiBeforeBufferRenderEvent beforeCleanupEvent = new DhApiBeforeBufferRenderEvent() { + @Override + public void beforeRender(DhApiEventParam input) { + DHCompatInternal instance = getInstance(); + if (instance.shouldOverride) { + DhApiVec3f modelPos = input.value.modelPos; + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + instance.getShadowShader().bind(); + instance.getShadowShader().setModelPos(modelPos); + } else if (atTranslucent) { + instance.getTranslucentShader().bind(); + instance.getTranslucentShader().setModelPos(modelPos); + } else { + instance.getSolidShader().bind(); + instance.getSolidShader().setModelPos(modelPos); + } + } + } + }; + + DhApi.events.bind(DhApiBeforeBufferRenderEvent.class, beforeCleanupEvent); + } + + private static void setupBeforeRenderFrameBufferBinding() { + DhApiBeforeRenderSetupEvent beforeRenderPassEvent = new DhApiBeforeRenderSetupEvent() { + @Override + public void beforeSetup(DhApiEventParam event) { + DHCompatInternal instance = getInstance(); + + OverrideInjector.INSTANCE.unbind(IDhApiShadowCullingFrustum.class, (IDhApiOverrideable) ShadowRenderer.FRUSTUM); + OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getShadowFBWrapper()); + OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getSolidFBWrapper()); + OverrideInjector.INSTANCE.unbind(IDhApiGenericObjectShaderProgram.class, instance.getGenericShader()); + + if (instance.shouldOverride) { + if (instance.getGenericShader() != null) { + OverrideInjector.INSTANCE.bind(IDhApiGenericObjectShaderProgram.class, instance.getGenericShader()); + } + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered() && instance.shouldOverrideShadow) { + OverrideInjector.INSTANCE.bind(IDhApiFramebuffer.class, instance.getShadowFBWrapper()); + OverrideInjector.INSTANCE.bind(IDhApiShadowCullingFrustum.class, (IDhApiOverrideable) ShadowRenderer.FRUSTUM); + } else { + OverrideInjector.INSTANCE.bind(IDhApiFramebuffer.class, instance.getSolidFBWrapper()); + } + } + } + }; + DhApi.events.bind(DhApiBeforeRenderSetupEvent.class, beforeRenderPassEvent); + + } + + private static void setupBeforeRenderPassEvent() { + DhApiBeforeRenderPassEvent beforeCleanupEvent = new DhApiBeforeRenderPassEvent() { + @Override + public void beforeRender(DhApiEventParam event) { + DHCompatInternal instance = getInstance(); + + // config overrides + if (instance.shouldOverride) { + DhApi.Delayed.configs.graphics().ambientOcclusion().enabled().setValue(false); + DhApi.Delayed.configs.graphics().fog().drawMode().setValue(EDhApiFogDrawMode.FOG_DISABLED); + + if (event.value.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT) { + Iris.logger.error("Unexpected; somehow the Opaque + Translucent pass ran with shaders on."); + } + } else { + DhApi.Delayed.configs.graphics().ambientOcclusion().enabled().clearValue(); + DhApi.Delayed.configs.graphics().fog().drawMode().clearValue(); + } + + + // cleanup + if (event.value.renderPass == EDhApiRenderPass.OPAQUE) { + if (instance.shouldOverride) { + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + instance.getShadowShader().bind(); + } else { + instance.getSolidShader().bind(); + } + atTranslucent = false; + } + } + + + // opaque + if (event.value.renderPass == EDhApiRenderPass.OPAQUE) { + float partialTicks = event.value.partialTicks; + + if (instance.shouldOverride) { + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + instance.getShadowShader().fillUniformData( + ShadowRenderer.PROJECTION, ShadowRenderer.MODELVIEW, + WORLD_MIN_Y, + partialTicks); + } else { + Matrix4f projection = RenderingState.INSTANCE.getProjectionMatrix();; + + instance.getSolidShader().fillUniformData( + tempMat4.setPerspective(projection.perspectiveFov(), projection.m11() / projection.m00(), event.value.nearClipPlane, event.value.farClipPlane), + RenderingState.INSTANCE.getModelViewMatrix(), + WORLD_MIN_Y, + partialTicks); + } + } + } + + + // transparent + if (event.value.renderPass == EDhApiRenderPass.TRANSPARENT) { + float partialTicks = event.value.partialTicks; + int depthTextureId = DhApi.Delayed.renderProxy.getDhDepthTextureId().payload; + + if (instance.shouldOverrideShadow && ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + instance.getShadowShader().bind(); + instance.getShadowFB().bind(); + atTranslucent = true; + + return; + } + + if (instance.shouldOverride && instance.getTranslucentFB() != null) { + instance.copyTranslucents(textureWidth, textureHeight); + instance.getTranslucentShader().bind(); + Matrix4f projection = RenderingState.INSTANCE.getProjectionMatrix(); + GLStateManager.disableCull(); + + instance.getTranslucentShader().fillUniformData( + new Matrix4f().setPerspective(projection.perspectiveFov(), projection.m11() / projection.m00(), event.value.nearClipPlane, event.value.farClipPlane), + RenderingState.INSTANCE.getModelViewMatrix(), + WORLD_MIN_Y, + partialTicks); + + instance.getTranslucentFB().bind(); + } + + atTranslucent = true; + } + + } + }; + + DhApi.events.bind(DhApiBeforeRenderPassEvent.class, beforeCleanupEvent); + } + + private static void setupBeforeApplyShaderEvent() { + DhApiBeforeApplyShaderRenderEvent beforeApplyShaderEvent = new DhApiBeforeApplyShaderRenderEvent() { + @Override + public void beforeRender(DhApiCancelableEventParam event) { + if (IrisApi.getInstance().isShaderPackInUse()) { + DHCompatInternal instance = getInstance(); + + OverrideInjector.INSTANCE.unbind(IDhApiShadowCullingFrustum.class, (IDhApiOverrideable) ShadowRenderer.FRUSTUM); + OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getShadowFBWrapper()); + OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getSolidFBWrapper()); + + event.cancelEvent(); + } + } + }; + + DhApi.events.bind(DhApiBeforeApplyShaderRenderEvent.class, beforeApplyShaderEvent); + } + + +} diff --git a/src/main/java/net/coderbot/iris/config/IrisConfig.java b/src/main/java/net/coderbot/iris/config/IrisConfig.java index 86b2c8b26..47a1de440 100644 --- a/src/main/java/net/coderbot/iris/config/IrisConfig.java +++ b/src/main/java/net/coderbot/iris/config/IrisConfig.java @@ -33,12 +33,18 @@ public class IrisConfig { */ private boolean disableUpdateMessage; + /** + * If debug features should be enabled. Gives much more detailed OpenGL error outputs at the cost of performance. + */ + private boolean enableDebugOptions; + private final Path propertiesPath; public IrisConfig(Path propertiesPath) { shaderPackName = null; enableShaders = true; disableUpdateMessage = false; + enableDebugOptions = false; this.propertiesPath = propertiesPath; } @@ -103,6 +109,10 @@ public class IrisConfig { this.enableShaders = enabled; } + public boolean areDebugOptionsEnabled() { + return enableDebugOptions; + } + /** * loads the config file and then populates the string, int, and boolean entries with the parsed entries * @@ -121,6 +131,7 @@ public class IrisConfig { } shaderPackName = properties.getProperty("shaderPack"); enableShaders = !"false".equals(properties.getProperty("enableShaders")); + enableDebugOptions = "true".equals(properties.getProperty("enableDebugOptions")); disableUpdateMessage = "true".equals(properties.getProperty("disableUpdateMessage")); // TODO: GUI try { @@ -147,6 +158,7 @@ public class IrisConfig { final Properties properties = new Properties(); properties.setProperty("shaderPack", getShaderPackName().orElse("")); properties.setProperty("enableShaders", enableShaders ? "true" : "false"); + properties.setProperty("enableDebugOptions", enableDebugOptions ? "true" : "false"); properties.setProperty("disableUpdateMessage", disableUpdateMessage ? "true" : "false"); properties.setProperty("maxShadowRenderDistance", String.valueOf(IrisVideoSettings.shadowDistance)); // NB: This uses ISO-8859-1 with unicode escapes as the encoding diff --git a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java index 706a6ff46..c4f272e69 100644 --- a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java +++ b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java @@ -45,6 +45,12 @@ public class GlFramebuffer extends GlResource { this.hasDepthAttachment = true; } + public void addDepthAttachmentBypass(int texture) { + final int fb = getGlId(); + RenderSystem.framebufferTexture2D(fb, GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, texture, 0); + this.hasDepthAttachment = true; + } + public void addColorAttachment(int index, int texture) { final int fb = getGlId(); diff --git a/src/main/java/net/coderbot/iris/gl/shader/StandardMacros.java b/src/main/java/net/coderbot/iris/gl/shader/StandardMacros.java index 23c69dc54..caaa98d17 100644 --- a/src/main/java/net/coderbot/iris/gl/shader/StandardMacros.java +++ b/src/main/java/net/coderbot/iris/gl/shader/StandardMacros.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList; import com.gtnewhorizons.angelica.Tags; import com.gtnewhorizons.angelica.config.AngelicaConfig; import cpw.mods.fml.common.Loader; +import net.coderbot.iris.compat.dh.DHCompat; import net.coderbot.iris.parsing.BiomeCategories; import net.coderbot.iris.pipeline.HandRenderer; import net.coderbot.iris.pipeline.WorldRenderingPhase; @@ -77,10 +78,32 @@ public class StandardMacros { define(standardDefines, "MC_SPECULAR_MAP"); define(standardDefines, "MC_RENDER_QUALITY", "1.0"); define(standardDefines, "MC_SHADOW_QUALITY", "1.0"); - define(standardDefines, "IS_ANGELICA"); - if (AngelicaConfig.defineIsIris) { - define(standardDefines, "IS_IRIS"); - } + define(standardDefines, "IS_ANGELICA"); + if (AngelicaConfig.defineIsIris) { + define(standardDefines, "IS_IRIS"); + } + + if (DHCompat.hasRenderingEnabled()) { + define(standardDefines, "DISTANT_HORIZONS"); + } + + define(standardDefines, "DH_BLOCK_UNKNOWN", String.valueOf(0)); + define(standardDefines, "DH_BLOCK_LEAVES", String.valueOf(1)); + define(standardDefines, "DH_BLOCK_STONE", String.valueOf(2)); + define(standardDefines, "DH_BLOCK_WOOD", String.valueOf(3)); + define(standardDefines, "DH_BLOCK_METAL", String.valueOf(4)); + define(standardDefines, "DH_BLOCK_DIRT", String.valueOf(5)); + define(standardDefines, "DH_BLOCK_LAVA", String.valueOf(6)); + define(standardDefines, "DH_BLOCK_DEEPSLATE", String.valueOf(7)); + define(standardDefines, "DH_BLOCK_SNOW", String.valueOf(8)); + define(standardDefines, "DH_BLOCK_SAND", String.valueOf(9)); + define(standardDefines, "DH_BLOCK_TERRACOTTA", String.valueOf(10)); + define(standardDefines, "DH_BLOCK_NETHER_STONE", String.valueOf(11)); + define(standardDefines, "DH_BLOCK_WATER", String.valueOf(12)); + define(standardDefines, "DH_BLOCK_GRASS", String.valueOf(13)); + define(standardDefines, "DH_BLOCK_AIR", String.valueOf(14)); + define(standardDefines, "DH_BLOCK_ILLUMINATED", String.valueOf(15)); + define(standardDefines, "ANGELICA_VERSION", makeAngelicaVersion()); define(standardDefines, "MC_HAND_DEPTH", Float.toString(HandRenderer.DEPTH)); diff --git a/src/main/java/net/coderbot/iris/gl/uniform/DynamicLocationalUniformHolder.java b/src/main/java/net/coderbot/iris/gl/uniform/DynamicLocationalUniformHolder.java index e96058edc..6de2d5e05 100644 --- a/src/main/java/net/coderbot/iris/gl/uniform/DynamicLocationalUniformHolder.java +++ b/src/main/java/net/coderbot/iris/gl/uniform/DynamicLocationalUniformHolder.java @@ -3,6 +3,7 @@ package net.coderbot.iris.gl.uniform; import net.coderbot.iris.gl.state.ValueUpdateNotifier; import org.joml.Vector2i; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.joml.Vector4f; import org.joml.Vector4i; @@ -43,7 +44,7 @@ public interface DynamicLocationalUniformHolder extends LocationalUniformHolder, return this; } - default DynamicUniformHolder uniform3i(String name, Supplier value, ValueUpdateNotifier notifier) { + default DynamicUniformHolder uniform3i(String name, Supplier value, ValueUpdateNotifier notifier) { location(name, UniformType.VEC3I).ifPresent(id -> addDynamicUniform(new Vector3IntegerJomlUniform(id, value, notifier), notifier)); return this; diff --git a/src/main/java/net/coderbot/iris/gl/uniform/DynamicUniformHolder.java b/src/main/java/net/coderbot/iris/gl/uniform/DynamicUniformHolder.java index c130bd9d0..c02c952cd 100644 --- a/src/main/java/net/coderbot/iris/gl/uniform/DynamicUniformHolder.java +++ b/src/main/java/net/coderbot/iris/gl/uniform/DynamicUniformHolder.java @@ -3,6 +3,7 @@ package net.coderbot.iris.gl.uniform; import net.coderbot.iris.gl.state.ValueUpdateNotifier; import org.joml.Vector2i; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.joml.Vector4f; import org.joml.Vector4i; @@ -16,7 +17,7 @@ public interface DynamicUniformHolder extends UniformHolder { DynamicUniformHolder uniform1f(String name, DoubleSupplier value, ValueUpdateNotifier notifier); DynamicUniformHolder uniform1i(String name, IntSupplier value, ValueUpdateNotifier notifier); DynamicUniformHolder uniform2i(String name, Supplier value, ValueUpdateNotifier notifier); - DynamicUniformHolder uniform3i(String name, Supplier value, ValueUpdateNotifier notifier); + DynamicUniformHolder uniform3i(String name, Supplier value, ValueUpdateNotifier notifier); DynamicUniformHolder uniform4f(String name, Supplier value, ValueUpdateNotifier notifier); DynamicUniformHolder uniform4fArray(String name, Supplier value, ValueUpdateNotifier notifier); DynamicUniformHolder uniform4i(String name, Supplier value, ValueUpdateNotifier notifier); diff --git a/src/main/java/net/coderbot/iris/gl/uniform/LocationalUniformHolder.java b/src/main/java/net/coderbot/iris/gl/uniform/LocationalUniformHolder.java index bf2046c52..ae5997b70 100644 --- a/src/main/java/net/coderbot/iris/gl/uniform/LocationalUniformHolder.java +++ b/src/main/java/net/coderbot/iris/gl/uniform/LocationalUniformHolder.java @@ -2,11 +2,14 @@ package net.coderbot.iris.gl.uniform; import net.minecraft.util.Vec3; import org.joml.Matrix4f; +import org.joml.Matrix4fc; import org.joml.Vector2f; import org.joml.Vector2i; import org.joml.Vector3d; import org.joml.Vector3f; +import org.joml.Vector3fc; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.joml.Vector4f; import java.util.OptionalInt; @@ -70,14 +73,14 @@ public interface LocationalUniformHolder extends UniformHolder { } @Override - default LocationalUniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + default LocationalUniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier value) { location(name, UniformType.VEC3).ifPresent(id -> addUniform(updateFrequency, new Vector3Uniform(id, value))); return this; } @Override - default LocationalUniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + default LocationalUniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier value) { location(name, UniformType.VEC3I).ifPresent(id -> addUniform(updateFrequency, new Vector3IntegerJomlUniform(id, value))); return this; @@ -119,7 +122,7 @@ public interface LocationalUniformHolder extends UniformHolder { } @Override - default LocationalUniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + default LocationalUniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier value) { location(name, UniformType.MAT4).ifPresent(id -> addUniform(updateFrequency, new MatrixUniform(id, value))); return this; diff --git a/src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java b/src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java index 237843f68..541a5db5c 100644 --- a/src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java +++ b/src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java @@ -2,6 +2,7 @@ package net.coderbot.iris.gl.uniform; import com.gtnewhorizons.angelica.glsm.RenderSystem; import org.joml.Matrix4f; +import org.joml.Matrix4fc; import org.lwjgl.BufferUtils; import java.nio.FloatBuffer; @@ -10,9 +11,9 @@ import java.util.function.Supplier; public class MatrixUniform extends Uniform { private final FloatBuffer buffer = BufferUtils.createFloatBuffer(16); private Matrix4f cachedValue; - private final Supplier value; + private final Supplier value; - MatrixUniform(int location, Supplier value) { + MatrixUniform(int location, Supplier value) { super(location); this.cachedValue = null; @@ -21,7 +22,7 @@ public class MatrixUniform extends Uniform { @Override public void update() { - final Matrix4f newValue = value.get(); + final Matrix4fc newValue = value.get(); if( newValue == null ){ throw new RuntimeException("MatrixUniform value is null"); } diff --git a/src/main/java/net/coderbot/iris/gl/uniform/UniformHolder.java b/src/main/java/net/coderbot/iris/gl/uniform/UniformHolder.java index de6891d69..9fa8101f7 100644 --- a/src/main/java/net/coderbot/iris/gl/uniform/UniformHolder.java +++ b/src/main/java/net/coderbot/iris/gl/uniform/UniformHolder.java @@ -1,12 +1,13 @@ package net.coderbot.iris.gl.uniform; import net.minecraft.util.Vec3; -import org.joml.Matrix4f; +import org.joml.Matrix4fc; import org.joml.Vector2f; import org.joml.Vector2i; import org.joml.Vector3d; -import org.joml.Vector3f; +import org.joml.Vector3fc; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.joml.Vector4f; import java.util.function.BooleanSupplier; @@ -29,9 +30,9 @@ public interface UniformHolder { UniformHolder uniform2i(UniformUpdateFrequency updateFrequency, String name, Supplier value); - UniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier value); + UniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier value); - UniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier value); + UniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier value); UniformHolder uniformVanilla3f(UniformUpdateFrequency updateFrequency, String name, Supplier value); @@ -43,7 +44,7 @@ public interface UniformHolder { UniformHolder uniform4fArray(UniformUpdateFrequency updateFrequency, String name, Supplier value); - UniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier value); + UniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier value); UniformHolder uniformMatrixFromArray(UniformUpdateFrequency updateFrequency, String name, Supplier value); diff --git a/src/main/java/net/coderbot/iris/gl/uniform/Vector3IntegerJomlUniform.java b/src/main/java/net/coderbot/iris/gl/uniform/Vector3IntegerJomlUniform.java index 2ab719d83..30437adfb 100644 --- a/src/main/java/net/coderbot/iris/gl/uniform/Vector3IntegerJomlUniform.java +++ b/src/main/java/net/coderbot/iris/gl/uniform/Vector3IntegerJomlUniform.java @@ -3,21 +3,22 @@ package net.coderbot.iris.gl.uniform; import com.gtnewhorizons.angelica.glsm.RenderSystem; import net.coderbot.iris.gl.state.ValueUpdateNotifier; import org.joml.Vector3i; +import org.joml.Vector3ic; import java.util.function.Supplier; public class Vector3IntegerJomlUniform extends Uniform { - private Vector3i cachedValue; - private final Supplier value; + private final Vector3i cachedValue; + private final Supplier value; - Vector3IntegerJomlUniform(int location, Supplier value) { + Vector3IntegerJomlUniform(int location, Supplier value) { this(location, value, null); } - Vector3IntegerJomlUniform(int location, Supplier value, ValueUpdateNotifier notifier) { + Vector3IntegerJomlUniform(int location, Supplier value, ValueUpdateNotifier notifier) { super(location, notifier); - this.cachedValue = null; + this.cachedValue = new Vector3i(); this.value = value; } @@ -31,11 +32,11 @@ public class Vector3IntegerJomlUniform extends Uniform { } private void updateValue() { - Vector3i newValue = value.get(); + Vector3ic newValue = value.get(); - if (cachedValue == null || !newValue.equals(cachedValue)) { - cachedValue = newValue; - RenderSystem.uniform3i(this.location, newValue.x, newValue.y, newValue.z); + if (!newValue.equals(cachedValue)) { + cachedValue.set(newValue.x(), newValue.y(), newValue.z()); + RenderSystem.uniform3i(this.location, cachedValue.x(), cachedValue.y(), cachedValue.z()); } } } diff --git a/src/main/java/net/coderbot/iris/gl/uniform/Vector3Uniform.java b/src/main/java/net/coderbot/iris/gl/uniform/Vector3Uniform.java index 48ceadea7..790348bd8 100644 --- a/src/main/java/net/coderbot/iris/gl/uniform/Vector3Uniform.java +++ b/src/main/java/net/coderbot/iris/gl/uniform/Vector3Uniform.java @@ -3,15 +3,16 @@ package net.coderbot.iris.gl.uniform; import com.gtnewhorizons.angelica.glsm.RenderSystem; import org.joml.Vector3d; import org.joml.Vector3f; +import org.joml.Vector3fc; import org.joml.Vector4f; import java.util.function.Supplier; public class Vector3Uniform extends Uniform { private final Vector3f cachedValue; - private final Supplier value; + private final Supplier value; - Vector3Uniform(int location, Supplier value) { + Vector3Uniform(int location, Supplier value) { super(location); this.cachedValue = new Vector3f(); @@ -44,7 +45,7 @@ public class Vector3Uniform extends Uniform { @Override public void update() { - Vector3f newValue = value.get(); + Vector3fc newValue = value.get(); if (!newValue.equals(cachedValue)) { cachedValue.set(newValue.x(), newValue.y(), newValue.z()); diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 9ad878a5d..8c9107f09 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -29,12 +29,14 @@ import net.coderbot.iris.gl.buffer.ShaderStorageBufferHolder; import net.coderbot.iris.gl.buffer.ShaderStorageInfo; import net.coderbot.iris.gl.framebuffer.GlFramebuffer; import net.coderbot.iris.gl.image.GlImage; +import net.coderbot.iris.gl.image.ImageHolder; import net.coderbot.iris.gl.image.ImageInformation; import net.coderbot.iris.gl.program.ComputeProgram; import net.coderbot.iris.gl.program.Program; import net.coderbot.iris.gl.program.ProgramBuilder; import net.coderbot.iris.gl.program.ProgramImages; import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.sampler.SamplerHolder; import net.coderbot.iris.gl.state.FogMode; import net.coderbot.iris.gl.texture.DepthBufferFormat; import net.coderbot.iris.gl.texture.TextureType; @@ -177,6 +179,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R private final boolean oldLighting; private final boolean allowConcurrentCompute; private final OptionalInt forcedShadowRenderDistanceChunks; + private final CloudSetting dhCloudSetting; private Pass current = null; @@ -192,6 +195,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R private int currentSpecularTexture; private PackDirectives packDirectives; private final Set activeFeatures; + private final ProgramFallbackResolver resolver; public DeferredWorldRenderingPipeline(ProgramSet programs) { Objects.requireNonNull(programs); @@ -206,7 +210,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R .map(DeferredWorldRenderingPipeline::submitCompositeTransform) .orElse(null); - final ProgramFallbackResolver resolver = new ProgramFallbackResolver(programs); + resolver = new ProgramFallbackResolver(programs); final Map, CompletableFuture>> attributeTransformFutures = submitAttributeTransforms(resolver); final Optional terrainSource = first(programs.getGbuffersTerrain(), programs.getGbuffersTexturedLit(), programs.getGbuffersTextured(), programs.getGbuffersBasic()); @@ -228,6 +232,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R this.shouldRenderWeather = programs.getPackDirectives().shouldRenderWeather(); this.shouldRenderWeatherParticles = programs.getPackDirectives().shouldRenderWeatherParticles(); this.shouldWriteRainAndSnowToDepthBuffer = programs.getPackDirectives().rainDepth(); + this.dhCloudSetting = programs.getPackDirectives().getDHCloudSetting(); this.shouldRenderParticlesBeforeDeferred = programs.getPackDirectives().getParticleRenderingSettings() .map(s -> s == net.coderbot.iris.shaderpack.ParticleRenderingSettings.BEFORE || s == net.coderbot.iris.shaderpack.ParticleRenderingSettings.MIXED) .orElse(false); @@ -587,7 +592,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R renderTargets, flippedAfterPrepare, flippedAfterTranslucent, celeritasShadowFb); - this.dhCompat = new DHCompat(); + this.dhCompat = new DHCompat(this, shadowDirectives.isDhShadowEnabled().orElse(true)); } private RenderTargets getRenderTargets() { @@ -916,6 +921,38 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R return pass; } + public void addGbufferOrShadowSamplers(SamplerHolder samplers, ImageHolder images, Supplier> flipped, + boolean isShadowPass, boolean hasTexture, boolean hasLightmap, boolean hasOverlay) { + TextureStage textureStage = TextureStage.GBUFFERS_AND_SHADOW; + + ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = + ProgramSamplers.customTextureSamplerInterceptor(samplers, customTextureManager.getCustomTextureIdMap(textureStage)); + + IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false, this); + IrisImages.addRenderTargetImages(images, flipped, renderTargets); + + if (!shouldBindPBR) { + shouldBindPBR = IrisSamplers.hasPBRSamplers(customTextureSamplerInterceptor); + } + + IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(hasTexture, hasLightmap)); + if (!isShadowPass) { + IrisSamplers.addWorldDepthSamplers(customTextureSamplerInterceptor, renderTargets); + } + IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture()); + IrisSamplers.addCustomImages(customTextureSamplerInterceptor, customImages); + IrisSamplers.addCustomTextures(customTextureSamplerInterceptor, customTextureManager.getIrisCustomTextures()); + IrisImages.addCustomImages(images, customImages); + + if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { + IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get(), null, true); + } + + if (isShadowPass || IrisImages.hasShadowImages(images)) { + IrisImages.addShadowColorImages(images, shadowTargetsSupplier.get(), null); + } + } + private boolean isPostChain; private boolean isMainBound = true; @@ -947,6 +984,56 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R } } + public CloudSetting getDHCloudSetting() { + return dhCloudSetting; + } + + public Optional getDHTerrainShader() { + return resolver.resolve(ProgramId.DhTerrain); + } + + public Optional getDHGenericShader() { + return resolver.resolve(ProgramId.DhGeneric); + } + + public Optional getDHWaterShader() { + return resolver.resolve(ProgramId.DhWater); + } + + public Optional getDHShadowShader() { + return resolver.resolve(ProgramId.DhShadow); + } + + public CustomUniforms getCustomUniforms() { + return customUniforms; + } + + public GlFramebuffer createDHFramebuffer(ProgramSource sources, boolean trans) { + return renderTargets.createDHFramebuffer(trans ? flippedAfterTranslucent : flippedAfterPrepare, + sources.getDirectives().getDrawBuffers()); + } + + public ImmutableSet getFlippedBeforeShadow() { + return flippedBeforeShadow; + } + + public ImmutableSet getFlippedAfterPrepare() { + return flippedAfterPrepare; + } + + public ImmutableSet getFlippedAfterTranslucent() { + return flippedAfterTranslucent; + } + + public GlFramebuffer createDHFramebufferShadow(ProgramSource sources) { + + return shadowRenderTargets.createDHFramebuffer(ImmutableSet.of(), new int[]{0, 1}); + } + + public boolean hasShadowRenderTargets() { + return shadowRenderTargets != null; + } + private final class Pass { @Nullable private final Program program; @@ -1094,6 +1181,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R // While it's possible to just clear them instead and reuse them, we'd need to investigate whether or not this // would help performance. renderTargets.destroy(); + dhCompat.clearPipeline(); // destroy the shadow render targets if (shadowRenderTargets != null) { diff --git a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java index 5f255e898..4fbeaf67d 100644 --- a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java @@ -130,7 +130,7 @@ public class FixedFunctionWorldRenderingPipeline implements WorldRenderingPipeli return new FrameUpdateNotifier(); } - private static final DHCompat DH_COMPAT = new DHCompat(); + private static final DHCompat DH_COMPAT = new DHCompat(null, false); @Override public DHCompat getDHCompat() { diff --git a/src/main/java/net/coderbot/iris/pipeline/PatchedShaderPrinter.java b/src/main/java/net/coderbot/iris/pipeline/PatchedShaderPrinter.java index c6c8ffc1f..44c8d0886 100644 --- a/src/main/java/net/coderbot/iris/pipeline/PatchedShaderPrinter.java +++ b/src/main/java/net/coderbot/iris/pipeline/PatchedShaderPrinter.java @@ -39,6 +39,9 @@ public class PatchedShaderPrinter { } public static void debugPatchedShaders(String name, String vertex, String geometry, String tessControl, String tessEval, String fragment, String compute) { + if (!Iris.getIrisConfig().areDebugOptionsEnabled()) { + return; + } if (prettyPrintShaders) { final Path debugOutDir = Minecraft.getMinecraft().mcDataDir.toPath().resolve("patched_shaders"); if (!outputLocationCleared) { diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 39bff8b85..855614a8f 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -10,6 +10,7 @@ import com.gtnewhorizons.angelica.glsm.RenderSystem; import com.gtnewhorizons.angelica.rendering.RenderingState; import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasWorldRenderer; import net.coderbot.iris.Iris; +import net.coderbot.iris.compat.dh.DHCompat; import net.coderbot.iris.gui.option.IrisVideoSettings; import net.coderbot.iris.layer.GbufferPrograms; import net.coderbot.iris.shaderpack.PackDirectives; @@ -43,6 +44,7 @@ import net.minecraft.profiler.Profiler; import net.minecraft.tileentity.TileEntity; import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider; import org.joml.Matrix4f; +import org.joml.Matrix4fc; import org.joml.Vector3d; import org.joml.Vector3f; import org.joml.Vector4f; @@ -68,6 +70,8 @@ public class ShadowRenderer { public static final List globalTileEntities = new ArrayList<>(); public static boolean ACTIVE = false; + public static Frustrum FRUSTUM; + private static final Comparator ENTITY_CLASS_COMPARATOR = Comparator.comparingInt(a -> System.identityHashCode(a.getClass())); private static final NonCullingFrustum NON_CULLING_FRUSTUM = new NonCullingFrustum(); private static final CullEverythingFrustum CULL_EVERYTHING_FRUSTUM = new CullEverythingFrustum(); @@ -111,12 +115,16 @@ public class ShadowRenderer { private double lastBoxCullerDistance = -1; private double lastAdvancedBoxCullerDistance = -1; private double lastTileEntityCullerDistance = -1; + private final boolean shouldRenderDH; + private final float nearPlane, farPlane; public ShadowRenderer(ProgramSource shadow, PackDirectives directives, ShadowRenderTargets shadowRenderTargets, ShadowCompositeRenderer compositeRenderer) { this.profiler = Minecraft.getMinecraft().mcProfiler; final PackShadowDirectives shadowDirectives = directives.getShadowDirectives(); + this.nearPlane = shadowDirectives.getNearPlane(); + this.farPlane = shadowDirectives.getFarPlane(); this.halfPlaneLength = shadowDirectives.getDistance(); this.voxelDistance = shadowDirectives.getVoxelDistance(); @@ -129,6 +137,7 @@ public class ShadowRenderer { this.shouldRenderEntities = shadowDirectives.shouldRenderEntities(); this.shouldRenderPlayer = shadowDirectives.shouldRenderPlayer(); this.shouldRenderBlockEntities = shadowDirectives.shouldRenderBlockEntities(); + this.shouldRenderDH = shadowDirectives.isDhShadowEnabled().orElse(false); this.compositeRenderer = compositeRenderer; @@ -348,14 +357,16 @@ public class ShadowRenderer { shadowLightVectorCache.set(shadowLightPosition.x(), shadowLightPosition.y(), shadowLightPosition.z()); shadowLightVectorCache.normalize(); + Matrix4fc projView = ((shouldRenderDH && DHCompat.hasRenderingEnabled()) ? DHCompat.getProjection() : RenderingState.INSTANCE.getProjectionMatrix()); + if (hasSafeZone) { BoxCuller distanceCuller = new BoxCuller(halfPlaneLength * renderMultiplier); SafeZoneCullingFrustum safeZoneFrustum = new SafeZoneCullingFrustum( - RenderingState.INSTANCE.getModelViewMatrix(), RenderingState.INSTANCE.getProjectionMatrix(), + RenderingState.INSTANCE.getModelViewMatrix(), projView, shadowLightVectorCache, boxCuller, distanceCuller); return holder.setInfo(safeZoneFrustum, distanceInfo, cullingInfo); } else { - cachedAdvancedFrustum.init(RenderingState.INSTANCE.getModelViewMatrix(), RenderingState.INSTANCE.getProjectionMatrix(), shadowLightVectorCache, boxCuller); + cachedAdvancedFrustum.init(RenderingState.INSTANCE.getModelViewMatrix(), projView, shadowLightVectorCache, boxCuller); return holder.setInfo(cachedAdvancedFrustum, distanceInfo, cullingInfo); } } @@ -630,12 +641,12 @@ public class ShadowRenderer { final MatrixStack modelView = getShadowModelView(); MODELVIEW.set(modelView.peek().getModel()); - final Matrix4f shadowProjection; + final Matrix4f shadowProjection; if (this.fov != null) { // If FOV is not null, the pack wants a perspective based projection matrix. (This is to support legacy packs) - shadowProjection = ShadowMatrices.createPerspectiveMatrix(this.fov); + shadowProjection = ShadowMatrices.createPerspectiveMatrix(this.fov); } else { - shadowProjection = ShadowMatrices.createOrthoMatrix(halfPlaneLength); + shadowProjection = ShadowMatrices.createOrthoMatrix(halfPlaneLength, nearPlane < 0 ? -DHCompat.getRenderDistance() : nearPlane, farPlane < 0 ? DHCompat.getRenderDistance() : farPlane); } PROJECTION.set(shadowProjection); @@ -649,6 +660,7 @@ public class ShadowRenderer { profiler.startSection("initialize frustum"); terrainFrustumHolder = createShadowFrustum(renderDistanceMultiplier, terrainFrustumHolder); + FRUSTUM = terrainFrustumHolder.getFrustum(); // Use the player/entity position for shadow rendering final Vector3d entityPos = playerCamera.getEntityPos(); diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/DHGenericTransformer.java b/src/main/java/net/coderbot/iris/pipeline/transform/DHGenericTransformer.java new file mode 100644 index 000000000..024f711d2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/DHGenericTransformer.java @@ -0,0 +1,114 @@ +package net.coderbot.iris.pipeline.transform; + +import net.coderbot.iris.gl.shader.ShaderType; +import net.coderbot.iris.pipeline.transform.parameter.Parameters; +import org.taumc.glsl.Transformer; + +public class DHGenericTransformer { + public static void transform(Transformer transformer, Parameters parameters, int glslVersion) { + CommonTransformer.transform(transformer, parameters, true, glslVersion); + + transformer.replaceExpression("gl_TextureMatrix[0]", "mat4(1.0)"); + transformer.replaceExpression("gl_TextureMatrix[1]", "mat4(1.0)"); + transformer.rename("gl_ProjectionMatrix", "iris_ProjectionMatrix"); + + if (parameters.type == ShaderType.VERTEX) { + // Alias of gl_MultiTexCoord1 on 1.15+ for OptiFine + // See https://github.com/IrisShaders/Iris/issues/1149 + transformer.rename("gl_MultiTexCoord2", "gl_MultiTexCoord1"); + + transformer.replaceExpression("gl_MultiTexCoord0", "vec4(0.0, 0.0, 0.0, 1.0)"); + transformer.replaceExpression("gl_MultiTexCoord1", "vec4(_vert_tex_light_coord, 0.0, 1.0)"); + + replaceGlMultiTexCoordBounded(transformer, 4, 7); + } + + transformer.rename("gl_Color", "_vert_color"); + + if (parameters.type == ShaderType.VERTEX) { + transformer.replaceExpression("gl_Normal", "_vert_normal"); + } + + transformer.replaceExpression("gl_NormalMatrix", "iris_NormalMatrix"); + addIfNotExists(transformer, "iris_NormalMatrix", "uniform mat3 iris_NormalMatrix;"); + addIfNotExists(transformer, "iris_ModelViewMatrixInverse", "uniform mat4 iris_ModelViewMatrixInverse;"); + addIfNotExists(transformer, "iris_ProjectionMatrixInverse", "uniform mat4 iris_ProjectionMatrixInverse;"); + + transformer.rename("gl_ModelViewMatrix", "iris_ModelViewMatrix"); + transformer.rename("gl_ModelViewMatrixInverse", "iris_ModelViewMatrixInverse"); + transformer.rename("gl_ProjectionMatrixInverse", "iris_ProjectionMatrixInverse"); + + if (parameters.type == ShaderType.VERTEX) { + if (transformer.containsCall("ftransform")) { + transformer.injectFunction("vec4 ftransform() { return gl_ModelViewProjectionMatrix * gl_Vertex; }"); + } + + addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;"); + addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;"); + transformer.injectFunction("vec4 getVertexPosition() { return vec4(_vert_position, 1.0); }"); + transformer.replaceExpression("gl_Vertex", "getVertexPosition()"); + + injectVertInit(transformer); + } else { + addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;"); + addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;"); + } + + transformer.replaceExpression("gl_ModelViewProjectionMatrix", "(iris_ProjectionMatrix * iris_ModelViewMatrix)"); + ShaderTransformer.applyIntelHd4000Workaround(transformer); + } + + public static void injectVertInit(Transformer transformer) { + addIfNotExists(transformer, "_vert_position", "vec3 _vert_position;"); + addIfNotExists(transformer, "_vert_tex_light_coord", "vec2 _vert_tex_light_coord;"); + addIfNotExists(transformer, "dhMaterialId", "int dhMaterialId;"); + addIfNotExists(transformer, "_vert_color", "vec4 _vert_color;"); + addIfNotExists(transformer, "_vert_normal", "vec3 _vert_normal;"); + addIfNotExists(transformer, "uOffsetChunk", "uniform ivec3 uOffsetChunk;"); + addIfNotExists(transformer, "uOffsetSubChunk", "uniform vec3 uOffsetSubChunk;"); + addIfNotExists(transformer, "uCameraPosChunk", "uniform ivec3 uCameraPosChunk;"); + addIfNotExists(transformer, "uCameraPosSubChunk", "uniform vec3 uCameraPosSubChunk;"); + addIfNotExists(transformer, "uSkyLight", "uniform int uSkyLight;"); + addIfNotExists(transformer, "uBlockLight", "uniform int uBlockLight;"); + addIfNotExists(transformer, "iris_color", "in vec4 iris_color;"); + addIfNotExists(transformer, "aScale", "in vec3 aScale;"); + addIfNotExists(transformer, "aTranslateChunk", "in ivec3 aTranslateChunk;"); + addIfNotExists(transformer, "aTranslateSubChunk", "in vec3 aTranslateSubChunk;"); + addIfNotExists(transformer, "aMaterial", "in int aMaterial;"); + addIfNotExists(transformer, "vPosition", "in vec3 vPosition;"); + + transformer.injectFunction("const vec3 irisNormals[6] = vec3[](vec3(0,0,-1), vec3(0,0,1), vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0));"); + transformer.injectFunction( + "void _vert_init() {" + + " vec3 trans = vec3(aTranslateChunk + uOffsetChunk - uCameraPosChunk) * 16.0;" + + " trans += (aTranslateSubChunk + uOffsetSubChunk - uCameraPosSubChunk);" + + " mat4 transform = mat4(" + + " aScale.x, 0.0, 0.0, 0.0," + + " 0.0, aScale.y, 0.0, 0.0," + + " 0.0, 0.0, aScale.z, 0.0," + + " trans.x, trans.y, trans.z, 1.0" + + " );" + + " _vert_position = (transform * vec4(vPosition, 1.0)).xyz;" + + " _vert_normal = irisNormals[int(floor(float(gl_VertexID) / 4.0))];" + + " float blockLight = (float(uBlockLight) + 0.5) / 16.0;" + + " float skyLight = (float(uSkyLight) + 0.5) / 16.0;" + + " _vert_tex_light_coord = vec2(blockLight, skyLight);" + + " dhMaterialId = aMaterial;" + + " _vert_color = iris_color;" + + " }" + ); + transformer.prependMain("_vert_init();"); + } + + private static void addIfNotExists(Transformer transformer, String name, String code) { + if (!transformer.hasVariable(name)) { + transformer.injectVariable(code); + } + } + + private static void replaceGlMultiTexCoordBounded(Transformer transformer, int from, int to) { + for (int i = from; i <= to; i++) { + transformer.replaceExpression("gl_MultiTexCoord" + i, "vec4(0.0, 0.0, 0.0, 1.0)"); + } + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/DHTerrainTransformer.java b/src/main/java/net/coderbot/iris/pipeline/transform/DHTerrainTransformer.java new file mode 100644 index 000000000..0f9ae6f93 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/DHTerrainTransformer.java @@ -0,0 +1,106 @@ +package net.coderbot.iris.pipeline.transform; + +import net.coderbot.iris.gl.shader.ShaderType; +import net.coderbot.iris.pipeline.transform.parameter.Parameters; +import org.taumc.glsl.Transformer; + +public class DHTerrainTransformer { + public static void transform(Transformer transformer, Parameters parameters, int glslVersion) { + CommonTransformer.transform(transformer, parameters, true, glslVersion); + + transformer.replaceExpression("gl_TextureMatrix[0]", "mat4(1.0)"); + transformer.replaceExpression("gl_TextureMatrix[1]", "mat4(1.0)"); + transformer.rename("gl_ProjectionMatrix", "iris_ProjectionMatrix"); + + if (parameters.type == ShaderType.VERTEX) { + // Alias of gl_MultiTexCoord1 on 1.15+ for OptiFine + // See https://github.com/IrisShaders/Iris/issues/1149 + transformer.rename("gl_MultiTexCoord2", "gl_MultiTexCoord1"); + + transformer.replaceExpression("gl_MultiTexCoord0", "vec4(0.0, 0.0, 0.0, 1.0)"); + transformer.replaceExpression("gl_MultiTexCoord1", "vec4(_vert_tex_light_coord, 0.0, 1.0)"); + + replaceGlMultiTexCoordBounded(transformer, 4, 7); + } + + transformer.rename("gl_Color", "_vert_color"); + + if (parameters.type == ShaderType.VERTEX) { + transformer.replaceExpression("gl_Normal", "_vert_normal"); + } + + transformer.replaceExpression("gl_NormalMatrix", "iris_NormalMatrix"); + addIfNotExists(transformer, "iris_NormalMatrix", "uniform mat3 iris_NormalMatrix;"); + addIfNotExists(transformer, "iris_ModelViewMatrixInverse", "uniform mat4 iris_ModelViewMatrixInverse;"); + addIfNotExists(transformer, "iris_ProjectionMatrixInverse", "uniform mat4 iris_ProjectionMatrixInverse;"); + + transformer.rename("gl_ModelViewMatrix", "iris_ModelViewMatrix"); + transformer.rename("gl_ModelViewMatrixInverse", "iris_ModelViewMatrixInverse"); + transformer.rename("gl_ProjectionMatrixInverse", "iris_ProjectionMatrixInverse"); + + if (parameters.type == ShaderType.VERTEX) { + if (transformer.containsCall("ftransform")) { + transformer.injectFunction("vec4 ftransform() { return gl_ModelViewProjectionMatrix * gl_Vertex; }"); + } + + addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;"); + addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;"); + transformer.injectFunction("vec4 getVertexPosition() { return vec4(modelOffset + _vert_position, 1.0); }"); + transformer.replaceExpression("gl_Vertex", "getVertexPosition()"); + + injectVertInit(transformer); + } else { + addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;"); + addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;"); + } + + transformer.replaceExpression("gl_ModelViewProjectionMatrix", "(iris_ProjectionMatrix * iris_ModelViewMatrix)"); + ShaderTransformer.applyIntelHd4000Workaround(transformer); + } + + public static void injectVertInit(Transformer transformer) { + addIfNotExists(transformer, "_vert_position", "vec3 _vert_position;"); + addIfNotExists(transformer, "_vert_tex_light_coord", "vec2 _vert_tex_light_coord;"); + addIfNotExists(transformer, "dhMaterialId", "int dhMaterialId;"); + addIfNotExists(transformer, "_vert_color", "vec4 _vert_color;"); + addIfNotExists(transformer, "_vert_normal", "vec3 _vert_normal;"); + addIfNotExists(transformer, "mircoOffset", "uniform float mircoOffset;"); + addIfNotExists(transformer, "modelOffset", "uniform vec3 modelOffset;"); + addIfNotExists(transformer, "iris_color", "in vec4 iris_color;"); + addIfNotExists(transformer, "vPosition", "in uvec4 vPosition;"); + addIfNotExists(transformer, "irisExtra", "in uvec4 irisExtra;"); + + transformer.injectFunction("const vec3 irisNormals[6] = vec3[](vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1), vec3(-1,0,0), vec3(1,0,0));"); + transformer.injectFunction( + "void _vert_init() {" + + " uint meta = vPosition.a;" + + " uint mirco = (meta & 0xFF00u) >> 8u;" + + " float mx = (mirco & 1u) != 0u ? mircoOffset : 0.0;" + + " mx = (mirco & 2u) != 0u ? -mx : mx;" + + " float my = (mirco & 4u) != 0u ? mircoOffset : 0.0;" + + " my = (mirco & 8u) != 0u ? -my : my;" + + " float mz = (mirco & 16u) != 0u ? mircoOffset : 0.0;" + + " mz = (mirco & 32u) != 0u ? -mz : mz;" + + " uint lights = meta & 0xFFu;" + + " _vert_position = (vPosition.xyz + vec3(mx, my, mz));" + + " _vert_normal = irisNormals[int(irisExtra.y)];" + + " dhMaterialId = int(irisExtra.x);" + + " _vert_tex_light_coord = vec2((float(lights / 16u) + 0.5) / 16.0, (mod(float(lights), 16.0) + 0.5) / 16.0);" + + " _vert_color = iris_color;" + + " }" + ); + transformer.prependMain("_vert_init();"); + } + + private static void addIfNotExists(Transformer transformer, String name, String code) { + if (!transformer.hasVariable(name)) { + transformer.injectVariable(code); + } + } + + private static void replaceGlMultiTexCoordBounded(Transformer transformer, int from, int to) { + for (int i = from; i <= to; i++) { + transformer.replaceExpression("gl_MultiTexCoord" + i, "vec4(0.0, 0.0, 0.0, 1.0)"); + } + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/Patch.java b/src/main/java/net/coderbot/iris/pipeline/transform/Patch.java index 5158dd7cd..7d0f450e8 100644 --- a/src/main/java/net/coderbot/iris/pipeline/transform/Patch.java +++ b/src/main/java/net/coderbot/iris/pipeline/transform/Patch.java @@ -4,5 +4,7 @@ public enum Patch { ATTRIBUTES, CELERITAS_TERRAIN, COMPOSITE, - COMPUTE + COMPUTE, + DH_TERRAIN, + DH_GENERIC } diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/ShaderTransformer.java b/src/main/java/net/coderbot/iris/pipeline/transform/ShaderTransformer.java index 97248c350..f2e8a32fc 100644 --- a/src/main/java/net/coderbot/iris/pipeline/transform/ShaderTransformer.java +++ b/src/main/java/net/coderbot/iris/pipeline/transform/ShaderTransformer.java @@ -439,6 +439,12 @@ public class ShaderTransformer { case COMPUTE: ComputeTransformer.transform(transformer, parameters, versionInt); break; + case DH_TERRAIN: + DHTerrainTransformer.transform(transformer, parameters, versionInt); + break; + case DH_GENERIC: + DHGenericTransformer.transform(transformer, parameters, versionInt); + break; default: throw new IllegalStateException("Unknown patch type: " + patchType.name()); } diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/TransformPatcher.java b/src/main/java/net/coderbot/iris/pipeline/transform/TransformPatcher.java index 5b8446c5f..8c45d378f 100644 --- a/src/main/java/net/coderbot/iris/pipeline/transform/TransformPatcher.java +++ b/src/main/java/net/coderbot/iris/pipeline/transform/TransformPatcher.java @@ -7,6 +7,7 @@ import net.coderbot.iris.helpers.Tri; import net.coderbot.iris.pipeline.transform.parameter.AttributeParameters; import net.coderbot.iris.pipeline.transform.parameter.CeleritasTerrainParameters; import net.coderbot.iris.pipeline.transform.parameter.ComputeParameters; +import net.coderbot.iris.pipeline.transform.parameter.DHParameters; import net.coderbot.iris.pipeline.transform.parameter.Parameters; import net.coderbot.iris.pipeline.transform.parameter.TextureStageParameters; import net.coderbot.iris.shaderpack.texture.TextureStage; @@ -127,6 +128,23 @@ public class TransformPatcher { return transform(vertex, geometry, tessControl, tessEval, fragment, new TextureStageParameters(Patch.COMPOSITE, stage, textureMap)); } + + public static Map patchDHTerrain( + String name, String vertex, String tessControl, String tessEval, String geometry, String fragment, + Object2ObjectMap, String> textureMap) { + return transform(vertex, geometry, tessControl, tessEval, fragment, + new DHParameters(Patch.DH_TERRAIN, textureMap)); + } + + + public static Map patchDHGeneric( + String name, String vertex, String tessControl, String tessEval, String geometry, String fragment, + Object2ObjectMap, String> textureMap) { + return transform(vertex, geometry, tessControl, tessEval, fragment, + new DHParameters(Patch.DH_GENERIC, textureMap)); + + } + public static Map patchComposite(String vertex, String geometry, String fragment, TextureStage stage, Object2ObjectMap, String> textureMap) { return patchComposite(vertex, geometry, null, null, fragment, stage, textureMap); } diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/parameter/DHParameters.java b/src/main/java/net/coderbot/iris/pipeline/transform/parameter/DHParameters.java new file mode 100644 index 000000000..1898357c5 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/parameter/DHParameters.java @@ -0,0 +1,18 @@ +package net.coderbot.iris.pipeline.transform.parameter; + +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import net.coderbot.iris.gl.texture.TextureType; +import net.coderbot.iris.helpers.Tri; +import net.coderbot.iris.pipeline.transform.Patch; +import net.coderbot.iris.shaderpack.texture.TextureStage; + +public class DHParameters extends Parameters { + public DHParameters(Patch patch, Object2ObjectMap, String> textureMap) { + super(patch, textureMap); + } + + @Override + public TextureStage getTextureStage() { + return TextureStage.GBUFFERS_AND_SHADOW; + } +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java index 3d9cc53d9..33f0beb07 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java @@ -248,6 +248,16 @@ public class RenderTargets { return framebuffer; } + public GlFramebuffer createDHFramebuffer(ImmutableSet stageWritesToAlt, int[] drawBuffers) { + if (drawBuffers.length == 0) { + return createEmptyFramebuffer(); + } + + ImmutableSet stageWritesToMain = invert(stageWritesToAlt, drawBuffers); + + return createColorFramebuffer(stageWritesToMain, drawBuffers); + } + public GlFramebuffer createGbufferFramebuffer(ImmutableSet stageWritesToAlt, int[] drawBuffers) { if (drawBuffers.length == 0) { return createEmptyFramebuffer(); diff --git a/src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java b/src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java index 763f27d93..d0fa8df5d 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java +++ b/src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java @@ -28,7 +28,7 @@ public class PackDirectives { @Getter private float eyeBrightnessHalfLife; @Getter private float centerDepthHalfLife; @Getter private CloudSetting cloudSetting; - @Getter private CloudSetting dhCloudSetting; + private CloudSetting dhCloudSetting; private boolean underwaterOverlay; private boolean vignette; private boolean sun; @@ -181,6 +181,10 @@ public class PackDirectives { return concurrentCompute; } + public CloudSetting getDHCloudSetting() { + return dhCloudSetting; + } + private static float clamp(float val, float lo, float hi) { return Math.max(lo, Math.min(hi, val)); } diff --git a/src/main/java/net/coderbot/iris/shaderpack/PackShadowDirectives.java b/src/main/java/net/coderbot/iris/shaderpack/PackShadowDirectives.java index 4d32029a3..55902a291 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/PackShadowDirectives.java +++ b/src/main/java/net/coderbot/iris/shaderpack/PackShadowDirectives.java @@ -30,6 +30,8 @@ public class PackShadowDirectives { private final boolean shouldRenderPlayer; private final boolean shouldRenderBlockEntities; @Getter private final ShadowCullState cullingState; + private final OptionalBoolean dhShadowEnabled; + private float nearPlane, farPlane; private final ImmutableList depthSamplingSettings; private final ImmutableList colorSamplingSettings; @@ -53,6 +55,8 @@ public class PackShadowDirectives { // shadowRenderDistanceMul to a nonzero value, since having a high shadow render distance will impact // performance quite heavily on most systems. this.distance = 160.0f; + this.nearPlane = 0.05f; + this.farPlane = 256.0f; this.voxelDistance = 0.0f; // By default, shadows are not culled based on distance from the player. However, pack authors may @@ -81,6 +85,7 @@ public class PackShadowDirectives { this.shouldRenderBlockEntities = properties.getShadowBlockEntities().orElse(true); this.cullingState = properties.getShadowCulling(); this.shadowEnabled = properties.getShadowEnabled(); + this.dhShadowEnabled = properties.getDhShadowEnabled(); this.depthSamplingSettings = ImmutableList.of(new DepthSamplingSettings(), new DepthSamplingSettings()); @@ -97,6 +102,8 @@ public class PackShadowDirectives { this.resolution = shadowDirectives.resolution; this.fov = shadowDirectives.fov; this.distance = shadowDirectives.distance; + this.nearPlane = shadowDirectives.nearPlane; + this.farPlane = shadowDirectives.farPlane; this.voxelDistance = shadowDirectives.voxelDistance; this.distanceRenderMul = shadowDirectives.distanceRenderMul; this.entityShadowDistanceMul = shadowDirectives.entityShadowDistanceMul; @@ -111,6 +118,7 @@ public class PackShadowDirectives { this.depthSamplingSettings = shadowDirectives.depthSamplingSettings; this.colorSamplingSettings = shadowDirectives.colorSamplingSettings; this.shadowEnabled = shadowDirectives.shadowEnabled; + this.dhShadowEnabled = shadowDirectives.dhShadowEnabled; } public int getResolution() { @@ -125,6 +133,18 @@ public class PackShadowDirectives { return distance; } + public float getNearPlane() { + return nearPlane; + } + + public float getFarPlane() { + return farPlane; + } + + public OptionalBoolean isDhShadowEnabled() { + return dhShadowEnabled; + } + public float getVoxelDistance() { return voxelDistance; } @@ -186,7 +206,8 @@ public class PackShadowDirectives { directives.acceptCommentFloatDirective("SHADOWHPL", distance -> this.distance = distance); directives.acceptConstFloatDirective("shadowDistance", distance -> this.distance = distance); - + directives.acceptConstFloatDirective("shadowNearPlane", nearPlane -> this.nearPlane = nearPlane); + directives.acceptConstFloatDirective("shadowFarPlane", farPlane -> this.farPlane = farPlane); directives.acceptConstFloatDirective("entityShadowDistanceMul", distance -> this.entityShadowDistanceMul = distance); directives.acceptConstFloatDirective("shadowDistanceRenderMul", distanceRenderMul -> { diff --git a/src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java b/src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java index 4a69a9b02..042e9f6a8 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java +++ b/src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java @@ -56,7 +56,10 @@ public class ProgramSet { private final ComputeSource[][] compositeCompute; private final ProgramSource compositeFinal; private final ComputeSource[] finalCompute; - + private final ProgramSource dhTerrain; + private final ProgramSource dhGeneric; + private final ProgramSource dhWater; + private final ProgramSource dhShadow; private final ShaderPack pack; @@ -119,6 +122,10 @@ public class ProgramSet { this.gbuffersBlock = readProgramSource(directory, sourceProvider, "gbuffers_block", this, shaderProperties); this.gbuffersBlockTrans = readProgramSource(directory, sourceProvider, "gbuffers_block_translucent", this, shaderProperties); this.gbuffersHand = readProgramSource(directory, sourceProvider, "gbuffers_hand", this, shaderProperties); + this.dhTerrain = readProgramSource(directory, sourceProvider, "dh_terrain", this, shaderProperties); + this.dhGeneric = readProgramSource(directory, sourceProvider, "dh_generic", this, shaderProperties); + this.dhWater = readProgramSource(directory, sourceProvider, "dh_water", this, shaderProperties); + this.dhShadow = readProgramSource(directory, sourceProvider, "dh_shadow", this, shaderProperties); this.deferred = readProgramArray(directory, sourceProvider, "deferred", shaderProperties); this.deferredCompute = new ComputeSource[deferred.length][]; @@ -219,7 +226,7 @@ public class ProgramSet { gbuffersBasic, gbuffersBeaconBeam, gbuffersTextured, gbuffersTexturedLit, gbuffersTerrain, gbuffersDamagedBlock, gbuffersSkyBasic, gbuffersSkyTextured, gbuffersClouds, gbuffersWeather, gbuffersEntities, gbuffersEntitiesTrans, gbuffersEntitiesGlowing, gbuffersGlint, gbuffersEntityEyes, gbuffersBlock, gbuffersBlockTrans, - gbuffersHand + gbuffersHand, dhShadow, dhTerrain, dhGeneric, dhWater )); for (ComputeSource[] computeSources : compositeCompute) { @@ -387,33 +394,53 @@ public class ProgramSet { return gbuffersHand.requireValid(); } + public Optional getDhTerrain() { + return dhTerrain.requireValid(); + } + + public Optional getDhGeneric() { + return dhGeneric.requireValid(); + } + + public Optional getDhWater() { + return dhWater.requireValid(); + } + + public Optional getDhShadow() { + return dhShadow.requireValid(); + } + public Optional get(ProgramId programId) { - return switch (programId) { - case Shadow -> getShadow(); - case Basic -> getGbuffersBasic(); - case Line -> gbuffersLine.requireValid(); - case Textured -> getGbuffersTextured(); - case TexturedLit -> getGbuffersTexturedLit(); - case SkyBasic -> getGbuffersSkyBasic(); - case SkyTextured -> getGbuffersSkyTextured(); - case Clouds -> getGbuffersClouds(); - case Terrain -> getGbuffersTerrain(); - case DamagedBlock -> getGbuffersDamagedBlock(); - case Block -> getGbuffersBlock(); + return switch (programId) { + case Shadow -> getShadow(); + case Basic -> getGbuffersBasic(); + case Line -> gbuffersLine.requireValid(); + case Textured -> getGbuffersTextured(); + case TexturedLit -> getGbuffersTexturedLit(); + case SkyBasic -> getGbuffersSkyBasic(); + case SkyTextured -> getGbuffersSkyTextured(); + case Clouds -> getGbuffersClouds(); + case Terrain -> getGbuffersTerrain(); + case DamagedBlock -> getGbuffersDamagedBlock(); + case Block -> getGbuffersBlock(); case BlockTrans -> getGbuffersBlockTrans(); - case BeaconBeam -> getGbuffersBeaconBeam(); - case Entities -> getGbuffersEntities(); - case EntitiesTrans -> getGbuffersEntitiesTrans(); - case EntitiesGlowing -> getGbuffersEntitiesGlowing(); - case ArmorGlint -> getGbuffersGlint(); - case SpiderEyes -> getGbuffersEntityEyes(); - case Hand -> getGbuffersHand(); - case Weather -> getGbuffersWeather(); - case Water -> getGbuffersWater(); - case HandWater -> getGbuffersHandWater(); - case Final -> getCompositeFinal(); - default -> Optional.empty(); - }; + case BeaconBeam -> getGbuffersBeaconBeam(); + case Entities -> getGbuffersEntities(); + case EntitiesTrans -> getGbuffersEntitiesTrans(); + case EntitiesGlowing -> getGbuffersEntitiesGlowing(); + case ArmorGlint -> getGbuffersGlint(); + case SpiderEyes -> getGbuffersEntityEyes(); + case Hand -> getGbuffersHand(); + case Weather -> getGbuffersWeather(); + case Water -> getGbuffersWater(); + case HandWater -> getGbuffersHandWater(); + case Final -> getCompositeFinal(); + case DhTerrain -> getDhTerrain(); + case DhGeneric -> getDhGeneric(); + case DhWater -> getDhWater(); + case DhShadow -> getDhShadow(); + default -> Optional.empty(); + }; } public ProgramSource[] getDeferred() { diff --git a/src/main/java/net/coderbot/iris/shaderpack/ShaderProperties.java b/src/main/java/net/coderbot/iris/shaderpack/ShaderProperties.java index c3543302d..a8f4c689c 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/ShaderProperties.java +++ b/src/main/java/net/coderbot/iris/shaderpack/ShaderProperties.java @@ -495,15 +495,15 @@ public class ShaderProperties { customUniforms.addVariable(parts[0], parts[1], value, false); }); - handlePassDirective("uniform.", key, value, pass -> { - String[] parts = pass.split("\\."); - if (parts.length != 2) { - Iris.logger.warn("Custom uniforms sould take the form of `uniform.. = . Ignoring " + key); - return; - } + handlePassDirective("uniform.", key, value, pass -> { + String[] parts = pass.split("\\."); + if (parts.length != 2) { + Iris.logger.warn("Custom uniforms sould take the form of `uniform.. = . Ignoring " + key); + return; + } - customUniforms.addVariable(parts[0], parts[1], value, true); - }); + customUniforms.addVariable(parts[0], parts[1], value, true); + }); // TODO: Buffer size directives // TODO: Conditional program enabling directives diff --git a/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramGroup.java b/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramGroup.java index 468a7cd81..cf74efb0b 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramGroup.java +++ b/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramGroup.java @@ -7,7 +7,8 @@ public enum ProgramGroup { Gbuffers("gbuffers"), Deferred("deferred"), Composite("composite"), - Final("final") + Final("final"), + Dh("dh") ; private final String baseName; diff --git a/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramId.java b/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramId.java index 8ae96395a..a7ff96467 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramId.java +++ b/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramId.java @@ -47,6 +47,10 @@ public enum ProgramId { Weather(ProgramGroup.Gbuffers, "weather", TexturedLit), Water(ProgramGroup.Gbuffers, "water", Terrain), HandWater(ProgramGroup.Gbuffers, "hand_water", Hand), + DhTerrain(ProgramGroup.Dh, "terrain"), + DhWater(ProgramGroup.Dh, "water", DhTerrain), + DhGeneric(ProgramGroup.Dh, "generic", DhTerrain), + DhShadow(ProgramGroup.Dh, "shadow"), Final(ProgramGroup.Final, ""), ; diff --git a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java index 7142d5e73..f5480f9ab 100644 --- a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java +++ b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java @@ -11,16 +11,16 @@ public class ShadowMatrices { // NB: These matrices are in column-major order, not row-major order like what you'd expect! - public static Matrix4f createOrthoMatrix(float halfPlaneLength) { + public static Matrix4f createOrthoMatrix(float halfPlaneLength, float nearPlane, float farPlane) { return new Matrix4f( // column 1 1.0f / halfPlaneLength, 0f, 0f, 0f, // column 2 0f, 1.0f / halfPlaneLength, 0f, 0f, // column 3 - 0f, 0f, 2.0f / (NEAR - FAR), 0f, + 0f, 0f, 2.0f / (nearPlane - farPlane), 0f, // column 4 - 0f, 0f, -(FAR + NEAR) / (FAR - NEAR), 1f + 0f, 0f, -(farPlane + nearPlane) / (farPlane - nearPlane), 1f ); } @@ -104,7 +104,7 @@ public class ShadowMatrices { 0f, 0f, -1.000390648841858f, 1f ); - test("ortho projection hpl=32", expected, createOrthoMatrix(32.0f)); + test("ortho projection hpl=32", expected, createOrthoMatrix(32.0f, 0.05f, 256.0f)); // const float shadowDistance = 110.0; // /* SHADOWHPL:110.0 */ @@ -115,7 +115,7 @@ public class ShadowMatrices { 0, 0, -1.000390648841858f, 1 ); - test("ortho projection hpl=110", expected110, createOrthoMatrix(110.0f)); + test("ortho projection hpl=110", expected110, createOrthoMatrix(110.0f, 0.05f, 256.0f)); Matrix4f expected90Proj = new Matrix4f( 1.0f, 0.0f, 0.0f, 0.0f, diff --git a/src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java b/src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java index 005b0bf16..21a8a7c9c 100644 --- a/src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java +++ b/src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java @@ -206,6 +206,20 @@ public class ShadowRenderTargets { return framebuffer; } + public GlFramebuffer createDHFramebuffer(ImmutableSet stageWritesToAlt, int[] drawBuffers) { + if (drawBuffers.length == 0) { + return createEmptyFramebuffer(); + } + + ImmutableSet stageWritesToMain = invert(stageWritesToAlt, drawBuffers); + + GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); + + framebuffer.addDepthAttachment(mainDepth.getTextureId()); + + return framebuffer; + } + public GlFramebuffer createShadowFramebuffer(ImmutableSet stageWritesToAlt, int[] drawBuffers) { if (drawBuffers.length == 0) { return createEmptyFramebuffer(); diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java index c9507e541..1daa3232c 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java @@ -1,5 +1,8 @@ package net.coderbot.iris.shadows.frustum; +import cpw.mods.fml.common.Optional; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum; +import com.seibel.distanthorizons.api.objects.math.DhApiMat4f; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.util.AxisAlignedBB; import org.embeddedt.embeddium.impl.render.viewport.Viewport; @@ -7,7 +10,8 @@ import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider; import org.embeddedt.embeddium.impl.render.viewport.frustum.Frustum; import org.joml.Vector3d; -public class CullEverythingFrustum extends Frustrum implements ViewportProvider, Frustum { +@Optional.Interface(modid = "distanthorizons", iface = "com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum") +public class CullEverythingFrustum extends Frustrum implements ViewportProvider, Frustum, IDhApiShadowCullingFrustum { private final Vector3d position = new Vector3d(); @Override @@ -24,4 +28,16 @@ public class CullEverythingFrustum extends Frustrum implements ViewportProvider, public Viewport sodium$createViewport() { return new Viewport(this, position.set(xPosition, yPosition, zPosition)); } + + @Optional.Method(modid = "distanthorizons") + @Override + public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection) { + + } + + @Optional.Method(modid = "distanthorizons") + @Override + public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) { + return false; + } } diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java index 9f2b27aeb..97a8da77e 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java @@ -1,5 +1,8 @@ package net.coderbot.iris.shadows.frustum.advanced; +import cpw.mods.fml.common.Optional; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum; +import com.seibel.distanthorizons.api.objects.math.DhApiMat4f; import net.coderbot.iris.shadows.frustum.BoxCuller; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.util.AxisAlignedBB; @@ -8,6 +11,7 @@ import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider; import org.embeddedt.embeddium.impl.render.viewport.frustum.Frustum; import org.joml.Math; import org.joml.Matrix4f; +import org.joml.Matrix4fc; import org.joml.Vector3d; import org.joml.Vector3f; import org.joml.Vector4f; @@ -32,7 +36,8 @@ import org.joml.Vector4f; * are not sensitive to the specific internal ordering of planes and corners, in order to avoid potential bugs at the * cost of slightly more computations.

*/ -public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportProvider, Frustum { +@Optional.Interface(modid = "distanthorizons", iface = "com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum") +public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportProvider, Frustum, IDhApiShadowCullingFrustum { private static final int MAX_CLIPPING_PLANES = 13; /** @@ -79,6 +84,8 @@ public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportPr private final BaseClippingPlanes baseClippingPlanes = new BaseClippingPlanes(); private final boolean[] isBackArray = new boolean[6]; + private int worldMinYDH; + private int worldMaxYDH; public AdvancedShadowCullingFrustum() { for (int i = 0; i < MAX_CLIPPING_PLANES; i++) { @@ -86,7 +93,7 @@ public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportPr } } - public void init(Matrix4f playerView, Matrix4f playerProjection, Vector3f shadowLightVector, BoxCuller boxCuller) { + public void init(Matrix4fc playerView, Matrix4fc playerProjection, Vector3f shadowLightVector, BoxCuller boxCuller) { this.shadowLightVectorFromOrigin.set(shadowLightVector); this.boxCuller = boxCuller; this.planeCount = 0; @@ -298,4 +305,17 @@ public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportPr return true; } + + @Optional.Method(modid = "distanthorizons") + @Override + public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection) { + this.worldMinYDH = worldMinBlockY; + this.worldMaxYDH = worldMaxBlockY; + } + + @Optional.Method(modid = "distanthorizons") + @Override + public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) { + return this.isVisible(lodBlockPosMinX, this.worldMinYDH, lodBlockPosMinZ, lodBlockPosMinX + lodBlockWidth, this.worldMaxYDH, lodBlockPosMinZ + lodBlockWidth); + } } diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/advanced/BaseClippingPlanes.java b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/BaseClippingPlanes.java index b5b3bcf6c..75e30ebbf 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/advanced/BaseClippingPlanes.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/BaseClippingPlanes.java @@ -1,6 +1,7 @@ package net.coderbot.iris.shadows.frustum.advanced; import org.joml.Matrix4f; +import org.joml.Matrix4fc; import org.joml.Vector4f; public class BaseClippingPlanes { @@ -13,7 +14,7 @@ public class BaseClippingPlanes { } } - public void init(Matrix4f view, Matrix4f projection) { + public void init(Matrix4fc view, Matrix4fc projection) { // Transform = Transpose(Projection x View) transformScratch.set(projection); transformScratch.mul(view); diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/advanced/SafeZoneCullingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/SafeZoneCullingFrustum.java index 849166df3..3a11b38ec 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/advanced/SafeZoneCullingFrustum.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/SafeZoneCullingFrustum.java @@ -3,12 +3,13 @@ package net.coderbot.iris.shadows.frustum.advanced; import net.coderbot.iris.shadows.frustum.BoxCuller; import net.minecraft.util.AxisAlignedBB; import org.joml.Matrix4f; +import org.joml.Matrix4fc; import org.joml.Vector3f; public class SafeZoneCullingFrustum extends AdvancedShadowCullingFrustum { private final BoxCuller distanceCuller; - public SafeZoneCullingFrustum(Matrix4f playerView, Matrix4f playerProjection, Vector3f shadowLightVector, BoxCuller voxelCuller, BoxCuller distanceCuller) { + public SafeZoneCullingFrustum(Matrix4fc playerView, Matrix4fc playerProjection, Vector3f shadowLightVector, BoxCuller voxelCuller, BoxCuller distanceCuller) { super(); init(playerView, playerProjection, shadowLightVector, voxelCuller); this.distanceCuller = distanceCuller; diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java index bec8f8e6f..0e34750ef 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java @@ -1,5 +1,8 @@ package net.coderbot.iris.shadows.frustum.fallback; +import cpw.mods.fml.common.Optional; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum; +import com.seibel.distanthorizons.api.objects.math.DhApiMat4f; import net.coderbot.iris.shadows.frustum.BoxCuller; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.util.AxisAlignedBB; @@ -8,9 +11,12 @@ import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider; import org.embeddedt.embeddium.impl.render.viewport.frustum.Frustum; import org.joml.Vector3d; -public class BoxCullingFrustum extends Frustrum implements ViewportProvider, Frustum { +@Optional.Interface(modid = "distanthorizons", iface = "com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum") +public class BoxCullingFrustum extends Frustrum implements ViewportProvider, Frustum, IDhApiShadowCullingFrustum { private final BoxCuller boxCuller; private final Vector3d position = new Vector3d(); + private int worldMinYDH; + private int worldMaxYDH; public BoxCullingFrustum(BoxCuller boxCuller) { this.boxCuller = boxCuller; @@ -36,4 +42,17 @@ public class BoxCullingFrustum extends Frustrum implements ViewportProvider, Fru public Viewport sodium$createViewport() { return new Viewport(this, position.set(xPosition, yPosition, zPosition)); } + + @Optional.Method(modid = "distanthorizons") + @Override + public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection) { + this.worldMinYDH = worldMinBlockY; + this.worldMaxYDH = worldMaxBlockY; + } + + @Optional.Method(modid = "distanthorizons") + @Override + public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) { + return !boxCuller.isCulled(lodBlockPosMinX, this.worldMinYDH, lodBlockPosMinZ, lodBlockPosMinX + lodBlockWidth, this.worldMaxYDH, lodBlockPosMinZ + lodBlockWidth); + } } diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java index 76f078ec8..8244c9a43 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java @@ -1,5 +1,8 @@ package net.coderbot.iris.shadows.frustum.fallback; +import cpw.mods.fml.common.Optional; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum; +import com.seibel.distanthorizons.api.objects.math.DhApiMat4f; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.util.AxisAlignedBB; import org.embeddedt.embeddium.impl.render.viewport.Viewport; @@ -7,7 +10,8 @@ import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider; import org.embeddedt.embeddium.impl.render.viewport.frustum.Frustum; import org.joml.Vector3d; -public class NonCullingFrustum extends Frustrum implements ViewportProvider, Frustum { +@Optional.Interface(modid = "distanthorizons", iface = "com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum") +public class NonCullingFrustum extends Frustrum implements ViewportProvider, Frustum, IDhApiShadowCullingFrustum { private final Vector3d position = new Vector3d(); @Override @@ -24,4 +28,17 @@ public class NonCullingFrustum extends Frustrum implements ViewportProvider, Fru public Viewport sodium$createViewport() { return new Viewport(this, position.set(xPosition, yPosition, zPosition)); } + + @Optional.Method(modid = "distanthorizons") + @Override + public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection) { + + } + + @Optional.Method(modid = "distanthorizons") + @Override + public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) { + return true; + } + } diff --git a/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java index 866171cbc..7b27b9299 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java @@ -4,8 +4,12 @@ import com.gtnewhorizons.angelica.rendering.RenderingState; import lombok.Getter; import net.coderbot.iris.gl.uniform.UniformHolder; import net.minecraft.client.Minecraft; +import org.joml.Matrix3f; import org.joml.Vector3d; -import org.joml.Vector3dc; +import org.joml.Vector3f; +import org.joml.Vector3fc; +import org.joml.Vector3i; +import org.joml.Vector3ic; import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.ONCE; import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; @@ -15,6 +19,8 @@ import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; */ public class CameraUniforms { private static final Minecraft client = Minecraft.getMinecraft(); + private static final Vector3f tempVec3f = new Vector3f(); + private static final Vector3i tempVec3i = new Vector3i(); private CameraUniforms() { } @@ -27,7 +33,27 @@ public class CameraUniforms { .uniform1f(PER_FRAME, "far", CameraUniforms::getRenderDistanceInBlocks) .uniform3d(PER_FRAME, "cameraPosition", tracker::getCurrentCameraPosition) .uniform1f(PER_FRAME, "eyeAltitude", tracker::getCurrentCameraPositionY) - .uniform3d(PER_FRAME, "previousCameraPosition", tracker::getPreviousCameraPosition); + .uniform3d(PER_FRAME, "previousCameraPosition", tracker::getPreviousCameraPosition) + .uniform3i(PER_FRAME, "cameraPositionInt", () -> getCameraPositionInt(getUnshiftedCameraPosition())) + .uniform3f(PER_FRAME, "cameraPositionFract", () -> getCameraPositionFract(getUnshiftedCameraPosition())) + .uniform3i(PER_FRAME, "previousCameraPositionInt", () -> getCameraPositionInt(tracker.getPreviousCameraPositionUnshifted())) + .uniform3f(PER_FRAME, "previousCameraPositionFract", () -> getCameraPositionFract(tracker.getPreviousCameraPositionUnshifted())); + } + + public static Vector3fc getCameraPositionFract(Vector3d originalPos) { + return tempVec3f.set( + (float) (originalPos.x - Math.floor(originalPos.x)), + (float) (originalPos.y - Math.floor(originalPos.y)), + (float) (originalPos.z - Math.floor(originalPos.z)) + ); + } + + public static Vector3ic getCameraPositionInt(Vector3d originalPos) { + return tempVec3i.set( + (int) Math.floor(originalPos.x), + (int) Math.floor(originalPos.y), + (int) Math.floor(originalPos.z) + ); } private static int getRenderDistanceInBlocks() { @@ -35,7 +61,7 @@ public class CameraUniforms { return client.gameSettings.renderDistanceChunks * 16; } - public static Vector3dc getUnshiftedCameraPosition() { + public static Vector3d getUnshiftedCameraPosition() { return RenderingState.INSTANCE.getCameraPosition(); } @@ -50,10 +76,12 @@ public class CameraUniforms { private static final double TP_RANGE = 1000; @Getter - private Vector3d previousCameraPosition = new Vector3d(); + private Vector3d previousCameraPosition = new Vector3d(); @Getter - private Vector3d currentCameraPosition = new Vector3d(); + private Vector3d currentCameraPosition = new Vector3d(); private final Vector3d shift = new Vector3d(); + private Vector3d previousCameraPositionUnshifted = new Vector3d(); + private Vector3d currentCameraPositionUnshifted = new Vector3d(); CameraPositionTracker(FrameUpdateNotifier notifier) { notifier.addListener(this::update); @@ -61,7 +89,9 @@ public class CameraUniforms { private void update() { previousCameraPosition.set(currentCameraPosition); + previousCameraPositionUnshifted = currentCameraPositionUnshifted; currentCameraPosition.set(getUnshiftedCameraPosition()).add(shift); + currentCameraPositionUnshifted.set(getUnshiftedCameraPosition()); updateShift(); } @@ -104,8 +134,12 @@ public class CameraUniforms { previousCameraPosition.z += dZ; } - public double getCurrentCameraPositionY() { + public double getCurrentCameraPositionY() { return currentCameraPosition.y; } + + public Vector3d getPreviousCameraPositionUnshifted() { + return previousCameraPositionUnshifted; + } } } diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index 4edc89ecf..04acc25db 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -7,6 +7,7 @@ import com.gtnewhorizons.angelica.glsm.texture.TextureInfo; import com.gtnewhorizons.angelica.glsm.texture.TextureInfoCache; import com.gtnewhorizons.angelica.client.rendering.TextureTracker; import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor; +import net.coderbot.iris.compat.dh.DHCompat; import net.coderbot.iris.gl.state.FogMode; import net.coderbot.iris.gl.state.ValueUpdateNotifier; import net.coderbot.iris.gl.uniform.DynamicUniformHolder; @@ -137,7 +138,10 @@ public final class CommonUniforms { .uniform1f(PER_TICK, "rainStrength", CommonUniforms::getRainStrength) .uniform1f(PER_TICK, "wetness", new SmoothedFloat(directives.getWetnessHalfLife(), directives.getDrynessHalfLife(), CommonUniforms::getRainStrength, updateNotifier)) .uniform3d(PER_FRAME, "skyColor", CommonUniforms::getSkyColor) - .uniform3d(PER_FRAME, "fogColor", GLStateManager::getFogColor); + .uniform3d(PER_FRAME, "fogColor", GLStateManager::getFogColor) + .uniform1f(PER_FRAME, "dhFarPlane", DHCompat::getFarPlane) + .uniform1f(PER_FRAME, "dhNearPlane", DHCompat::getNearPlane) + .uniform1i(PER_FRAME, "dhRenderDistance", DHCompat::getRenderDistance); } private static boolean isOnGround() { diff --git a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java index 1ab96f1d3..d1ccf7ce9 100644 --- a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java @@ -1,11 +1,13 @@ package net.coderbot.iris.uniforms; import com.gtnewhorizons.angelica.rendering.RenderingState; +import net.coderbot.iris.compat.dh.DHCompat; import net.coderbot.iris.gl.uniform.UniformHolder; import net.coderbot.iris.pipeline.ShadowRenderer; import net.coderbot.iris.shaderpack.PackDirectives; import net.coderbot.iris.shadow.ShadowMatrices; import org.joml.Matrix4f; +import org.joml.Matrix4fc; import java.util.function.Supplier; @@ -20,27 +22,37 @@ public final class MatrixUniforms { // TODO: In some cases, gbufferProjectionInverse takes on a value much different than OptiFine... // We need to audit Mojang's linear algebra. addMatrix(uniforms, "Projection", RenderingState.INSTANCE::getProjectionMatrix); + addDHMatrix(uniforms, "Projection", DHCompat::getProjection); addShadowMatrix(uniforms, "ModelView", () -> ShadowRenderer.createShadowModelView(directives.getSunPathRotation(), directives.getShadowDirectives().getIntervalSize()).peek().getModel()); - addShadowMatrix(uniforms, "Projection", () -> ShadowMatrices.createOrthoMatrix(directives.getShadowDirectives().getDistance())); + addShadowMatrix(uniforms, "Projection", () -> ShadowMatrices.createOrthoMatrix(directives.getShadowDirectives().getDistance(), directives.getShadowDirectives().getNearPlane() < 0 ? -DHCompat.getRenderDistance() : directives.getShadowDirectives().getNearPlane(), + directives.getShadowDirectives().getFarPlane() < 0 ? DHCompat.getRenderDistance() : directives.getShadowDirectives().getFarPlane())); } - private static void addMatrix(UniformHolder uniforms, String name, Supplier supplier) { + private static void addMatrix(UniformHolder uniforms, String name, Supplier supplier) { uniforms .uniformMatrix(PER_FRAME, "gbuffer" + name, supplier) .uniformMatrix(PER_FRAME, "gbuffer" + name + "Inverse", new Inverted(supplier)) .uniformMatrix(PER_FRAME, "gbufferPrevious" + name, new Previous(supplier)); } - private static void addShadowMatrix(UniformHolder uniforms, String name, Supplier supplier) { + private static void addDHMatrix(UniformHolder uniforms, String name, Supplier supplier) { + uniforms + .uniformMatrix(PER_FRAME, "dh" + name, supplier) + .uniformMatrix(PER_FRAME, "dh" + name + "Inverse", new Inverted(supplier)) + .uniformMatrix(PER_FRAME, "dhPrevious" + name, new Previous(supplier)); + } + + + private static void addShadowMatrix(UniformHolder uniforms, String name, Supplier supplier) { uniforms .uniformMatrix(PER_FRAME, "shadow" + name, supplier) .uniformMatrix(PER_FRAME, "shadow" + name + "Inverse", new Inverted(supplier)); } - private static class Inverted implements Supplier { - private final Supplier parent; + private static class Inverted implements Supplier { + private final Supplier parent; - Inverted(Supplier parent) { + Inverted(Supplier parent) { this.parent = parent; } @@ -56,11 +68,11 @@ public final class MatrixUniforms { } - private static class Previous implements Supplier { - private final Supplier parent; - private Matrix4f previous; + private static class Previous implements Supplier { + private final Supplier parent; + private Matrix4fc previous; - Previous(Supplier parent) { + Previous(Supplier parent) { this.parent = parent; this.previous = new Matrix4f(); } diff --git a/src/main/java/net/coderbot/iris/uniforms/custom/CustomUniformFixedInputUniformsHolder.java b/src/main/java/net/coderbot/iris/uniforms/custom/CustomUniformFixedInputUniformsHolder.java index ea9487800..824eb8ad5 100644 --- a/src/main/java/net/coderbot/iris/uniforms/custom/CustomUniformFixedInputUniformsHolder.java +++ b/src/main/java/net/coderbot/iris/uniforms/custom/CustomUniformFixedInputUniformsHolder.java @@ -25,7 +25,8 @@ import org.joml.Vector2f; import org.joml.Vector2i; import org.joml.Vector3d; import org.joml.Vector3f; -import org.joml.Vector3i; +import org.joml.Vector3fc; +import org.joml.Vector3ic; import org.joml.Vector4f; import java.util.Collection; @@ -116,12 +117,12 @@ public class CustomUniformFixedInputUniformsHolder { } @Override - public Builder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + public Builder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier value) { return this.put(name, new Float3VectorCachedUniform(name, updateFrequency, value)); } @Override - public Builder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + public Builder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier value) { return this.put(name, new Int3VectorCachedUniform(name, updateFrequency, value)); } @@ -172,7 +173,7 @@ public class CustomUniformFixedInputUniformsHolder { @Override public UniformHolder uniformMatrix( - UniformUpdateFrequency updateFrequency, String name, Supplier value) { + UniformUpdateFrequency updateFrequency, String name, Supplier value) { return this.put(name, new Float4MatrixCachedUniform(name, updateFrequency, value)); } diff --git a/src/main/java/net/coderbot/iris/uniforms/custom/cached/Float3VectorCachedUniform.java b/src/main/java/net/coderbot/iris/uniforms/custom/cached/Float3VectorCachedUniform.java index 374e4f19b..2c8e1dab8 100644 --- a/src/main/java/net/coderbot/iris/uniforms/custom/cached/Float3VectorCachedUniform.java +++ b/src/main/java/net/coderbot/iris/uniforms/custom/cached/Float3VectorCachedUniform.java @@ -4,23 +4,24 @@ import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; import net.coderbot.iris.parsing.VectorType; import org.joml.Vector3f; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import org.joml.Vector3fc; import java.util.function.Supplier; -public class Float3VectorCachedUniform extends VectorCachedUniform { +public class Float3VectorCachedUniform extends VectorCachedUniform { - public Float3VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier supplier) { + public Float3VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier supplier) { super(name, updateFrequency, new Vector3f(), supplier); } @Override - protected void setFrom(Vector3f other) { - this.cached.set(other); + protected void setFrom(Vector3fc other) { + ((Vector3f)this.cached).set(other); } @Override public void push(int location) { - GLStateManager.glUniform3f(location, this.cached.x, this.cached.y, this.cached.z); + GLStateManager.glUniform3f(location, this.cached.x(), this.cached.y(), this.cached.z()); } @Override diff --git a/src/main/java/net/coderbot/iris/uniforms/custom/cached/Float4MatrixCachedUniform.java b/src/main/java/net/coderbot/iris/uniforms/custom/cached/Float4MatrixCachedUniform.java index a210aff7a..83e73b5a9 100644 --- a/src/main/java/net/coderbot/iris/uniforms/custom/cached/Float4MatrixCachedUniform.java +++ b/src/main/java/net/coderbot/iris/uniforms/custom/cached/Float4MatrixCachedUniform.java @@ -4,21 +4,22 @@ import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; import net.coderbot.iris.parsing.MatrixType; import org.joml.Matrix4f; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import org.joml.Matrix4fc; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.util.function.Supplier; -public class Float4MatrixCachedUniform extends VectorCachedUniform { +public class Float4MatrixCachedUniform extends VectorCachedUniform { final private FloatBuffer buffer = ByteBuffer.allocateDirect(16 << 2).order(ByteOrder.nativeOrder()).asFloatBuffer(); - public Float4MatrixCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier supplier) { + public Float4MatrixCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier supplier) { super(name, updateFrequency, new Matrix4f(), supplier); } @Override - protected void setFrom(Matrix4f other) { + protected void setFrom(Matrix4fc other) { ((Matrix4f) this.cached).set(other); } diff --git a/src/main/java/net/coderbot/iris/uniforms/custom/cached/Int3VectorCachedUniform.java b/src/main/java/net/coderbot/iris/uniforms/custom/cached/Int3VectorCachedUniform.java index 7bc85f17c..32f61ad10 100644 --- a/src/main/java/net/coderbot/iris/uniforms/custom/cached/Int3VectorCachedUniform.java +++ b/src/main/java/net/coderbot/iris/uniforms/custom/cached/Int3VectorCachedUniform.java @@ -4,23 +4,24 @@ import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; import net.coderbot.iris.parsing.VectorType; import org.joml.Vector3i; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import org.joml.Vector3ic; import java.util.function.Supplier; -public class Int3VectorCachedUniform extends VectorCachedUniform { +public class Int3VectorCachedUniform extends VectorCachedUniform { - public Int3VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier supplier) { + public Int3VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier supplier) { super(name, updateFrequency, new Vector3i(), supplier); } @Override - protected void setFrom(Vector3i other) { - this.cached.set(other); + protected void setFrom(Vector3ic other) { + ((Vector3i)this.cached).set(other); } @Override public void push(int location) { - GLStateManager.glUniform3i(location, this.cached.x, this.cached.y, this.cached.z); + GLStateManager.glUniform3i(location, this.cached.x(), this.cached.y(), this.cached.z()); } @Override diff --git a/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index 28abbf20d..03f471afd 100644 --- a/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -7,6 +7,7 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalRef; import net.coderbot.iris.Iris; +import net.coderbot.iris.compat.dh.DHCompat; import net.coderbot.iris.gl.program.Program; import net.coderbot.iris.pipeline.HandRenderer; import net.coderbot.iris.pipeline.WorldRenderingPhase; @@ -35,6 +36,9 @@ public abstract class MixinEntityRenderer implements IResourceManagerReloadListe @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/culling/ClippingHelperImpl;getInstance()Lnet/minecraft/client/renderer/culling/ClippingHelper;", shift = At.Shift.AFTER, ordinal = 0), method = "renderWorld(FJ)V") private void iris$beginRender(float partialTicks, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + DHCompat.checkFrame(); + Iris.tryLoadShaderpackWhenPossible(); + CapturedRenderingState.INSTANCE.setTickDelta(partialTicks); SystemTimeUniforms.COUNTER.beginFrame(); SystemTimeUniforms.TIMER.beginFrame(System.nanoTime());