diff --git a/gradle.properties b/gradle.properties index c073e24..c252235 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ loader_version=0.16.14 loom_version=1.11-SNAPSHOT # Mod Properties -mod_version=1.0.1 +mod_version=1.1.0 maven_group=restudio.reglass archives_base_name=reglass diff --git a/src/main/java/restudio/reglass/client/LiquidGlassUniforms.java b/src/main/java/restudio/reglass/client/LiquidGlassUniforms.java index 176e981..916e8a5 100644 --- a/src/main/java/restudio/reglass/client/LiquidGlassUniforms.java +++ b/src/main/java/restudio/reglass/client/LiquidGlassUniforms.java @@ -41,6 +41,14 @@ public final class LiquidGlassUniforms { private List usedBlurRadiiOrdered = new ArrayList<>(); private final HashMap blurRadiusToIndex = new HashMap<>(); + private static final class FadeState { + float hover; + float focus; + } + + private final HashMap fades = new HashMap<>(); + private double dtSeconds = 0.0; + private LiquidGlassUniforms() { samplerInfo = RenderSystem.getDevice().createBuffer(() -> "reglass SamplerInfo", 130, 16); @@ -57,6 +65,11 @@ private LiquidGlassUniforms() { calc.putFloat(); calc.putFloat(); calc.putFloat(); + calc.putFloat(); + calc.putFloat(); + calc.putFloat(); + calc.putFloat(); + calc.putFloat(); int customUniformsSize = calc.get(); customUniforms = RenderSystem.getDevice().createBuffer(() -> "reglass CustomUniforms", 130, customUniformsSize); @@ -71,11 +84,12 @@ private LiquidGlassUniforms() { bgConfig = RenderSystem.getDevice().createBuffer(() -> "reglass BgConfig", 130, bgConfigSize); } - public void beginFrame() { + public void beginFrame(double dtSeconds) { widgets.clear(); screenWantsBlur = false; usedBlurRadiiOrdered.clear(); blurRadiusToIndex.clear(); + this.dtSeconds = Math.max(0.0, dtSeconds); } public void setScreenWantsBlur(boolean wantsBlur) { this.screenWantsBlur = wantsBlur; } @@ -118,6 +132,11 @@ public void uploadSharedUniforms() { b.putFloat(ReGlassAnim.INSTANCE.debugStep()); b.putFloat(config.features.pixelatedGrid ? 1.0f : 0.0f); b.putFloat(ReGlassAnim.INSTANCE.pixelatedGridSize()); + b.putFloat(ReGlassAnim.INSTANCE.hoverScalePx()); + b.putFloat(ReGlassAnim.INSTANCE.focusScalePx()); + b.putFloat(ReGlassAnim.INSTANCE.focusBorderWidthPx()); + b.putFloat(ReGlassAnim.INSTANCE.focusBorderIntensity()); + b.putFloat(ReGlassAnim.INSTANCE.focusBorderSpeed()); } try (var map = RenderSystem.getDevice().createCommandEncoder().mapBuffer(bgConfig, false, true)) { @@ -140,6 +159,23 @@ public void addWidget(LiquidGlassGuiElementRenderState element) { widgets.add(element); } + private static long rectKey(int x1, int y1, int x2, int y2) { + long a = (((long) x1) & 0xFFFFFFFFL) | ((((long) y1) & 0xFFFFFFFFL) << 32); + long b = (((long) x2) & 0xFFFFFFFFL) | ((((long) y2) & 0xFFFFFFFFL) << 32); + long h = 1469598103934665603L; + h ^= a; h *= 1099511628211L; + h ^= b; h *= 1099511628211L; + return h; + } + + private float smoothToward(float current, float target, double dt, float tau) { + if (tau <= 1e-5f) return target; + float a = (float) (1.0 - Math.exp(-Math.max(0.0, dt) / Math.max(1e-4, tau))); + float v = current + (target - current) * a; + if (Math.abs(v - target) < 1e-4f) return target; + return v; + } + public void uploadWidgetInfo() { MinecraftClient mc = MinecraftClient.getInstance(); int fbH = mc.getFramebuffer().textureHeight; @@ -259,7 +295,14 @@ public void uploadWidgetInfo() { int radius = Math.max(0, s.getBlurRadius()); Integer idx = blurRadiusToIndex.get(radius); if (idx == null) idx = 0; - b.putVec4((float) idx, 0f, 0f, 0f); + var w = widgets.get(i); + long key = rectKey(w.x1(), w.y1(), w.x2(), w.y2()); + FadeState fs = fades.computeIfAbsent(key, k -> new FadeState()); + fs.hover = smoothToward(fs.hover, Math.max(0f, Math.min(1f, w.hover())), dtSeconds, 0.12f); + fs.focus = smoothToward(fs.focus, Math.max(0f, Math.min(1f, w.focus())), dtSeconds, 0.18f); + double h = Math.sin(w.x1() * 12.9898 + w.y1() * 78.233 + i * 37.719); + float seed = (float) (h - Math.floor(h)); + b.putVec4((float) idx, fs.hover, fs.focus, seed); } else b.putVec4(0f, 0f, 0f, 0f); } } diff --git a/src/main/java/restudio/reglass/client/api/ReGlassApi.java b/src/main/java/restudio/reglass/client/api/ReGlassApi.java index e385326..1060bc8 100644 --- a/src/main/java/restudio/reglass/client/api/ReGlassApi.java +++ b/src/main/java/restudio/reglass/client/api/ReGlassApi.java @@ -27,6 +27,8 @@ public static class Builder { private float cornerRadius = -1f; @Nullable private Text text = null; private WidgetStyle style = new WidgetStyle(); + private float hoverAmount = 0f; + private float focusAmount = 0f; private Builder(DrawContext context) { this.context = context; @@ -70,11 +72,31 @@ public Builder style(WidgetStyle style) { return this; } + public Builder hover(float amount) { + if (Float.isNaN(amount)) amount = 0f; + this.hoverAmount = Math.max(0f, Math.min(1f, amount)); + return this; + } + + public Builder focus(float amount) { + if (Float.isNaN(amount)) amount = 0f; + this.focusAmount = Math.max(0f, Math.min(1f, amount)); + return this; + } + + public Builder selected(float amount) { + return this.focus(amount); + } + public void render() { float finalCornerRadius = this.cornerRadius < 0 ? 0.5f * Math.min(this.width, this.height) : this.cornerRadius; Matrix3x2f pose = new Matrix3x2f(context.getMatrices()); ScreenRect scissorRect = ((DrawContextAccessor) context).getScissorStack().peekLast(); - context.state.addSpecialElement(new LiquidGlassGuiElementRenderState(this.x, this.y, this.x + this.width, this.y + this.height, finalCornerRadius, this.text, this.style, pose, scissorRect)); + context.state.addSpecialElement(new LiquidGlassGuiElementRenderState( + this.x, this.y, this.x + this.width, this.y + this.height, + finalCornerRadius, this.text, this.style, pose, scissorRect, + this.hoverAmount, this.focusAmount + )); } } } \ No newline at end of file diff --git a/src/main/java/restudio/reglass/client/api/ReGlassConfig.java b/src/main/java/restudio/reglass/client/api/ReGlassConfig.java index d5e3bf0..991f50c 100644 --- a/src/main/java/restudio/reglass/client/api/ReGlassConfig.java +++ b/src/main/java/restudio/reglass/client/api/ReGlassConfig.java @@ -45,6 +45,12 @@ public class ReGlassConfig { public float debugStep = 9.0f; public float pixelatedGridSize = 8.0f; + public float hoverScalePx = 1.5f; + public float focusScalePx = 2.5f; + public float focusBorderWidthPx = 2.0f; + public float focusBorderIntensity = 0.75f; + public float focusBorderSpeed = 1.6f; + private ReGlassConfig() {} public static class Features { diff --git a/src/main/java/restudio/reglass/client/config/ReGlassSettingsIO.java b/src/main/java/restudio/reglass/client/config/ReGlassSettingsIO.java index 2e92672..9c976f5 100644 --- a/src/main/java/restudio/reglass/client/config/ReGlassSettingsIO.java +++ b/src/main/java/restudio/reglass/client/config/ReGlassSettingsIO.java @@ -81,6 +81,12 @@ private static Data snapshot() { d.pixelatedGridSize = c.pixelatedGridSize; + d.hoverScalePx = c.hoverScalePx; + d.focusScalePx = c.focusScalePx; + d.focusBorderWidthPx = c.focusBorderWidthPx; + d.focusBorderIntensity = c.focusBorderIntensity; + d.focusBorderSpeed = c.focusBorderSpeed; + return d; } @@ -121,6 +127,12 @@ public static void apply(Data d) { c.defaultGlareAngleRad = d.glareAngleRad; c.pixelatedGridSize = d.pixelatedGridSize; + + c.hoverScalePx = d.hoverScalePx; + c.focusScalePx = d.focusScalePx; + c.focusBorderWidthPx = d.focusBorderWidthPx; + c.focusBorderIntensity = d.focusBorderIntensity; + c.focusBorderSpeed = d.focusBorderSpeed; } public static class Data { @@ -158,5 +170,11 @@ public static class Data { public float glareAngleRad = (float) (-45.0 * Math.PI / 180.0); public float pixelatedGridSize = 8.0f; + + public float hoverScalePx = 1.5f; + public float focusScalePx = 2.5f; + public float focusBorderWidthPx = 2.0f; + public float focusBorderIntensity = 0.75f; + public float focusBorderSpeed = 1.6f; } } \ No newline at end of file diff --git a/src/main/java/restudio/reglass/client/gui/LiquidGlassGuiElementRenderState.java b/src/main/java/restudio/reglass/client/gui/LiquidGlassGuiElementRenderState.java index 925f2c8..8f09641 100644 --- a/src/main/java/restudio/reglass/client/gui/LiquidGlassGuiElementRenderState.java +++ b/src/main/java/restudio/reglass/client/gui/LiquidGlassGuiElementRenderState.java @@ -7,7 +7,7 @@ import org.joml.Matrix3x2f; import restudio.reglass.client.api.WidgetStyle; -public record LiquidGlassGuiElementRenderState(int x1, int y1, int x2, int y2, float cornerRadius, @Nullable Text text, WidgetStyle style, Matrix3x2f pose, @Nullable ScreenRect scissorArea) implements SpecialGuiElementRenderState { +public record LiquidGlassGuiElementRenderState(int x1, int y1, int x2, int y2, float cornerRadius, @Nullable Text text, WidgetStyle style, Matrix3x2f pose, @Nullable ScreenRect scissorArea, float hover, float focus) implements SpecialGuiElementRenderState { @Override public float scale() { diff --git a/src/main/java/restudio/reglass/client/runtime/ReGlassAnim.java b/src/main/java/restudio/reglass/client/runtime/ReGlassAnim.java index d853773..b8f231c 100644 --- a/src/main/java/restudio/reglass/client/runtime/ReGlassAnim.java +++ b/src/main/java/restudio/reglass/client/runtime/ReGlassAnim.java @@ -32,6 +32,12 @@ public final class ReGlassAnim { private float debugStep; private float pixelatedGridSize; + private float hoverScalePx; + private float focusScalePx; + private float focusBorderWidthPx; + private float focusBorderIntensity; + private float focusBorderSpeed; + private ReGlassAnim() {} public void update(ReGlassConfig cfg, double dtSeconds) { @@ -59,6 +65,11 @@ public void update(ReGlassConfig cfg, double dtSeconds) { glareAngleRad = cfg.defaultGlareAngleRad; debugStep = cfg.debugStep; pixelatedGridSize = cfg.pixelatedGridSize; + hoverScalePx = cfg.hoverScalePx; + focusScalePx = cfg.focusScalePx; + focusBorderWidthPx = cfg.focusBorderWidthPx; + focusBorderIntensity = cfg.focusBorderIntensity; + focusBorderSpeed = cfg.focusBorderSpeed; init = true; return; } @@ -83,6 +94,11 @@ public void update(ReGlassConfig cfg, double dtSeconds) { glareAngleRad = lerp(glareAngleRad, cfg.defaultGlareAngleRad, a); debugStep = lerp(debugStep, cfg.debugStep, a); pixelatedGridSize = lerp(pixelatedGridSize, cfg.pixelatedGridSize, a); + hoverScalePx = lerp(hoverScalePx, cfg.hoverScalePx, a); + focusScalePx = lerp(focusScalePx, cfg.focusScalePx, a); + focusBorderWidthPx = lerp(focusBorderWidthPx, cfg.focusBorderWidthPx, a); + focusBorderIntensity = lerp(focusBorderIntensity, cfg.focusBorderIntensity, a); + focusBorderSpeed = lerp(focusBorderSpeed, cfg.focusBorderSpeed, a); } private static float alpha(double dt, float tau) { @@ -120,4 +136,10 @@ private static float lerp(float a, float b, float t) { public float debugStep() { return debugStep; } public float pixelatedGridSize() { return pixelatedGridSize; } + + public float hoverScalePx() { return hoverScalePx; } + public float focusScalePx() { return focusScalePx; } + public float focusBorderWidthPx() { return focusBorderWidthPx; } + public float focusBorderIntensity() { return focusBorderIntensity; } + public float focusBorderSpeed() { return focusBorderSpeed; } } \ No newline at end of file diff --git a/src/main/java/restudio/reglass/client/screen/config/ReGlassConfigScreen.java b/src/main/java/restudio/reglass/client/screen/config/ReGlassConfigScreen.java index 59999b7..1ec8504 100644 --- a/src/main/java/restudio/reglass/client/screen/config/ReGlassConfigScreen.java +++ b/src/main/java/restudio/reglass/client/screen/config/ReGlassConfigScreen.java @@ -126,6 +126,20 @@ protected void init() { addSlider(MappedSlider.floatSlider(widgetX, y, widgetWidth, widgetHeight, Text.literal("Glare Factor"), 0f, 100f, cfg.defaultGlareFactor, v -> cfg.defaultGlareFactor = v.floatValue()), y).active = cfg.features.enableRedesign; y += widgetHeight + gap * 2; + addTitle("Interactions", widgetX, y, widgetWidth); + y += widgetHeight; + + addSlider(MappedSlider.floatSlider(widgetX, y, widgetWidth, widgetHeight, Text.literal("Hover Scale (px)"), 0f, 6f, cfg.hoverScalePx, v -> cfg.hoverScalePx = v.floatValue()), y).active = cfg.features.enableRedesign; + y += widgetHeight + gap; + addSlider(MappedSlider.floatSlider(widgetX, y, widgetWidth, widgetHeight, Text.literal("Focus Scale (px)"), 0f, 8f, cfg.focusScalePx, v -> cfg.focusScalePx = v.floatValue()), y).active = cfg.features.enableRedesign; + y += widgetHeight + gap; + addSlider(MappedSlider.floatSlider(widgetX, y, widgetWidth, widgetHeight, Text.literal("Focus Border Width (px)"), 0f, 6f, cfg.focusBorderWidthPx, v -> cfg.focusBorderWidthPx = v.floatValue()), y).active = cfg.features.enableRedesign; + y += widgetHeight + gap; + addSlider(MappedSlider.floatSlider(widgetX, y, widgetWidth, widgetHeight, Text.literal("Focus Border Intensity"), 0f, 1f, cfg.focusBorderIntensity, v -> cfg.focusBorderIntensity = v.floatValue()), y).active = cfg.features.enableRedesign; + y += widgetHeight + gap; + addSlider(MappedSlider.floatSlider(widgetX, y, widgetWidth, widgetHeight, Text.literal("Focus Border Speed"), 0f, 4f, cfg.focusBorderSpeed, v -> cfg.focusBorderSpeed = v.floatValue()), y).active = cfg.features.enableRedesign; + y += widgetHeight + gap * 2; + addTitle("Debug", widgetX, y, widgetWidth); y += widgetHeight; @@ -250,7 +264,7 @@ public void renderWidget(DrawContext context, int mouseX, int mouseY, float delt public boolean isMouseOver(double mouseX, double mouseY) { return false; } - + @Override protected void appendClickableNarrations(NarrationMessageBuilder builder) {} } diff --git a/src/main/java/restudio/reglass/client/screen/widget/world/WorldListEntryWidget.java b/src/main/java/restudio/reglass/client/screen/widget/world/WorldListEntryWidget.java index c752fdd..debcd16 100644 --- a/src/main/java/restudio/reglass/client/screen/widget/world/WorldListEntryWidget.java +++ b/src/main/java/restudio/reglass/client/screen/widget/world/WorldListEntryWidget.java @@ -81,9 +81,10 @@ private void loadIcon() { public void render(DrawContext context, int index, int x, int y, int width, int height, int mouseX, int mouseY, boolean hovered, float delta) { super.render(context, index, x, y, width, height, mouseX, mouseY, hovered, delta); + boolean isSelected = this.parent.getList().getSelectedEntries().contains(this); WidgetStyle style = defaultStyle; - if (this.parent.getList().getSelectedEntries().contains(this)) { + if (isSelected) { style = selectedStyle; } else if (hovered) { style = hoveredStyle; @@ -93,6 +94,8 @@ public void render(DrawContext context, int index, int x, int y, int width, int .dimensions(x, y, width, height) .cornerRadius(8) .style(style) + .hover(hovered ? 1f : 0f) + .focus(isSelected ? 1f : 0f) .render(); String displayName = summary.getDisplayName(); @@ -137,4 +140,4 @@ public void close() { this.iconTexture = null; } } -} +} \ No newline at end of file diff --git a/src/main/java/restudio/reglass/extensions/PressableWidgetExtension.java b/src/main/java/restudio/reglass/extensions/PressableWidgetExtension.java new file mode 100644 index 0000000..3ae66f1 --- /dev/null +++ b/src/main/java/restudio/reglass/extensions/PressableWidgetExtension.java @@ -0,0 +1,10 @@ +package restudio.reglass.extensions; + +import org.spongepowered.asm.mixin.Unique; + +public interface PressableWidgetExtension { + @Unique + boolean reglass$isDragging(); + @Unique + void reglass$setIsDragging(boolean isDragging); +} diff --git a/src/main/java/restudio/reglass/mixin/client/InGameHudMixin.java b/src/main/java/restudio/reglass/mixin/client/InGameHudMixin.java index 0035e35..809e384 100644 --- a/src/main/java/restudio/reglass/mixin/client/InGameHudMixin.java +++ b/src/main/java/restudio/reglass/mixin/client/InGameHudMixin.java @@ -6,6 +6,7 @@ import net.minecraft.client.render.RenderTickCounter; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; +import net.minecraft.util.Arm; import net.minecraft.util.profiler.Profilers; import net.minecraft.world.GameMode; import org.spongepowered.asm.mixin.Final; @@ -66,11 +67,11 @@ protected abstract void renderHotbarItem( int hotbarWidth = 182; int hotbarHeight = 22; - int x = context.getScaledWindowWidth() / 2 - hotbarWidth / 2; - int y = context.getScaledWindowHeight() - hotbarHeight; + int x = this.client.getWindow().getScaledWidth() / 2 - hotbarWidth / 2; + int offhandY = this.client.getWindow().getScaledHeight() - hotbarHeight; ReGlassApi.create(context) - .dimensions(x, y, hotbarWidth, hotbarHeight) + .dimensions(x, offhandY, hotbarWidth, hotbarHeight) .cornerRadius(11) .style(new WidgetStyle().tint(0x000000, 0.3f)) .render(); @@ -102,14 +103,15 @@ protected abstract void renderHotbarItem( WidgetStyle selectorStyle = new WidgetStyle().smoothing(-0.005f); ReGlassApi.create(context) - .dimensions(circleX, y, hotbarHeight, hotbarHeight) + .dimensions(circleX, offhandY, hotbarHeight, hotbarHeight) .cornerRadius(0.5f * hotbarHeight) .style(selectorStyle) + .focus(1f) .render(); for (int i = 0; i < 9; ++i) { int itemX = x + 3 + i * 20; - int itemY = y + 3; + int itemY = offhandY + 3; this.renderHotbarItem( context, itemX, @@ -121,6 +123,20 @@ protected abstract void renderHotbarItem( ); } + ItemStack offHandStack = player.getOffHandStack(); + if (!offHandStack.isEmpty()) { + Arm arm = player.getMainArm().getOpposite(); + int offhandX = (arm == Arm.LEFT ? x - hotbarHeight - 4 : x + hotbarWidth + 4); + + ReGlassApi.create(context) + .dimensions(offhandX, offhandY, hotbarHeight, hotbarHeight) + .cornerRadius(hotbarHeight * 0.5f) + .style(new WidgetStyle().tint(0x000000, 0.3f)) + .render(); + + this.renderHotbarItem(context, offhandX + 3, offhandY + 3, tickCounter, player, offHandStack, 0); + } + LiquidGlassUniforms.get().tryApplyBlur(context); Profilers.get().pop(); diff --git a/src/main/java/restudio/reglass/mixin/client/ScreenMixin.java b/src/main/java/restudio/reglass/mixin/client/ScreenMixin.java index 9b69352..2272961 100644 --- a/src/main/java/restudio/reglass/mixin/client/ScreenMixin.java +++ b/src/main/java/restudio/reglass/mixin/client/ScreenMixin.java @@ -3,13 +3,10 @@ import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.render.state.GuiRenderState; import net.minecraft.client.gui.screen.Screen; -import org.lwjgl.glfw.GLFW; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import restudio.reglass.client.Config; import restudio.reglass.client.LiquidGlassUniforms; import restudio.reglass.client.api.ReGlassConfig; import restudio.reglass.mixin.accessor.GuiRenderStateAccessor; @@ -31,21 +28,6 @@ public class ScreenMixin { } } - @Inject( - method = "keyPressed", - at = @At("HEAD"), - cancellable = true - ) - private void onKeyPressed( - int keyCode, int scanCode, int modifiers, CallbackInfoReturnable cir - ) { - if (keyCode == GLFW.GLFW_KEY_V) { - Config.redesginMinecraft = !Config.redesginMinecraft; - ReGlassConfig.INSTANCE.features.enableRedesign = Config.redesginMinecraft; - cir.setReturnValue(true); - } - } - @Inject( method = "renderDarkening(Lnet/minecraft/client/gui/DrawContext;)V", at = @At("HEAD"), diff --git a/src/main/java/restudio/reglass/mixin/logical/GameRendererMixin.java b/src/main/java/restudio/reglass/mixin/logical/GameRendererMixin.java index 4b93966..33a2c21 100644 --- a/src/main/java/restudio/reglass/mixin/logical/GameRendererMixin.java +++ b/src/main/java/restudio/reglass/mixin/logical/GameRendererMixin.java @@ -30,7 +30,6 @@ public abstract class GameRendererMixin { @Inject(method = "render", at = @At("HEAD")) private void reglass$beginGuiFrame(RenderTickCounter tickCounter, boolean tick, CallbackInfo ci) { - LiquidGlassUniforms.get().beginFrame(); double deltaTicks; try { deltaTicks = tickCounter.getDynamicDeltaTicks(); @@ -38,6 +37,7 @@ public abstract class GameRendererMixin { deltaTicks = 1.0 / 60.0 * 20.0; } double dt = deltaTicks / 20.0; + LiquidGlassUniforms.get().beginFrame(dt); ReGlassAnim.INSTANCE.update(ReGlassConfig.INSTANCE, dt); } diff --git a/src/main/java/restudio/reglass/mixin/widgets/ClickableWidgetMixin.java b/src/main/java/restudio/reglass/mixin/widgets/ClickableWidgetMixin.java new file mode 100644 index 0000000..d9b0b1c --- /dev/null +++ b/src/main/java/restudio/reglass/mixin/widgets/ClickableWidgetMixin.java @@ -0,0 +1,52 @@ +package restudio.reglass.mixin.widgets; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.client.gui.widget.PressableWidget; +import net.minecraft.client.sound.SoundManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import restudio.reglass.extensions.PressableWidgetExtension; + +@Mixin(ClickableWidget.class) +public abstract class ClickableWidgetMixin { + @Shadow + public abstract void playDownSound(SoundManager soundManager); + + @Shadow + public abstract void onClick(double mouseX, double mouseY); + + @Redirect(method = "mouseClicked", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/ClickableWidget;playDownSound(Lnet/minecraft/client/sound/SoundManager;)V")) + private void redirectPlayDownSound(ClickableWidget instance, SoundManager soundManager) { + if ((Object) this instanceof PressableWidget) { + // Just play nothing. + return; + } + playDownSound(soundManager); + } + + @Redirect(method = "mouseClicked", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/ClickableWidget;onClick(DD)V")) + private void redirectOnClick(ClickableWidget instance, double mouseX, double mouseY) { + if ((Object) this instanceof PressableWidget) { + ((PressableWidgetExtension) this).reglass$setIsDragging(true); + // Just play nothing. + return; + } + onClick(mouseX, mouseY); + } + + @Inject(method = "mouseReleased", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/ClickableWidget;onRelease(DD)V")) + private void modifyOnRelease(double mouseX, double mouseY, int button, CallbackInfoReturnable cir) { + if ((Object) this instanceof PressableWidget pressableWidget) { + if (pressableWidget.isMouseOver(mouseX, mouseY)) { + pressableWidget.playDownSound(MinecraftClient.getInstance().getSoundManager()); + pressableWidget.onClick(mouseX, mouseY); + } + ((PressableWidgetExtension) pressableWidget).reglass$setIsDragging(false); + } + } +} diff --git a/src/main/java/restudio/reglass/mixin/widgets/DrawContextMixin.java b/src/main/java/restudio/reglass/mixin/widgets/DrawContextMixin.java deleted file mode 100644 index 9a2fc7b..0000000 --- a/src/main/java/restudio/reglass/mixin/widgets/DrawContextMixin.java +++ /dev/null @@ -1,36 +0,0 @@ -package restudio.reglass.mixin.widgets; - -import com.mojang.blaze3d.pipeline.RenderPipeline; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.util.Identifier; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import restudio.reglass.client.api.ReGlassApi; -import restudio.reglass.client.api.ReGlassConfig; - -@Mixin(DrawContext.class) -public abstract class DrawContextMixin { - - @Unique - private static final Identifier BUTTON_TEXTURE = Identifier.ofVanilla("widget/button"); - @Unique - private static final Identifier BUTTON_DISABLED_TEXTURE = Identifier.ofVanilla("widget/button_disabled"); - @Unique - private static final Identifier BUTTON_HIGHLIGHTED_TEXTURE = Identifier.ofVanilla("widget/button_highlighted"); - - @Inject(method = "drawGuiTexture(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/util/Identifier;IIIII)V", - at = @At("HEAD"), cancellable = true) - private void onDrawTexture(RenderPipeline pipeline, Identifier sprite, int x, int y, int width, int height, int color, CallbackInfo ci) { - boolean isButtonTexture = sprite.getPath().equals(BUTTON_TEXTURE.getPath()) - || sprite.getPath().equals(BUTTON_DISABLED_TEXTURE.getPath()) - || sprite.getPath().equals(BUTTON_HIGHLIGHTED_TEXTURE.getPath()); - - if (isButtonTexture && (ReGlassConfig.INSTANCE.features.enableRedesign && ReGlassConfig.INSTANCE.features.buttons)) { - ReGlassApi.create((DrawContext)(Object) this).position(x, y).size(width, height).render(); - ci.cancel(); - } - } -} \ No newline at end of file diff --git a/src/main/java/restudio/reglass/mixin/widgets/PressableWidgetMixin.java b/src/main/java/restudio/reglass/mixin/widgets/PressableWidgetMixin.java new file mode 100644 index 0000000..f5bc52f --- /dev/null +++ b/src/main/java/restudio/reglass/mixin/widgets/PressableWidgetMixin.java @@ -0,0 +1,68 @@ +package restudio.reglass.mixin.widgets; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.widget.PressableWidget; +import net.minecraft.util.math.ColorHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import restudio.reglass.client.LiquidGlassUniforms; +import restudio.reglass.client.api.ReGlassApi; +import restudio.reglass.client.api.ReGlassConfig; +import restudio.reglass.client.api.WidgetStyle; +import restudio.reglass.extensions.PressableWidgetExtension; + +@Mixin(PressableWidget.class) +public abstract class PressableWidgetMixin implements PressableWidgetExtension { + @Unique + private boolean reglass$isDragging; + @Shadow + public abstract void drawMessage(DrawContext context, TextRenderer textRenderer, int color); + + @Inject(method = "renderWidget", at = @At("HEAD"), cancellable = true) + private void modifyRenderWidget(DrawContext context, int mouseX, int mouseY, float deltaTicks, CallbackInfo ci) { + if ((Object) this instanceof PressableWidget pressableWidget) { + if (!ReGlassConfig.INSTANCE.features.enableRedesign || !ReGlassConfig.INSTANCE.features.buttons) { + return; + } + + boolean isDisabled = !pressableWidget.active; + boolean isHighlighted = pressableWidget.isHovered(); + boolean isFocused = isHighlighted && reglass$isDragging; + + if (ReGlassConfig.INSTANCE.features.enableRedesign && ReGlassConfig.INSTANCE.features.buttons) { + ReGlassApi.create(context) + .position(pressableWidget.getX(), pressableWidget.getY()) + .size(pressableWidget.getWidth(), pressableWidget.getHeight()) + .hover(isHighlighted ? 1f : 0f) + .focus(isFocused ? 1.0f : 0.0f) + .style(WidgetStyle.create().tint(isDisabled ? 0xFF000000 : 0xFFFFFFFF, isDisabled ? 0.4f : 0f)) + .render(); + + LiquidGlassUniforms.get().tryApplyBlur(context); + + TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; + int i = ColorHelper.withAlpha(1.0f, pressableWidget.active ? -1 : -6250336); + drawMessage(context, textRenderer, i); + // context.drawCenteredTextWithShadow(textRenderer, buttonWidget.getMessage(), buttonWidget.getX() + buttonWidget.getWidth() / 2, buttonWidget.getY() + (buttonWidget.getHeight() - 8) / 2, finalColor); + + ci.cancel(); + } + } + } + + @Override + public void reglass$setIsDragging(boolean isDragging) { + this.reglass$isDragging = isDragging; + } + + @Override + public boolean reglass$isDragging() { + return reglass$isDragging; + } +} diff --git a/src/main/java/restudio/reglass/mixin/widgets/SliderWidgetMixin.java b/src/main/java/restudio/reglass/mixin/widgets/SliderWidgetMixin.java index f719b87..b8b7ee6 100644 --- a/src/main/java/restudio/reglass/mixin/widgets/SliderWidgetMixin.java +++ b/src/main/java/restudio/reglass/mixin/widgets/SliderWidgetMixin.java @@ -37,12 +37,17 @@ private void onRenderWidget(DrawContext context, int mouseX, int mouseY, float d ci.cancel(); int knobX = (int) (this.getX() + (((SliderWidgetAccessor) this).getValue() * (this.getWidth() - 4))); + boolean hoveredBg = this.isMouseOver(mouseX, mouseY); + boolean knobHovered = mouseX >= knobX && mouseX < knobX + 4 && mouseY >= getY() && mouseY < getY() + getHeight(); + boolean focus = this.isFocused(); - ReGlassApi.create(context).fromWidget(this).render(); + ReGlassApi.create(context).fromWidget(this).hover(hoveredBg ? 1f : 0f).focus(focus ? 1f : 0f).render(); ReGlassApi.create(context) .size(4, getHeight()) .position(knobX, getY()) .style(knobStyle) + .hover(knobHovered ? 1f : 0f) + .focus(focus ? 1f : 0f) .render(); LiquidGlassUniforms.get().tryApplyBlur(context); diff --git a/src/main/resources/assets/reglass/shaders/program/liquid_glass_gui.fsh b/src/main/resources/assets/reglass/shaders/program/liquid_glass_gui.fsh index f66d538..db90f3a 100644 --- a/src/main/resources/assets/reglass/shaders/program/liquid_glass_gui.fsh +++ b/src/main/resources/assets/reglass/shaders/program/liquid_glass_gui.fsh @@ -5,7 +5,12 @@ uniform sampler2D Sampler2; uniform sampler2D Sampler3; uniform sampler2D Sampler4; uniform sampler2D Sampler5; -layout(std140) uniform SamplerInfo { vec2 OutSize; vec2 InSize; }; + +layout(std140) uniform SamplerInfo { + vec2 OutSize; + vec2 InSize; +}; + layout(std140) uniform CustomUniforms { float Time; vec4 Mouse; @@ -16,7 +21,13 @@ layout(std140) uniform CustomUniforms { float DebugStep; float Pixelated; float PixelGridSize; + float HoverScalePx; + float FocusScalePx; + float FocusBorderWidthPx; + float FocusBorderIntensity; + float FocusBorderSpeed; }; + #define MAX_WIDGETS 64 layout(std140) uniform WidgetInfo { float Count; @@ -32,24 +43,31 @@ layout(std140) uniform WidgetInfo { vec4 ShadowColor[MAX_WIDGETS]; vec4 Extra0[MAX_WIDGETS]; }; -layout(std140) uniform BgConfig { float ShadowExpand; float ShadowFactor; vec2 ShadowOffset; }; + +layout(std140) uniform BgConfig { + float ShadowExpand; + float ShadowFactor; + vec2 ShadowOffset; +}; + out vec4 fragColor; -#define PI 3.141592653589793 struct SDFResult { float dist; vec2 normal; float aspect; int index; }; -vec2 screenToUV(vec2 screen, vec2 res) { return (screen.xy - 0.5 * res.xy) / res.y; } +vec2 screenToUV(vec2 screen, vec2 res) { + return (screen.xy - 0.5 * res.xy) / res.y; +} vec3 sdgBox(in vec2 p, in vec2 b, vec4 ra) { ra.xy = (p.x > 0.0) ? ra.xy : ra.zw; float r = (p.y > 0.0) ? ra.x : ra.y; vec2 w = abs(p) - (b - r); - vec2 s = vec2(p.x < 0.0 ? -1 : 1, p.y < 0.0 ? -1 : 1); + vec2 s = vec2(p.x < 0.0 ? -1.0 : 1.0, p.y < 0.0 ? -1.0 : 1.0); float g = max(w.x, w.y); vec2 q = max(w, 0.0); float l = length(q); float dist = (g > 0.0) ? l - r : g - r; - vec2 n = (g > 0.0) ? (q / max(l, 1e-6)) : ((w.x > w.y) ? vec2(1, 0) : vec2(0, 1)); + vec2 n = (g > 0.0) ? (q / max(l, 1e-6)) : ((w.x > w.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0)); return vec3(dist, s * n); } @@ -82,24 +100,35 @@ vec4 sampleBlur(int idx, vec2 uv) { SDFResult fieldWidgets(vec2 p, vec2 inSize, vec2 fragCoord) { int n = int(Count + 0.5); if (n == 0) return SDFResult(1e6, vec2(0.0), 1.0, -1); + SDFResult pos = SDFResult(1e6, vec2(0.0), 1.0, -1); bool hasPos = false; for (int i = 0; i < MAX_WIDGETS; i++) { if (i >= n) break; if (Smoothings[i].x < 0.0) continue; + vec4 sc = ScissorRects[i]; if (fragCoord.x < sc.x || fragCoord.y < sc.y || fragCoord.x > sc.z || fragCoord.y > sc.w) continue; + vec4 rc = Rects[i]; vec4 rr = Rads[i]; vec2 cPx = vec2(rc.x + 0.5 * rc.z, rc.y + 0.5 * rc.w); vec2 c = screenToUV(cPx, inSize); vec2 b = 0.5 * vec2(rc.z, rc.w) / inSize.y; vec4 rad = rr / inSize.y; + vec3 g = sdgBox(p - c, b, rad); + + vec4 extra = Extra0[i]; + float scaleOff = (HoverScalePx * extra.y + FocusScalePx * extra.z) / inSize.y; + float dist = g.x - scaleOff; + float aspect = min(rc.z, rc.w) / max(rc.z, rc.w); - SDFResult s = SDFResult(g.x, g.yz, aspect, i); - if (!hasPos) { pos = s; hasPos = true; } else { pos = opSmoothUnion(pos, s, Smoothings[i].x); } + SDFResult s = SDFResult(dist, g.yz, aspect, i); + + if (!hasPos) { pos = s; hasPos = true; } + else { pos = opSmoothUnion(pos, s, Smoothings[i].x); } } SDFResult f = pos; @@ -107,17 +136,26 @@ SDFResult fieldWidgets(vec2 p, vec2 inSize, vec2 fragCoord) { for (int i = 0; i < MAX_WIDGETS; i++) { if (i >= n) break; if (Smoothings[i].x >= 0.0) continue; + vec4 sc = ScissorRects[i]; if (fragCoord.x < sc.x || fragCoord.y < sc.y || fragCoord.x > sc.z || fragCoord.y > sc.w) continue; + vec4 rc = Rects[i]; vec4 rr = Rads[i]; vec2 cPx = vec2(rc.x + 0.5 * rc.z, rc.y + 0.5 * rc.w); vec2 c = screenToUV(cPx, inSize); vec2 b = 0.5 * vec2(rc.z, rc.w) / inSize.y; vec4 rad = rr / inSize.y; + vec3 g = sdgBox(p - c, b, rad); + + vec4 extra = Extra0[i]; + float scaleOff = (HoverScalePx * extra.y + FocusScalePx * extra.z) / inSize.y; + float dist = g.x - scaleOff; + float aspect = min(rc.z, rc.w) / max(rc.z, rc.w); - SDFResult s = SDFResult(g.x, g.yz, aspect, i); + SDFResult s = SDFResult(dist, g.yz, aspect, i); + float repulsion = -Smoothings[i].x; SDFResult se = SDFResult(s.dist - repulsion, s.normal, s.aspect, s.index); f = opHardSubtract(f, se); @@ -127,33 +165,31 @@ SDFResult fieldWidgets(vec2 p, vec2 inSize, vec2 fragCoord) { return f; } -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0/3.0, 1.0/3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} -float vec2ToAngle(vec2 v) { float a = atan(v.y, v.x); if (a < 0.0) a += 2.0 * PI; return a; } -vec3 vec2ToRgb(vec2 v) { float hue = vec2ToAngle(normalize(v)) / (2.0 * PI); return hsv2rgb(vec3(hue, 1.0, 1.0)); } - void main() { - vec2 inSize = InSize; if (inSize.x <= 0.0 || inSize.y <= 0.0) inSize = vec2(textureSize(Sampler0, 0)); - vec2 original_coord = gl_FragCoord.xy; - vec2 original_UV = original_coord / inSize; - vec3 base = texture(Sampler0, original_UV).rgb; + vec2 inSize = InSize; + if (inSize.x <= 0.0 || inSize.y <= 0.0) inSize = vec2(textureSize(Sampler0, 0)); + + vec2 coord = gl_FragCoord.xy; + vec2 uv = coord / inSize; + vec3 base = texture(Sampler0, uv).rgb; vec3 baseShadowed = base; int n = int(Count + 0.5); for (int i = 0; i < MAX_WIDGETS; i++) { if (i >= n) break; + vec4 sc = ScissorRects[i]; - if (original_coord.x < sc.x || original_coord.y < sc.y || original_coord.x > sc.z || original_coord.y > sc.w) continue; + if (coord.x < sc.x || coord.y < sc.y || coord.x > sc.z || coord.y > sc.w) continue; + vec4 rc = Rects[i]; vec4 rr = Rads[i]; vec2 cPx = vec2(rc.x + 0.5 * rc.z, rc.y + 0.5 * rc.w); - vec2 pShadow = screenToUV(original_coord + Shadow0[i].zw, inSize); + + vec2 pShadow = screenToUV(coord + Shadow0[i].zw, inSize); vec2 c = screenToUV(cPx, inSize); vec2 b = 0.5 * vec2(rc.z, rc.w) / inSize.y; vec4 rad = rr / inSize.y; + vec3 g = sdgBox(pShadow - c, b, rad); float expand = max(Shadow0[i].x, 1e-4); float factor = Shadow0[i].y; @@ -163,47 +199,53 @@ void main() { baseShadowed = mix(baseShadowed, scol, sa); } - vec2 p = screenToUV(original_coord, inSize); - SDFResult f = fieldWidgets(p, inSize, original_coord); + vec2 p = screenToUV(coord, inSize); + SDFResult f = fieldWidgets(p, inSize, coord); float merged = f.dist; int STEP = int(DebugStep + 0.5); - - if (STEP <= 0) { - float px = 2.0 / inSize.y; - vec3 col = (merged > 0.0 ? vec3(1.0) * merged : vec3(1.0) * (-merged) * 2.0) * 3.0; - col = mix(col, vec3(1.0), 1.0 - smoothstep(0.5 / inSize.y - px, 0.5 / inSize.y + px, abs(merged))); - fragColor = vec4(col, 1.0); return; - } if (STEP <= 1) { - float px = 2.0 / inSize.y; vec3 col = (merged > 0.0) ? vec3(0.9, 0.6, 0.3) : vec3(0.65, 0.85, 1.0); col *= 1.0 - exp(-0.03 * abs(merged) * inSize.y); - col *= 0.6 + 0.4 * smoothstep(-0.5, 0.5, cos(0.25 * abs(merged) * inSize.y * 2.0)); - col = mix(col, vec3(1.0), 1.0 - smoothstep(1.5 / inSize.y - px, 1.5 / inSize.y + px, abs(merged))); - fragColor = vec4(col, 1.0); return; + fragColor = vec4(col, 1.0); + return; } - if (merged >= 0.0) { fragColor = vec4(baseShadowed, 1.0); return; } - vec2 coord_pixelated = original_coord; + if (merged >= 0.0) { + fragColor = vec4(baseShadowed, 1.0); + return; + } + + vec2 coordPix = coord; if (Pixelated > 0.5) { - coord_pixelated = floor(original_coord / PixelGridSize) * PixelGridSize + 0.5 * PixelGridSize; + coordPix = floor(coord / PixelGridSize) * PixelGridSize + 0.5 * PixelGridSize; } - vec2 UV_pixelated = coord_pixelated / inSize; + vec2 uvPix = coordPix / inSize; int idx = f.index; vec4 o0 = Optics0[idx]; vec4 o1 = Optics1[idx]; vec4 o2 = Optics2[idx]; vec4 tint = Tints[idx]; + vec4 extra = Extra0[idx]; + + float refThickness = o0.x; + float refFactor = o0.y; + float refDisp = o0.z; + float refFresRange = o0.w; - float refThickness = o0.x, refFactor = o0.y, refDisp = o0.z, refFresRange = o0.w; - float refFresHard = o1.x / 100.0, refFresFac = o1.y / 100.0, glareRange = o1.z, glareHard = o1.w / 100.0; - float glareConv = o2.x / 100.0, glareOpp = o2.y / 100.0, glareFac = o2.z / 100.0, glareAngle = o2.w; + float refFresHard = o1.x / 100.0; + float refFresFac = o1.y / 100.0; + float glareRange = o1.z; + float glareHard = o1.w / 100.0; - vec2 normal = f.normal; float nlen = length(normal); if (nlen > 1e-6) normal /= nlen; + float hoverK = extra.y; + float focusK = extra.z; + int blurIndex = int(extra.x + 0.5); - if (STEP <= 2) { vec3 normalColor = vec2ToRgb(normal); fragColor = vec4(normalColor, nlen); return; } + vec2 normal = f.normal; + float nlen = length(normal); + if (nlen > 1e-6) normal /= nlen; float nmerged = -merged * inSize.y; float xR = 1.0 - nmerged / max(refThickness, 1e-6); @@ -212,62 +254,66 @@ void main() { float edgeFactor = -tan(thetaT - thetaI); if (nmerged >= refThickness) edgeFactor = 0.0; - if (STEP <= 3) { fragColor = vec4(vec3(edgeFactor), 1.0); return; } - - if (STEP <= 4) { - vec3 normalColor = vec2ToRgb(normal); - float ring = max(edgeFactor, 0.0); - vec3 outC = clamp(normalColor * ring * 4.0, 0.0, 1.0); - fragColor = vec4(outC, 1.0); return; - } - - int blurIndex = int(Extra0[idx].x + 0.5); vec2 refrOffset = -normal * edgeFactor * 0.08 * vec2(inSize.y / inSize.x, 1.0); + vec4 blurred = sampleBlur(blurIndex, uvPix + refrOffset); - if (STEP <= 5) { vec4 outColor = sampleBlur(blurIndex, UV_pixelated); fragColor = outColor; return; } - if (STEP <= 6) { vec4 outColor = sampleBlur(blurIndex, UV_pixelated + refrOffset); fragColor = outColor; return; } - - float fresnelFactor = clamp(pow(1.0 + merged * inSize.y / 1500.0 * pow(500.0 / max(refFresRange, 1e-6), 2.0) + refFresHard, 5.0), 0.0, 1.0); - - if (STEP <= 7) { - vec4 blurredPixel = sampleBlur(blurIndex, UV_pixelated + refrOffset); - vec4 outColor = mix(blurredPixel, vec4(1.0), (fresnelFactor * refFresFac * 0.7) * nlen); - fragColor = outColor; return; - } - - if (STEP <= 8) { - vec4 blurredPixel = sampleBlur(blurIndex, UV_pixelated + refrOffset); - float glareGeo = clamp(pow(1.0 + merged * inSize.y / 1500.0 * pow(500.0 / max(glareRange, 1e-6), 2.0) + glareHard, 5.0), 0.0, 1.0); - float ang = (atan(normal.y, normal.x) - PI * 0.25 + glareAngle) * 2.0; - int farSide = 0; if ((ang > PI * (2.0 - 0.5) && ang < PI * (4.0 - 0.5)) || (ang < PI * (0.0 - 0.5))) farSide = 1; - float gAngle = (0.5 + sin(ang) * 0.5) * (farSide == 1 ? 1.2 * glareOpp : 1.2) * glareFac; - gAngle = clamp(pow(gAngle, 0.1 + glareConv * 2.0), 0.0, 1.0); - vec4 outColor = mix(blurredPixel, vec4(1.0), gAngle * glareGeo); - fragColor = outColor; return; - } - - vec4 blurredPixel = sampleBlur(blurIndex, UV_pixelated + refrOffset); vec4 dispPixel; - { const float NR = 0.98, NG = 1.00, NB = 1.02; - dispPixel.r = sampleBlur(blurIndex, UV_pixelated + refrOffset * (1.0 - (NR - 1.0) * refDisp)).r; - dispPixel.g = sampleBlur(blurIndex, UV_pixelated + refrOffset * (1.0 - (NG - 1.0) * refDisp)).g; - dispPixel.b = sampleBlur(blurIndex, UV_pixelated + refrOffset * (1.0 - (NB - 1.0) * refDisp)).b; - dispPixel.a = 1.0; } + { + const float NR = 0.985; + const float NG = 1.000; + const float NB = 1.015; + dispPixel.r = sampleBlur(blurIndex, uvPix + refrOffset * (1.0 - (NR - 1.0) * refDisp)).r; + dispPixel.g = sampleBlur(blurIndex, uvPix + refrOffset * (1.0 - (NG - 1.0) * refDisp)).g; + dispPixel.b = sampleBlur(blurIndex, uvPix + refrOffset * (1.0 - (NB - 1.0) * refDisp)).b; + dispPixel.a = 1.0; + } vec4 outColor = mix(dispPixel, vec4(tint.rgb, 1.0), tint.a * 0.8); - float fres = fresnelFactor; + float fresnelFactor = clamp(pow(1.0 + merged * inSize.y / 1500.0 * pow(500.0 / max(refFresRange, 1e-6), 2.0) + refFresHard, 5.0), 0.0, 1.0); vec3 fresTint = mix(vec3(1.0), tint.rgb, tint.a * 0.5); - outColor = mix(outColor, vec4(fresTint, 1.0), fres * refFresFac * 0.7 * nlen); + outColor = mix(outColor, vec4(fresTint, 1.0), fresnelFactor * refFresFac * 0.7 * nlen); float glareGeo = clamp(pow(1.0 + merged * inSize.y / 1500.0 * pow(500.0 / max(glareRange, 1e-6), 2.0) + glareHard, 5.0), 0.0, 1.0); - float ang = (atan(normal.y, normal.x) - PI * 0.25 + glareAngle) * 2.0; - int farSide = 0; if ((ang > PI * (2.0 - 0.5) && ang < PI * (4.0 - 0.5)) || (ang < PI * (0.0 - 0.5))) farSide = 1; - float gAngle = (0.5 + sin(ang) * 0.5) * (farSide == 1 ? 1.2 * glareOpp : 1.2) * glareFac; - gAngle = clamp(pow(gAngle, 0.1 + glareConv * 2.0), 0.0, 1.0); - vec3 glareMix = mix(blurredPixel.rgb, tint.rgb, tint.a * 0.5); - vec3 glareCol = glareMix; - outColor = mix(outColor, vec4(glareCol, 1.0), gAngle * glareGeo * nlen); + vec3 glareMix = mix(blurred.rgb, tint.rgb, tint.a * 0.5); + outColor.rgb = mix(outColor.rgb, glareMix, 0.25 * glareGeo * nlen); + + float edgeProx = exp(-abs(merged) * inSize.y / 9.0); + + if (hoverK > 0.0001) { + vec2 tdir = normalize(vec2(-normal.y, normal.x)); + float refBoost = 1.0 + 0.35 * hoverK * edgeProx; + vec2 refrHover = -normal * edgeFactor * 0.08 * refBoost * vec2(inSize.y / inSize.x, 1.0); + vec2 chromaT = tdir * 0.0008 * hoverK * edgeProx * vec2(inSize.y / inSize.x, 1.0); + vec3 subtle = vec3( + sampleBlur(blurIndex, uvPix + refrHover + chromaT).r, + sampleBlur(blurIndex, uvPix + refrHover).g, + sampleBlur(blurIndex, uvPix + refrHover - chromaT).b + ); + vec3 add = mix(subtle, vec3(1.0), 0.08) * (0.15 + 0.35 * edgeProx) * hoverK; + outColor.rgb = clamp(outColor.rgb + add, 0.0, 1.0); + } + + if (focusK > 0.0001) { + vec4 rc = Rects[idx]; + vec2 centerPx = vec2(rc.x + 0.5 * rc.z, rc.y + 0.5 * rc.w); + vec2 v = (coord - centerPx) / inSize.y; + + float phi = atan(v.y, v.x); + float phi0 = Time * FocusBorderSpeed; + float c = 0.5 + 0.5 * cos(phi - phi0); + float sweep = smoothstep(0.75, 1.0, c); + + float mergedPx = merged * inSize.y; + float w = max(FocusBorderWidthPx, 1e-3); + float outside = step(0.0, mergedPx); + float band = exp(-pow(max(0.0, mergedPx) / w, 2.0)) * outside; + + float intensity = FocusBorderIntensity * focusK; + vec3 ringTint = mix(vec3(1.0), tint.rgb, 0.2); + vec3 ring = ringTint * (band * sweep) * intensity; + outColor.rgb = clamp(outColor.rgb + ring, 0.0, 1.0); + } vec3 finalCol = mix(outColor.rgb, baseShadowed, smoothstep(-0.001, 0.001, merged)); fragColor = vec4(finalCol, 1.0); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 163451a..4591118 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,13 +1,13 @@ { "schemaVersion": 1, "id": "reglass", - "version": "1.0.1", + "version": "1.1.0", "name": "ReGlass", "description": "Liquid Glass Implemented On Your Favorite Pixelated And Cubic Game.", "authors": [ "RedxAx" ], - "license": "CC0-1.0", + "license": "MIT", "environment": "client", "entrypoints": { "client": [ diff --git a/src/main/resources/reglass.mixins.json b/src/main/resources/reglass.mixins.json index a90c76e..bc5d299 100644 --- a/src/main/resources/reglass.mixins.json +++ b/src/main/resources/reglass.mixins.json @@ -24,6 +24,7 @@ "client.ScreenMixin", "client.TitleScreenMixin", "logical.GameRendererMixin", - "widgets.DrawContextMixin" + "widgets.ClickableWidgetMixin", + "widgets.PressableWidgetMixin" ] } \ No newline at end of file