Compare commits

...
1 Commits
Author SHA1 Message Date
selimaj-devandclaude 7bc308155e Split the blur into world, menu and widget blurs
The world or panorama keeps its animated background blur, while glass
behind menus and behind widgets (buttons, the dock, the account chip)
each get a fixed blur of their own. Glass is left out when its blur is 0.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 21:35:23 +02:00
10 changed files with 45 additions and 43 deletions
@@ -28,12 +28,6 @@ public interface SaturnProvider {
*/ */
public IdentifierRef getPlayerSkin(); public IdentifierRef getPlayerSkin();
/**
* Whether this version draws glass (the blurred game behind translucent
* panels), so screens needn't blur the whole background.
*/
public boolean supportsGlass();
/** Shows a warning toast. Safe to call from any thread. */ /** Shows a warning toast. Safe to call from any thread. */
public void showWarning(String title, String message); public void showWarning(String title, String message);
} }
@@ -19,7 +19,11 @@ public class Config {
public static BoolProperty saturnTitleScreen = Property.bool(true); public static BoolProperty saturnTitleScreen = Property.bool(true);
public static BoolProperty cloakPhysics = Property.bool(true); public static BoolProperty cloakPhysics = Property.bool(true);
public static BoolProperty stagger = Property.bool(true); public static BoolProperty stagger = Property.bool(true);
/** The world or panorama behind Saturn's screens, faded in as they open */
public static IntProperty backgroundBlur = Property.integer(5).range(0, 10); public static IntProperty backgroundBlur = Property.integer(5).range(0, 10);
/** Glass behind translucent menus (panels), and widgets (buttons, the dock) */
public static IntProperty menuBlur = Property.integer(8).range(0, 20);
public static IntProperty widgetBlur = Property.integer(6).range(0, 20);
// How big Saturn's screens are, relative to Minecraft's GUI scale // How big Saturn's screens are, relative to Minecraft's GUI scale
public static FloatProperty titleScale = guiScale(); public static FloatProperty titleScale = guiScale();
public static FloatProperty menuScale = guiScale(); public static FloatProperty menuScale = guiScale();
@@ -43,7 +47,9 @@ public class Config {
config.property("Open Emote Wheel", openEmoteWheel, "The key that opens the emote wheel"); config.property("Open Emote Wheel", openEmoteWheel, "The key that opens the emote wheel");
config.property("Cloak Physics", cloakPhysics, "Let cloaks swing as you move"); config.property("Cloak Physics", cloakPhysics, "Let cloaks swing as you move");
config.property("Stagger Animations", stagger, "Animate list items one after another"); config.property("Stagger Animations", stagger, "Animate list items one after another");
config.property("Background blur", backgroundBlur, "How much the game behind Saturn's screens is blurred"); config.property("World blur", backgroundBlur, "How much the world or panorama behind Saturn's screens is blurred");
config.property("Menu blur", menuBlur, "How much the game is blurred through translucent menus");
config.property("Widget blur", widgetBlur, "How much the game is blurred through translucent buttons and the dock");
config.property("Title screen scale", titleScale, "How big the title screen is, relative to Minecraft's GUI scale"); config.property("Title screen scale", titleScale, "How big the title screen is, relative to Minecraft's GUI scale");
config.property("Menu scale", menuScale, "How big the mods, settings and cosmetics menus are, relative to Minecraft's GUI scale"); config.property("Menu scale", menuScale, "How big the mods, settings and cosmetics menus are, relative to Minecraft's GUI scale");
config.property("HUD menu scale", hudMenuScale, "How big the emote wheel and shift menu are, relative to Minecraft's GUI scale"); config.property("HUD menu scale", hudMenuScale, "How big the emote wheel and shift menu are, relative to Minecraft's GUI scale");
@@ -1,6 +1,5 @@
package org.saturnclient.ui; package org.saturnclient.ui;
import org.saturnclient.common.provider.Providers;
import org.saturnclient.ui.components.Sidebar; import org.saturnclient.ui.components.Sidebar;
import org.saturnclient.ui.elements.ImageTexture; import org.saturnclient.ui.elements.ImageTexture;
import org.saturnclient.ui.elements.Panel; import org.saturnclient.ui.elements.Panel;
@@ -39,9 +38,6 @@ public abstract class PanelScreen extends SaturnScreen {
@Override @Override
public final void ui() { public final void ui() {
// The panels are frosted themselves, so the rest of the game stays clear.
blurBackground = !Providers.saturn.supportsGlass();
panelWidth = Math.min(MAX_WIDTH, width - MARGIN * 2 - Sidebar.WIDTH - GAP); panelWidth = Math.min(MAX_WIDTH, width - MARGIN * 2 - Sidebar.WIDTH - GAP);
panelHeight = Math.min(MAX_HEIGHT, height - MARGIN * 2); panelHeight = Math.min(MAX_HEIGHT, height - MARGIN * 2);
@@ -55,19 +55,33 @@ public interface RenderScope {
/** /**
* Frosts a rounded rectangle for a translucent background to be drawn over: * Frosts a rounded rectangle for a translucent background to be drawn over:
* the game behind the screen, blurred, cut to exactly the shape * the game behind the screen, blurred by {@code blur}, cut to exactly the
* {@link #drawRoundedRectangle} draws. Draws nothing on versions without * shape {@link #drawRoundedRectangle} draws. Draws nothing on versions
* glass. * without glass.
*/ */
default void drawGlass(int x, int y, int width, int height, int radius) { default void drawGlass(int x, int y, int width, int height, int radius, int blur) {
drawGlass(getRoundedRectangle(width, height, radius), x, y, width, height); drawGlass(getRoundedRectangle(width, height, radius), x, y, width, height, blur);
} }
/** /**
* Draws the blurred game behind the screen where {@code mask}, stretched * Draws the game behind the screen, blurred by {@code blur}, where
* over the area, is opaque. * {@code mask}, stretched over the area, is opaque.
*/ */
default void drawGlass(IdentifierRef mask, int x, int y, int width, int height) { default void drawGlass(IdentifierRef mask, int x, int y, int width, int height, int blur) {
}
/**
* A {@link #drawRoundedRectangle} with a border, frosted with glass blurred
* by {@code blur} when the background isn't solid. A blur of 0 leaves it
* plain, showing the screen's own background blur.
*/
default void drawGlassRectangle(int x, int y, int width, int height, int radius, int blur, int thickness,
int background, int border) {
if (blur > 0 && background >>> 24 < 0xFF) {
drawGlass(x, y, width, height, radius, blur);
}
drawRoundedRectangle(x, y, width, height, radius, thickness, background, border);
} }
/** /**
@@ -46,11 +46,11 @@ public abstract class SaturnScreen {
} }
/** /**
* How much to blur the game behind this screen and its glass right now: the * How much to blur the game behind this screen right now: the client's
* client's setting, faded in over the screen's first moments. * setting, faded in over the screen's first moments.
*/ */
public int getBlurRadius() { public int getBackgroundBlur() {
if (start == null) { if (!blurBackground || start == null) {
return 0; return 0;
} }
@@ -58,14 +58,6 @@ public abstract class SaturnScreen {
return Math.round(Config.backgroundBlur.value * Math.min(elapsed / (float) BLUR_FADE_IN, 1f)); return Math.round(Config.backgroundBlur.value * Math.min(elapsed / (float) BLUR_FADE_IN, 1f));
} }
/**
* How much to blur the whole game behind this screen right now, or 0 when it
* isn't.
*/
public int getBackgroundBlur() {
return blurBackground ? getBlurRadius() : 0;
}
/** /**
* The GUI scale setting this screen follows; the menu scale unless the * The GUI scale setting this screen follows; the menu scale unless the
* screen is another kind. * screen is another kind.
@@ -3,6 +3,7 @@ package org.saturnclient.ui.components;
import org.saturnclient.client.ServiceClient; import org.saturnclient.client.ServiceClient;
import org.saturnclient.common.provider.Providers; import org.saturnclient.common.provider.Providers;
import org.saturnclient.common.ref.asset.IdentifierRef; import org.saturnclient.common.ref.asset.IdentifierRef;
import org.saturnclient.config.Config;
import org.saturnclient.config.Theme; import org.saturnclient.config.Theme;
import org.saturnclient.ui.Element; import org.saturnclient.ui.Element;
import org.saturnclient.ui.ElementContext; import org.saturnclient.ui.ElementContext;
@@ -36,8 +37,8 @@ public class AccountChip extends Element {
@Override @Override
public void render(RenderScope renderScope, ElementContext ctx) { public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1, Theme.getPanelBg(), renderScope.drawGlassRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, Config.widgetBlur.value, 1,
Theme.getBorder()); Theme.getPanelBg(), Theme.getBorder());
// The face, then the hat layer over it, from the 64x64 skin // The face, then the hat layer over it, from the 64x64 skin
IdentifierRef skin = Providers.saturn.getPlayerSkin(); IdentifierRef skin = Providers.saturn.getPlayerSkin();
@@ -3,6 +3,7 @@ package org.saturnclient.ui.components;
import java.util.List; import java.util.List;
import org.saturnclient.common.ref.asset.IdentifierRef; import org.saturnclient.common.ref.asset.IdentifierRef;
import org.saturnclient.config.Config;
import org.saturnclient.config.Theme; import org.saturnclient.config.Theme;
import org.saturnclient.ui.Element; import org.saturnclient.ui.Element;
import org.saturnclient.ui.ElementContext; import org.saturnclient.ui.ElementContext;
@@ -32,7 +33,8 @@ public class Dock extends Element {
@Override @Override
public void render(RenderScope renderScope, ElementContext ctx) { public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value + 4, 1, Theme.getPanelBg(), renderScope.drawGlassRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value + 4, Config.widgetBlur.value, 1,
Theme.getPanelBg(),
Theme.withAlpha(0.1f, Theme.FOREGROUND.value)); Theme.withAlpha(0.1f, Theme.FOREGROUND.value));
for (int i = 0; i < items.size(); i++) { for (int i = 0; i < items.size(); i++) {
@@ -1,5 +1,6 @@
package org.saturnclient.ui.elements; package org.saturnclient.ui.elements;
import org.saturnclient.config.Config;
import org.saturnclient.config.Theme; import org.saturnclient.config.Theme;
import org.saturnclient.ui.Element; import org.saturnclient.ui.Element;
import org.saturnclient.ui.ElementContext; import org.saturnclient.ui.ElementContext;
@@ -38,7 +39,7 @@ public class Button extends Element {
* The button's surface, shared with {@link IconButton}. * The button's surface, shared with {@link IconButton}.
*/ */
static void drawSurface(RenderScope renderScope, int width, int height, boolean hovered) { static void drawSurface(RenderScope renderScope, int width, int height, boolean hovered) {
renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1, renderScope.drawGlassRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, Config.widgetBlur.value, 1,
hovered ? Theme.PRIMARY.value : Theme.getPanelBg(), hovered ? Theme.PRIMARY.value : Theme.getPanelBg(),
Theme.withAlpha(hovered ? 0.25f : 0.1f, Theme.FOREGROUND.value)); Theme.withAlpha(hovered ? 0.25f : 0.1f, Theme.FOREGROUND.value));
} }
@@ -1,5 +1,6 @@
package org.saturnclient.ui.elements; package org.saturnclient.ui.elements;
import org.saturnclient.config.Config;
import org.saturnclient.config.Theme; import org.saturnclient.config.Theme;
import org.saturnclient.ui.Element; import org.saturnclient.ui.Element;
import org.saturnclient.ui.ElementContext; import org.saturnclient.ui.ElementContext;
@@ -17,12 +18,7 @@ public class Panel extends Element {
} }
public static void drawBackground(RenderScope renderScope, int width, int height) { public static void drawBackground(RenderScope renderScope, int width, int height) {
// Frosted behind a background that isn't solid renderScope.drawGlassRectangle(0, 0, width, height, Theme.BG_RADIUS.value, Config.menuBlur.value, 1,
if (Theme.getPanelBg() >>> 24 < 0xFF) {
renderScope.drawGlass(0, 0, width, height, Theme.BG_RADIUS.value);
}
renderScope.drawRoundedRectangle(0, 0, width, height, Theme.BG_RADIUS.value, 1,
Theme.getPanelBg(), Theme.getBorder()); Theme.getPanelBg(), Theme.getBorder());
} }
} }
@@ -131,8 +131,8 @@ public class EmoteWheel extends SaturnScreen {
@Override @Override
public void render(RenderScope renderScope, ElementContext ctx) { public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1, renderScope.drawGlassRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, Config.widgetBlur.value,
Theme.getPanelBg(), Theme.getBorder()); 1, Theme.getPanelBg(), Theme.getBorder());
float titleScale = 0.54f; float titleScale = 0.54f;
drawCentered(renderScope, "EMOTES", titleScale, pages > 1 ? 24 : (height - 10) / 2, Theme.getMutedFg()); drawCentered(renderScope, "EMOTES", titleScale, pages > 1 ? 24 : (height - 10) / 2, Theme.getMutedFg());