diff --git a/patches/com/mojang/blaze3d/pipeline/MainTarget.java.patch b/patches/com/mojang/blaze3d/pipeline/MainTarget.java.patch new file mode 100644 index 00000000000..8071336f342 --- /dev/null +++ b/patches/com/mojang/blaze3d/pipeline/MainTarget.java.patch @@ -0,0 +1,15 @@ +--- a/com/mojang/blaze3d/pipeline/MainTarget.java ++++ b/com/mojang/blaze3d/pipeline/MainTarget.java +@@ -16,7 +_,11 @@ + static final MainTarget.Dimension DEFAULT_DIMENSIONS = new MainTarget.Dimension(854, 480); + + public MainTarget(int p_166137_, int p_166138_) { +- super(true); ++ this(net.neoforged.neoforge.client.ClientHooks.configureMainRenderTarget(), p_166137_, p_166138_); ++ } ++ ++ private MainTarget(net.neoforged.neoforge.client.event.ConfigureMainRenderTargetEvent e, int p_166137_, int p_166138_) { ++ super(e.useDepth(), e.useStencil()); + this.createFrameBuffer(p_166137_, p_166138_); + } + diff --git a/patches/com/mojang/blaze3d/pipeline/RenderTarget.java.patch b/patches/com/mojang/blaze3d/pipeline/RenderTarget.java.patch new file mode 100644 index 00000000000..bddf05a9c12 --- /dev/null +++ b/patches/com/mojang/blaze3d/pipeline/RenderTarget.java.patch @@ -0,0 +1,134 @@ +--- a/com/mojang/blaze3d/pipeline/RenderTarget.java ++++ b/com/mojang/blaze3d/pipeline/RenderTarget.java +@@ -25,17 +_,31 @@ + public int viewWidth; + public int viewHeight; + public final boolean useDepth; ++ public final boolean useStencil; + public int frameBufferId; + protected int colorTextureId; + protected int depthBufferId; ++ protected int stencilBufferId; + private final float[] clearChannels = Util.make(() -> new float[]{1.0F, 1.0F, 1.0F, 0.0F}); + public int filterMode; + + public RenderTarget(boolean p_166199_) { +- this.useDepth = p_166199_; ++ this(p_166199_, false); ++ } ++ ++ public RenderTarget(boolean useDepth, boolean useStencil) { ++ this.useDepth = useDepth; ++ this.useStencil = useStencil; + this.frameBufferId = -1; + this.colorTextureId = -1; + this.depthBufferId = -1; ++ ++ if (!useDepth && useStencil) { ++ var capabilities = org.lwjgl.opengl.GL.getCapabilities(); ++ if (!capabilities.GL_ARB_texture_stencil8 && !capabilities.OpenGL44) { ++ throw new UnsupportedOperationException("Stencil-only buffers require GL_ARB_texture_stencil8 OR OpenGL 4.4"); ++ } ++ } + } + + public void resize(int p_83942_, int p_83943_) { +@@ -53,6 +_,11 @@ + RenderSystem.assertOnRenderThreadOrInit(); + this.unbindRead(); + this.unbindWrite(); ++ if (this.stencilBufferId > -1 && this.stencilBufferId != this.depthBufferId) { ++ TextureUtil.releaseTextureId(this.stencilBufferId);; ++ this.stencilBufferId = -1; ++ } ++ + if (this.depthBufferId > -1) { + TextureUtil.releaseTextureId(this.depthBufferId); + this.depthBufferId = -1; +@@ -96,9 +_,50 @@ + GlStateManager._texParameter(3553, 34892, 0); + GlStateManager._texParameter(3553, 10242, 33071); + GlStateManager._texParameter(3553, 10243, 33071); ++ if (!this.useStencil) // If stenciling is enabled, we will fill this later + GlStateManager._texImage2D(3553, 0, 6402, this.width, this.height, 0, 6402, 5126, null); + } + ++ if (this.useStencil) { ++ if (this.useDepth) { ++ // If depth and stencil buffers are both enabled, we must combine them ++ this.stencilBufferId = this.depthBufferId; ++ } else { ++ // Otherwise, we can generate a new texture in its place. ++ this.stencilBufferId = TextureUtil.generateTextureId(); ++ GlStateManager._bindTexture(this.stencilBufferId); ++ GlStateManager._texParameter(3553, 10241, 9728); ++ GlStateManager._texParameter(3553, 10240, 9728); ++ GlStateManager._texParameter(3553, 34892, 0); ++ GlStateManager._texParameter(3553, 10242, 33071); ++ GlStateManager._texParameter(3553, 10243, 33071); ++ } ++ ++ if (this.useDepth) { ++ // Use a combined format for both depth and stencil. ++ GlStateManager._texImage2D( ++ org.lwjgl.opengl.GL32.GL_TEXTURE_2D, ++ 0, ++ org.lwjgl.opengl.GL32.GL_DEPTH24_STENCIL8, ++ this.width, this.height, ++ 0, ++ org.lwjgl.opengl.GL32.GL_DEPTH_STENCIL, ++ org.lwjgl.opengl.GL32.GL_UNSIGNED_INT_24_8, ++ null); ++ } else { ++ // Otherwise, we can use a separate format. Testing for this was done in the constructor already. ++ GlStateManager._texImage2D( ++ org.lwjgl.opengl.GL32.GL_TEXTURE_2D, ++ 0, ++ org.lwjgl.opengl.GL32.GL_STENCIL_INDEX8, ++ this.width, this.height, ++ 0, ++ org.lwjgl.opengl.GL32.GL_STENCIL_INDEX, ++ org.lwjgl.opengl.GL32.GL_BYTE, ++ null); ++ } ++ } ++ + this.setFilterMode(9728, true); + GlStateManager._bindTexture(this.colorTextureId); + GlStateManager._texParameter(3553, 10242, 33071); +@@ -109,6 +_,14 @@ + if (this.useDepth) { + GlStateManager._glFramebufferTexture2D(36160, 36096, 3553, this.depthBufferId, 0); + } ++ if (this.useStencil) { ++ GlStateManager._glFramebufferTexture2D( ++ org.lwjgl.opengl.GL32.GL_FRAMEBUFFER, ++ org.lwjgl.opengl.GL32.GL_STENCIL_ATTACHMENT, ++ org.lwjgl.opengl.GL32.GL_TEXTURE_2D, ++ this.stencilBufferId, ++ 0); ++ } + + this.checkStatus(); + this.clear(); +@@ -218,6 +_,10 @@ + GlStateManager._clearDepth(1.0); + i |= 256; + } ++ if (this.useStencil) { ++ GlStateManager._clearStencil(0); ++ i |= org.lwjgl.opengl.GL32.GL_STENCIL_BUFFER_BIT; ++ } + + GlStateManager._clear(i); + this.unbindWrite(); +@@ -229,5 +_,9 @@ + + public int getDepthTextureId() { + return this.depthBufferId; ++ } ++ ++ public int getStencilBufferId() { ++ return this.stencilBufferId; + } + } diff --git a/patches/net/minecraft/client/Minecraft.java.patch b/patches/net/minecraft/client/Minecraft.java.patch index d73618ac551..2aa7566298f 100644 --- a/patches/net/minecraft/client/Minecraft.java.patch +++ b/patches/net/minecraft/client/Minecraft.java.patch @@ -17,7 +17,7 @@ this.demo = p_91084_.game.demo; this.allowsMultiplayer = !p_91084_.game.disableMultiplayer; this.allowsChat = !p_91084_.game.disableChat; -@@ -488,15 +_,15 @@ +@@ -488,15 +_,16 @@ LOGGER.error("Couldn't set icon", (Throwable)ioexception); } @@ -27,11 +27,12 @@ this.keyboardHandler = new KeyboardHandler(this); - this.keyboardHandler.setup(this.window.getWindow()); RenderSystem.initRenderer(this.options.glDebugVerbosity, false); ++ net.neoforged.neoforge.client.loading.ClientModLoader.begin(this); this.mainRenderTarget = new MainTarget(this.window.getWidth(), this.window.getHeight()); this.mainRenderTarget.setClearColor(0.0F, 0.0F, 0.0F, 0.0F); this.mainRenderTarget.clear(); this.resourceManager = new ReloadableResourceManager(PackType.CLIENT_RESOURCES); -+ net.neoforged.neoforge.client.loading.ClientModLoader.begin(this, this.resourcePackRepository, this.resourceManager); ++ net.neoforged.neoforge.client.loading.ClientModLoader.finish(this.resourcePackRepository, this.resourceManager); this.resourcePackRepository.reload(); this.options.loadSelectedResourcePacks(this.resourcePackRepository); this.languageManager = new LanguageManager(this.options.languageCode, p_344151_ -> { @@ -184,7 +185,7 @@ this.deltaTracker.updatePauseState(this.pause); this.deltaTracker.updateFrozenState(!this.isLevelRunningNormally()); long l = Util.getNanos(); -@@ -1358,10 +_,12 @@ +@@ -1358,10 +_,13 @@ this.window.setGuiScale((double)i); if (this.screen != null) { this.screen.resize(this, this.window.getGuiScaledWidth(), this.window.getGuiScaledHeight()); @@ -192,6 +193,7 @@ } RenderTarget rendertarget = this.getMainRenderTarget(); ++ if (rendertarget != null) rendertarget.resize(this.window.getWidth(), this.window.getHeight()); + if (this.gameRenderer != null) this.gameRenderer.resize(this.window.getWidth(), this.window.getHeight()); diff --git a/src/main/java/net/neoforged/neoforge/client/ClientHooks.java b/src/main/java/net/neoforged/neoforge/client/ClientHooks.java index ce6aa279b3b..91f41b6e1ef 100644 --- a/src/main/java/net/neoforged/neoforge/client/ClientHooks.java +++ b/src/main/java/net/neoforged/neoforge/client/ClientHooks.java @@ -145,6 +145,7 @@ import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent; import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.client.event.ComputeFovModifierEvent; +import net.neoforged.neoforge.client.event.ConfigureMainRenderTargetEvent; import net.neoforged.neoforge.client.event.CustomizeGuiOverlayEvent; import net.neoforged.neoforge.client.event.EntityRenderersEvent; import net.neoforged.neoforge.client.event.GatherEffectScreenTooltipsEvent; @@ -1105,4 +1106,10 @@ public static Map gatherMaterialAtlases(Map< ModLoader.postEvent(new RegisterMaterialAtlasesEvent(vanillaAtlases)); return Map.copyOf(vanillaAtlases); } + + public static ConfigureMainRenderTargetEvent configureMainRenderTarget() { + var e = new ConfigureMainRenderTargetEvent(); + ModLoader.postEvent(e); + return e; + } } diff --git a/src/main/java/net/neoforged/neoforge/client/event/ConfigureMainRenderTargetEvent.java b/src/main/java/net/neoforged/neoforge/client/event/ConfigureMainRenderTargetEvent.java new file mode 100644 index 00000000000..c4bc57ad89e --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/event/ConfigureMainRenderTargetEvent.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.event; + +import com.mojang.blaze3d.pipeline.MainTarget; +import com.mojang.blaze3d.pipeline.RenderTarget; +import net.neoforged.bus.api.Event; +import net.neoforged.bus.api.ICancellableEvent; +import net.neoforged.fml.LogicalSide; +import net.neoforged.fml.event.IModBusEvent; +import org.jetbrains.annotations.ApiStatus; + +/** + * Fired when configuring the main {@linkplain RenderTarget render target}. + *

+ * This event fires during startup when the {@link MainTarget} is constructed. + *

+ * This event is not {@linkplain ICancellableEvent cancellable}. + *

+ * This event is fired on the mod-speciffic event bus, only on the {@linkplain LogicalSide#CLIENT logical client}. + */ +public class ConfigureMainRenderTargetEvent extends Event implements IModBusEvent { + private boolean useDepth; + private boolean useStencil; + + @ApiStatus.Internal + public ConfigureMainRenderTargetEvent() { + this.useDepth = true; + this.useStencil = false; + } + + /** + * Returns whether the depth buffer is enabled. + * + * @return true, if the depth buffer is enabled, or false otherwise. + */ + public boolean useDepth() { + return this.useDepth; + } + + /** + * Returns whether the stencil buffer is enabled. + * + * @return true, if the stencil buffer is enabled, or false otherwise. + */ + public boolean useStencil() { + return this.useStencil; + } + + /** + * Enable the depth buffer for the main render target. + * + * @return this, for method chaining. + */ + public ConfigureMainRenderTargetEvent enableDepth() { + this.useDepth = true; + return this; + } + + /** + * Enable the stencil buffer for the main render target. + * + * @return this, for method chaining. + */ + public ConfigureMainRenderTargetEvent enableStencil() { + this.useStencil = true; + return this; + } +} diff --git a/src/main/java/net/neoforged/neoforge/client/loading/ClientModLoader.java b/src/main/java/net/neoforged/neoforge/client/loading/ClientModLoader.java index d8c4a35e616..4ee4d48b270 100644 --- a/src/main/java/net/neoforged/neoforge/client/loading/ClientModLoader.java +++ b/src/main/java/net/neoforged/neoforge/client/loading/ClientModLoader.java @@ -47,7 +47,7 @@ public class ClientModLoader extends CommonModLoader { @Nullable private static ModLoadingException error; - public static void begin(final Minecraft minecraft, final PackRepository defaultResourcePacks, final ReloadableResourceManager mcResourceManager) { + public static void begin(final Minecraft minecraft) { // force log4j to shutdown logging in a shutdown hook. This is because we disable default shutdown hook so the server properly logs it's shutdown Runtime.getRuntime().addShutdownHook(new Thread(LogManager::shutdown)); ImmediateWindowHandler.updateProgress("Loading mods"); @@ -60,6 +60,9 @@ public static void begin(final Minecraft minecraft, final PackRepository default } catch (ModLoadingException e) { error = e; } + } + + public static void finish(final PackRepository defaultResourcePacks, final ReloadableResourceManager mcResourceManager) { if (error == null) { ResourcePackLoader.populatePackRepository(defaultResourcePacks, PackType.CLIENT_RESOURCES, false); DataPackConfig.DEFAULT.addModPacks(ResourcePackLoader.getPackNames(PackType.SERVER_DATA));