diff --git a/common b/common index 4d9c629..7bc3081 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 4d9c629eaf4f5d315d772d7e07336ff237369390 +Subproject commit 7bc308155e882743badc71e8465ec8e913022c0a diff --git a/src/main/java/org/saturnclient/impl/features/mixins/render/GameRendererMixin.java b/src/main/java/org/saturnclient/impl/features/mixins/render/GameRendererMixin.java index 324fe01..be65e23 100644 --- a/src/main/java/org/saturnclient/impl/features/mixins/render/GameRendererMixin.java +++ b/src/main/java/org/saturnclient/impl/features/mixins/render/GameRendererMixin.java @@ -49,13 +49,12 @@ public class GameRendererMixin { //? if >=1.21.6 { // From 1.21.6 the menu blur's strength is the vanilla setting, read here every frame. While a - // Saturn screen is open, it's Saturn's background blur instead, faded in with the screen. Glass - // uses the same blur, so this holds even when the screen doesn't blur its whole background. + // Saturn screen is open, it's Saturn's background blur instead, faded in with the screen. @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/GameOptions;getMenuBackgroundBlurrinessValue()I")) private int useSaturnBlur(GameOptions options) { if (MinecraftClient.getInstance().currentScreen instanceof SaturnScreenFabric saturnScreen) { - return saturnScreen.screen.getBlurRadius(); + return saturnScreen.screen.getBackgroundBlur(); } return options.getMenuBackgroundBlurrinessValue(); diff --git a/src/main/java/org/saturnclient/impl/provider/SaturnProviderImpl.java b/src/main/java/org/saturnclient/impl/provider/SaturnProviderImpl.java index f468ed4..fb9b976 100644 --- a/src/main/java/org/saturnclient/impl/provider/SaturnProviderImpl.java +++ b/src/main/java/org/saturnclient/impl/provider/SaturnProviderImpl.java @@ -76,14 +76,6 @@ public class SaturnProviderImpl implements SaturnProvider { return (IdentifierRef) (Object) playerSkin.get(); } - @Override - public boolean supportsGlass() { - //? if >=1.21.11 { - return true; - //?} else - //return false; - } - @Override public String getModVersion() { return FabricLoader.getInstance().getModContainer(SaturnClient.MOD_ID) diff --git a/src/main/java/org/saturnclient/impl/ui/GlassRenderer.java b/src/main/java/org/saturnclient/impl/ui/GlassRenderer.java index 1c2f589..cee6ba6 100644 --- a/src/main/java/org/saturnclient/impl/ui/GlassRenderer.java +++ b/src/main/java/org/saturnclient/impl/ui/GlassRenderer.java @@ -1,28 +1,38 @@ package org.saturnclient.impl.ui; //? if >=1.21.11 { +import java.io.Reader; +import java.util.HashMap; +import java.util.Map; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.textures.FilterMode; import com.mojang.blaze3d.textures.GpuTextureView; +import com.mojang.serialization.JsonOps; import org.saturnclient.saturnclient.SaturnClient; import net.minecraft.client.gl.Framebuffer; import net.minecraft.client.gl.GpuSampler; +import net.minecraft.client.gl.PostEffectPipeline; import net.minecraft.client.gl.PostEffectProcessor; import net.minecraft.client.gl.RenderPipelines; import net.minecraft.client.gl.SimpleFramebuffer; import net.minecraft.client.render.DefaultFramebufferSet; +import net.minecraft.client.render.ProjectionMatrix2; import net.minecraft.client.texture.TextureSetup; import net.minecraft.client.util.Pool; import net.minecraft.util.Identifier; -// Glass: a copy of the game behind the screen, blurred with vanilla's blur (as strong as Saturn's -// background blur), drawn through each panel's rounded rectangle texture (shaders/core/glass.fsh). -// The copy is made while the screen builds its GUI, before the GUI is drawn, so it holds the world -// or panorama alone. -// TODO: glass before 1.21.11 (#23). Those versions blur the whole background instead. +// Glass: a copy of the game behind the screen, blurred, drawn through each panel's rounded rectangle +// texture (shaders/core/glass.fsh). There's a copy for each blur strength in use (menus and widgets +// have their own), made while the screen builds its GUI, before the GUI is drawn, so it holds the +// world or panorama alone, without the screen's own animated background blur. +// TODO: glass before 1.21.11 (#23). Those versions draw translucent panels without it. public final class GlassRenderer { public static final RenderPipeline PIPELINE = RenderPipeline.builder(RenderPipelines.POSITION_TEX_COLOR_SNIPPET) .withLocation(Identifier.of("saturnclient", "pipeline/glass")) @@ -30,23 +40,29 @@ public final class GlassRenderer { .withSampler("Sampler1") .build(); - private static final Identifier BLUR = Identifier.ofVanilla("blur"); - // For the blur's intermediate target, freed once unused for a few frames + private static final Identifier BLUR = Identifier.ofVanilla("post_effect/blur.json"); + private static final ProjectionMatrix2 PROJECTION = new ProjectionMatrix2("saturn glass", 0.1f, 1000f, false); + // For the blurs' intermediate targets, freed once unused for a few frames private static final Pool POOL = new Pool(3); - private static SimpleFramebuffer backdrop; + // By blur strength. A blur that failed to load is kept as null, so it isn't retried every frame. + private static final Map BLURS = new HashMap<>(); + private static final Map BACKDROPS = new HashMap<>(); private GlassRenderer() { } - // Copies the main framebuffer and blurs the copy. Call once a frame, before drawing glass. - public static void captureBackdrop() { + // Copies the main framebuffer and blurs the copy by blur. Call once a frame for each blur, before + // drawing glass with it. + public static void captureBackdrop(int blur) { Framebuffer main = SaturnClient.client.getFramebuffer(); int width = main.textureWidth; int height = main.textureHeight; + SimpleFramebuffer backdrop = BACKDROPS.get(blur); if (backdrop == null) { - backdrop = new SimpleFramebuffer("Saturn glass", width, height, false); + backdrop = new SimpleFramebuffer("Saturn glass " + blur, width, height, false); + BACKDROPS.put(blur, backdrop); } else if (backdrop.textureWidth != width || backdrop.textureHeight != height) { backdrop.resize(width, height); } @@ -54,18 +70,53 @@ public final class GlassRenderer { RenderSystem.getDevice().createCommandEncoder().copyTextureToTexture( main.getColorAttachment(), backdrop.getColorAttachment(), 0, 0, 0, 0, 0, width, height); - PostEffectProcessor blur = SaturnClient.client.getShaderLoader().loadPostEffect(BLUR, - DefaultFramebufferSet.MAIN_ONLY); - if (blur != null) { - blur.render(backdrop, POOL); + PostEffectProcessor processor = getBlur(blur); + if (processor != null) { + processor.render(backdrop, POOL); } POOL.decrementLifespan(); } - // The mask, then the blurred copy, as the glass pipeline samples them - public static TextureSetup textures(GpuTextureView mask, GpuSampler maskSampler) { - return TextureSetup.of(mask, maskSampler, backdrop.getColorAttachmentView(), + // The mask, then the copy blurred by blur, as the glass pipeline samples them + public static TextureSetup textures(GpuTextureView mask, GpuSampler maskSampler, int blur) { + return TextureSetup.of(mask, maskSampler, BACKDROPS.get(blur).getColorAttachmentView(), RenderSystem.getSamplerCache().get(FilterMode.LINEAR)); } + + private static PostEffectProcessor getBlur(int blur) { + if (!BLURS.containsKey(blur)) { + BLURS.put(blur, loadBlur(blur)); + } + return BLURS.get(blur); + } + + // Vanilla's blur, with its radius set to blur. Vanilla's own leaves it at 0, which makes the shader + // read the menu blur setting (Saturn's animated background blur while a Saturn screen is open). + private static PostEffectProcessor loadBlur(int blur) { + try (Reader reader = SaturnClient.client.getResourceManager().getResourceOrThrow(BLUR).getReader()) { + JsonElement json = JsonParser.parseReader(reader); + setRadius(json, blur); + + PostEffectPipeline pipeline = PostEffectPipeline.CODEC.parse(JsonOps.INSTANCE, json).getOrThrow(); + return PostEffectProcessor.parseEffect(pipeline, SaturnClient.client.getTextureManager(), + DefaultFramebufferSet.MAIN_ONLY, Identifier.of("saturnclient", "glass_blur_" + blur), PROJECTION); + } catch (Exception e) { + SaturnClient.LOGGER.error("Couldn't load the glass blur", e); + return null; + } + } + + // Sets every "Radius" uniform in the effect + private static void setRadius(JsonElement json, int radius) { + if (json.isJsonArray()) { + json.getAsJsonArray().forEach(element -> setRadius(element, radius)); + } else if (json.isJsonObject()) { + JsonObject object = json.getAsJsonObject(); + if (object.has("name") && object.get("name").getAsString().equals("Radius")) { + object.addProperty("value", (float) radius); + } + object.entrySet().forEach(entry -> setRadius(entry.getValue(), radius)); + } + } } //?} diff --git a/src/main/java/org/saturnclient/impl/ui/RenderScopeImpl.java b/src/main/java/org/saturnclient/impl/ui/RenderScopeImpl.java index 5c8b123..d9004bc 100644 --- a/src/main/java/org/saturnclient/impl/ui/RenderScopeImpl.java +++ b/src/main/java/org/saturnclient/impl/ui/RenderScopeImpl.java @@ -5,7 +5,9 @@ package org.saturnclient.impl.ui; //? if >=1.21.6 { import java.util.ArrayDeque; import java.util.Deque; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; import org.jetbrains.annotations.Nullable; import org.joml.Matrix3x2f; @@ -62,8 +64,8 @@ public class RenderScopeImpl implements RenderScope { private ScissorStack scissorStack; private int opacity = 0xFF << 24; //? if >=1.21.11 { - // Whether the glass backdrop was made for this scope's frame - private boolean backdropCaptured = false; + // The glass blurs made for this scope's frame + private final Set capturedBlurs = new HashSet<>(); //?} public RenderScopeImpl(DrawContext context) { @@ -236,20 +238,19 @@ public class RenderScopeImpl implements RenderScope { //? if >=1.21.11 { @Override - public void drawGlass(IdentifierRef mask, int x, int y, int width, int height) { + public void drawGlass(IdentifierRef mask, int x, int y, int width, int height, int blur) { int color = getColor(0xFFFFFFFF); if (mask == null || color >>> 24 == 0) return; - if (!backdropCaptured) { - GlassRenderer.captureBackdrop(); - backdropCaptured = true; + if (capturedBlurs.add(blur)) { + GlassRenderer.captureBackdrop(blur); } AbstractTexture maskTexture = SaturnClient.client.getTextureManager().getTexture((Identifier) (Object) mask); this.state.addSimpleElement(new TexturedQuadGuiElementRenderState( GlassRenderer.PIPELINE, - GlassRenderer.textures(maskTexture.getGlTextureView(), maskTexture.getSampler()), + GlassRenderer.textures(maskTexture.getGlTextureView(), maskTexture.getSampler(), blur), new Matrix3x2f(this.matrices.stack), x, y, x + width, y + height, 0, 1, 0, 1, color, this.scissorStack.peekLast()));