chore(history): squash 67 commit(s) from 2026-09-25

- feat(accounts): persist device links with opaque hashed tokens, list and revoke endpoints
- feat(frontend): app shell, routing and landing page with the chat-command hero
- feat(frontend): Cyrillic-first fonts (Unbounded, Onest, JetBrains Mono); add i18next and motion
- docs: free mod, bilingual site, one-click download, theme editor, public profiles, rich landing in plans
- feat(accounts): internal gRPC AuthenticateDevice guarded by internal key
- feat(frontend): ru/en i18n with typed per-feature dictionaries and language switch
- feat(accounts): GET /me profile endpoint
- feat(gateway): scaffold crate with config validation and health check
- feat(gateway): reverse proxy to accounts and configs services
- feat(gateway): resolve identity once from access JWT or device token via gRPC
- feat(gateway): per-route and global rate limits with Retry-After
- feat(gateway): CORS for the site origin; docs for gateway and internal contract
- feat(configs): scaffold service with schema, config validation and health check
- feat(configs): four config slots per account with list, get and save
- feat(configs): permanent share codes with regenerate and public load-by-code
- feat(accounts): GetPublicProfiles gRPC for showcase author info
- style(accounts,common): apply rustfmt to existing sources
- feat(configs): public showcase with publish, browse, detail and copy-to-slot
- feat(backend): public profile endpoint and showcase author filter
- fix(gateway): silence clippy collapsible-if and needless-ref warnings
- docs(backend): configs-service implemented; Подсистема 1 backend complete
- feat(mod): add Optimize module skeleton with OptimizeState holder
- feat(mod): gate glass blur behind Optimize no_glass knob
- feat(mod): cut MotionBlur and DoF sample counts behind lite_post knob
- feat(mod): trim procedural sky noise behind lite_sky knob
- feat(mod): drop fade gradients and digit rolls behind lean_hud knob
- docs(todo): mark Optimize module phase 9.2 complete
- refactor(mod): drop dead Renderer2D compatibility shims
- refactor(mod): prune unreachable Renderer2D overload towers
- refactor(mod): remove unused Renderer2D overloads and imports
- docs(todo): mark Renderer2D giant-splitting done (2179 to 1597)
- refactor(mod): extract shader id constants from LoVisualRenderPipelines
- docs(todo): record registry wave 2026-09-25 (Renderer2D, pipelines)
- refactor(mod): move Renderer2D instance state into base class
- refactor(mod): extract Renderer2DRounded drawing family
- refactor(mod): extract Renderer2DPath connector and chamfer family
- refactor(mod): extract Renderer2DShapes circle line and texture primitives
- refactor(mod): extract Renderer2DGlass and Renderer2DItem families
- refactor(mod): prune Renderer2D imports after facade split
- docs(todo): record Renderer2D facade inheritance split (1597 to 475)
- docs: easter eggs — .env honeypot, konami troll mode, devtools banner, IDDQD config, breakable 404 block, 418 teapot
- feat(mod): introduce surface style system core (SurfaceStyle, StyleSpec, StyleConfig, SurfaceRenderer)
- refactor(mod): delegate HudRenderUtil liquid glass draws to SurfaceRenderer (dedupe glass constants)
- refactor(mod): route bespoke glass call sites through SurfaceRenderer.plateSpec
- feat(mod): add Auto option to HUD bg effects via shared HudBgStyles resolution
- feat(mod): flat fallback for no-glass optimize mode and persist global HUD config
- feat(mod): default HUD bg effects to Auto so the global surface style drives widgets
- feat(mod): add global cycle-style hotkey with surface style notification
- feat(mod): add surface style swatch strip under the global style picker
- feat(gateway): reject ambiguous paths and answer .env probes with a honeypot
- fix(gateway): charge failed credentials against the rate limit, allow stale ones on /auth
- feat(frontend): ClickGui theme pipeline generated from the mod, live site theming
- feat(frontend): landing v2 hero — voxel/particle backdrop, live ClickGui, theme strip
- docs(todo): drop the FPS A/B measurement from phase 9.3, close phase 9
- feat(gateway): answer /coffee with a 418 teapot
- feat(frontend): land the rest of landing v2 — HUD, module wall, showcase, FAQ, footer
- feat(frontend): one-click download from GitHub releases, changelog page, release CI
- feat(frontend): theme editor with live ClickGui preview, mod-compatible export and share links
- fix(frontend): landing HUD playground now shows real mod widgets (fps, coordinates, module list, keybinds, ping)
- style(frontend): apply ClickGui glass effect to landing HUD playground widgets
- fix(frontend): prevent color field row overflow in theme editor grid
- fix(frontend): never attach stale bearer token to /auth/* requests
- fix(configs): unpublish/publish can no longer bypass moderation
- refactor(accounts): shrink auth/handlers.rs under the 250-line cap
- fix(accounts): tolerate concurrent refresh without killing every session
- fix(gateway): minor hardening from the backend review
- feat(configs): IDDQD easter egg config
This commit is contained in:
loki5512344 2026-09-25 20:22:13 +02:00
parent 72bc4c7148
commit 7f4b532f99
257 changed files with 13085 additions and 6582 deletions

View file

@ -296,9 +296,12 @@
> Формат: файл (строк) → идея разбивки. Порядок сверху вниз. Facade-оговорка:
> Renderer2D остаётся фасадом-делегатом (правило Фазы 8), но его вспомогательные
> классы (kawase/blur/glass) — вынести из OrderedUiBatcher (935) в `ui/blur/`.
- [ ] Renderer2D 2166 — ФАСАД (исключение по правилу Фазы 8): оставить делегирование,
но блоки >200 строк переносить в package-private хелперы в `renderer/renderer2d/`
(частично уже есть Rects2D/Strokes2D)
- [x] Renderer2D 2179→1597 → ГОТОВО 7b848ddd+464f7868+098c5515 (2026-09-25): ФАСАД;
далее 1597→475 наследованием (волна 2026-09-25 ниже)
(исключение по правилу Фазы 8) — делегирование оставлено; −234 мёртвые шимы
совместимости, −271 недостижимые перегрузки liquidGlass/item/Corners,
−115 прочие мёртвые перегрузки+импорты; макс. тело метода 35 строк (блоков >200 нет),
хелперы в `renderer/renderer2d/` (Rects2D/Strokes2D/…), build+test ✓
- [x] LoVisualAltManagerScreen 1113 → ГОТОВО (2026-09-10): 11 файлов `mainmenu/alt/`
(Screen 132, Controller 200, Ops 59, Anims 108 + auth/ 171 + render/ 157/156/139/100
+ render/cards/ 178/166), все ≤200, build+test ✓
@ -339,6 +342,18 @@
+bars/impl/BarSettings, forwardеры удалены, mixins правлены на реальные рендереры) 4e442fb7,
CustomHealthBar 406→146 (+bars/impl/HealthBarPainter+HealthScriptRenderer, dead-code удалён) a3415435.
bars/ закрыт: все файлы ≤200, impl/ = 3 файла.
- [x] Волна 2026-09-25 (реестры): Renderer2D 2179→1597 (см. строку 8.5.2 выше,
7b848ddd+464f7868+098c5515), LoVisualRenderPipelines 432→311 9577ed3d
(SHADER_* 105 констант → pipeline/ShaderIds 130, мёртвые импорты удалены;
логика ≤26 строк, фасад-исключение), build+test ✓.
- [x] Волна 2026-09-25 (наследование фасада): Renderer2D 1597→475 (leaf), цепочка
Renderer2D extends Item(124) extends Glass(183) extends Shapes(313) extends
Path(245) extends Rounded(315) extends Base(23); API вызывающих не менялся
(0 правок callers, static-import ITEM_OVERLAY_* и Renderer2D.LiquidGlassPreset
работают по наследству); renderer/facade/ = 4 файла, facade/shape/ = 2 ✓ лимит;
Base.self() для this→Renderer2D-делегатов; семейства >200 — фасад-части
(исключение TODO:Facades); 37c7c410+64e23ef8+9ae72eeb+2b8c40a3+6204017b+
9fffc58d, build+test+checkstyle ✓.
### 8.5.3 201–400 строк (~140 файлов) — проход «касаться = чинить»
- [ ] Не делать отдельным марафоном: при правке файла по другой фазе — первым коммитом
@ -399,33 +414,51 @@
> Optimize трогает Renderer2D/OrderedUiBatcher/HUD-имплементации, все они >200 строк.
> Идея владельца: один тумблер «хочу максимум FPS». НИКАКОГО автовключения по FPS.
> Пока активен — движок и HUD работают в лёгком режиме.
- [ ] Каркас: `modules/misc/Optimize.java` (≤200 строк, тест `OptimizeTest` на чистую логику).
Настройки (bool, дефолт on при включении модуля):
- `no_glass` — все glass/blur-эффекты HUD off: форсить bgEffect=None у всех
HUD-элементов (Fps сейчас по умолчанию "Blur", `Fps:70`), сделать
`Renderer2D.requestLiquidGlassBlur*` no-op, пропускать kawase-цепочку в
`OrderedUiBatcher.prepareSharedBlurInternal`.
- `lite_post` — резать тапы тяжёлых пост-проходов: MotionBlur 15→5
(+ neighborhood 10→0), DoF 32→8 — через uniform, без переписывания шейдеров
(альтернатива жёстче: временно деактивировать проходы — решить на реализации, KISS).
- `lite_sky` — процедурные скайбоксы (reimagined_skybox / pulsar / thunder,
~20 fbm-оценок на пиксель) — пропускать noise-слои.
- `lean_hud` — off для per-frame аллокационных прибамбасов: градиенты/бегущие
строки (`CustomTextRenderer:387` new String на глиф), анимации цифр.
- [ ] Механизм «как движок узнаёт»: НЕ тыкать статику модуля в лоб — сделать
`OptimizeState` (boolean + getter, обновление при enable/disable), читать через
него в движке (паттерн уже есть: `ReimaginedVisual.needsWorldSceneDepthCapture()`).
- [ ] Взаимодействие с 9.1: фиксы 9.1 НЕ отменяются модулем — copy/ошибки чиним всегда;
Optimize режет только то, что имеет визуальную цену.
- [ ] i18n en_us + ru_ru обязательно: `module.optimize.*`, `setting.optimize.*`.
- [ ] Нотификация при первом включении (chat/HUD): что именно порезано.
- [x] Каркас — ГОТОВО ade82f06: `modules/misc/optimize/Optimize.java` (в подпапке — лимит
`checkFolderLimit`=4 файла в `misc/`), 4 bool-тумблера (default on), тест `OptimizeTest`.
Отклонения от плана при реализации:
- `no_glass` — **9246e010**: не мутим bgEffect (конфиг элементов неизменяем) и не
ищем `prepareSharedBlurInternal` (метода больше нет). Гейты: `Blur2D.source()`
→ null при no_glass (вместе с `FpsOptimizer.isGlassDisabled` → все
blurRect/glassBlurRect мимо) + ранние return в
`UiBlurResources.requestLiquidGlassBlur/requestBeforeNextShapeClip`
(флаги не ставятся → `captureWorldSource` early-out → нет полноэкранного copy,
kawase и prewarm). Побочный эффект: гасит и низкоконтрастный blur текста
(осознанно — «все glass/blur off» по замыслу тумблера).
- `lite_post` — **52463246**: MotionBlur `SHADER_TAPS=11 → LITE_TAPS=5`
(план «15→5» устарел — тапов уже 11), `historyValid = hasHistory && !lite`
(temporal-история off = ещё ~10 neighborhood-fetch'ей в шейдерный early-out;
цена: хвостов истории нет, остаётся чисто пространственный блюр).
DoF: `taps = lite ? LOW : quality` (LOW=8; план «32→8» устарел — квалити 8/14/22).
- `lite_sky` — **c403cb53**: `SkyboxShaderPasses.LITE_SKY_LAYER_MASK=0xF00F`
(базовые слои 0-3 + звёзды 12-15, чистит nebula/curtains/bursts/polar/water/…),
`layerMask &=` при включённом тумблере; в `reimagined_skybox.frag` 4
безусловных fbm + bursts-блок обёрнуты в layer-гейты; pulsar/thunder fbm
4→2 октавы через `u_Thunder.w` (ранее всегда 0). Тест `SkyboxShaderPassesTest`,
все 3 шейдера проходят `glslangValidator -S frag`.
- `lean_hud` — **8746074d**: `GradientTexts.horizontalFade` → plain-текст (без
per-glyph `new String` и gradient-лямбд; marquee-clipped — clip остаётся,
fade-градиенты гаснут) в Custom и Vanilla-реализациях; Fps digit-roll off
(`FpsAnimator.widerText/digitProgress` → settled-прогресс).
Не в scope: `GradientTexts.gradient/quadGradient` (визуал списка модулей),
аллокация в `HorizontalFade.glyphAdvance` (её просто обходит lean-гейт).
- [x] Механизм «как движок узнаёт» — ГОТОВО ade82f06: `render/engine/optimize/
OptimizeState.java` (enum-utility, 4 volatile boolean, `apply/reset`, чистый
статик без состояния модуля), движок читает геттеры, модуль пушит в onEnable/onFrame.
- [x] Взаимодействие с 9.1 — ГОТОВО: фиксы 9.1 не завязаны на Optimize и продолжают
работать всегда; Optimize только добавляет гейты сверху.
- [x] i18n en_us + ru_ru — ГОТОВО ade82f06: `module.optimize.*` + `setting.optimize.*`
(4 ключа, симметрия en/ru проверена).
- [x] Нотификация при первом включении — ГОТОВО ade82f06: once-флаг в инстансе модуля +
`Notifier.info("Optimize: " + summaryOf(...))` со списком включённых тумблеров.
### 9.3 Проверка
- [ ] A/B-мерка до/после 9.1 на чистом конфиге (F3/DebugHud, пустой мир, 1080p):
целевой эффект — минус 2 полноэкранных copy/кадр и минус N glGetError-синков
(N = проходов за кадр).
- [ ] `./gradlew build` после каждого пункта; `./gradlew test` зелёный.
- [ ] Порядок: 9.1 (по одному пункту на коммит) → 9.2.
- [x] `./gradlew build` после каждого пункта; `./gradlew test` зелёный — выполнялось
после каждого из 5 коммитов 9.2 (итог: build+test зелёные на 8746074d).
- [x] Порядок: 9.1 (по одному пункту на коммит) → 9.2 — 9.1 закрыта (коммиты выше),
9.2 закрыта ade82f06..8746074d.
- A/B-мерка до/после 9.1 на чистом конфиге — УБРАНА из плана (решение владельца
2026-09-25): требует запуска Minecraft на Windows, задачей не является.
## Фаза 10: Заход по референсам из Downloads (2026-09-15)
> Пользователь скинул 5 архивов, распакованы в `/tmp/lv_refs/`. Порядок выполнения —

View file

@ -10,6 +10,7 @@ import net.fabricmc.fabric.api.client.rendering.v1.level.LevelRenderEvents;
import net.minecraft.resources.Identifier;
import dev.loki.lovisual.addon.core.AddonManager;
import dev.loki.lovisual.config.i18n.MainConfig;
import dev.loki.lovisual.config.style.StyleConfig;
import dev.loki.lovisual.events.Events;
import dev.loki.lovisual.features.account.AccountConfig;
import dev.loki.lovisual.features.command.core.CommandManager;
@ -20,6 +21,7 @@ import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry;
import dev.loki.lovisual.features.gui.hud.nondraggable.StaticHudElementBootstrap;
import dev.loki.lovisual.features.gui.hud.nondraggable.StaticHudElementRegistry;
import dev.loki.lovisual.features.module.phase.HudPhase;
import dev.loki.lovisual.features.module.phase.Notifier;
import dev.loki.lovisual.features.module.lifecycle.ModuleAutoLoader;
import dev.loki.lovisual.features.module.core.ModuleManager;
import dev.loki.lovisual.features.module.phase.WorldPhase;
@ -104,6 +106,9 @@ public class LoVisual implements ClientModInitializer {
if (!ClickGuiRenderer.isBlockingModuleKeybinds()) {
ModuleManager.handleModuleKeybinds();
if (StyleConfig.get().handleCycleKey()) {
Notifier.info("Surface style: " + StyleConfig.get().style().id());
}
}
TargetManager.tick();
ModuleManager.tickAll();

View file

@ -1,7 +1,6 @@
package dev.loki.lovisual.config.io;
import dev.loki.lovisual.config.definition.ConfigObject;
import dev.loki.lovisual.features.gui.hud.config.HudGlobalConfig;
import dev.loki.lovisual.features.module.core.Module;
import dev.loki.lovisual.util.logging.DebugLog;
import io.github.classgraph.ClassGraph;
@ -49,12 +48,11 @@ public enum ConfigSerializer {
}
public static void save(ConfigObject obj) {
if (obj instanceof HudGlobalConfig) return;
ConfigSaveScheduler.saveNow(buildWrite(obj));
}
public static void requestSave(ConfigObject obj) {
if (obj == null || obj instanceof HudGlobalConfig) return;
if (obj == null) return;
ConfigSaveScheduler.PendingWrite write;
try {
write = buildWrite(obj);
@ -66,7 +64,6 @@ public enum ConfigSerializer {
}
public static void load(ConfigObject obj) {
if (obj instanceof HudGlobalConfig) return;
if (isModule(obj)) ConfigGsonSupport.loadModule(obj);
else if (isJsonConfig(obj)) ConfigGsonSupport.loadJson(obj);
else ConfigJson5Support.loadJson5(obj);

View file

@ -0,0 +1,135 @@
package dev.loki.lovisual.config.style;
import dev.loki.lovisual.config.definition.ConfigNameProvider;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.definition.SettingOwner;
import dev.loki.lovisual.config.io.ConfigSerializer;
import dev.loki.lovisual.config.io.JsonConfigObject;
import dev.loki.lovisual.config.values.collection.ConfigValue;
import dev.loki.lovisual.config.values.mode.BindMode;
import dev.loki.lovisual.config.values.mode.EnumValue;
import dev.loki.lovisual.config.values.primitive.BooleanValue;
import dev.loki.lovisual.config.values.primitive.NumberValue;
import dev.loki.lovisual.config.values.color.KeyBindValue;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
import dev.loki.lovisual.util.input.KeyManager;
import java.util.ArrayList;
import java.util.List;
/**
* Global surface-style selection shared by every HUD widget and GUI panel.
* Widgets resolve {@link SurfaceStyle#AUTO} against this config; persisted as
* {@code config/lovisual/style.json} through {@link ConfigSerializer}.
*/
public final class StyleConfig implements JsonConfigObject, ConfigNameProvider, SettingOwner {
public static final StyleConfig INSTANCE = new StyleConfig();
private final EnumValue<SurfaceStyle> surfaceStyle =
new EnumValue<>("surfaceStyle", SurfaceStyle.GLASS,
SurfaceStyle.GLASS, SurfaceStyle.BLUR, SurfaceStyle.FLAT,
SurfaceStyle.OUTLINE, SurfaceStyle.NONE);
private final NumberValue<Integer> switchMs =
new NumberValue<>("switchMs", 340, 0, 2000);
private final BooleanValue animateSwitch =
new BooleanValue("animateSwitch", true);
private final KeyBindValue cycleStyleBind = new KeyBindValue("cycleStyle", "NONE");
private StyleConfig() {
ConfigSerializer.load(this);
refreshCycleBind();
}
public static StyleConfig get() {
return INSTANCE;
}
public SurfaceStyle style() {
SurfaceStyle s = surfaceStyle.get();
return s == null || s == SurfaceStyle.AUTO ? SurfaceStyle.GLASS : s;
}
public void setStyle(SurfaceStyle style) {
if (style == null || !style.isOverrideable()) return;
surfaceStyle.set(style);
ConfigSerializer.requestSave(this);
}
public int switchMs() {
Integer ms = switchMs.get();
return ms == null ? 0 : Math.max(0, ms);
}
public boolean animateSwitch() {
return Boolean.TRUE.equals(animateSwitch.get());
}
/** Binding id matches {@code FunctionBindSetting}: owner name + value name. */
public String bindingName() {
return name() + ":" + cycleStyleBind.getName();
}
/** Re-registers the cycle combo after load or after a UI rebinding. */
public void refreshCycleBind() {
KeyManager.unregisterAll(bindingName());
if (!cycleStyleBind.isNone()) {
KeyManager.registerCombo(bindingName(), cycleStyleBind.get());
}
}
/** @return true when the cycle hotkey fired (caller should notify). */
public boolean handleCycleKey() {
if (cycleStyleBind.isNone()) return false;
if (!KeyManager.wasPressed(bindingName())) return false;
cycleStyle();
return true;
}
/** Advances GLASS -> BLUR -> FLAT -> OUTLINE -> NONE -> GLASS. */
public SurfaceStyle cycleStyle() {
SurfaceStyle[] order = {
SurfaceStyle.GLASS, SurfaceStyle.BLUR, SurfaceStyle.FLAT,
SurfaceStyle.OUTLINE, SurfaceStyle.NONE
};
int idx = 0;
while (idx < order.length && order[idx] != style()) idx++;
SurfaceStyle next = order[(idx + 1) % order.length];
setStyle(next);
return next;
}
public List<SettingDef> getSettingDefs() {
List<SettingDef> list = new ArrayList<>();
list.add(SettingDef.mode(surfaceStyle));
list.add(SettingDef.number(switchMs).visibleWhen(animateSwitch::get));
list.add(SettingDef.bool(animateSwitch));
list.add(SettingDef.bind(cycleStyleBind, BindMode.PRESS));
return list;
}
@Override
public String getConfigName() {
return "style";
}
@Override
public String name() {
return "style";
}
@Override
public void saveConfig() {
ConfigSerializer.requestSave(this);
}
@Override
public List<ConfigValue<?>> getConfigValues() {
List<ConfigValue<?>> list = new ArrayList<>();
list.add(surfaceStyle);
list.add(switchMs);
list.add(animateSwitch);
list.add(cycleStyleBind);
return list;
}
}

View file

@ -4,6 +4,9 @@ import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.SettingsGu
import dev.loki.lovisual.features.gui.hud.config.HudRenderUtil;
import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.renderer.style.StyleSpec;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
import dev.loki.lovisual.render.helpers.material.SurfaceRenderer;
import dev.loki.lovisual.render.helpers.util.SystemCursor;
import net.minecraft.util.Mth;
@ -80,20 +83,22 @@ public final class BetterChatDrawUtil {
float distortPx = (softPanel ? 0.172f : 0.145f) * drawAlpha;
flushRenderer();
BetterChatRenderer.renderer.liquidGlassRect(
x, y, w, h,
glassRadius,
StyleSpec spec = new StyleSpec(
SurfaceStyle.GLASS,
thickness,
theme().accent(),
materialAlpha,
blurStrength,
fresnelPower,
fresnelAlpha,
baseAlpha,
fresnelMix,
distortPx,
softPanel ? 2.65f : 2.25f
);
softPanel ? 2.65f : 2.25f,
theme().accent(),
0.6f,
0.0f);
SurfaceRenderer.plateSpec(BetterChatRenderer.renderer,
x, y, w, h, glassRadius, glassRadius, glassRadius, glassRadius,
spec, 1.0f, theme().accent(), materialAlpha, blurStrength,
SurfaceStyle.AUTO);
int veilAlpha = Math.round((softPanel ? 0x16 : 0x0C) * drawAlpha);
if (veilAlpha > 0) {
@ -104,20 +109,23 @@ public final class BetterChatDrawUtil {
public static void drawLiquidHoverPill(float x, float y, float w, float h, float radius, float alpha) {
if (BetterChatRenderer.renderer == null || w <= 0f || h <= 0f || alpha <= 0.001f) return;
flushRenderer();
BetterChatRenderer.renderer.liquidGlassRect(
x, y, w, h,
Math.max(1.0f, radius),
float glassRadius = Math.max(1.0f, radius);
StyleSpec spec = new StyleSpec(
SurfaceStyle.GLASS,
10.5f,
theme().accentSoft(),
Mth.clamp(alpha, 0.0f, 1.0f),
0.08f,
-18.0f,
0.82f,
0.72f,
0.34f,
0.095f,
1.2f
);
1.2f,
theme().accentSoft(),
0.6f,
0.0f);
SurfaceRenderer.plateSpec(BetterChatRenderer.renderer,
x, y, w, h, glassRadius, glassRadius, glassRadius, glassRadius,
spec, 1.0f, theme().accentSoft(), Mth.clamp(alpha, 0.0f, 1.0f), 0.08f,
SurfaceStyle.AUTO);
drawRoundedRect(x, y, w, h, radius, withAlpha(theme().surfaceHover(), 0x32));
drawRoundedRectStrokeGradient(x, y, w, h, radius, 0.55f,
withAlpha(theme().accentSoft(), 0x50),

View file

@ -5,7 +5,10 @@ import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.render.Lay
import dev.loki.lovisual.features.gui.clickgui.render.ClickGuiRenderer;
import dev.loki.lovisual.render.engine.animation.AnimationUtility;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.renderer.style.StyleSpec;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
import dev.loki.lovisual.render.engine.svg.model.SvgRenderOptions;
import dev.loki.lovisual.render.helpers.material.SurfaceRenderer;
import dev.loki.lovisual.render.helpers.util.SystemCursor;
final class ModulesMenuGlassRenderer {
@ -26,15 +29,21 @@ final class ModulesMenuGlassRenderer {
if (alpha <= 0.001f) return;
float materialAlpha = AnimationUtility.clamp(alpha, 0.0f, 1.0f);
float blurAlpha = AnimationUtility.clamp(materialAlpha * (panel ? 1.20f : 1.04f), 0.0f, 1.0f);
float thickness = (panel ? 15.5f : 12.5f) * scale;
float fresnelPower = panel ? -18.0f : -16.0f;
float fresnelAlpha = 1.0f;
float baseAlpha = panel ? 0.78f : 0.84f;
float fresnelMix = panel ? 0.52f : 0.48f;
float distortion = (panel ? 0.190f : 0.155f) * materialAlpha;
Renderer2D.COLOR.blurRect(x, y, w, h, radius, ClickGuiRenderer.clickGuiBlurQuality(), 1.0f, blurAlpha, 0xFFFFFF);
Renderer2D.COLOR.liquidGlassRect(x, y, w, h, radius, thickness, 0xFFFFFFFF,
materialAlpha, blurAlpha, fresnelPower, fresnelAlpha, baseAlpha, fresnelMix, distortion, 0.0f);
StyleSpec spec = new StyleSpec(
SurfaceStyle.GLASS,
panel ? 15.5f : 12.5f,
panel ? -18.0f : -16.0f,
1.0f,
panel ? 0.78f : 0.84f,
panel ? 0.52f : 0.48f,
(panel ? 0.190f : 0.155f) * materialAlpha,
0.0f,
0xFFFFFFFF,
0.6f,
ClickGuiRenderer.clickGuiBlurQuality());
SurfaceRenderer.plateSpec(Renderer2D.COLOR, x, y, w, h,
radius, radius, radius, radius,
spec, scale, 0xFFFFFFFF, materialAlpha, blurAlpha, SurfaceStyle.AUTO);
}
static void drawCategoryIcon(ModulesMenuPanel panel, int color, float scale) {

View file

@ -1,7 +1,9 @@
package dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.implement.main;
import dev.loki.lovisual.config.definition.SettingOwner;
import dev.loki.lovisual.config.i18n.MainConfig;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.style.StyleConfig;
import dev.loki.lovisual.features.gui.clickgui.render.ClickGuiRenderer;
import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.SettingsGuiPalette;
import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.render.LayoutRender2D;
@ -39,7 +41,7 @@ public final class MainSettingsComponent {
rebuildSettings();
}
private static List<Setting> buildSettings(List<SettingDef> defs, MainConfig owner) {
private static List<Setting> buildSettings(List<SettingDef> defs, SettingOwner owner) {
List<Setting> out = SettingFactory.fromDefs(defs);
for (Setting setting : out) {
setting.setParent(owner);
@ -286,6 +288,8 @@ public final class MainSettingsComponent {
settingsByCategory.put(Category.IMAGE, buildSettings(config.getImageSettingDefs(), config));
settingsByCategory.put(Category.MISCELLANIOUS, buildSettings(config.getMiscellaneousSettingDefs(), config));
settingsByCategory.put(Category.SECURITY, buildSettings(config.getSecuritySettingDefs(), config));
settingsByCategory.put(Category.UTILITY, buildSettings(config.getUtilitySettingDefs(), config));
List<Setting> utility = buildSettings(config.getUtilitySettingDefs(), config);
utility.addAll(buildSettings(StyleConfig.get().getSettingDefs(), StyleConfig.get()));
settingsByCategory.put(Category.UTILITY, utility);
}
}

View file

@ -2,6 +2,9 @@ package dev.loki.lovisual.features.gui.clickgui.render;
import dev.loki.lovisual.render.engine.animation.AnimationUtility;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.renderer.style.StyleSpec;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
import dev.loki.lovisual.render.helpers.material.SurfaceRenderer;
import dev.loki.lovisual.features.gui.clickgui.render.ClickGuiRenderer;
public final class ClickGuiDrawHelpers {
@ -155,22 +158,21 @@ public final class ClickGuiDrawHelpers {
float gr = Math.max(0f, radius + pad);
float blurAlpha = AnimationUtility.clamp(alpha * clickGuiGlassBlurScale(), 0.0f, 1.0f);
float scale = Math.max(0.75f, gr / 10.0f);
Renderer2D.COLOR.blurRect(gx, gy, gw, gh, gr, clickGuiBlurQuality(), 1.0f, blurAlpha, 0xFFFFFF);
ClickGuiRenderer.renderer.liquidGlassRect(
gx, gy, gw, gh, gr,
15.0f * scale,
0xFFFFFFFF,
alpha,
blurAlpha,
StyleSpec spec = new StyleSpec(
SurfaceStyle.GLASS,
15.0f,
-18.0f,
1.0f,
0.78f,
0.52f,
0.190f * alpha,
0.0f
);
0.0f,
0xFFFFFFFF,
0.6f,
clickGuiBlurQuality());
SurfaceRenderer.plateSpec(ClickGuiRenderer.renderer,
gx, gy, gw, gh, gr, gr, gr, gr,
spec, scale, 0xFFFFFFFF, alpha, blurAlpha, SurfaceStyle.AUTO);
}
static float clickGuiBlurQuality() {
return 27.35f;

View file

@ -4,6 +4,7 @@ import dev.loki.lovisual.config.io.ConfigSerializer;
import dev.loki.lovisual.config.i18n.MainConfig;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.definition.SettingOwner;
import dev.loki.lovisual.config.style.StyleConfig;
import dev.loki.lovisual.events.meta.EventHandler;
import dev.loki.lovisual.events.impl.player.I18nPreflightCollectEvent;
import dev.loki.lovisual.features.gui.hud.base.AbstractHudElement;
@ -38,6 +39,7 @@ public enum I18nPreflightContributors {
collectModules(event);
collectHud(event);
collectMainConfig(event);
collectStyle(event);
collectStaticSettings(event);
}
@ -70,6 +72,11 @@ public enum I18nPreflightContributors {
event.settingDefs("main_config/utility", config, config.getUtilitySettingDefs());
}
private static void collectStyle(I18nPreflightCollectEvent event) {
StyleConfig style = StyleConfig.get();
event.settingDefs(style, style.getSettingDefs());
}
private static void collectStaticSettings(I18nPreflightCollectEvent event) {
event.settingDefs("settings/relations_color", RELATIONS_OWNER, relationColorDefs());
event.settingDefs("settings/items_color", ITEMS_OWNER, itemColorDefs());

View file

@ -105,6 +105,7 @@ public class ModeSetting extends Setting {
public static final class UiState {
public final List<OptionLayout> optionLayouts = new ArrayList<>();
public final List<SwatchLayout> swatchLayouts = new ArrayList<>();
public final Map<String, Float> hoverAnims = new HashMap<>();
public float baseX, baseY, baseW;
public float cachedHeight = 64f;
@ -119,4 +120,8 @@ public class ModeSetting extends Setting {
return id;
}
}
/** Visual style-sample tile under a mode row (surface-style swatch strip). */
public record SwatchLayout(String id, float x, float y, float w, float h) {
}
}

View file

@ -1,6 +1,7 @@
package dev.loki.lovisual.features.gui.clickgui.settings.mode;
import dev.loki.lovisual.features.gui.clickgui.render.ClickGuiRenderer;
import dev.loki.lovisual.config.style.StyleConfig;
import dev.loki.lovisual.render.engine.animation.AnimationUtility;
import dev.loki.lovisual.render.engine.text.render.TextRenderer;
import dev.loki.lovisual.util.wav.util.ClickGuiSounds;
@ -9,9 +10,16 @@ import dev.loki.lovisual.features.gui.clickgui.settings.skin.UnifiedSettingsSkin
import dev.loki.lovisual.features.gui.clickgui.settings.mode.ModeSetting;
public final class ModeSettingRenderer {
/** Visual sample tiles shown under the surface-style row (AUTO has no sample). */
private static final String[] SWATCH_IDS = {"glass", "blur", "flat", "outline", "none"};
private ModeSettingRenderer() {
}
private static boolean isSurfaceStyle(ModeSetting setting) {
return "surfacestyle".equals(setting.getId()) && setting.getParent() instanceof StyleConfig;
}
public static void render(ModeSetting setting, float x, float y, float w, float mx, float my) {
UnifiedSettingsSkin.syncTheme();
ModeSetting.UiState ui = setting.ui();
@ -35,25 +43,38 @@ public final class ModeSettingRenderer {
int color = active ? UnifiedSettingsSkin.ACCENT : UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, hoverAnim * 0.50f);
ClickGuiRenderer.drawText(font, opt.label(), ox, oy, size, color, false);
}
renderSwatches(setting, x, y, mx, my);
}
public static void mouseClicked(ModeSetting setting, double mx, double my, int button) {
if (button != 0) return;
ModeSetting.UiState ui = setting.ui();
if (isSurfaceStyle(setting)) {
for (ModeSetting.SwatchLayout sw : ui.swatchLayouts) {
float ox = ui.baseX + sw.x();
float oy = ui.baseY + sw.y();
if (!UnifiedSettingsSkin.inside(mx, my, ox, oy, sw.w(), sw.h())) continue;
applySelection(setting, sw.id(), setting.selectedId());
return;
}
}
for (ModeSetting.OptionLayout opt : ui.optionLayouts) {
float ox = ui.baseX + opt.x();
float oy = ui.baseY + opt.y();
if (!UnifiedSettingsSkin.inside(mx, my, ox - SettingSkinUtil.m(2f, 2f), oy - SettingSkinUtil.m(1f, 1f), opt.w() + SettingSkinUtil.m(4f, 4f), SettingSkinUtil.m(16f, 8f)))
continue;
String before = setting.selectedId();
setting.selectId(opt.getId());
if (!opt.getId().equals(before)) ClickGuiSounds.changeMode();
if (setting.onChange() != null) setting.onChange().run();
if (setting.getParent() != null) setting.getParent().saveConfig();
applySelection(setting, opt.getId(), setting.selectedId());
return;
}
}
private static void applySelection(ModeSetting setting, String id, String before) {
setting.selectId(id);
if (!id.equals(before)) ClickGuiSounds.changeMode();
if (setting.onChange() != null) setting.onChange().run();
if (setting.getParent() != null) setting.getParent().saveConfig();
}
public static float getHeight(ModeSetting setting) {
layoutMode(setting);
return setting.ui().cachedHeight;
@ -83,11 +104,81 @@ public final class ModeSettingRenderer {
}
maxRowW = Math.max(maxRowW, offsetX);
ui.selectW = Math.max(0f, maxRowW + SettingSkinUtil.m(2f, 2f));
ui.cachedHeight = SettingSkinUtil.m(45f, 22f) + offsetY;
layoutSwatches(setting, ui, offsetY);
if (ui.swatchLayouts.isEmpty()) {
ui.cachedHeight = SettingSkinUtil.m(45f, 22f) + offsetY;
} else {
ModeSetting.SwatchLayout last = ui.swatchLayouts.get(ui.swatchLayouts.size() - 1);
ui.cachedHeight = last.y() + last.h() + SettingSkinUtil.m(15f, 7f);
}
ui.lastLayoutW = width;
ui.layoutOptionCount = count;
}
private static void layoutSwatches(ModeSetting setting, ModeSetting.UiState ui, float offsetY) {
ui.swatchLayouts.clear();
if (!isSurfaceStyle(setting)) return;
float sw = SettingSkinUtil.m(30f, 14f);
float sh = SettingSkinUtil.m(16f, 7f);
float gap = SettingSkinUtil.m(4f, 3f);
float rowY = SettingSkinUtil.m(27f, 10.7f) + offsetY + optionContainerHeightMode(ui) + SettingSkinUtil.m(5f, 4f);
float sx = SettingSkinUtil.m(7f, 6f);
for (String id : SWATCH_IDS) {
ui.swatchLayouts.add(new ModeSetting.SwatchLayout(id, sx, rowY, sw, sh));
sx += sw + gap;
}
}
private static void renderSwatches(ModeSetting setting, float x, float y, float mx, float my) {
ModeSetting.UiState ui = setting.ui();
if (ui.swatchLayouts.isEmpty()) return;
TextRenderer font = UnifiedSettingsSkin.fontMedium();
float size = SettingSkinUtil.m(11f, 5f);
float radius = SettingSkinUtil.m(3f, 3f);
for (ModeSetting.SwatchLayout sw : ui.swatchLayouts) {
float ox = x + sw.x();
float oy = y + sw.y();
boolean active = sw.id().equals(setting.selectedId());
boolean hover = UnifiedSettingsSkin.inside(mx, my, ox, oy, sw.w(), sw.h());
float hoverAnim = AnimationUtility.approach(ui.hoverAnims.getOrDefault(sw.id(), 0f), hover ? 1f : 0f, 0.20f);
ui.hoverAnims.put(sw.id(), hoverAnim);
drawSwatchSample(sw.id(), ox, oy, sw.w(), sw.h(), radius, hoverAnim);
int stroke = active
? UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 210)
: UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 70 + Math.round(hoverAnim * 70f));
ClickGuiRenderer.drawRoundedRectStroke(ox, oy, sw.w(), sw.h(), radius, SettingSkinUtil.m(0.8f, 0.5f), stroke);
String label = setting.getOptionDisplayName(sw.id());
float tw = UnifiedSettingsSkin.textWidth(font, label, size);
int color = active
? UnifiedSettingsSkin.ACCENT
: UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, 0.55f + hoverAnim * 0.45f);
ClickGuiRenderer.drawText(font, label, ox + Math.max(0f, (sw.w() - tw) * 0.5f), oy + sw.h() + SettingSkinUtil.m(3f, 1.5f), size, color, false);
}
}
private static void drawSwatchSample(String id, float x, float y, float w, float h, float radius, float hoverAnim) {
switch (id) {
case "glass" -> {
ClickGuiRenderer.drawRoundedRect(x, y, w, h, radius, 0x33FFFFFF);
ClickGuiRenderer.drawRoundedRect(x + w * 0.08f, y + h * 0.12f, w * 0.84f, h * 0.34f, radius, 0x40FFFFFF);
}
case "blur" -> {
ClickGuiRenderer.drawRoundedRect(x, y, w, h, radius, 0x4D8A8A96);
ClickGuiRenderer.drawRoundedRect(x, y + h * 0.55f, w, h * 0.30f, radius, 0x3360606E);
}
case "flat" -> ClickGuiRenderer.drawRoundedRect(x, y, w, h, radius, 0xFF3A3A46);
case "outline" -> {
}
case "none" -> ClickGuiRenderer.drawRoundedRect(x, y, w, h, radius, 0x14000000);
default -> {
}
}
if (hoverAnim > 0.01f && ("outline".equals(id) || "none".equals(id))) {
ClickGuiRenderer.drawRoundedRect(x, y, w, h, radius,
UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.SURFACE_HOVER, Math.round(95f * hoverAnim)));
}
}
private static float optionContainerHeightMode(ModeSetting.UiState ui) {
float max = SettingSkinUtil.m(10f, 10f);
for (ModeSetting.OptionLayout opt : ui.optionLayouts) max = Math.max(max, opt.y() - SettingSkinUtil.m(19f, 9.7f) + SettingSkinUtil.m(16f, 8f));

View file

@ -4,7 +4,10 @@ import dev.loki.lovisual.features.theme.Theme;
import dev.loki.lovisual.features.gui.clickgui.render.ClickGuiRenderer;
import dev.loki.lovisual.features.theme.Themes;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.renderer.style.StyleSpec;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
import dev.loki.lovisual.render.engine.svg.model.SvgRenderOptions;
import dev.loki.lovisual.render.helpers.material.SurfaceRenderer;
import dev.loki.lovisual.render.engine.text.font.info.FontInfo;
import dev.loki.lovisual.render.engine.text.font.Fonts;
import dev.loki.lovisual.render.engine.text.render.TextRenderer;
@ -107,19 +110,23 @@ public enum ModulesSettingsSkin {
static void drawGlass(float x, float y, float w, float h, float radius, float alpha) {
if (alpha <= 0.001f) return;
float a = clamp01(alpha);
Renderer2D.COLOR.liquidGlassRect(
x, y, w, h,
radius,
float glassAlpha = a * 0.58f;
StyleSpec spec = new StyleSpec(
SurfaceStyle.GLASS,
Math.max(3.0f * scale(), radius * 0.65f),
Theme.theme().accent(),
a * 0.58f,
-50.0f,
0.95f,
0.58f,
0.10f,
0.055f * a,
0.0f
);
0.0f,
Theme.theme().accent(),
0.6f,
0.0f);
SurfaceRenderer.plateSpec(Renderer2D.COLOR,
x, y, w, h, radius, radius, radius, radius,
spec, 1.0f, Theme.theme().accent(), glassAlpha, glassAlpha,
SurfaceStyle.AUTO);
}
static String fit(TextRenderer font, String text, float size, float width) {

View file

@ -0,0 +1,61 @@
package dev.loki.lovisual.features.gui.hud.config;
import dev.loki.lovisual.config.style.StyleConfig;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
/**
* Shared option ids and resolution for HUD widget background effects.
* Replaces the per-widget {@code EFFECT_NONE/BLUR/GLASS} string copies;
* {@link #AUTO} follows the global {@link StyleConfig} selection.
*/
public final class HudBgStyles {
public static final String NONE = "None";
public static final String BLUR = "Blur";
public static final String GLASS = "Glass";
public static final String AUTO = "Auto";
private HudBgStyles() {
}
/** Option list for every bg-effect ModeValue: legacy trio plus Auto. */
public static String[] options() {
return new String[]{NONE, BLUR, GLASS, AUTO};
}
/** Resolves a raw option id; {@code Auto} maps to the global style. */
public static SurfaceStyle resolve(String effect) {
if (GLASS.equals(effect)) return SurfaceStyle.GLASS;
if (BLUR.equals(effect)) return SurfaceStyle.BLUR;
if (AUTO.equals(effect)) return StyleConfig.get().style();
return SurfaceStyle.NONE;
}
public static boolean isNone(String effect) {
return resolve(effect) == SurfaceStyle.NONE;
}
public static boolean isBlur(String effect) {
return resolve(effect) == SurfaceStyle.BLUR;
}
public static boolean isGlass(String effect) {
return resolve(effect) == SurfaceStyle.GLASS;
}
public static boolean hasEffect(String effect) {
return !isNone(effect);
}
/**
* Normalizes an effect id for the JS compact-stat layer, which only knows
* Blur/Glass/None; FLAT/OUTLINE fall back to a plain fill there.
*/
public static String scriptEffect(String effect) {
return switch (resolve(effect)) {
case GLASS -> GLASS;
case BLUR -> BLUR;
case FLAT, OUTLINE, NONE, AUTO -> NONE;
};
}
}

View file

@ -4,14 +4,12 @@ import dev.loki.lovisual.config.definition.ConfigNameProvider;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.definition.SettingOwner;
import dev.loki.lovisual.config.io.ConfigPaths;
import dev.loki.lovisual.config.io.ConfigSerializer;
import dev.loki.lovisual.config.io.JsonConfigObject;
import dev.loki.lovisual.config.io.SettingDefProvider;
import dev.loki.lovisual.config.values.collection.ConfigValue;
import dev.loki.lovisual.config.values.mode.EnumValue;
import dev.loki.lovisual.config.values.primitive.NumberValue;
import dev.loki.lovisual.config.values.collection.ConfigValue;
import dev.loki.lovisual.config.values.mode.EnumValue;
import dev.loki.lovisual.config.values.primitive.NumberValue;
import dev.loki.lovisual.render.engine.math.HudScale;
import java.io.IOException;
@ -75,7 +73,7 @@ public final class HudGlobalConfig implements JsonConfigObject, ConfigNameProvid
@Override
public void saveConfig() {
// Global HUD values are code defaults only; no hud/global.json is written.
ConfigSerializer.requestSave(this);
}
@Override

View file

@ -4,6 +4,8 @@ import dev.loki.lovisual.features.theme.Theme;
import dev.loki.lovisual.features.theme.Themes;
import dev.loki.lovisual.render.engine.animation.AnimationUtility;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
import dev.loki.lovisual.render.helpers.material.SurfaceRenderer;
/**
* Shared helpers for HUD widget visuals.
@ -55,62 +57,8 @@ public enum HudRenderUtil {
boolean large,
float blurAlpha,
float glassAlpha) {
if (blurAlpha <= 0.001f && glassAlpha <= 0.001f) return;
float blurStrength = AnimationUtility.clamp(blurAlpha, 0.0f, 1.0f);
float materialAlpha = AnimationUtility.clamp(glassAlpha, 0.0f, 1.0f);
float safeScale = Math.max(0.001f, scale);
float fresnelPower = large ? -22.0f : -18.0f;
float thickness = (large ? 13.0f : 11.0f) * safeScale;
float baseAlpha = large ? 0.74f : 0.82f;
float fresnelMix = large ? 0.34f : 0.38f;
float distort = large ? 0.155f : 0.135f;
Renderer2D.COLOR.liquidGlassRect(
x,
y,
w,
h,
radius,
thickness,
0xFFFFFFFF,
materialAlpha,
blurStrength,
fresnelPower,
1.0f,
baseAlpha,
fresnelMix,
distort * materialAlpha,
0.0f
);
}
public static void drawLiquidGlassCorners(float x,
float y,
float w,
float h,
float radiusTL,
float radiusTR,
float radiusBR,
float radiusBL,
float scale,
boolean large,
float alpha) {
drawLiquidGlassCorners(
x,
y,
w,
h,
radiusTL,
radiusTR,
radiusBR,
radiusBL,
scale,
large,
alpha,
0xFFFFFFFF
);
SurfaceRenderer.plate(Renderer2D.COLOR, x, y, w, h, radius,
scale, large, blurAlpha, glassAlpha, 0xFFFFFFFF, SurfaceStyle.GLASS);
}
public static void drawLiquidGlassCorners(float x,
@ -141,38 +89,9 @@ public enum HudRenderUtil {
float blurAlpha,
float glassAlpha,
int tintArgb) {
if (blurAlpha <= 0.001f && glassAlpha <= 0.001f) return;
float blurStrength = AnimationUtility.clamp(blurAlpha, 0.0f, 1.0f);
float materialAlpha = AnimationUtility.clamp(glassAlpha, 0.0f, 1.0f);
float safeScale = Math.max(0.001f, scale);
float fresnelPower = large ? -22.0f : -18.0f;
float thickness = (large ? 13.0f : 11.0f) * safeScale;
float baseAlpha = large ? 0.74f : 0.82f;
float fresnelMix = large ? 0.34f : 0.38f;
float distort = large ? 0.155f : 0.135f;
Renderer2D.COLOR.liquidGlassRectCorners(
x,
y,
w,
h,
radiusTL,
radiusTR,
radiusBR,
radiusBL,
thickness,
tintArgb,
materialAlpha,
blurStrength,
fresnelPower,
1.0f,
baseAlpha,
fresnelMix,
distort * materialAlpha,
0.0f
);
SurfaceRenderer.plateCorners(Renderer2D.COLOR, x, y, w, h,
radiusTL, radiusTR, radiusBR, radiusBL,
scale, large, blurAlpha, glassAlpha, tintArgb, SurfaceStyle.GLASS);
}
public static void drawHudBackground(Renderer2D renderer,

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
@ -52,8 +53,6 @@ public final class Triangulator extends DraggableHudElement {
private static final String COLOR_THEME = "Theme";
private static final String COLOR_CUSTOM = "Custom";
private static final String EFFECT_NONE = "None";
private static final String EFFECT_BLUR = "Blur";
private final HudGlobalConfig hud = HudGlobalConfig.get();
private final ScriptedTriangulatorHudPanel scriptedPanel = new ScriptedTriangulatorHudPanel();
@ -62,7 +61,7 @@ public final class Triangulator extends DraggableHudElement {
private final NumberValue<Double> scaleValue = new NumberValue<>("triangulator_scale", 1.68, 0.5, 5.0);
private final ModeValue colorMode = new ModeValue("triangulator_color_mode", "Theme", COLOR_THEME, COLOR_CUSTOM);
private final ModeValue bgEffect = new ModeValue("triangulator_bg_effect", "Blur", EFFECT_NONE, EFFECT_BLUR);
private final ModeValue bgEffect = new ModeValue("triangulator_bg_effect", HudBgStyles.AUTO, HudBgStyles.NONE, HudBgStyles.BLUR, HudBgStyles.AUTO);
private final RGBAColorValue bg = new RGBAColorValue("triangulator_bg", "#F7343434");
private final RGBAColorValue bg2 = new RGBAColorValue("triangulator_bg_secondary", "#F7161616");
private final NumberValue<Integer> bgAlpha = new NumberValue<>("triangulator_bg_alpha", 225, 0, 255);
@ -290,7 +289,7 @@ public final class Triangulator extends DraggableHudElement {
}
private boolean hasEffect() {
return !EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
private boolean isNether() {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.combat;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.values.color.KeyBindValue;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
@ -36,7 +37,7 @@ public final class Inventory extends DraggableHudElement {
final NumberValue<Double> scaleValue = new NumberValue<>("inventory_scale", 1.32, HudPanelLayoutModes.SCALE_MIN, HudPanelLayoutModes.SCALE_MAX);
final ModeValue layoutMode = new ModeValue("inventory_layout", "Unified Divider", HudPanelLayoutModes.SPLIT_HEADER, HudPanelLayoutModes.UNIFIED_DIVIDER);
final ModeValue colorMode = new ModeValue("inventory_color_mode", "Theme", InventoryConstants.COLOR_THEME, InventoryConstants.COLOR_CUSTOM);
final ModeValue bgEffect = new ModeValue("inventory_bg_effect", "Blur", InventoryConstants.EFFECT_NONE, InventoryConstants.EFFECT_BLUR);
final ModeValue bgEffect = new ModeValue("inventory_bg_effect", HudBgStyles.AUTO, HudBgStyles.NONE, HudBgStyles.BLUR, HudBgStyles.AUTO);
final RGBAColorValue bg = new RGBAColorValue("inventory_bg", "#F7343434");
final RGBAColorValue bg2 = new RGBAColorValue("inventory_bg_secondary", "#F7161616");
final NumberValue<Integer> bgAlpha = new NumberValue<>("inventory_bg_alpha", 194, 0, 255);
@ -135,7 +136,7 @@ public final class Inventory extends DraggableHudElement {
}
boolean hasEffect() {
return !InventoryConstants.EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
void setSize(float w, float h) {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.combat;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
@ -38,7 +39,7 @@ public final class MediaPlayer extends DraggableHudElement {
final NumberValue<Integer> bgAlpha = new NumberValue<>("media_player_bg_alpha", 124, 0, 255);
final RGBColorValue accent = new RGBColorValue("media_player_accent", "#FF2F2F");
final RGBColorValue text = new RGBColorValue("media_player_text", "#FFFFFF");
final ModeValue bgEffect = new ModeValue("media_player_bg_effect", "None", MediaPlayerConstants.EFFECT_NONE, MediaPlayerConstants.EFFECT_BLUR, MediaPlayerConstants.EFFECT_GLASS);
final ModeValue bgEffect = new ModeValue("media_player_bg_effect", HudBgStyles.AUTO, HudBgStyles.NONE, HudBgStyles.BLUR, HudBgStyles.GLASS, HudBgStyles.AUTO);
final NumberValue<Integer> blurAlpha = new NumberValue<>("media_player_blur_alpha", 255, 0, 255);
final BooleanValue gradient = new BooleanValue("media_player_gradient", true);
float anim = 0f;
@ -138,15 +139,15 @@ public final class MediaPlayer extends DraggableHudElement {
}
boolean hasEffect() {
return !MediaPlayerConstants.EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
boolean isBlurEffect() {
return MediaPlayerConstants.EFFECT_BLUR.equals(bgEffect.get());
return HudBgStyles.isBlur(bgEffect.get());
}
boolean isGlassEffect() {
return MediaPlayerConstants.EFFECT_GLASS.equals(bgEffect.get());
return HudBgStyles.isGlass(bgEffect.get());
}
int getBgAlpha() {

View file

@ -37,6 +37,4 @@ final class InventoryConstants {
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
}

View file

@ -22,9 +22,6 @@ final class MediaPlayerConstants {
static final float BASE_TITLE_SCROLL_GAP = 14f;
static final float BASE_TITLE_FADE = 12f;
static final float TITLE_SCROLL_PAUSE_SEC = 0.8f;
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final String EFFECT_GLASS = "Glass";
static final float BASE_CONTENT_W = 170f;
static final int ICON_PAUSE = 0xEA02;
static final int ICON_PLAY = 0xEA03;

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.metrics;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
import dev.loki.lovisual.config.values.mode.EnumValue;
@ -42,9 +43,6 @@ public final class Coordinates extends DraggableHudElement implements Scriptable
static final float RIGHT_PAD = 5f;
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final String EFFECT_GLASS = "Glass";
final HudGlobalConfig hud = HudGlobalConfig.get();
final EnumValue<NetherMode> netherMode =
@ -55,7 +53,7 @@ public final class Coordinates extends DraggableHudElement implements Scriptable
final RGBColorValue labelColor = visibleWhen(colorNoAlpha("xyz_label_color", "#9B9B9B"), this::isCustomMode);
final RGBColorValue valueColor = visibleWhen(colorNoAlpha("xyz_value_color", "#FFFFFF"), this::isCustomMode);
final RGBColorValue extraColor = visibleWhen(colorNoAlpha("xyz_extra_color", "#BEBEBE"), this::isCustomMode);
final ModeValue bgEffect = mode("xyz_bg_effect", "bg_effect", "Blur", new String[]{EFFECT_NONE, EFFECT_BLUR, EFFECT_GLASS});
final ModeValue bgEffect = mode("xyz_bg_effect", "bg_effect", HudBgStyles.AUTO, HudBgStyles.options());
final RGBAColorValue bg = visibleWhen(color("xyz_bg", "#F7343434"), () -> isCustomMode() && !isGlassEffect());
final RGBAColorValue bg2 = visibleWhen(color("xyz_bg_secondary", "#F7161616"), () -> isCustomMode() && !isGlassEffect());
final RGBColorValue stroke = visibleWhen(colorNoAlpha("xyz_stroke", "#5A5A5A"), () -> isCustomMode() && !isGlassEffect());
@ -141,11 +139,11 @@ public final class Coordinates extends DraggableHudElement implements Scriptable
}
boolean isGlassEffect() {
return EFFECT_GLASS.equals(bgEffect.get());
return HudBgStyles.isGlass(bgEffect.get());
}
boolean hasEffect() {
return !EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
enum NetherMode implements EnumValue.IdProvider {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.metrics;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
import dev.loki.lovisual.config.values.mode.EnumValue;
@ -39,9 +40,6 @@ public final class GameTime extends DraggableHudElement implements ScriptableHud
static final String WIDTH_TEMPLATE = "00:00";
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final String EFFECT_GLASS = "Glass";
static final long SUNRISE_START = 23000L;
static final long SUNRISE_END = 1000L;
static final long SUNSET_START = 12000L;
@ -64,7 +62,7 @@ public final class GameTime extends DraggableHudElement implements ScriptableHud
final ModeValue colorMode = mode("game_time_color_mode", "color_mode", "Theme", new String[]{COLOR_THEME, COLOR_CUSTOM});
final RGBColorValue iconColor = visibleWhen(colorNoAlpha("game_time_icon_color", "#FFFFFF"), this::isCustomMode);
final RGBColorValue valueColor = visibleWhen(colorNoAlpha("game_time_value_color", "#FFFFFF"), this::isCustomMode);
final ModeValue bgEffect = mode("game_time_bg_effect", "bg_effect", "None", new String[]{EFFECT_NONE, EFFECT_BLUR, EFFECT_GLASS});
final ModeValue bgEffect = mode("game_time_bg_effect", "bg_effect", HudBgStyles.AUTO, HudBgStyles.options());
final RGBAColorValue bg = visibleWhen(color("game_time_bg", "#EB111318"), () -> isCustomMode() && !isGlassEffect());
final RGBAColorValue bg2 = visibleWhen(color("game_time_bg_secondary", "#F7161616"), () -> isCustomMode() && !isGlassEffect());
final RGBColorValue stroke = visibleWhen(colorNoAlpha("game_time_stroke", "#5A5A5A"), () -> isCustomMode() && !isGlassEffect());
@ -134,10 +132,10 @@ public final class GameTime extends DraggableHudElement implements ScriptableHud
}
boolean isGlassEffect() {
return EFFECT_GLASS.equals(bgEffect.get());
return HudBgStyles.isGlass(bgEffect.get());
}
boolean hasEffect() {
return !EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
}

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.metrics;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
import dev.loki.lovisual.config.values.mode.EnumValue;
@ -42,9 +43,6 @@ public final class SpeedBps extends DraggableHudElement implements ScriptableHud
static final float KMH_MULT = 3.6f;
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final String EFFECT_GLASS = "Glass";
static final long SAMPLE_INTERVAL_MS = 75L;
static final int SAMPLE_COUNT = 20;
@ -57,7 +55,7 @@ public final class SpeedBps extends DraggableHudElement implements ScriptableHud
final RGBColorValue iconColor = visibleWhen(colorNoAlpha("speed_bps_icon_color", "#FFFFFF"), this::isCustomMode);
final RGBColorValue valueColor = visibleWhen(colorNoAlpha("speed_bps_value_color", "#FFFFFF"), this::isCustomMode);
final RGBColorValue metaColor = visibleWhen(colorNoAlpha("speed_bps_meta_color", "#9B9B9B"), this::isCustomMode);
final ModeValue bgEffect = mode("speed_bps_bg_effect", "bg_effect", "Blur", new String[]{EFFECT_NONE, EFFECT_BLUR, EFFECT_GLASS});
final ModeValue bgEffect = mode("speed_bps_bg_effect", "bg_effect", HudBgStyles.AUTO, HudBgStyles.options());
final RGBAColorValue bg = visibleWhen(color("speed_bps_bg", "#F7343434"), () -> isCustomMode() && !isGlassEffect());
final RGBAColorValue bg2 = visibleWhen(color("speed_bps_bg_secondary", "#F7161616"), () -> isCustomMode() && !isGlassEffect());
final RGBColorValue stroke = visibleWhen(colorNoAlpha("speed_bps_stroke", "#5A5A5A"), () -> isCustomMode() && !isGlassEffect());
@ -127,11 +125,11 @@ public final class SpeedBps extends DraggableHudElement implements ScriptableHud
}
boolean isGlassEffect() {
return EFFECT_GLASS.equals(bgEffect.get());
return HudBgStyles.isGlass(bgEffect.get());
}
boolean hasEffect() {
return !EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
float hudX() {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.metrics;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
import dev.loki.lovisual.config.values.mode.EnumValue;
@ -40,9 +41,6 @@ public final class SystemTime extends DraggableHudElement implements ScriptableH
static final String WIDTH_TEMPLATE_SECONDS = "00:00:00";
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final String EFFECT_GLASS = "Glass";
final HudGlobalConfig hud = HudGlobalConfig.get();
final BooleanValue showSeconds = bool("system_time_seconds", false);
@ -50,7 +48,7 @@ public final class SystemTime extends DraggableHudElement implements ScriptableH
final ModeValue colorMode = mode("system_time_color_mode", "color_mode", "Theme", new String[]{COLOR_THEME, COLOR_CUSTOM});
final RGBColorValue iconColor = visibleWhen(colorNoAlpha("system_time_icon_color", "#FFFFFF"), this::isCustomMode);
final RGBColorValue valueColor = visibleWhen(colorNoAlpha("system_time_value_color", "#FFFFFF"), this::isCustomMode);
final ModeValue bgEffect = mode("system_time_bg_effect", "bg_effect", "Blur", new String[]{EFFECT_NONE, EFFECT_BLUR, EFFECT_GLASS});
final ModeValue bgEffect = mode("system_time_bg_effect", "bg_effect", HudBgStyles.AUTO, HudBgStyles.options());
final RGBAColorValue bg = visibleWhen(color("system_time_bg", "#EB111318"), () -> isCustomMode() && !isGlassEffect());
final RGBAColorValue bg2 = visibleWhen(color("system_time_bg_secondary", "#F7161616"), () -> isCustomMode() && !isGlassEffect());
final RGBColorValue stroke = visibleWhen(colorNoAlpha("system_time_stroke", "#5A5A5A"), () -> isCustomMode() && !isGlassEffect());
@ -120,10 +118,10 @@ public final class SystemTime extends DraggableHudElement implements ScriptableH
}
boolean isGlassEffect() {
return EFFECT_GLASS.equals(bgEffect.get());
return HudBgStyles.isGlass(bgEffect.get());
}
boolean hasEffect() {
return !EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
}

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.panels;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
@ -36,8 +37,6 @@ public final class Keybinds extends DraggableHudElement {
static final float COUNT_LABEL_OFFSET = 22.0f;
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final String MODE_PRESS = "Press";
static final String MODE_HOLD = "Hold";
@ -46,7 +45,7 @@ public final class Keybinds extends DraggableHudElement {
final NumberValue<Double> scaleValue = new NumberValue<>("keybinds_scale", 1.0, HudPanelLayoutModes.SCALE_MIN, HudPanelLayoutModes.SCALE_MAX);
final ModeValue layoutMode = new ModeValue("keybinds_layout", "Unified Divider", HudPanelLayoutModes.SPLIT_HEADER, HudPanelLayoutModes.UNIFIED_DIVIDER);
final ModeValue colorMode = new ModeValue("keybinds_color_mode", "Theme", COLOR_THEME, COLOR_CUSTOM);
final ModeValue bgEffect = new ModeValue("keybinds_bg_effect", "None", EFFECT_NONE, EFFECT_BLUR);
final ModeValue bgEffect = new ModeValue("keybinds_bg_effect", HudBgStyles.AUTO, HudBgStyles.NONE, HudBgStyles.BLUR, HudBgStyles.AUTO);
final RGBAColorValue bg = new RGBAColorValue("keybinds_bg", "#F7343434");
final RGBAColorValue bg2 = new RGBAColorValue("keybinds_bg_secondary", "#F7161616");
final NumberValue<Integer> bgAlpha = new NumberValue<>("keybinds_bg_alpha", 225, 0, 255);

View file

@ -36,7 +36,7 @@ public final class ModuleList extends DraggableHudElement implements ConfigValue
final EnumValue<ColorMode> colorMode =
new EnumValue<>("module_list_color_mode", ColorMode.CUSTOM, ColorMode.THEME, ColorMode.CUSTOM);
final EnumValue<BgEffect> bgEffect =
new EnumValue<>("module_list_bg_effect", BgEffect.BLUR, BgEffect.NONE, BgEffect.BLUR, BgEffect.GLASS);
new EnumValue<>("module_list_bg_effect", BgEffect.AUTO, BgEffect.NONE, BgEffect.BLUR, BgEffect.GLASS, BgEffect.AUTO);
final NumberValue<Integer> bgAlpha =
new NumberValue<>("module_list_bg_alpha", 226, 0, 255);
final NumberValue<Integer> blurAlpha =
@ -153,7 +153,7 @@ public final class ModuleList extends DraggableHudElement implements ConfigValue
void clampX(float maxX) { float nx = getX(); if (nx > maxX) nx = maxX; if (nx < 0f) nx = 0f; moveTo(nx, getY()); }
enum ColorMode implements EnumValue.IdProvider { THEME("Theme"), CUSTOM("Custom"); private final String id; ColorMode(String id){this.id=id;} @Override public String id(){return id;} }
enum BgEffect implements EnumValue.IdProvider { NONE("None"), BLUR("Blur"), GLASS("Glass"); private final String id; BgEffect(String id){this.id=id;} @Override public String id(){return id;} }
enum BgEffect implements EnumValue.IdProvider { NONE("None"), BLUR("Blur"), GLASS("Glass"), AUTO("Auto"); private final String id; BgEffect(String id){this.id=id;} @Override public String id(){return id;} }
enum TextEffect implements EnumValue.IdProvider { NONE("None"), SHIMMER("Shimmer"); private final String id; TextEffect(String id){this.id=id;} @Override public String id(){return id;} }
static final class Row {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.panels;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.values.color.KeyBindValue;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
@ -53,7 +54,7 @@ public final class Scoreboard extends DraggableHudElement {
final KeyBindValue toggleBind = new KeyBindValue("toggle_bind", "Э");
final NumberValue<Double> scale = new NumberValue<>("scoreboard_scale", 1.93, 0.5, 5.0);
final ModeValue colorMode = new ModeValue("scoreboard_color_mode", "Theme", "Theme", "Custom");
final ModeValue bgEffect = new ModeValue("scoreboard_bg_effect", "Blur", "None", "Blur");
final ModeValue bgEffect = new ModeValue("scoreboard_bg_effect", HudBgStyles.AUTO, HudBgStyles.NONE, HudBgStyles.BLUR, HudBgStyles.AUTO);
final NumberValue<Integer> blurAlpha = new NumberValue<>("scoreboard_blur_alpha", 255, 0, 255);
final NumberValue<Integer> bgAlpha = new NumberValue<>("scoreboard_bg_alpha", 182, 0, 255);
final RGBAColorValue bg = new RGBAColorValue("scoreboard_bg", "#820A0A0A");
@ -216,11 +217,11 @@ public final class Scoreboard extends DraggableHudElement {
}
boolean isBlurEffect() {
return "Blur".equals(bgEffect.get());
return HudBgStyles.isBlur(bgEffect.get());
}
boolean hasEffect() {
return !"None".equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
void setSize(float w, float h) {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.panels;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.features.gui.hud.config.HudRenderUtil;
import static dev.loki.lovisual.features.theme.Theme.theme;
@ -54,6 +55,6 @@ final class KeybindsPalette {
}
static boolean hasEffect(Keybinds host) {
return !Keybinds.EFFECT_NONE.equals(host.bgEffect.get());
return HudBgStyles.hasEffect(host.bgEffect.get());
}
}

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.panels;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.features.gui.hud.config.HudRenderUtil;
import dev.loki.lovisual.render.engine.animation.AnimatedRenderColors;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
@ -19,15 +20,15 @@ final class ModuleListPalette {
}
static boolean isBlurEffect(ModuleList host) {
return host.bgEffect.get() == ModuleList.BgEffect.BLUR;
return HudBgStyles.isBlur(host.bgEffect.get().id());
}
static boolean isGlassEffect(ModuleList host) {
return host.bgEffect.get() == ModuleList.BgEffect.GLASS;
return HudBgStyles.isGlass(host.bgEffect.get().id());
}
static boolean hasEffect(ModuleList host) {
return host.bgEffect.get() != ModuleList.BgEffect.NONE;
return HudBgStyles.hasEffect(host.bgEffect.get().id());
}
static boolean hasAnimatedTextGradient(ModuleList host) {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.stats;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
import dev.loki.lovisual.config.values.mode.EnumValue;
@ -43,9 +44,6 @@ public final class Fps extends DraggableHudElement implements ScriptableHudStatW
static final float RIGHT_PAD = 5f;
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final String EFFECT_GLASS = "Glass";
static final long DIGIT_ANIMATION_DURATION_MS = 200L;
static final float DIGIT_ANIMATION_OFFSET = 8.0f;
@ -55,7 +53,7 @@ public final class Fps extends DraggableHudElement implements ScriptableHudStatW
final RGBColorValue iconColor = visibleWhen(colorNoAlpha("fps_icon_color", "#FFFFFF"), this::isCustomMode);
final RGBColorValue valueColor = visibleWhen(colorNoAlpha("fps_value_color", "#FFFFFF"), this::isCustomMode);
final RGBColorValue metaColor = visibleWhen(colorNoAlpha("fps_meta_color", "#9B9B9B"), this::isCustomMode);
final ModeValue bgEffect = mode("fps_bg_effect", "bg_effect", "Blur", new String[]{EFFECT_NONE, EFFECT_BLUR, EFFECT_GLASS});
final ModeValue bgEffect = mode("fps_bg_effect", "bg_effect", HudBgStyles.AUTO, HudBgStyles.options());
final RGBAColorValue bg = visibleWhen(color("fps_bg", "#F7343434"), () -> isCustomMode() && !isGlassEffect());
final RGBAColorValue bg2 = visibleWhen(color("fps_bg_secondary", "#F7161616"), () -> isCustomMode() && !isGlassEffect());
final RGBColorValue stroke = visibleWhen(colorNoAlpha("fps_stroke", "#5A5A5A"), () -> isCustomMode() && !isGlassEffect());
@ -139,11 +137,11 @@ public final class Fps extends DraggableHudElement implements ScriptableHudStatW
}
boolean isGlassEffect() {
return EFFECT_GLASS.equals(bgEffect.get());
return HudBgStyles.isGlass(bgEffect.get());
}
boolean hasEffect() {
return !EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
public float hudX() {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.stats;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
import dev.loki.lovisual.config.values.mode.EnumValue;
@ -41,9 +42,6 @@ public final class Memory extends DraggableHudElement implements ScriptableHudSt
static final float RIGHT_PAD = 5f;
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final String EFFECT_GLASS = "Glass";
final HudGlobalConfig hud = HudGlobalConfig.get();
final NumberValue<Double> scale = num("memory_scale", 2.37, 0.5, 5.0);
@ -52,7 +50,7 @@ public final class Memory extends DraggableHudElement implements ScriptableHudSt
final RGBColorValue valueColor = visibleWhen(colorNoAlpha("memory_value_color", "#FFFFFF"), this::isCustomMode);
final RGBColorValue metaColor = visibleWhen(colorNoAlpha("memory_meta_color", "#9B9B9B"), this::isCustomMode);
final RGBColorValue extraColor = visibleWhen(colorNoAlpha("memory_extra_color", "#BEBEBE"), this::isCustomMode);
final ModeValue bgEffect = mode("memory_bg_effect", "bg_effect", "Blur", new String[]{EFFECT_NONE, EFFECT_BLUR, EFFECT_GLASS});
final ModeValue bgEffect = mode("memory_bg_effect", "bg_effect", HudBgStyles.AUTO, HudBgStyles.options());
final RGBAColorValue bg = visibleWhen(color("memory_bg", "#F7343434"), () -> isCustomMode() && !isGlassEffect());
final RGBAColorValue bg2 = visibleWhen(color("memory_bg_secondary", "#F7161616"), () -> isCustomMode() && !isGlassEffect());
final RGBColorValue stroke = visibleWhen(colorNoAlpha("memory_stroke", "#5A5A5A"), () -> isCustomMode() && !isGlassEffect());
@ -122,11 +120,11 @@ public final class Memory extends DraggableHudElement implements ScriptableHudSt
}
boolean isGlassEffect() {
return EFFECT_GLASS.equals(bgEffect.get());
return HudBgStyles.isGlass(bgEffect.get());
}
boolean hasEffect() {
return !EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
public float hudX() {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.stats;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
import dev.loki.lovisual.config.values.mode.EnumValue;
@ -41,9 +42,6 @@ public final class Ping extends DraggableHudElement implements ScriptableHudStat
static final float RIGHT_PAD = 5f;
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final String EFFECT_GLASS = "Glass";
final HudGlobalConfig hud = HudGlobalConfig.get();
final NumberValue<Double> scale = num("ping_scale", 2.58, 0.5, 5.0);
@ -51,7 +49,7 @@ public final class Ping extends DraggableHudElement implements ScriptableHudStat
final RGBColorValue iconColor = visibleWhen(colorNoAlpha("ping_icon_color", "#FFFFFF"), this::isCustomMode);
final RGBColorValue valueColor = visibleWhen(colorNoAlpha("ping_value_color", "#FFFFFF"), this::isCustomMode);
final RGBColorValue metaColor = visibleWhen(colorNoAlpha("ping_meta_color", "#9B9B9B"), this::isCustomMode);
final ModeValue bgEffect = mode("ping_bg_effect", "bg_effect", "None", new String[]{EFFECT_NONE, EFFECT_BLUR, EFFECT_GLASS});
final ModeValue bgEffect = mode("ping_bg_effect", "bg_effect", HudBgStyles.AUTO, HudBgStyles.options());
final RGBAColorValue bg = visibleWhen(color("ping_bg", "#F7343434"), () -> isCustomMode() && !isGlassEffect());
final RGBAColorValue bg2 = visibleWhen(color("ping_bg_secondary", "#F7161616"), () -> isCustomMode() && !isGlassEffect());
final RGBColorValue stroke = visibleWhen(colorNoAlpha("ping_stroke", "#5A5A5A"), () -> isCustomMode() && !isGlassEffect());
@ -116,11 +114,11 @@ public final class Ping extends DraggableHudElement implements ScriptableHudStat
}
boolean isGlassEffect() {
return EFFECT_GLASS.equals(bgEffect.get());
return HudBgStyles.isGlass(bgEffect.get());
}
boolean hasEffect() {
return !EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
public float hudX() {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.stats;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
import dev.loki.lovisual.config.values.mode.EnumValue;
@ -42,9 +43,6 @@ public final class Tps extends DraggableHudElement implements ScriptableHudStatW
static final float RIGHT_PAD = 5f;
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final String EFFECT_GLASS = "Glass";
final HudGlobalConfig hud = HudGlobalConfig.get();
final BooleanValue extra = bool("tps_extra", false);
@ -54,7 +52,7 @@ public final class Tps extends DraggableHudElement implements ScriptableHudStatW
final RGBColorValue valueColor = visibleWhen(colorNoAlpha("tps_value_color", "#FFFFFF"), this::isCustomMode);
final RGBColorValue metaColor = visibleWhen(colorNoAlpha("tps_meta_color", "#9B9B9B"), this::isCustomMode);
final RGBColorValue extraColor = visibleWhen(colorNoAlpha("tps_extra_color", "#BEBEBE"), this::isCustomMode);
final ModeValue bgEffect = mode("tps_bg_effect", "bg_effect", "Blur", new String[]{EFFECT_NONE, EFFECT_BLUR, EFFECT_GLASS});
final ModeValue bgEffect = mode("tps_bg_effect", "bg_effect", HudBgStyles.AUTO, HudBgStyles.options());
final RGBAColorValue bg = visibleWhen(color("tps_bg", "#F7343434"), () -> isCustomMode() && !isGlassEffect());
final RGBAColorValue bg2 = visibleWhen(color("tps_bg_secondary", "#F7161616"), () -> isCustomMode() && !isGlassEffect());
final RGBColorValue stroke = visibleWhen(colorNoAlpha("tps_stroke", "#5A5A5A"), () -> isCustomMode() && !isGlassEffect());
@ -125,11 +123,11 @@ public final class Tps extends DraggableHudElement implements ScriptableHudStatW
}
boolean isGlassEffect() {
return EFFECT_GLASS.equals(bgEffect.get());
return HudBgStyles.isGlass(bgEffect.get());
}
boolean hasEffect() {
return !EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
public float hudX() {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.stats;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.features.gui.hud.config.HudRenderUtil;
import static dev.loki.lovisual.features.theme.Theme.theme;
@ -44,10 +45,10 @@ final class FpsPalette {
}
static boolean isGlassEffect(Fps host) {
return Fps.EFFECT_GLASS.equals(host.bgEffect.get());
return HudBgStyles.isGlass(host.bgEffect.get());
}
static boolean hasEffect(Fps host) {
return !Fps.EFFECT_NONE.equals(host.bgEffect.get());
return HudBgStyles.hasEffect(host.bgEffect.get());
}
}

View file

@ -4,6 +4,7 @@ import dev.loki.lovisual.features.gui.hud.base.HudTextEffects;
import dev.loki.lovisual.features.gui.hud.config.HudRenderUtil;
import dev.loki.lovisual.features.gui.hud.script.ScriptedCompactHudStatRenderer;
import dev.loki.lovisual.render.engine.math.HudScale;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.text.font.Fonts;
import dev.loki.lovisual.render.engine.text.font.info.FontInfo;
@ -29,8 +30,14 @@ final class FpsRender {
long nowMs = Util.getMillis();
String value = FpsAnimator.resolveDisplayedFps(host, Integer.toString(fps), nowMs);
String unit = "FPS";
float digitAnimProgress = FpsAnimator.digitProgress(host, nowMs);
String widthValue = host.digitAnimation.get() ? FpsAnimator.widerText(value, host.previousShownFps) : value;
// Optimize.lean_hud: no digit roll — single string, settled progress.
boolean digitAnim = host.digitAnimation.get() && !OptimizeState.isLeanHud();
float digitAnimProgress = 1.0f;
String widthValue = value;
if (digitAnim) {
digitAnimProgress = FpsAnimator.digitProgress(host, nowMs);
widthValue = FpsAnimator.widerText(value, host.previousShownFps);
}
FpsPalette.update(host);
TextRenderer fallback = textRenderer != null ? textRenderer : TextRenderer.get();
@ -91,7 +98,7 @@ final class FpsRender {
host.scriptModel.unit().set(unit, "OnestMedium", drawScale, unitX - baseX, textY - baseY, unitW, host.uiMetaColor);
host.scriptModel.extra().hidden();
host.scriptModel.animation().setLabelEffect(host.labelEffect.get().name(), host.labelEffectSpeed.get(), time)
.setDigitAnimation(host.digitAnimation.get(), host.previousShownFps, digitAnimProgress, Fps.DIGIT_ANIMATION_OFFSET);
.setDigitAnimation(digitAnim, host.previousShownFps, digitAnimProgress, Fps.DIGIT_ANIMATION_OFFSET);
host.scriptModel.data("fps", fps)
.data("valueText", value)
.data("unitText", unit);

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.status;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
@ -42,15 +43,13 @@ public final class Admins extends DraggableHudElement {
static final float ROW_CONTENT_CENTER_OFFSET = 1.95f;
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
final HudGlobalConfig hud = HudGlobalConfig.get();
final ScriptedListHudPanel scriptedPanel = new ScriptedListHudPanel();
final NumberValue<Double> scaleValue = new NumberValue<>("admins_scale", 1.0, HudPanelLayoutModes.SCALE_MIN, HudPanelLayoutModes.SCALE_MAX);
final ModeValue layoutMode = new ModeValue("admins_layout", "Split Header", HudPanelLayoutModes.SPLIT_HEADER, HudPanelLayoutModes.UNIFIED_DIVIDER);
final ModeValue colorMode = new ModeValue("admins_color_mode", "Theme", COLOR_THEME, COLOR_CUSTOM);
final ModeValue bgEffect = new ModeValue("admins_bg_effect", "Blur", EFFECT_NONE, EFFECT_BLUR);
final ModeValue bgEffect = new ModeValue("admins_bg_effect", HudBgStyles.AUTO, HudBgStyles.NONE, HudBgStyles.BLUR, HudBgStyles.AUTO);
final RGBAColorValue bg = new RGBAColorValue("admins_bg", "#EB111318");
final RGBAColorValue bg2 = new RGBAColorValue("admins_bg_secondary", "#F7161616");
final NumberValue<Integer> bgAlpha = new NumberValue<>("admins_bg_alpha", 131, 0, 255);

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.status;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
@ -57,8 +58,6 @@ public final class Cooldowns extends DraggableHudElement {
static final double BLINK_SPEED = 0.008;
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final int PVP_ACTIVE_COLOR = 0xFFFFA500;
static final int PVP_IDLE_COLOR = 0xFF00A0FF;
static final int PVP_BLOCKED_COLOR = 0xFFFF5656;
@ -70,7 +69,7 @@ public final class Cooldowns extends DraggableHudElement {
final NumberValue<Double> scaleValue = new NumberValue<>("cooldowns_scale", 1.0, HudPanelLayoutModes.SCALE_MIN, HudPanelLayoutModes.SCALE_MAX);
final ModeValue layoutMode = new ModeValue("cooldowns_layout", "Split Header", HudPanelLayoutModes.SPLIT_HEADER, HudPanelLayoutModes.UNIFIED_DIVIDER);
final ModeValue colorMode = new ModeValue("cooldowns_color_mode", "Theme", COLOR_THEME, COLOR_CUSTOM);
final ModeValue bgEffect = new ModeValue("cooldowns_bg_effect", "Blur", EFFECT_NONE, EFFECT_BLUR);
final ModeValue bgEffect = new ModeValue("cooldowns_bg_effect", HudBgStyles.AUTO, HudBgStyles.NONE, HudBgStyles.BLUR, HudBgStyles.AUTO);
final BooleanValue blink = new BooleanValue("cooldowns_blink", true);
final RGBAColorValue bg = new RGBAColorValue("cooldowns_bg", "#EB111318");
final RGBAColorValue bg2 = new RGBAColorValue("cooldowns_bg_secondary", "#F7161616");

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.status;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
@ -55,8 +56,6 @@ public final class Potions extends DraggableHudElement {
static final double BLINK_SPEED = 0.009;
static final String COLOR_THEME = "Theme";
static final String COLOR_CUSTOM = "Custom";
static final String EFFECT_NONE = "None";
static final String EFFECT_BLUR = "Blur";
static final int NEGATIVE_EFFECT_RGB = 0xFFFF554B;
static final Identifier[] PREVIEW_ICONS = new Identifier[]{
Identifier.fromNamespaceAndPath("minecraft", "textures/mob_effect/speed.png"),
@ -71,7 +70,7 @@ public final class Potions extends DraggableHudElement {
final NumberValue<Double> scaleValue = new NumberValue<>("potions_scale", 1.05, HudPanelLayoutModes.SCALE_MIN, HudPanelLayoutModes.SCALE_MAX);
final ModeValue layoutMode = new ModeValue("potions_layout", "Unified Divider", HudPanelLayoutModes.SPLIT_HEADER, HudPanelLayoutModes.UNIFIED_DIVIDER);
final ModeValue colorMode = new ModeValue("potions_color_mode", "Theme", COLOR_THEME, COLOR_CUSTOM);
final ModeValue bgEffect = new ModeValue("potions_bg_effect", "Blur", EFFECT_NONE, EFFECT_BLUR);
final ModeValue bgEffect = new ModeValue("potions_bg_effect", HudBgStyles.AUTO, HudBgStyles.NONE, HudBgStyles.BLUR, HudBgStyles.AUTO);
final RGBAColorValue bg = new RGBAColorValue("potions_bg", "#EB784F4F");
final RGBAColorValue bg2 = new RGBAColorValue("potions_bg_secondary", "#F7161616");
final NumberValue<Integer> bgAlpha = new NumberValue<>("potions_bg_alpha", 200, 0, 255);

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.status;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.features.gui.hud.config.HudRenderUtil;
import static dev.loki.lovisual.features.theme.Theme.theme;
@ -70,6 +71,6 @@ final class AdminsPalette {
}
static boolean hasEffect(Admins host) {
return !Admins.EFFECT_NONE.equals(host.bgEffect.get());
return HudBgStyles.hasEffect(host.bgEffect.get());
}
}

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.status;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.features.gui.hud.config.HudRenderUtil;
import static dev.loki.lovisual.features.theme.Theme.theme;
@ -45,5 +46,5 @@ final class CooldownsPalette {
static boolean isThemeMode(Cooldowns host) { return Cooldowns.COLOR_THEME.equals(host.colorMode.get()); }
static boolean isCustomMode(Cooldowns host) { return Cooldowns.COLOR_CUSTOM.equals(host.colorMode.get()); }
static boolean hasEffect(Cooldowns host) { return !Cooldowns.EFFECT_NONE.equals(host.bgEffect.get()); }
static boolean hasEffect(Cooldowns host) { return HudBgStyles.hasEffect(host.bgEffect.get()); }
}

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.status;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.features.gui.hud.config.HudRenderUtil;
import static dev.loki.lovisual.features.theme.Theme.theme;
@ -56,6 +57,6 @@ final class PotionsPalette {
}
static boolean hasEffect(Potions host) {
return !Potions.EFFECT_NONE.equals(host.bgEffect.get());
return HudBgStyles.hasEffect(host.bgEffect.get());
}
}

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.draggable.impl.targethud;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
import dev.loki.lovisual.config.values.mode.ModeValue;
@ -104,9 +105,6 @@ public final class TargetHud extends DraggableHudElement {
public static final String COLOR_THEME = "Theme";
public static final String COLOR_CUSTOM = "Custom";
public static final String EFFECT_NONE = "None";
public static final String EFFECT_BLUR = "Blur";
public static final String EFFECT_GLASS = "Glass";
public static final String EFFECTS_OFF = "Off";
public static final String EFFECTS_COMPACT = "Compact";
public static final String EQUIPMENT_OFF = "Off";
@ -171,7 +169,7 @@ public final class TargetHud extends DraggableHudElement {
public final RGBColorValue hitInner =
new RGBColorValue("target_hit_inner", "#FF7373");
public final ModeValue bgEffect =
new ModeValue("target_bg_effect", "Glass", EFFECT_NONE, EFFECT_BLUR, EFFECT_GLASS);
new ModeValue("target_bg_effect", HudBgStyles.AUTO, HudBgStyles.NONE, HudBgStyles.BLUR, HudBgStyles.GLASS, HudBgStyles.AUTO);
public final BooleanValue hitAnim =
new BooleanValue("target_hit_anim", true);
public final NumberValue<Double> hitPulse =
@ -308,15 +306,15 @@ public final class TargetHud extends DraggableHudElement {
}
public boolean hasEffect() {
return !EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
public boolean isBlurEffect() {
return EFFECT_BLUR.equals(bgEffect.get());
return HudBgStyles.isBlur(bgEffect.get());
}
public boolean isGlassEffect() {
return EFFECT_GLASS.equals(bgEffect.get());
return HudBgStyles.isGlass(bgEffect.get());
}
public boolean isEffectsEnabled() {

View file

@ -10,6 +10,9 @@ import dev.loki.lovisual.render.engine.color.RenderColor;
import dev.loki.lovisual.render.engine.core.context.ViewportContext;
import dev.loki.lovisual.render.engine.math.HudScale;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.renderer.style.StyleSpecs;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
import dev.loki.lovisual.render.helpers.material.SurfaceRenderer;
import dev.loki.lovisual.render.engine.text.font.info.FontInfo;
import dev.loki.lovisual.render.engine.text.font.Fonts;
import dev.loki.lovisual.render.engine.text.render.TextRenderer;
@ -26,14 +29,7 @@ public final class SwapTooltip extends AbstractHudElement {
private static final float PAD_X = 5.0f;
private static final float PAD_Y = 3.8f;
private static final float EXTRA_OFFSET_NO_BARS = 14.0f;
private static final int GLASS_TINT = 0xFFFFFFFF;
private static final int GLASS_VEIL = 0x2A141414;
private static final float GLASS_THICKNESS = 11.0f;
private static final float GLASS_FRESNEL_POWER = -18.0f;
private static final float GLASS_FRESNEL_ALPHA = 1.0f;
private static final float GLASS_BASE_ALPHA = 0.82f;
private static final float GLASS_FRESNEL_MIX = 0.38f;
private static final float GLASS_DISTORT = 0.135f;
private static String text;
private static int color;
@ -205,23 +201,10 @@ public final class SwapTooltip extends AbstractHudElement {
}
private static void drawGlass(float x, float y, float w, float h, float radius, float alpha) {
if (alpha <= 0.001f || w <= 0.0f || h <= 0.0f) return;
Renderer2D.COLOR.liquidGlassRect(
x,
y,
w,
h,
radius,
GLASS_THICKNESS,
GLASS_TINT,
alpha,
GLASS_FRESNEL_POWER,
GLASS_FRESNEL_ALPHA,
GLASS_BASE_ALPHA,
GLASS_FRESNEL_MIX,
GLASS_DISTORT,
0.0f
);
SurfaceRenderer.plateSpec(Renderer2D.COLOR, x, y, w, h,
radius, radius, radius, radius,
StyleSpecs.glass(false), 1.0f, 0xFFFFFFFF, alpha, 0.0f,
SurfaceStyle.AUTO);
}
private static void resetState() {

View file

@ -1,5 +1,6 @@
package dev.loki.lovisual.features.gui.hud.nondraggable.impl.hotbar;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.values.color.RGBAColorValue;
import dev.loki.lovisual.config.values.color.RGBColorValue;
@ -31,9 +32,6 @@ import static dev.loki.lovisual.features.theme.Theme.theme;
public final class CustomHotbar extends AbstractHudElement {
/** Sentinel values for the {@code bg_effect} / {@code hotbar_color_mode} mode-settings. */
private static final String EFFECT_NONE = "None";
private static final String EFFECT_BLUR = "Blur";
private static final String EFFECT_GLASS = "Glass";
private static final String COLOR_THEME = "Theme";
private static final String COLOR_CUSTOM = "Custom";
@ -48,7 +46,7 @@ public final class CustomHotbar extends AbstractHudElement {
private final BooleanValue customSelectColor = new BooleanValue("custom_select_color", false);
private final BooleanValue customDividerColor = new BooleanValue("custom_divider_color", false);
private final NumberValue<Integer> accentAlpha = new NumberValue<>("accent_alpha", 255, 0, 255);
private final ModeValue bgEffect = new ModeValue("bg_effect", "Glass", EFFECT_NONE, EFFECT_BLUR, EFFECT_GLASS);
private final ModeValue bgEffect = new ModeValue("bg_effect", HudBgStyles.AUTO, HudBgStyles.NONE, HudBgStyles.BLUR, HudBgStyles.GLASS, HudBgStyles.AUTO);
private final NumberValue<Integer> blurAlpha = new NumberValue<>("blur_alpha", 255, 20, 255);
private CustomHotbar() {
@ -140,7 +138,7 @@ public final class CustomHotbar extends AbstractHudElement {
}
boolean hasEffect() {
return !EFFECT_NONE.equals(bgEffect.get());
return HudBgStyles.hasEffect(bgEffect.get());
}
private boolean isThemeMode() {
@ -152,11 +150,11 @@ public final class CustomHotbar extends AbstractHudElement {
}
private boolean isBlurEffect() {
return EFFECT_BLUR.equals(bgEffect.get());
return HudBgStyles.isBlur(bgEffect.get());
}
private boolean isGlassEffect() {
return EFFECT_GLASS.equals(bgEffect.get());
return HudBgStyles.isGlass(bgEffect.get());
}
/** How the off-hand slot is composed with the main 9-slot row. */

View file

@ -2,6 +2,9 @@ package dev.loki.lovisual.features.gui.hud.nondraggable.impl.locator.panel;
import dev.loki.lovisual.render.engine.math.ColorMath;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.renderer.style.StyleSpec;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
import dev.loki.lovisual.render.helpers.material.SurfaceRenderer;
import net.minecraft.util.Mth;
import static dev.loki.lovisual.features.gui.hud.nondraggable.impl.bars.CustomBar.*;
@ -24,25 +27,23 @@ public final class CustomLocatorLabelPanel {
float effectiveAlpha = Mth.clamp(alpha * (bm != null ? bm.getHudOverlayAlphaFactor() : 1.0f), 0.0f, 1.0f);
float materialAlpha = Mth.clamp(0.78f + effectiveAlpha * 0.22f, 0.0f, 1.0f);
float blurAlpha = effectiveAlpha;
float thickness = 15.5f * Math.max(0.001f, scale);
r2d.liquidGlassRect(
x,
y,
w,
h,
radius,
thickness,
0xFFFFFFFF,
materialAlpha,
blurAlpha,
StyleSpec spec = new StyleSpec(
SurfaceStyle.GLASS,
15.5f,
-26.0f,
0.96f,
0.98f,
0.46f,
0.172f * materialAlpha,
2.65f
);
2.65f,
0xFFFFFFFF,
0.6f,
0.0f);
SurfaceRenderer.plateSpec(r2d,
x, y, w, h, radius, radius, radius, radius,
spec, Math.max(0.001f, scale), 0xFFFFFFFF, materialAlpha, blurAlpha,
SurfaceStyle.AUTO);
r2d.roundedRect(
x,

View file

@ -1,5 +1,7 @@
package dev.loki.lovisual.features.gui.hud.script;
import dev.loki.lovisual.features.gui.hud.config.HudBgStyles;
import java.util.LinkedHashMap;
public final class CompactHudParts {
@ -28,7 +30,7 @@ public final class CompactHudParts {
}
void writeTo(LinkedHashMap<String, Object> p) {
p.put("backgroundEffect", effect);
p.put("backgroundEffect", HudBgStyles.scriptEffect(effect));
p.put("backgroundTheme", theme);
p.put("blurAlpha", blurAlpha);
p.put("bgPrimary", CompactHudCodec.color(primary));

View file

@ -0,0 +1,88 @@
package dev.loki.lovisual.features.module.modules.misc.optimize;
import dev.loki.lovisual.config.values.primitive.BooleanValue;
import dev.loki.lovisual.features.module.core.Module;
import dev.loki.lovisual.features.module.core.ModuleCategory;
import dev.loki.lovisual.features.module.core.ModuleInfo;
import dev.loki.lovisual.features.module.phase.Notifier;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
/**
* Manual FPS rubilnik: one switch plus four knobs, each cutting a named cost.
*
* <p>No auto-degradation by FPS — the owner's rule. Render code reads
* {@link OptimizeState}, never this class; this module only pushes state into it.
*/
@ModuleInfo(
id = "optimize",
displayName = "Optimize",
category = ModuleCategory.MISC
)
public final class Optimize extends Module {
private final BooleanValue noGlass = bool("no_glass", true);
private final BooleanValue litePost = bool("lite_post", true);
private final BooleanValue liteSky = bool("lite_sky", true);
private final BooleanValue leanHud = bool("lean_hud", true);
private boolean notified;
@Override
public void onEnable() {
pushState();
if (!notified) {
notified = true;
Notifier.info(
"Optimize: "
+ summaryOf(noGlass.get(), litePost.get(), liteSky.get(), leanHud.get()));
}
}
@Override
public void onDisable() {
OptimizeState.reset();
}
/** Picks up knob changes made while the module stays on. */
@Override
public void onFrame(float d) {
pushState();
}
private void pushState() {
boolean on = isEnabled();
OptimizeState.apply(
on && noGlass.get(),
on && litePost.get(),
on && liteSky.get(),
on && leanHud.get());
}
/** Compact list of what is being cut, for the first-enable notice. */
static String summaryOf(boolean glass, boolean post, boolean sky, boolean hud) {
StringBuilder out = new StringBuilder();
if (glass) {
append(out, "no glass");
}
if (post) {
append(out, "light post");
}
if (sky) {
append(out, "simple sky");
}
if (hud) {
append(out, "lean HUD");
}
if (out.length() == 0) {
return "no knobs active";
}
return out.toString();
}
private static void append(StringBuilder out, String knob) {
if (out.length() > 0) {
out.append(", ");
}
out.append(knob);
}
}

View file

@ -15,6 +15,7 @@ import dev.loki.lovisual.features.module.core.Module;
import dev.loki.lovisual.features.module.core.ModuleCategory;
import dev.loki.lovisual.features.module.core.ModuleInfo;
import dev.loki.lovisual.render.engine.RenderState;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines;
import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer;
import dev.loki.lovisual.render.engine.uniform.impl.post.MotionBlurUniforms;
@ -31,6 +32,7 @@ public final class MotionBlur extends Module implements PostProcessPass {
private static final float HORIZONTAL_DEGREES_PER_SCREEN = 90.0f;
private static final float VERTICAL_DEGREES_PER_SCREEN = 70.0f;
private static final int SHADER_TAPS = 11;
private static final int LITE_TAPS = 5;
private final MotionBlurResources resources = new MotionBlurResources();
@ -135,7 +137,15 @@ public final class MotionBlur extends Module implements PostProcessPass {
return false;
}
float temporalBlend = computeHistoryBlend(motion, hasHistory);
// Optimize.lite_post: fewer taps and no temporal history, which the shader then
// early-outs on — skipping the neighborhood/closest-history texture fetches.
boolean historyValid = hasHistory && !OptimizeState.isLitePost();
int taps = SHADER_TAPS;
if (OptimizeState.isLitePost()) {
taps = LITE_TAPS;
}
float temporalBlend = computeHistoryBlend(motion, historyValid);
MotionBlurUniforms.update(
width,
height,
@ -145,9 +155,9 @@ public final class MotionBlur extends Module implements PostProcessPass {
motion.history().yPixels(),
maxBlurPixels.get(),
minPixels,
SHADER_TAPS,
taps,
temporalBlend,
hasHistory,
historyValid,
historyClamp.get()
);

View file

@ -8,6 +8,9 @@ import dev.loki.lovisual.render.engine.text.font.info.FontInfo;
import dev.loki.lovisual.render.engine.text.font.Fonts;
import dev.loki.lovisual.render.engine.text.render.TextRenderer;
import dev.loki.lovisual.render.helpers.material.MatteHudStyle;
import dev.loki.lovisual.render.engine.renderer.style.StyleSpecs;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
import dev.loki.lovisual.render.helpers.material.SurfaceRenderer;
import dev.loki.lovisual.features.module.modules.visuals.nametags.NameTagLayoutEngine;
import dev.loki.lovisual.features.module.modules.visuals.nametags.NameTagModel;
import dev.loki.lovisual.features.module.modules.visuals.nametags.NameTags;
@ -24,14 +27,7 @@ public final class NameTagPlateRenderer {
private static final float NAMEPLATE_RADIUS = 7.0f;
private static final float MATTE_NAMEPLATE_RADIUS = 4.0f;
private static final int NAMEPLATE_GLASS_TINT = 0xFFFFFFFF;
private static final int NAMEPLATE_GLASS_VEIL = 0x2A141414;
private static final float NAMEPLATE_GLASS_THICKNESS = 11.0f;
private static final float NAMEPLATE_GLASS_FRESNEL_POWER = -18.0f;
private static final float NAMEPLATE_GLASS_FRESNEL_ALPHA = 1.0f;
private static final float NAMEPLATE_GLASS_BASE_ALPHA = 0.82f;
private static final float NAMEPLATE_GLASS_FRESNEL_MIX = 0.38f;
private static final float NAMEPLATE_GLASS_DISTORT = 0.135f;
private static ItemStack totemBadgeStack;
private NameTagPlateRenderer() {
@ -62,29 +58,20 @@ public final class NameTagPlateRenderer {
if (alpha <= 0) return;
float globalAlpha = alpha / 255.0f;
if (isMatteNameplate(self)) {
MatteHudStyle.drawPlate(renderer, layout.bgX(), layout.bgY(), layout.bgW(), layout.bgH(),
nameplateRadius(self, layout), globalAlpha);
return;
}
float radius = nameplateRadius(self, layout);
Renderer2D.COLOR.liquidGlassRect(
SurfaceRenderer.plateSpec(renderer,
layout.bgX(),
layout.bgY(),
layout.bgW(),
layout.bgH(),
radius,
NAMEPLATE_GLASS_THICKNESS,
NAMEPLATE_GLASS_TINT,
radius, radius, radius, radius,
StyleSpecs.glass(false),
1.0f,
0xFFFFFFFF,
globalAlpha,
NAMEPLATE_GLASS_FRESNEL_POWER,
NAMEPLATE_GLASS_FRESNEL_ALPHA,
NAMEPLATE_GLASS_BASE_ALPHA,
NAMEPLATE_GLASS_FRESNEL_MIX,
NAMEPLATE_GLASS_DISTORT,
0.0f
);
0.0f,
isMatteNameplate(self) ? SurfaceStyle.FLAT : SurfaceStyle.GLASS);
if (isMatteNameplate(self)) return;
renderer.roundedRect(
layout.bgX(),
layout.bgY(),

View file

@ -8,6 +8,7 @@ import dev.loki.lovisual.features.module.lifecycle.Modules;
import dev.loki.lovisual.render.engine.RenderState;
import dev.loki.lovisual.render.engine.core.system.LoVisualWorldMatrices;
import dev.loki.lovisual.render.engine.depth.WorldSceneDepth;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines;
import dev.loki.lovisual.render.engine.postprocess.blur.DepthOfFieldDepthSource;
import dev.loki.lovisual.render.engine.postprocess.blur.DepthOfFieldQuality;
@ -55,7 +56,11 @@ final class ReimaginedDepthOfFieldHelper implements PostProcessPass {
depth = new ReimaginedDepthBindings(null, null, null, null, null, null);
}
buildProjection();
DepthOfFieldUniforms.update(projection, context.width(), context.height(), 0.0f, 0.0f, farStart.get(), farTransition.get(), strength.get(), maxRadius.get(), quality.get().taps(), 0.85f, debugCoc.get(), depth.hasMain(), depth.hasTranslucent(), depth.hasItemEntity(), depth.hasParticles(), depth.hasWeather(), depth.hasClouds());
int taps = quality.get().taps();
if (OptimizeState.isLitePost()) {
taps = DepthOfFieldQuality.LOW.taps();
}
DepthOfFieldUniforms.update(projection, context.width(), context.height(), 0.0f, 0.0f, farStart.get(), farTransition.get(), strength.get(), maxRadius.get(), taps, 0.85f, debugCoc.get(), depth.hasMain(), depth.hasTranslucent(), depth.hasItemEntity(), depth.hasParticles(), depth.hasWeather(), depth.hasClouds());
try {
FullScreenRenderer.ensureInit();
FullScreenRenderer.begin("LoVisual DepthOfField Pass").attachment(dst).pipeline(LoVisualRenderPipelines.DEPTH_OF_FIELD).uniform("DepthOfField", DepthOfFieldUniforms.get()).sampler("u_Texture", src, PostProcessManager.getSampler()).sampler("u_MainDepth", depth.mainOr(src), PostProcessManager.getSampler()).sampler("u_TranslucentDepth", depth.translucentOr(src), PostProcessManager.getSampler()).sampler("u_ItemEntityDepth", depth.itemEntityOr(src), PostProcessManager.getSampler()).sampler("u_ParticlesDepth", depth.particlesOr(src), PostProcessManager.getSampler()).sampler("u_WeatherDepth", depth.weatherOr(src), PostProcessManager.getSampler()).sampler("u_CloudsDepth", depth.cloudsOr(src), PostProcessManager.getSampler()).end();

View file

@ -0,0 +1,47 @@
package dev.loki.lovisual.render.engine.optimize;
/**
* Plain boolean holder for the manual {@code Optimize} module knobs.
*
* <p>Render code reads these getters instead of poking the module class, so the engine
* never depends on {@code features.module}: the module pushes its state here on
* enable/disable and re-syncs while it stays on.
*
* <p>Shape follows the house idiom of enum-utility state holders
* ({@code PreTranslucentDepth}, {@code RenderResourceReadiness}).
*/
public enum OptimizeState {
;
private static volatile boolean noGlass;
private static volatile boolean litePost;
private static volatile boolean liteSky;
private static volatile boolean leanHud;
public static boolean isNoGlass() {
return noGlass;
}
public static boolean isLitePost() {
return litePost;
}
public static boolean isLiteSky() {
return liteSky;
}
public static boolean isLeanHud() {
return leanHud;
}
public static void apply(boolean glass, boolean post, boolean sky, boolean hud) {
noGlass = glass;
litePost = post;
liteSky = sky;
leanHud = hud;
}
public static void reset() {
apply(false, false, false, false);
}
}

View file

@ -15,15 +15,10 @@ import dev.loki.lovisual.render.engine.rhi.pipeline.layout.RenderPipelineRegistr
import dev.loki.lovisual.render.engine.shader.LoVisualShaderSources;
import dev.loki.lovisual.render.engine.vertex.LoVisualVertexFormats;
import dev.loki.lovisual.util.logging.DebugLog;
import dev.loki.lovisual.features.module.modules.visuals.effects.hits.KillEffect;
import dev.loki.lovisual.features.module.modules.visuals.esp.ESP;
import dev.loki.lovisual.features.module.modules.visuals.fx.MotionBlur;
import dev.loki.lovisual.features.module.modules.visuals.fx.PostFX;
import dev.loki.lovisual.features.module.modules.visuals.scene.BlockHighlight;
import dev.loki.lovisual.features.module.modules.visuals.weather.sky.ShaderSky;
import net.minecraft.resources.Identifier;
import net.minecraft.server.packs.resources.ResourceManager;
import static dev.loki.lovisual.render.engine.pipeline.ShaderIds.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -31,123 +26,14 @@ import java.util.List;
/**
* Pipeline registry for LoVisual's custom rendering engine.
*
* <p>Public API facade: every shader identifier and pipeline constant keeps its original
* name and value. The repetitive builder chains live in the template classes of
* {@link dev.loki.lovisual.render.engine.pipeline.pipelines}.</p>
* <p>Public API facade: every pipeline constant keeps its original name and value;
* shader identifiers live in {@link ShaderIds}. The repetitive builder chains live in
* the template classes of {@link dev.loki.lovisual.render.engine.pipeline.pipelines}.</p>
*
* <p>Keep this class free of module-specific logic: it is the foundation for all custom 3D/2D effects.</p>
*/
public enum LoVisualRenderPipelines {
;
// ======================
// Shaders (assets/lovisual/shaders/*)
// ======================
// Core colored / line / fog shaders
public static final Identifier SHADER_POS_COLOR_VERT = shader("pos_color.vert");
public static final Identifier SHADER_WIDE_LINE_VERT = shader("wide_line.vert");
public static final Identifier SHADER_POS_COLOR_FRAG = shader("pos_color.frag");
public static final Identifier SHADER_POS_COLOR_FOG_VERT = shader("pos_color_fog.vert");
public static final Identifier SHADER_POS_COLOR_FOG_FRAG = shader("pos_color_fog.frag");
// Rect-parameter vertex shaders (batched shapes)
public static final Identifier SHADER_POS_COLOR_RECT_PARAMS_VERT = shader("pos_color_rect_params.vert");
public static final Identifier SHADER_POS_COLOR_RECT_PARAMS2_VERT = shader("pos_color_rect_params2.vert");
public static final Identifier SHADER_POS_LOCAL_COLOR_RECT_PARAMS_VERT = shader("pos_local_color_rect_params.vert");
public static final Identifier SHADER_POS_LOCAL_COLOR_RECT_PARAMS2_VERT = shader("pos_local_color_rect_params2.vert");
public static final Identifier SHADER_POS_LOCAL_COLOR_RECT_PARAMS5_VERT = shader("pos_local_color_rect_params5.vert");
public static final Identifier SHADER_POS_LOCAL_COLOR_RECT_PARAMS5_GENERIC_VERT = shader("pos_local_color_rect_params5_generic.vert");
// Textured primitives & GUI lookup
public static final Identifier SHADER_POS_TEX_COLOR_VERT = shader("pos_tex_color.vert");
public static final Identifier SHADER_POS_TEX_COLOR_PARAMS2_VERT = shader("pos_tex_color_params2.vert");
public static final Identifier SHADER_POS_TEX_COLOR_FRAG = shader("pos_tex_color.frag");
public static final Identifier SHADER_GUI_TEXTURE_LOOKUP_FRAG = shader("gui_texture_lookup.frag");
public static final Identifier SHADER_POS_TEX_COLOR_TINT_FRAG = shader("pos_tex_color_tint.frag");
public static final Identifier SHADER_POS_TEX_COLOR_SKY_FOG_VERT = shader("pos_tex_color_sky_fog.vert");
public static final Identifier SHADER_POS_TEX_COLOR_SKY_FOG_FRAG = shader("pos_tex_color_sky_fog.frag");
public static final Identifier SHADER_POS_TEX_COLOR_SKY_FOG_ADDITIVE_FRAG = shader("pos_tex_color_sky_fog_additive.frag");
// Skyboxes & shader skies
public static final Identifier SHADER_POS_COLOR_SKYBOX_SHADER_VERT = shader("pos_color_skybox_shader.vert");
public static final Identifier SHADER_REIMAGINED_SKYBOX_FRAG = shader("reimagined_skybox.frag");
public static final Identifier SHADER_SHADER_SKY_THUNDER_FRAG = shader("shader_sky_thunder.frag");
public static final Identifier SHADER_SHADER_SKY_PULSAR_FRAG = shader("shader_sky_pulsar.frag");
public static final Identifier SHADER_POS_TEX_COLOR_RECT_PARAMS_VERT = shader("pos_tex_color_rect_params.vert");
public static final Identifier SHADER_POS_TEX_LOCAL_COLOR_RECT_PARAMS_VERT = shader("pos_tex_local_color_rect_params.vert");
public static final Identifier SHADER_POS_TEX_LOCAL_COLOR_RECT_PARAMS2_VERT = shader("pos_tex_local_color_rect_params2.vert");
public static final Identifier SHADER_POS_TEX_COLOR_RECT_PARAMS2_VERT = shader("pos_tex_color_rect_params2.vert");
// Text & MSDF
public static final Identifier SHADER_TEXT_VERT = shader("text.vert");
public static final Identifier SHADER_TEXT_FRAG = shader("text.frag");
public static final Identifier SHADER_TEXT_MSDF_FRAG = shader("text_msdf.frag");
public static final Identifier SHADER_SVG_MSDF_FRAG = shader("svg_msdf.frag");
public static final Identifier SHADER_TEXT_LIQUID_GLASS_FRAG = shader("text_liquid_glass.frag");
public static final Identifier SHADER_TEXT_LIQUID_GLASS_MSDF_FRAG = shader("text_liquid_glass_msdf.frag");
// Batched UI shapes (SDF fragments)
public static final Identifier SHADER_CIRCLE_BATCH_FRAG = shader("circle_batch.frag");
public static final Identifier SHADER_ARC_BATCH_FRAG = shader("arc_batch.frag");
public static final Identifier SHADER_ORBIZ_RING_BATCH_FRAG = shader("orbiz_ring_batch.frag");
public static final Identifier SHADER_WORLD_DECAL_SDF_FRAG = shader("world_decal_sdf.frag");
public static final Identifier SHADER_ROUNDED_RECT_STROKE_CORNERS_BATCH_FRAG = shader("rounded_rect_stroke_corners_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_BATCH_FRAG = shader("rounded_rect_batch.frag");
public static final Identifier SHADER_UI_ROUNDED_FILL_SMOKE_BATCH_FRAG = shader("ui_rounded_fill_smoke_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_STROKE_BATCH_FRAG = shader("rounded_rect_stroke_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_STROKE_ANGULAR_BATCH_FRAG = shader("rounded_rect_stroke_angular_batch.frag");
public static final Identifier SHADER_CHAMFERED_RECT_BATCH_FRAG = shader("chamfered_rect_batch.frag");
public static final Identifier SHADER_UI_SHAPE_BATCH_FRAG = shader("ui_shape_batch.frag");
public static final Identifier SHADER_CHAMFERED_RECT_STROKE_BATCH_FRAG = shader("chamfered_rect_stroke_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_CORNERS_BATCH_FRAG = shader("rounded_rect_corners_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_GLOW_BATCH_FRAG = shader("rounded_rect_glow_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_SHADOW_BATCH_FRAG = shader("rounded_rect_shadow_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_SOFT_SHADOW_BATCH_FRAG = shader("rounded_rect_soft_shadow_batch.frag");
public static final Identifier SHADER_RADIAL_GLOW_BATCH_FRAG = shader("radial_glow_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_TEX_BATCH_FRAG = shader("rounded_rect_tex_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_TEX_MASK_BATCH_FRAG = shader("rounded_rect_tex_mask_batch.frag");
public static final Identifier SHADER_UI_BLUR_BATCH_FRAG = shader("ui_blur_batch.frag");
public static final Identifier SHADER_UI_BLUR_BATCH_CORNERS_FRAG = shader("ui_blur_batch_corners.frag");
public static final Identifier SHADER_UI_LIQUID_GLASS_BATCH_FRAG = shader("ui_liquid_glass_batch.frag");
// Fullscreen post-processing & overlays
public static final Identifier SHADER_DAMAGE_TINT_VERT = shader("damage_tint.vert");
public static final Identifier SHADER_DAMAGE_TINT_FRAG = shader("damage_tint.frag");
public static final Identifier SHADER_POST_FX_FRAG = shader("post_fx.frag");
public static final Identifier SHADER_MOTION_BLUR_FRAG = shader("motion_blur.frag");
public static final Identifier SHADER_DEPTH_OF_FIELD_FRAG = shader("depth_of_field.frag");
public static final Identifier SHADER_WET_SURFACE_FRAG = shader("wet_surface.frag");
public static final Identifier SHADER_HEAT_FX_FRAG = shader("heat_fx.frag");
public static final Identifier SHADER_ESP_GRADIENT_FRAG = shader("shader_esp_gradient.frag");
public static final Identifier SHADER_ESP_SHADOW_FRAG = shader("shader_esp_shadow.frag");
public static final Identifier SHADER_ESP_SMOKE_FRAG = shader("shader_esp_smoke.frag");
public static final Identifier SHADER_PORTAL_RIFT_FRAG = shader("portal_rift.frag");
public static final Identifier SHADER_SLEEP_OVERLAY_FRAG = shader("sleep_overlay.frag");
// Hand effects & chams
public static final Identifier SHADER_HAND_SMOKE_FRAG = shader("hand_smoke.frag");
public static final Identifier SHADER_HAND_METALLIC_FRAG = shader("hand_metallic.frag");
public static final Identifier SHADER_HAND_NOISE_FRAG = shader("hand_noise.frag");
public static final Identifier SHADER_UI_BLUR_FRAG = shader("ui_blur.frag");
public static final Identifier SHADER_HAND_GLASS_FRAG = shader("hand_glass.frag");
public static final Identifier SHADER_HAND_CHAMS_SOLID_FRAG = shader("hand_chams_solid.frag");
public static final Identifier SHADER_HAND_CHAMS_CHROMA_FRAG = shader("hand_chams_chroma.frag");
public static final Identifier SHADER_HAND_CHAMS_STRIPES_FRAG = shader("hand_chams_stripes.frag");
public static final Identifier SHADER_HAND_CHAMS_GLOW_FRAG = shader("hand_chams_glow.frag");
public static final Identifier SHADER_HAND_CHAMS_SNOW_FRAG = shader("hand_chams_snow.frag");
public static final Identifier SHADER_HAND_CHAMS_INVERT_FRAG = shader("hand_chams_invert.frag");
public static final Identifier SHADER_HAND_CHAMS_BALATRO_FRAG = shader("hand_chams_balatro.frag");
public static final Identifier SHADER_HAND_CHAMS_BLEND_FRAG = shader("hand_chams_blend.frag");
// Sky & menu backgrounds
public static final Identifier SHADER_SKY_SUN_FRAG = shader("sky_sun.frag");
public static final Identifier SHADER_MENU_BACKGROUND_WAVES_FRAG = shader("menu_background_waves.frag");
public static final Identifier SHADER_MENU_BACKGROUND_AURORA_FRAG = shader("menu_background_aurora.frag");
public static final Identifier SHADER_SKY_SHADER_SKY_FRAG = shader("sky_shader_sky.frag");
public static final Identifier SHADER_SKY_SHADER_WATER_FRAG = shader("sky_shader_water.frag");
// KillEffect procedural beam shaders
public static final Identifier SHADER_KILL_EFFECT_PORTAL_FRAG = shader("kill_effect_portal.frag");
public static final Identifier SHADER_KILL_EFFECT_TORNADO_FRAG = shader("kill_effect_tornado.frag");
// BlockHighlight procedural shader outlines
public static final Identifier SHADER_BLOCK_HIGHLIGHT_WATERCAUSTIC_FRAG = shader("block_highlight_watercaustic.frag");
public static final Identifier SHADER_BLOCK_HIGHLIGHT_SCANLINES_FRAG = shader("block_highlight_scanlines.frag");
public static final Identifier SHADER_BLOCK_HIGHLIGHT_HOLOGRAM_FRAG = shader("block_highlight_hologram.frag");
// SkyShader nebula
public static final Identifier SHADER_SKY_SHADER_NEBULA_FRAG = shader("sky_shader_nebula.frag");
public static final Identifier SHADER_SKY_SHADER_CAUSTIC_FRAG = shader("sky_shader_caustic.frag");
// SkyShader starry (procedural stars + milky way + round moon)
public static final Identifier SHADER_SKY_SHADER_STARRY_FRAG = shader("sky_shader_starry.frag");
private static final List<RenderPipeline> PIPELINES = new ArrayList<>();
@ -422,11 +308,4 @@ public enum LoVisualRenderPipelines {
}
}
/**
* LoVisual shader asset identifier for "shaders/&lt;name&gt;".
*/
private static Identifier shader(String name) {
return Identifier.fromNamespaceAndPath("lovisual", "shaders/" + name);
}
}

View file

@ -0,0 +1,130 @@
package dev.loki.lovisual.render.engine.pipeline;
import net.minecraft.resources.Identifier;
/**
* Shader asset identifiers for {@code assets/lovisual/shaders/*}.
*
* <p>Split out of {@link LoVisualRenderPipelines} to keep the registry small;
* the registry references them through a static import.</p>
*/
public final class ShaderIds {
private ShaderIds() {
}
// ======================
// Shaders (assets/lovisual/shaders/*)
// ======================
// Core colored / line / fog shaders
public static final Identifier SHADER_POS_COLOR_VERT = shader("pos_color.vert");
public static final Identifier SHADER_WIDE_LINE_VERT = shader("wide_line.vert");
public static final Identifier SHADER_POS_COLOR_FRAG = shader("pos_color.frag");
public static final Identifier SHADER_POS_COLOR_FOG_VERT = shader("pos_color_fog.vert");
public static final Identifier SHADER_POS_COLOR_FOG_FRAG = shader("pos_color_fog.frag");
// Rect-parameter vertex shaders (batched shapes)
public static final Identifier SHADER_POS_COLOR_RECT_PARAMS_VERT = shader("pos_color_rect_params.vert");
public static final Identifier SHADER_POS_COLOR_RECT_PARAMS2_VERT = shader("pos_color_rect_params2.vert");
public static final Identifier SHADER_POS_LOCAL_COLOR_RECT_PARAMS_VERT = shader("pos_local_color_rect_params.vert");
public static final Identifier SHADER_POS_LOCAL_COLOR_RECT_PARAMS2_VERT = shader("pos_local_color_rect_params2.vert");
public static final Identifier SHADER_POS_LOCAL_COLOR_RECT_PARAMS5_VERT = shader("pos_local_color_rect_params5.vert");
public static final Identifier SHADER_POS_LOCAL_COLOR_RECT_PARAMS5_GENERIC_VERT = shader("pos_local_color_rect_params5_generic.vert");
// Textured primitives & GUI lookup
public static final Identifier SHADER_POS_TEX_COLOR_VERT = shader("pos_tex_color.vert");
public static final Identifier SHADER_POS_TEX_COLOR_PARAMS2_VERT = shader("pos_tex_color_params2.vert");
public static final Identifier SHADER_POS_TEX_COLOR_FRAG = shader("pos_tex_color.frag");
public static final Identifier SHADER_GUI_TEXTURE_LOOKUP_FRAG = shader("gui_texture_lookup.frag");
public static final Identifier SHADER_POS_TEX_COLOR_TINT_FRAG = shader("pos_tex_color_tint.frag");
public static final Identifier SHADER_POS_TEX_COLOR_SKY_FOG_VERT = shader("pos_tex_color_sky_fog.vert");
public static final Identifier SHADER_POS_TEX_COLOR_SKY_FOG_FRAG = shader("pos_tex_color_sky_fog.frag");
public static final Identifier SHADER_POS_TEX_COLOR_SKY_FOG_ADDITIVE_FRAG = shader("pos_tex_color_sky_fog_additive.frag");
// Skyboxes & shader skies
public static final Identifier SHADER_POS_COLOR_SKYBOX_SHADER_VERT = shader("pos_color_skybox_shader.vert");
public static final Identifier SHADER_REIMAGINED_SKYBOX_FRAG = shader("reimagined_skybox.frag");
public static final Identifier SHADER_SHADER_SKY_THUNDER_FRAG = shader("shader_sky_thunder.frag");
public static final Identifier SHADER_SHADER_SKY_PULSAR_FRAG = shader("shader_sky_pulsar.frag");
public static final Identifier SHADER_POS_TEX_COLOR_RECT_PARAMS_VERT = shader("pos_tex_color_rect_params.vert");
public static final Identifier SHADER_POS_TEX_LOCAL_COLOR_RECT_PARAMS_VERT = shader("pos_tex_local_color_rect_params.vert");
public static final Identifier SHADER_POS_TEX_LOCAL_COLOR_RECT_PARAMS2_VERT = shader("pos_tex_local_color_rect_params2.vert");
public static final Identifier SHADER_POS_TEX_COLOR_RECT_PARAMS2_VERT = shader("pos_tex_color_rect_params2.vert");
// Text & MSDF
public static final Identifier SHADER_TEXT_VERT = shader("text.vert");
public static final Identifier SHADER_TEXT_FRAG = shader("text.frag");
public static final Identifier SHADER_TEXT_MSDF_FRAG = shader("text_msdf.frag");
public static final Identifier SHADER_SVG_MSDF_FRAG = shader("svg_msdf.frag");
public static final Identifier SHADER_TEXT_LIQUID_GLASS_FRAG = shader("text_liquid_glass.frag");
public static final Identifier SHADER_TEXT_LIQUID_GLASS_MSDF_FRAG = shader("text_liquid_glass_msdf.frag");
// Batched UI shapes (SDF fragments)
public static final Identifier SHADER_CIRCLE_BATCH_FRAG = shader("circle_batch.frag");
public static final Identifier SHADER_ARC_BATCH_FRAG = shader("arc_batch.frag");
public static final Identifier SHADER_ORBIZ_RING_BATCH_FRAG = shader("orbiz_ring_batch.frag");
public static final Identifier SHADER_WORLD_DECAL_SDF_FRAG = shader("world_decal_sdf.frag");
public static final Identifier SHADER_ROUNDED_RECT_STROKE_CORNERS_BATCH_FRAG = shader("rounded_rect_stroke_corners_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_BATCH_FRAG = shader("rounded_rect_batch.frag");
public static final Identifier SHADER_UI_ROUNDED_FILL_SMOKE_BATCH_FRAG = shader("ui_rounded_fill_smoke_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_STROKE_BATCH_FRAG = shader("rounded_rect_stroke_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_STROKE_ANGULAR_BATCH_FRAG = shader("rounded_rect_stroke_angular_batch.frag");
public static final Identifier SHADER_CHAMFERED_RECT_BATCH_FRAG = shader("chamfered_rect_batch.frag");
public static final Identifier SHADER_UI_SHAPE_BATCH_FRAG = shader("ui_shape_batch.frag");
public static final Identifier SHADER_CHAMFERED_RECT_STROKE_BATCH_FRAG = shader("chamfered_rect_stroke_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_CORNERS_BATCH_FRAG = shader("rounded_rect_corners_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_GLOW_BATCH_FRAG = shader("rounded_rect_glow_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_SHADOW_BATCH_FRAG = shader("rounded_rect_shadow_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_SOFT_SHADOW_BATCH_FRAG = shader("rounded_rect_soft_shadow_batch.frag");
public static final Identifier SHADER_RADIAL_GLOW_BATCH_FRAG = shader("radial_glow_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_TEX_BATCH_FRAG = shader("rounded_rect_tex_batch.frag");
public static final Identifier SHADER_ROUNDED_RECT_TEX_MASK_BATCH_FRAG = shader("rounded_rect_tex_mask_batch.frag");
public static final Identifier SHADER_UI_BLUR_BATCH_FRAG = shader("ui_blur_batch.frag");
public static final Identifier SHADER_UI_BLUR_BATCH_CORNERS_FRAG = shader("ui_blur_batch_corners.frag");
public static final Identifier SHADER_UI_LIQUID_GLASS_BATCH_FRAG = shader("ui_liquid_glass_batch.frag");
// Fullscreen post-processing & overlays
public static final Identifier SHADER_DAMAGE_TINT_VERT = shader("damage_tint.vert");
public static final Identifier SHADER_DAMAGE_TINT_FRAG = shader("damage_tint.frag");
public static final Identifier SHADER_POST_FX_FRAG = shader("post_fx.frag");
public static final Identifier SHADER_MOTION_BLUR_FRAG = shader("motion_blur.frag");
public static final Identifier SHADER_DEPTH_OF_FIELD_FRAG = shader("depth_of_field.frag");
public static final Identifier SHADER_WET_SURFACE_FRAG = shader("wet_surface.frag");
public static final Identifier SHADER_HEAT_FX_FRAG = shader("heat_fx.frag");
public static final Identifier SHADER_ESP_GRADIENT_FRAG = shader("shader_esp_gradient.frag");
public static final Identifier SHADER_ESP_SHADOW_FRAG = shader("shader_esp_shadow.frag");
public static final Identifier SHADER_ESP_SMOKE_FRAG = shader("shader_esp_smoke.frag");
public static final Identifier SHADER_PORTAL_RIFT_FRAG = shader("portal_rift.frag");
public static final Identifier SHADER_SLEEP_OVERLAY_FRAG = shader("sleep_overlay.frag");
// Hand effects & chams
public static final Identifier SHADER_HAND_SMOKE_FRAG = shader("hand_smoke.frag");
public static final Identifier SHADER_HAND_METALLIC_FRAG = shader("hand_metallic.frag");
public static final Identifier SHADER_HAND_NOISE_FRAG = shader("hand_noise.frag");
public static final Identifier SHADER_UI_BLUR_FRAG = shader("ui_blur.frag");
public static final Identifier SHADER_HAND_GLASS_FRAG = shader("hand_glass.frag");
public static final Identifier SHADER_HAND_CHAMS_SOLID_FRAG = shader("hand_chams_solid.frag");
public static final Identifier SHADER_HAND_CHAMS_CHROMA_FRAG = shader("hand_chams_chroma.frag");
public static final Identifier SHADER_HAND_CHAMS_STRIPES_FRAG = shader("hand_chams_stripes.frag");
public static final Identifier SHADER_HAND_CHAMS_GLOW_FRAG = shader("hand_chams_glow.frag");
public static final Identifier SHADER_HAND_CHAMS_SNOW_FRAG = shader("hand_chams_snow.frag");
public static final Identifier SHADER_HAND_CHAMS_INVERT_FRAG = shader("hand_chams_invert.frag");
public static final Identifier SHADER_HAND_CHAMS_BALATRO_FRAG = shader("hand_chams_balatro.frag");
public static final Identifier SHADER_HAND_CHAMS_BLEND_FRAG = shader("hand_chams_blend.frag");
// Sky & menu backgrounds
public static final Identifier SHADER_SKY_SUN_FRAG = shader("sky_sun.frag");
public static final Identifier SHADER_MENU_BACKGROUND_WAVES_FRAG = shader("menu_background_waves.frag");
public static final Identifier SHADER_MENU_BACKGROUND_AURORA_FRAG = shader("menu_background_aurora.frag");
public static final Identifier SHADER_SKY_SHADER_SKY_FRAG = shader("sky_shader_sky.frag");
public static final Identifier SHADER_SKY_SHADER_WATER_FRAG = shader("sky_shader_water.frag");
// KillEffect procedural beam shaders
public static final Identifier SHADER_KILL_EFFECT_PORTAL_FRAG = shader("kill_effect_portal.frag");
public static final Identifier SHADER_KILL_EFFECT_TORNADO_FRAG = shader("kill_effect_tornado.frag");
// BlockHighlight procedural shader outlines
public static final Identifier SHADER_BLOCK_HIGHLIGHT_WATERCAUSTIC_FRAG = shader("block_highlight_watercaustic.frag");
public static final Identifier SHADER_BLOCK_HIGHLIGHT_SCANLINES_FRAG = shader("block_highlight_scanlines.frag");
public static final Identifier SHADER_BLOCK_HIGHLIGHT_HOLOGRAM_FRAG = shader("block_highlight_hologram.frag");
// SkyShader nebula
public static final Identifier SHADER_SKY_SHADER_NEBULA_FRAG = shader("sky_shader_nebula.frag");
public static final Identifier SHADER_SKY_SHADER_CAUSTIC_FRAG = shader("sky_shader_caustic.frag");
// SkyShader starry (procedural stars + milky way + round moon)
public static final Identifier SHADER_SKY_SHADER_STARRY_FRAG = shader("sky_shader_starry.frag");
/**
* LoVisual shader asset identifier for "shaders/<name>".
*/
private static Identifier shader(String name) {
return Identifier.fromNamespaceAndPath("lovisual", "shaders/" + name);
}
}

View file

@ -5,7 +5,7 @@ import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.shaders.UniformType;
import dev.loki.lovisual.render.engine.pipeline.ExtendedRenderPipelineBuilder;
import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines;
import dev.loki.lovisual.render.engine.pipeline.ShaderIds;
import dev.loki.lovisual.render.engine.vertex.LoVisualVertexFormats;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.resources.Identifier;
@ -25,7 +25,7 @@ public final class ScreenPipelines {
public static RenderPipeline guiTextureLookup() {
return new ExtendedRenderPipelineBuilder(RenderPipelines.GUI_TEXTURED_SNIPPET)
.withLocation(PipelineTemplates.location("gui_texture_lookup"))
.withFragmentShader(LoVisualRenderPipelines.SHADER_GUI_TEXTURE_LOOKUP_FRAG)
.withFragmentShader(ShaderIds.SHADER_GUI_TEXTURE_LOOKUP_FRAG)
.build();
}
@ -35,7 +35,7 @@ public final class ScreenPipelines {
public static RenderPipeline screen(String name, Identifier fragmentShader, String uniform, String... samplers) {
ExtendedRenderPipelineBuilder builder = base(name)
.withVertexFormat(LoVisualVertexFormats.POS2, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_DAMAGE_TINT_VERT)
.withVertexShader(ShaderIds.SHADER_DAMAGE_TINT_VERT)
.withFragmentShader(fragmentShader);
for (String sampler : samplers) {
builder.withSampler(sampler);

View file

@ -6,7 +6,7 @@ import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.vertex.VertexFormat;
import dev.loki.lovisual.render.engine.pipeline.ExtendedRenderPipelineBuilder;
import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines;
import dev.loki.lovisual.render.engine.pipeline.ShaderIds;
import dev.loki.lovisual.render.engine.vertex.LoVisualVertexFormats;
import net.minecraft.resources.Identifier;
@ -25,8 +25,8 @@ public final class UiPipelines {
public static RenderPipeline colored(String name, PrimitiveTopology topology) {
return PipelineTemplates.finish(base(name)
.withVertexFormat(LoVisualVertexFormats.POS2_COLOR, topology)
.withVertexShader(LoVisualRenderPipelines.SHADER_POS_COLOR_VERT)
.withFragmentShader(LoVisualRenderPipelines.SHADER_POS_COLOR_FRAG), false, BlendFunction.TRANSLUCENT, true);
.withVertexShader(ShaderIds.SHADER_POS_COLOR_VERT)
.withFragmentShader(ShaderIds.SHADER_POS_COLOR_FRAG), false, BlendFunction.TRANSLUCENT, true);
}
/**
@ -53,7 +53,7 @@ public final class UiPipelines {
public static RenderPipeline textLiquidGlass(String name, Identifier fragmentShader, boolean msdf) {
ExtendedRenderPipelineBuilder builder = base(name)
.withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_COLOR, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_TEXT_VERT)
.withVertexShader(ShaderIds.SHADER_TEXT_VERT)
.withFragmentShader(fragmentShader)
.withSampler("u_Texture")
.withSampler("u_SceneTexture")

View file

@ -6,7 +6,7 @@ import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import dev.loki.lovisual.render.engine.pipeline.ExtendedRenderPipelineBuilder;
import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines;
import dev.loki.lovisual.render.engine.pipeline.ShaderIds;
import dev.loki.lovisual.render.engine.vertex.LoVisualVertexFormats;
import dev.loki.lovisual.features.module.modules.visuals.effects.hits.KillEffect;
import dev.loki.lovisual.features.module.modules.visuals.scene.BlockHighlight;
@ -27,8 +27,8 @@ public final class WorldPipelines {
public static RenderPipeline colored(String name, boolean depthTest, BlendFunction blend) {
return PipelineTemplates.finish(base(name)
.withVertexFormat(DefaultVertexFormat.POSITION_COLOR, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_POS_COLOR_VERT)
.withFragmentShader(LoVisualRenderPipelines.SHADER_POS_COLOR_FRAG), depthTest, blend, false);
.withVertexShader(ShaderIds.SHADER_POS_COLOR_VERT)
.withFragmentShader(ShaderIds.SHADER_POS_COLOR_FRAG), depthTest, blend, false);
}
/**
@ -38,8 +38,8 @@ public final class WorldPipelines {
return PipelineTemplates.finish(base(name)
.withLineSmooth()
.withVertexFormat(DefaultVertexFormat.POSITION_COLOR, PrimitiveTopology.DEBUG_LINES)
.withVertexShader(LoVisualRenderPipelines.SHADER_POS_COLOR_VERT)
.withFragmentShader(LoVisualRenderPipelines.SHADER_POS_COLOR_FRAG), depthTest, BlendFunction.TRANSLUCENT, false);
.withVertexShader(ShaderIds.SHADER_POS_COLOR_VERT)
.withFragmentShader(ShaderIds.SHADER_POS_COLOR_FRAG), depthTest, BlendFunction.TRANSLUCENT, false);
}
/**
@ -48,8 +48,8 @@ public final class WorldPipelines {
public static RenderPipeline wideLines(String name, boolean depthTest) {
return PipelineTemplates.finish(base(name)
.withVertexFormat(LoVisualVertexFormats.POS3_COLOR_LINE, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_WIDE_LINE_VERT)
.withFragmentShader(LoVisualRenderPipelines.SHADER_POS_COLOR_FRAG), depthTest, BlendFunction.TRANSLUCENT, false);
.withVertexShader(ShaderIds.SHADER_WIDE_LINE_VERT)
.withFragmentShader(ShaderIds.SHADER_POS_COLOR_FRAG), depthTest, BlendFunction.TRANSLUCENT, false);
}
/**
@ -58,8 +58,8 @@ public final class WorldPipelines {
public static RenderPipeline textured(String name, boolean depthTest, BlendFunction blend) {
return PipelineTemplates.finish(base(name)
.withVertexFormat(DefaultVertexFormat.POSITION_TEX_COLOR, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_POS_TEX_COLOR_VERT)
.withFragmentShader(LoVisualRenderPipelines.SHADER_POS_TEX_COLOR_FRAG)
.withVertexShader(ShaderIds.SHADER_POS_TEX_COLOR_VERT)
.withFragmentShader(ShaderIds.SHADER_POS_TEX_COLOR_FRAG)
.withSampler("u_Texture"), depthTest, blend, false);
}
@ -69,8 +69,8 @@ public final class WorldPipelines {
public static RenderPipeline tintedTextured(String name, boolean depthTest) {
return PipelineTemplates.finish(base(name)
.withVertexFormat(DefaultVertexFormat.POSITION_TEX_COLOR, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_POS_TEX_COLOR_VERT)
.withFragmentShader(LoVisualRenderPipelines.SHADER_POS_TEX_COLOR_TINT_FRAG)
.withVertexShader(ShaderIds.SHADER_POS_TEX_COLOR_VERT)
.withFragmentShader(ShaderIds.SHADER_POS_TEX_COLOR_TINT_FRAG)
.withSampler("u_Texture")
.withUniform("TextureTint", UniformType.UNIFORM_BUFFER), depthTest, PipelineTemplates.ADDITIVE, false);
}
@ -81,8 +81,8 @@ public final class WorldPipelines {
public static RenderPipeline decalSdf(String name, boolean depthTest) {
return PipelineTemplates.finish(base(name)
.withVertexFormat(LoVisualVertexFormats.POS3_TEXTURE_COLOR_PARAMS2, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_POS_TEX_COLOR_PARAMS2_VERT)
.withFragmentShader(LoVisualRenderPipelines.SHADER_WORLD_DECAL_SDF_FRAG), depthTest, BlendFunction.TRANSLUCENT, false);
.withVertexShader(ShaderIds.SHADER_POS_TEX_COLOR_PARAMS2_VERT)
.withFragmentShader(ShaderIds.SHADER_WORLD_DECAL_SDF_FRAG), depthTest, BlendFunction.TRANSLUCENT, false);
}
/**
@ -91,7 +91,7 @@ public final class WorldPipelines {
public static RenderPipeline worldText(String name, boolean depthTest, Identifier fragmentShader, boolean msdf) {
ExtendedRenderPipelineBuilder builder = base(name)
.withVertexFormat(DefaultVertexFormat.POSITION_TEX_COLOR, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_TEXT_VERT)
.withVertexShader(ShaderIds.SHADER_TEXT_VERT)
.withFragmentShader(fragmentShader)
.withSampler("u_Texture");
if (msdf) {
@ -106,8 +106,8 @@ public final class WorldPipelines {
public static RenderPipeline skySun(String name) {
return PipelineTemplates.finish(base(name)
.withVertexFormat(DefaultVertexFormat.POSITION_TEX_COLOR, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_POS_TEX_COLOR_VERT)
.withFragmentShader(LoVisualRenderPipelines.SHADER_SKY_SUN_FRAG)
.withVertexShader(ShaderIds.SHADER_POS_TEX_COLOR_VERT)
.withFragmentShader(ShaderIds.SHADER_SKY_SUN_FRAG)
.withUniform("SkySun", UniformType.UNIFORM_BUFFER), false, PipelineTemplates.ADDITIVE, false);
}
@ -117,7 +117,7 @@ public final class WorldPipelines {
public static RenderPipeline killEffectBeam(String name, Identifier fragmentShader) {
return PipelineTemplates.finish(base(name)
.withVertexFormat(DefaultVertexFormat.POSITION_TEX_COLOR, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_POS_TEX_COLOR_VERT)
.withVertexShader(ShaderIds.SHADER_POS_TEX_COLOR_VERT)
.withFragmentShader(fragmentShader)
.withUniform("KillEffectBeam", UniformType.UNIFORM_BUFFER), false, PipelineTemplates.ADDITIVE, false);
}
@ -128,7 +128,7 @@ public final class WorldPipelines {
public static RenderPipeline waterHighlight(String name, Identifier fragmentShader) {
return PipelineTemplates.finish(base(name)
.withVertexFormat(DefaultVertexFormat.POSITION_TEX_COLOR, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_POS_TEX_COLOR_VERT)
.withVertexShader(ShaderIds.SHADER_POS_TEX_COLOR_VERT)
.withFragmentShader(fragmentShader)
.withUniform("WaterData", UniformType.UNIFORM_BUFFER), false, PipelineTemplates.ADDITIVE, false);
}
@ -139,7 +139,7 @@ public final class WorldPipelines {
public static RenderPipeline texturedSkyboxFog(String name, Identifier fragmentShader, BlendFunction blend) {
return PipelineTemplates.finish(fogBase(name)
.withVertexFormat(DefaultVertexFormat.POSITION_TEX_COLOR, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_POS_TEX_COLOR_SKY_FOG_VERT)
.withVertexShader(ShaderIds.SHADER_POS_TEX_COLOR_SKY_FOG_VERT)
.withFragmentShader(fragmentShader)
.withSampler("u_Texture")
.withUniform("SkyboxShader", UniformType.UNIFORM_BUFFER), false, blend, false);
@ -151,7 +151,7 @@ public final class WorldPipelines {
public static RenderPipeline proceduralSkyboxFog(String name, Identifier fragmentShader) {
return PipelineTemplates.finish(fogBase(name)
.withVertexFormat(LoVisualVertexFormats.POS2, PrimitiveTopology.TRIANGLES)
.withVertexShader(LoVisualRenderPipelines.SHADER_DAMAGE_TINT_VERT)
.withVertexShader(ShaderIds.SHADER_DAMAGE_TINT_VERT)
.withFragmentShader(fragmentShader)
.withUniform("SkyboxShader", UniformType.UNIFORM_BUFFER), false, BlendFunction.TRANSLUCENT, false);
}

View file

@ -0,0 +1,23 @@
package dev.loki.lovisual.render.engine.renderer.facade;
import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.uniform.MeshBuilder;
/** Instance fields and constructor shared by the Renderer2D facade hierarchy. */
public class Renderer2DBase {
protected final boolean textured;
protected final MeshBuilder texturedTriangles;
protected final int[] gradientTmp = new int[4];
protected double alpha = 1.0;
protected Renderer2DBase(boolean textured) {
this.textured = textured;
this.texturedTriangles = textured ? new MeshBuilder(LoVisualRenderPipelines.UI_TEXTURED) : null;
}
protected Renderer2D self() {
return (Renderer2D) this;
}
}

View file

@ -0,0 +1,183 @@
package dev.loki.lovisual.render.engine.renderer.facade;
import dev.loki.lovisual.render.engine.renderer.facade.shape.Renderer2DShapes;
import dev.loki.lovisual.render.engine.renderer.renderer2d.fx.Glass2D;
import static dev.loki.lovisual.render.engine.renderer.ui.draw.edge.UiMeshGeometry.*;
/** Liquid-glass effects of the Renderer2D facade. */
public class Renderer2DGlass extends Renderer2DShapes {
protected Renderer2DGlass(boolean textured) {
super(textured);
}
public enum LiquidGlassPreset {
LIGHT(7.0f, -5.50f, 0.70f, 0.42f, 0.40f, 0.030f),
BALANCED(11.0f, -7.50f, 0.78f, 0.52f, 0.42f, 0.040f),
HEAVY(15.0f, -9.00f, 0.86f, 0.62f, 0.48f, 0.052f),
HUD_SMALL(11.0f, -12.00f, 0.84f, 0.78f, 0.22f, 0.055f),
HUD_LARGE(13.5f, -14.00f, 0.88f, 0.72f, 0.20f, 0.060f),
HEALTH_BAR(3.25f, -18.00f, 0.52f, 0.96f, 0.055f, 0.0030f);
private final float thicknessPx;
private final float fresnelPower;
private final float fresnelAlpha;
private final float baseAlpha;
private final float fresnelMix;
private final float distortPx;
LiquidGlassPreset(float thicknessPx,
float fresnelPower,
float fresnelAlpha,
float baseAlpha,
float fresnelMix,
float distortPx) {
this.thicknessPx = thicknessPx;
this.fresnelPower = fresnelPower;
this.fresnelAlpha = fresnelAlpha;
this.baseAlpha = baseAlpha;
this.fresnelMix = fresnelMix;
this.distortPx = distortPx;
}
}
public void liquidGlassCircle(double cx, double cy, double radius,
float softness,
int tintArgb,
float globalAlpha,
float fresnelPower,
float fresnelAlpha,
float baseAlpha,
float fresnelMix,
float distortPx,
float squirclePower) {
if (radius <= 0.0) return;
double size = radius * 2.0;
liquidGlassRect(cx - radius, cy - radius, size, size,
(float) radius, softness,
tintArgb,
globalAlpha,
fresnelPower,
fresnelAlpha,
baseAlpha,
fresnelMix,
distortPx,
squirclePower);
}
public void liquidGlassRect(double x, double y, double w, double h,
float radius, float softness,
int tintArgb,
float globalAlpha,
float fresnelPower,
float fresnelAlpha,
float baseAlpha,
float fresnelMix,
float distortPx,
float squirclePower) {
liquidGlassRect(x, y, w, h,
radius, softness,
tintArgb,
globalAlpha,
globalAlpha,
fresnelPower,
fresnelAlpha,
baseAlpha,
fresnelMix,
distortPx,
squirclePower);
}
public void liquidGlassRect(double x, double y, double w, double h,
float radius, float softness,
int tintArgb,
float glassAlpha,
float blurAlpha,
float fresnelPower,
float fresnelAlpha,
float baseAlpha,
float fresnelMix,
float distortPx,
float squirclePower) {
liquidGlassRectCorners(x, y, w, h,
radius, radius, radius, radius,
softness,
tintArgb,
glassAlpha,
blurAlpha,
fresnelPower,
fresnelAlpha,
baseAlpha,
fresnelMix,
distortPx,
squirclePower);
}
public void liquidGlassRect(double x, double y, double w, double h,
float radius,
int tintArgb,
float glassAlpha,
float blurAlpha,
LiquidGlassPreset preset) {
liquidGlassRect(x, y, w, h,
radius,
tintArgb,
glassAlpha,
blurAlpha,
preset,
1.0f,
0.0f);
}
public void liquidGlassRect(double x, double y, double w, double h,
float radius,
int tintArgb,
float globalAlpha,
LiquidGlassPreset preset,
float thicknessScale,
float squirclePower) {
liquidGlassRect(x, y, w, h, radius, tintArgb, globalAlpha, globalAlpha, preset, thicknessScale, squirclePower);
}
public void liquidGlassRect(double x, double y, double w, double h,
float radius,
int tintArgb,
float glassAlpha,
float blurAlpha,
LiquidGlassPreset preset,
float thicknessScale,
float squirclePower) {
LiquidGlassPreset p = preset != null ? preset : LiquidGlassPreset.BALANCED;
float materialAlpha = clamp01(glassAlpha);
float blurStrength = clamp01(blurAlpha);
float scale = Math.max(0.001f, thicknessScale);
liquidGlassRect(x, y, w, h,
radius, p.thicknessPx * scale,
tintArgb,
materialAlpha,
blurStrength,
p.fresnelPower,
p.fresnelAlpha,
p.baseAlpha,
p.fresnelMix,
p.distortPx * materialAlpha,
squirclePower);
}
public void liquidGlassRectCorners(double x, double y, double w, double h,
float radiusTL, float radiusTR, float radiusBR, float radiusBL,
float softness,
int tintArgb,
float glassAlpha,
float blurAlpha,
float fresnelPower,
float fresnelAlpha,
float baseAlpha,
float fresnelMix,
float distortPx,
float squirclePower) {
Glass2D.liquidGlassRectCorners(self(), x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, softness,
tintArgb, glassAlpha, blurAlpha, fresnelPower, fresnelAlpha, baseAlpha, fresnelMix, distortPx, squirclePower);
}
}

View file

@ -0,0 +1,245 @@
package dev.loki.lovisual.render.engine.renderer.facade;
import dev.loki.lovisual.render.engine.renderer.renderer2d.Batch2D;
import dev.loki.lovisual.render.engine.renderer.renderer2d.Chamfered2D;
import static dev.loki.lovisual.render.engine.renderer.ui.draw.edge.UiMeshGeometry.*;
import dev.loki.lovisual.render.engine.renderer.renderer2d.path.Connectors2D;
import dev.loki.lovisual.render.engine.renderer.renderer2d.path.Polygons2D;
/** Chamfered, connector, cable and polygon family of the Renderer2D facade. */
public class Renderer2DPath extends Renderer2DRounded {
protected Renderer2DPath(boolean textured) {
super(textured);
}
public void chamferedRect(double x, double y, double width, double height,
double chamferTL, double chamferTR, double chamferBR, double chamferBL,
int argb) {
chamferedRectQuad(x, y, width, height,
chamferTL, chamferTR, chamferBR, chamferBL,
argb, argb, argb, argb);
}
public void chamferedRectGradient(double x, double y, double width, double height,
double chamferTL, double chamferTR, double chamferBR, double chamferBL,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
computeLinearGradientColors((float) width, (float) height, startArgb, endArgb, angleDeg, offsetPx, gradientTmp);
chamferedRectQuad(x, y, width, height,
chamferTL, chamferTR, chamferBR, chamferBL,
gradientTmp[0], gradientTmp[1], gradientTmp[2], gradientTmp[3]);
}
public void chamferedRectStroke(double x, double y, double width, double height,
double chamfer, double thickness, int argb) {
chamferedRectStrokeQuad(x, y, width, height, chamfer, thickness, argb, argb, argb, argb);
}
public void chamferedRectStroke(double x, double y, double width, double height,
double chamferTL, double chamferTR, double chamferBR, double chamferBL,
double thickness, int argb) {
chamferedRectStrokeQuad(x, y, width, height,
chamferTL, chamferTR, chamferBR, chamferBL,
thickness, argb, argb, argb, argb);
}
public void chamferedRectStrokeGradient(double x, double y, double width, double height,
double chamfer, double thickness,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
computeLinearGradientColors((float) width, (float) height, startArgb, endArgb, angleDeg, offsetPx, gradientTmp);
chamferedRectStrokeQuad(x, y, width, height, chamfer, thickness,
gradientTmp[0], gradientTmp[1], gradientTmp[2], gradientTmp[3]);
}
public void chamferedRectStrokeGradient(double x, double y, double width, double height,
double chamferTL, double chamferTR, double chamferBR, double chamferBL,
double thickness,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
computeLinearGradientColors((float) width, (float) height, startArgb, endArgb, angleDeg, offsetPx, gradientTmp);
chamferedRectStrokeQuad(x, y, width, height,
chamferTL, chamferTR, chamferBR, chamferBL,
thickness, gradientTmp[0], gradientTmp[1], gradientTmp[2], gradientTmp[3]);
}
public void chamferedRectQuad(double x, double y, double w, double h,
double chamferTL, double chamferTR, double chamferBR, double chamferBL,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
normalizeChamfers(w, h,
(float) chamferTL,
(float) chamferTR,
(float) chamferBR,
(float) chamferBL,
Batch2D.CORNER_RADII);
chamferedRectQuadAxes(x, y, w, h,
Batch2D.CORNER_RADII[0], Batch2D.CORNER_RADII[0],
Batch2D.CORNER_RADII[1], Batch2D.CORNER_RADII[1],
Batch2D.CORNER_RADII[2], Batch2D.CORNER_RADII[2],
Batch2D.CORNER_RADII[3], Batch2D.CORNER_RADII[3],
cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void chamferedRectQuadAxes(double x, double y, double w, double h,
double chamferTLX, double chamferTLY,
double chamferTRX, double chamferTRY,
double chamferBRX, double chamferBRY,
double chamferBLX, double chamferBLY,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
Chamfered2D.chamferedRectQuadAxes(self(), x, y, w, h,
chamferTLX, chamferTLY, chamferTRX, chamferTRY, chamferBRX, chamferBRY, chamferBLX, chamferBLY,
cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void chamferedRectStrokeQuad(double x, double y, double w, double h,
double chamfer, double thickness,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
chamferedRectStrokeQuad(x, y, w, h,
chamfer, chamfer, chamfer, chamfer,
thickness, cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void chamferedRectStrokeQuad(double x, double y, double w, double h,
double chamferTL, double chamferTR, double chamferBR, double chamferBL,
double thickness,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
Chamfered2D.chamferedRectStrokeQuad(self(), x, y, w, h,
chamferTL, chamferTR, chamferBR, chamferBL, thickness,
cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void notchedRect(double x, double y, double width, double height,
double notchWidth, double notchDepth, int argb) {
int count = buildNotchedRect(Batch2D.RECT_SHAPE, x, y, width, height, notchWidth, notchDepth);
Polygons2D.polygon(self(), Batch2D.RECT_SHAPE, count, argb);
}
public void notchedRectGradient(double x, double y, double width, double height,
double notchWidth, double notchDepth,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
int count = buildNotchedRect(Batch2D.RECT_SHAPE, x, y, width, height, notchWidth, notchDepth);
Polygons2D.polygonGradient(self(), Batch2D.RECT_SHAPE, count, x, y, width, height, startArgb, endArgb, angleDeg, offsetPx);
}
public void notchedRectStroke(double x, double y, double width, double height,
double notchWidth, double notchDepth, double thickness, int argb) {
int count = buildNotchedRect(Batch2D.RECT_SHAPE, x, y, width, height, notchWidth, notchDepth);
Polygons2D.polygonStroke(self(), Batch2D.RECT_SHAPE, count, thickness, true, argb);
}
public void notchedRectStrokeGradient(double x, double y, double width, double height,
double notchWidth, double notchDepth, double thickness,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
int count = buildNotchedRect(Batch2D.RECT_SHAPE, x, y, width, height, notchWidth, notchDepth);
Polygons2D.polylineLinearGradient(self(), Batch2D.RECT_SHAPE, count, thickness, true,
x, y, width, height, startArgb, endArgb, angleDeg, offsetPx, false);
}
public void beveledRect(double x, double y, double width, double height,
double bevel, int fillArgb, int highlightArgb, int shadowArgb) {
Chamfered2D.beveledRect(self(), x, y, width, height, bevel, fillArgb, highlightArgb, shadowArgb);
}
public void beveledRectStroke(double x, double y, double width, double height,
double bevel, double thickness, int argb) {
chamferedRectStroke(x, y, width, height, bevel, thickness, argb);
}
public void beveledRectGradient(double x, double y, double width, double height,
double bevel, int startArgb, int endArgb,
int highlightArgb, int shadowArgb, float angleDeg, float offsetPx) {
Chamfered2D.beveledRectGradient(self(), x, y, width, height, bevel, startArgb, endArgb,
highlightArgb, shadowArgb, angleDeg, offsetPx);
}
public void beveledRectStrokeGradient(double x, double y, double width, double height,
double bevel, double thickness,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
chamferedRectStrokeGradient(x, y, width, height, bevel, thickness, startArgb, endArgb, angleDeg, offsetPx);
}
public void connector(double x1, double y1, double x2, double y2, double thickness, int argb) {
Connectors2D.connector(self(), x1, y1, x2, y2, thickness, argb);
}
public void connectorGradient(double x1, double y1, double x2, double y2,
double thickness, int startArgb, int endArgb) {
Connectors2D.connectorGradient(self(), x1, y1, x2, y2, thickness, startArgb, endArgb);
}
public void wire(double x1, double y1, double x2, double y2, double thickness, int argb) {
connector(x1, y1, x2, y2, thickness, argb);
}
public void wireGradient(double x1, double y1, double x2, double y2,
double thickness, int startArgb, int endArgb) {
connectorGradient(x1, y1, x2, y2, thickness, startArgb, endArgb);
}
public void cable(double x1, double y1, double x2, double y2,
double thickness, int outerArgb, int innerArgb) {
connector(x1, y1, x2, y2, thickness + 2.0, outerArgb);
connector(x1, y1, x2, y2, Math.max(1.0, thickness), innerArgb);
}
public void cableGradient(double x1, double y1, double x2, double y2,
double thickness, int outerStartArgb, int outerEndArgb,
int innerStartArgb, int innerEndArgb) {
connectorGradient(x1, y1, x2, y2, thickness + 2.0, outerStartArgb, outerEndArgb);
connectorGradient(x1, y1, x2, y2, Math.max(1.0, thickness), innerStartArgb, innerEndArgb);
}
public void orthogonalConnector(double x1, double y1, double x2, double y2,
double midX, double thickness, int argb) {
Connectors2D.orthogonalConnector(self(), x1, y1, x2, y2, midX, thickness, argb);
}
public void orthogonalConnectorGradient(double x1, double y1, double x2, double y2,
double midX, double thickness, int startArgb, int endArgb) {
Connectors2D.orthogonalConnectorGradient(self(), x1, y1, x2, y2, midX, thickness, startArgb, endArgb);
}
public void bezierConnector(double x1, double y1,
double cx1, double cy1,
double cx2, double cy2,
double x2, double y2,
int segments,
double thickness,
int argb) {
Connectors2D.bezierConnector(self(), x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments, thickness, argb);
}
public void bezierConnectorGradient(double x1, double y1,
double cx1, double cy1,
double cx2, double cy2,
double x2, double y2,
int segments,
double thickness,
int startArgb,
int endArgb) {
Connectors2D.bezierConnectorGradient(self(), x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments, thickness, startArgb, endArgb);
}
public void nodeGraphEdge(double x1, double y1, double x2, double y2, double thickness, int argb) {
Connectors2D.nodeGraphEdge(self(), x1, y1, x2, y2, thickness, argb);
}
public void nodeGraphEdgeGradient(double x1, double y1, double x2, double y2,
double thickness, int startArgb, int endArgb) {
Connectors2D.nodeGraphEdgeGradient(self(), x1, y1, x2, y2, thickness, startArgb, endArgb);
}
public void spline(double[] points, int pointCount, double thickness, boolean closed, int argb) {
if (points == null || pointCount < 2) return;
Polygons2D.polyline(self(), points, pointCount, thickness, closed, argb, true);
}
public void splineGradient(double[] points, int pointCount, double thickness, boolean closed,
int startArgb, int endArgb) {
if (points == null || pointCount < 2) return;
Polygons2D.polylineGradient(self(), points, pointCount, thickness, closed, startArgb, endArgb, true);
}
public void polygon(double[] points, int pointCount, int argb) {
Polygons2D.polygon(self(), points, pointCount, argb);
}
}

View file

@ -0,0 +1,315 @@
package dev.loki.lovisual.render.engine.renderer.facade;
import dev.loki.lovisual.render.engine.renderer.renderer2d.Rects2D;
import dev.loki.lovisual.render.engine.renderer.renderer2d.Strokes2D;
import dev.loki.lovisual.render.engine.renderer.renderer2d.fx.Effects2D;
import dev.loki.lovisual.render.engine.renderer.renderer2d.fx.Smoke2D;
import dev.loki.lovisual.render.engine.renderer.renderer2d.path.Connectors2D;
import static dev.loki.lovisual.render.engine.renderer.ui.draw.edge.UiMeshGeometry.*;
/** Rounded-rect drawing family of the Renderer2D facade. */
public class Renderer2DRounded extends Renderer2DBase {
protected Renderer2DRounded(boolean textured) {
super(textured);
}
public void roundedRect(double x, double y, double w, double h,
float radius, float softness, int argb) {
roundedRectMasked(x, y, w, h, x, y, w, h, radius, 0.0f, argb);
}
public void roundedRect(double x, double y, double w, double h,
float radius, int argb) {
roundedRect(x, y, w, h, radius, 0.0f, argb);
}
public void roundedRectMasked(double x, double y, double w, double h,
double maskX, double maskY, double maskW, double maskH,
float radius, float softness, int argb) {
roundedRectMaskedQuad(x, y, w, h, maskX, maskY, maskW, maskH, radius, 0.0f, argb, argb, argb, argb);
}
public void roundedRectStroke(double x, double y, double w, double h,
float radius, float softness, float thickness, int argb) {
Strokes2D.roundedRectStroke(self(), x, y, w, h, radius, softness, thickness, argb);
}
public void roundedRectStroke(double x, double y, double w, double h,
float radius, float thickness, int argb) {
roundedRectStroke(x, y, w, h, radius, 0.0f, thickness, argb);
}
public void roundedRectStrokeAngularGradient(double x, double y, double w, double h,
float radius, float softness, float thickness,
int startArgb, int endArgb, float offset) {
Strokes2D.roundedRectStrokeAngularGradient(self(), x, y, w, h, radius, softness, thickness,
startArgb, endArgb, offset);
}
public void roundedRectStrokeCorners(double x, double y, double w, double h,
float radiusTL, float radiusTR, float radiusBR, float radiusBL,
float softness, float thickness, int argb) {
Strokes2D.roundedRectStrokeCorners(self(), x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL,
softness, thickness, argb);
}
public void roundedRectStrokeCorners(double x, double y, double w, double h,
float radiusTL, float radiusTR, float radiusBR, float radiusBL,
float thickness, int argb) {
roundedRectStrokeCorners(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, 0.0f, thickness, argb);
}
public void roundedRectCorners(double x, double y, double w, double h,
float radiusTL, float radiusTR, float radiusBR, float radiusBL,
float softness, int argb) {
roundedRectCornersQuad(x, y, w, h,
radiusTL, radiusTR, radiusBR, radiusBL,
0.0f,
argb, argb, argb, argb);
}
public void roundedRectCorners(double x, double y, double w, double h,
float radiusTL, float radiusTR, float radiusBR, float radiusBL,
int argb) {
roundedRectCorners(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, 0.0f, argb);
}
public void roundedRectCornersQuad(double x, double y, double w, double h,
float radiusTL, float radiusTR, float radiusBR, float radiusBL,
float softness,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
Rects2D.roundedRectCornersQuad(self(), x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, softness,
cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void roundedRectCornersQuad(double x, double y, double w, double h,
float radiusTL, float radiusTR, float radiusBR, float radiusBL,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
roundedRectCornersQuad(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, 0.0f,
cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void roundedRectGradient(double x, double y, double w, double h,
float radius, float softness,
int startArgb, int endArgb, float angleDeg) {
roundedRectGradient(x, y, w, h, radius, 0.0f, startArgb, endArgb, angleDeg, 0.0f);
}
public void roundedRectGradient(double x, double y, double w, double h,
float radius, int startArgb, int endArgb, float angleDeg) {
roundedRectGradient(x, y, w, h, radius, 0.0f, startArgb, endArgb, angleDeg, 0.0f);
}
public void roundedRectGradient(double x, double y, double w, double h,
float radius, float softness,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
computeLinearGradientColors((float) w, (float) h, startArgb, endArgb, angleDeg, offsetPx, gradientTmp);
roundedRectGradientQuad(x, y, w, h, radius, 0.0f, gradientTmp[0], gradientTmp[1], gradientTmp[2], gradientTmp[3]);
}
public void roundedRectGradient(double x, double y, double w, double h,
float radius,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
roundedRectGradient(x, y, w, h, radius, 0.0f, startArgb, endArgb, angleDeg, offsetPx);
}
/**
* Draws a progress segment clipped by the full rounded bar outline.
*
* <p>Unlike drawing a rounded rectangle with the current fill width, self() keeps the moving
* progress edge straight and lets only the fixed outer bar bounds define rounded ends. That
* prevents small health values from becoming a pill/capsule and prevents the fill from leaking
* outside the left/right rounded shell when the progress edge crosses an outer corner.</p>
*/
public void roundedProgressRectGradient(double x, double y, double w, double h,
float radius, float softness,
float progress,
boolean fromRight,
int startArgb, int endArgb,
float angleDeg, float offsetPx) {
Strokes2D.roundedProgressRectGradient(self(), x, y, w, h, radius, softness, progress, fromRight,
startArgb, endArgb, angleDeg, offsetPx);
}
public void roundedProgressRectGradient(double x, double y, double w, double h,
float radius,
float progress,
boolean fromRight,
int startArgb, int endArgb,
float angleDeg, float offsetPx) {
roundedProgressRectGradient(x, y, w, h, radius, 0.0f, progress, fromRight,
startArgb, endArgb, angleDeg, offsetPx);
}
public void roundedSmokeFill(double x, double y, double w, double h,
float radius, float softness,
float fillRatio,
boolean fromRight,
int firstArgb,
int secondArgb,
int thirdArgb,
float time,
float smokeScale,
float smokeMix,
int octaves,
float flowX,
float flowY,
float intensity) {
Smoke2D.roundedSmokeFill(self(), x, y, w, h, radius, softness, fillRatio, fromRight,
firstArgb, secondArgb, thirdArgb, time, smokeScale, smokeMix, octaves, flowX, flowY, intensity);
}
public void roundedSmokeFill(double x, double y, double w, double h,
float radius,
float fillRatio,
boolean fromRight,
int firstArgb,
int secondArgb,
int thirdArgb,
float time,
float smokeScale,
float smokeMix,
int octaves,
float flowX,
float flowY,
float intensity) {
roundedSmokeFill(x, y, w, h, radius, 0.0f, fillRatio, fromRight,
firstArgb, secondArgb, thirdArgb, time, smokeScale, smokeMix, octaves, flowX, flowY, intensity);
}
public void roundedRectStrokeGradient(double x, double y, double w, double h,
float radius, float softness, float thickness,
int startArgb, int endArgb, float angleDeg) {
roundedRectStrokeGradient(x, y, w, h, radius, 0.0f, thickness, startArgb, endArgb, angleDeg, 0.0f);
}
public void roundedRectStrokeGradient(double x, double y, double w, double h,
float radius, float thickness,
int startArgb, int endArgb, float angleDeg) {
roundedRectStrokeGradient(x, y, w, h, radius, 0.0f, thickness, startArgb, endArgb, angleDeg, 0.0f);
}
public void roundedRectStrokeGradient(double x, double y, double w, double h,
float radius, float softness, float thickness,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
computeLinearGradientColors((float) w, (float) h, startArgb, endArgb, angleDeg, offsetPx, gradientTmp);
roundedRectStrokeGradientQuad(x, y, w, h, radius, 0.0f, thickness, gradientTmp[0], gradientTmp[1], gradientTmp[2], gradientTmp[3]);
}
public void roundedRectStrokeGradient(double x, double y, double w, double h,
float radius, float thickness,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
roundedRectStrokeGradient(x, y, w, h, radius, 0.0f, thickness, startArgb, endArgb, angleDeg, offsetPx);
}
public void roundedRectGlow(double x, double y, double w, double h,
float radius, float softness, float glow, int argb) {
Effects2D.roundedRectGlow(self(), x, y, w, h, radius, softness, glow, argb);
}
public void roundedRectShadow(double x, double y, double w, double h,
float radius, float softness, float spread, int argb) {
Effects2D.roundedRectShadow(self(), x, y, w, h, radius, softness, spread, argb);
}
public void roundedRectSoftShadow(double x, double y, double w, double h,
float radius, float blur, float innerAlpha, int argb) {
Effects2D.roundedRectSoftShadow(self(), x, y, w, h, radius, blur, innerAlpha, argb);
}
public void radialGlowMasked(double x, double y, double w, double h,
float radius, float softness,
float glowRadius, float cx, float cy,
int argb) {
Effects2D.radialGlowMasked(self(), x, y, w, h, radius, softness, glowRadius, cx, cy, argb);
}
public void roundedRectGradientQuad(double x, double y, double w, double h,
float radius, float softness,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
roundedRectMaskedQuad(x, y, w, h, x, y, w, h, radius, 0.0f, cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void roundedRectGradientQuad(double x, double y, double w, double h,
float radius,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
roundedRectGradientQuad(x, y, w, h, radius, 0.0f, cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void roundedRectMaskedQuad(double x, double y, double w, double h,
double maskX, double maskY, double maskW, double maskH,
float radius, float softness,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
Rects2D.roundedRectMaskedQuad(self(), x, y, w, h, maskX, maskY, maskW, maskH, radius, softness,
cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void roundedRectStrokeGradientQuad(double x, double y, double w, double h,
float radius, float softness, float thickness,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
Strokes2D.roundedRectStrokeGradientQuad(self(), x, y, w, h, radius, softness, thickness,
cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void roundedRectStrokeGradientQuad(double x, double y, double w, double h,
float radius, float thickness,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
roundedRectStrokeGradientQuad(x, y, w, h, radius, 0.0f, thickness,
cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
/**
* Connects two rounded rectangles by their visible border, not by their centers.
* The connector uses the centers only as the direction vector used to find each border anchor.
*/
public void roundedRectConnector(double x1, double y1, double w1, double h1, double radius1,
double x2, double y2, double w2, double h2, double radius2,
double thickness, int argb) {
Connectors2D.roundedRectConnector(self(), x1, y1, w1, h1, radius1, x2, y2, w2, h2, radius2, thickness, argb);
}
public void roundedRectConnectorGradient(double x1, double y1, double w1, double h1, double radius1,
double x2, double y2, double w2, double h2, double radius2,
double thickness, int startArgb, int endArgb) {
Connectors2D.roundedRectConnectorGradient(self(), x1, y1, w1, h1, radius1, x2, y2, w2, h2, radius2,
thickness, startArgb, endArgb);
}
/**
* Draws a Bezier node graph edge between two rounded rectangles, anchored on their borders.
*/
public void roundedRectNodeGraphEdge(double x1, double y1, double w1, double h1, double radius1,
double x2, double y2, double w2, double h2, double radius2,
double thickness, int argb) {
Connectors2D.roundedRectNodeGraphEdge(self(), x1, y1, w1, h1, radius1, x2, y2, w2, h2, radius2, thickness, argb);
}
public void roundedRectNodeGraphEdgeGradient(double x1, double y1, double w1, double h1, double radius1,
double x2, double y2, double w2, double h2, double radius2,
double thickness, int startArgb, int endArgb) {
Connectors2D.roundedRectNodeGraphEdgeGradient(self(), x1, y1, w1, h1, radius1, x2, y2, w2, h2, radius2,
thickness, startArgb, endArgb);
}
/**
* Draws an orthogonal connector between two rounded rectangles, anchored on their borders.
*/
/**
* Draws an orthogonal connector between two rounded rectangles, anchored on their borders.
*/
public void roundedRectOrthogonalConnector(double x1, double y1, double w1, double h1, double radius1,
double x2, double y2, double w2, double h2, double radius2,
double midX, double thickness, int argb) {
Connectors2D.roundedRectOrthogonalConnector(self(), x1, y1, w1, h1, radius1, x2, y2, w2, h2, radius2,
midX, thickness, argb);
}
public void roundedRectOrthogonalConnectorGradient(double x1, double y1, double w1, double h1, double radius1,
double x2, double y2, double w2, double h2, double radius2,
double midX, double thickness, int startArgb, int endArgb) {
Connectors2D.roundedRectOrthogonalConnectorGradient(self(), x1, y1, w1, h1, radius1,
x2, y2, w2, h2, radius2, midX, thickness, startArgb, endArgb);
}
}

View file

@ -0,0 +1,124 @@
package dev.loki.lovisual.render.engine.renderer.facade.shape;
import dev.loki.lovisual.render.engine.renderer.facade.Renderer2DGlass;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;
import dev.loki.lovisual.render.engine.renderer.renderer2d.media.Items2D;
/** Item-slot drawing family of the Renderer2D facade. */
public class Renderer2DItem extends Renderer2DGlass {
protected Renderer2DItem(boolean textured) {
super(textured);
}
public static final int ITEM_OVERLAY_NONE = 0;
public static final int ITEM_OVERLAY_COUNT = 1;
public static final int ITEM_OVERLAY_DURABILITY = 1 << 1;
public static final int ITEM_OVERLAY_COOLDOWN = 1 << 2;
public static final int ITEM_OVERLAY_DURABILITY_TEXT = 1 << 3;
public static final int ITEM_OVERLAY_ALL = ITEM_OVERLAY_COUNT | ITEM_OVERLAY_DURABILITY | ITEM_OVERLAY_COOLDOWN;
private static final int DEFAULT_ITEM_DURABILITY_THRESHOLD = 100;
private static final int DEFAULT_ITEM_DURABILITY_TEXT_COLOR_THRESHOLD = 70;
// Use this path when the current projection is already the target space
// (for example UNSCALED_LOGICAL HUD / ClickGUI coordinates).
public void item(ItemStack stack, double x, double y) {
item(stack, x, y, 1.0f, 0, ITEM_OVERLAY_NONE, null);
}
public void item(ItemStack stack,
double x,
double y,
float scale,
int seed,
int overlayFlags,
@Nullable String stackCountText) {
item(null, stack, x, y, scale, seed, overlayFlags, stackCountText);
}
public void item(ItemStack stack,
double x,
double y,
float scale,
int seed,
int overlayFlags,
@Nullable String stackCountText,
int durabilityThresholdPercent,
int durabilityTextColorThresholdPercent) {
item(null, stack, x, y, scale, seed, overlayFlags, stackCountText,
durabilityThresholdPercent, durabilityTextColorThresholdPercent);
}
public void item(@Nullable LocalPlayer player,
ItemStack stack,
double x,
double y,
float scale,
int seed,
int overlayFlags,
@Nullable String stackCountText) {
item(player, stack, x, y, scale, seed, overlayFlags, stackCountText,
DEFAULT_ITEM_DURABILITY_THRESHOLD, DEFAULT_ITEM_DURABILITY_TEXT_COLOR_THRESHOLD);
}
public void item(@Nullable LocalPlayer player,
ItemStack stack,
double x,
double y,
float scale,
int seed,
int overlayFlags,
@Nullable String stackCountText,
int durabilityThresholdPercent,
int durabilityTextColorThresholdPercent) {
item(player, stack, x, y, scale, scale, 0.0f, 0.0f, false, seed, true, overlayFlags, stackCountText,
durabilityThresholdPercent, durabilityTextColorThresholdPercent);
}
public void itemPivot(ItemStack stack,
double x,
double y,
float scaleX,
float scaleY,
float pivotX,
float pivotY,
int seed,
int overlayFlags,
@Nullable String stackCountText) {
item(null, stack, x, y, scaleX, scaleY, pivotX, pivotY, true, seed, true, overlayFlags, stackCountText,
DEFAULT_ITEM_DURABILITY_THRESHOLD, DEFAULT_ITEM_DURABILITY_TEXT_COLOR_THRESHOLD);
}
public void itemOverlay(ItemStack stack,
double x,
double y,
float scale,
int overlayFlags,
@Nullable String stackCountText) {
item(null, stack, x, y, scale, scale, 0.0f, 0.0f, false, 0, false, overlayFlags, stackCountText,
DEFAULT_ITEM_DURABILITY_THRESHOLD, DEFAULT_ITEM_DURABILITY_TEXT_COLOR_THRESHOLD);
}
public void item(@Nullable LocalPlayer player,
ItemStack stack,
double x,
double y,
float scaleX,
float scaleY,
float pivotX,
float pivotY,
boolean pivoted,
int seed,
boolean drawItem,
int overlayFlags,
@Nullable String stackCountText,
int durabilityThresholdPercent,
int durabilityTextColorThresholdPercent) {
Items2D.submit(self(),
player, stack, x, y, scaleX, scaleY, pivotX, pivotY, pivoted, seed, drawItem, overlayFlags,
stackCountText, durabilityThresholdPercent, durabilityTextColorThresholdPercent);
}
}

View file

@ -0,0 +1,313 @@
package dev.loki.lovisual.render.engine.renderer.facade.shape;
import dev.loki.lovisual.render.engine.renderer.facade.Renderer2DPath;
import dev.loki.lovisual.render.engine.renderer.renderer2d.path.Circles2D;
import static dev.loki.lovisual.render.engine.renderer.ui.draw.edge.UiMeshGeometry.*;
import dev.loki.lovisual.render.engine.color.RenderColor;
import dev.loki.lovisual.render.engine.renderer.renderer2d.Rects2D;
import dev.loki.lovisual.render.engine.renderer.renderer2d.path.Lines2D;
import com.mojang.blaze3d.textures.GpuSampler;
import com.mojang.blaze3d.textures.GpuTextureView;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.AbstractTexture;
import net.minecraft.resources.Identifier;
import dev.loki.lovisual.render.engine.renderer.renderer2d.media.Textures2D;
import dev.loki.lovisual.render.engine.svg.backend.SvgMeshBackend;
import dev.loki.lovisual.render.engine.svg.parser.SvgRegistry;
import dev.loki.lovisual.render.engine.svg.model.SvgRenderOptions;
import java.nio.file.Path;
/** Circle, line/quad and texture primitives of the Renderer2D facade. */
public class Renderer2DShapes extends Renderer2DPath {
protected Renderer2DShapes(boolean textured) {
super(textured);
}
public void circle(double cx, double cy, double radius, int argb) {
circle(cx, cy, radius, 1.1f, argb);
}
public void circle(double cx, double cy, double radius, float softness, int argb) {
Circles2D.circle(self(), cx, cy, radius, softness, argb);
}
public void circleSoftShadow(double cx, double cy, double radius, float blur, float innerAlpha, int argb) {
if (radius <= 0.0) return;
double size = radius * 2.0;
roundedRectSoftShadow(cx - radius, cy - radius, size, size, (float) radius, blur, innerAlpha, argb);
}
public void circleStroke(double cx, double cy, double radius, double thickness, int argb) {
circleStroke(cx, cy, radius, thickness, 1.1f, argb);
}
public void circleStroke(double cx, double cy, double radius, double thickness, float softness, int argb) {
Circles2D.circleStroke(self(), cx, cy, radius, thickness, softness, argb);
}
public void arcStroke(double cx, double cy, double radius, double thickness,
float startAngleDeg, float endAngleDeg, int argb) {
arcStroke(cx, cy, radius, thickness, startAngleDeg, endAngleDeg, 1.1f, argb);
}
public void arcStroke(double cx, double cy, double radius, double thickness,
float startAngleDeg, float endAngleDeg, float softness, int argb) {
arcStrokeQuad(cx, cy, radius, thickness, startAngleDeg, endAngleDeg, softness, true,
argb, argb, argb, argb);
}
public void arcStrokeFlat(double cx, double cy, double radius, double thickness,
float startAngleDeg, float endAngleDeg, float softness, int argb) {
arcStrokeQuad(cx, cy, radius, thickness, startAngleDeg, endAngleDeg, softness, false,
argb, argb, argb, argb);
}
public void arcStrokeFlat(double cx, double cy, double radius, double thickness,
float startAngleDeg, float endAngleDeg, int argb) {
arcStrokeFlat(cx, cy, radius, thickness, startAngleDeg, endAngleDeg, 0.0f, argb);
}
public void arcStrokeGradient(double cx, double cy, double radius, double thickness,
float startAngleDeg, float endAngleDeg, float softness,
int startArgb, int endArgb, float angleDeg) {
arcStrokeGradient(cx, cy, radius, thickness, startAngleDeg, endAngleDeg, softness,
startArgb, endArgb, angleDeg, 0.0f);
}
public void arcStrokeGradient(double cx, double cy, double radius, double thickness,
float startAngleDeg, float endAngleDeg,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
arcStrokeGradient(cx, cy, radius, thickness, startAngleDeg, endAngleDeg, 0.0f,
startArgb, endArgb, angleDeg, offsetPx);
}
public void arcStrokeGradient(double cx, double cy, double radius, double thickness,
float startAngleDeg, float endAngleDeg, float softness,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
double outerRadius = radius + Math.max(0.0, thickness) * 0.5 + softness;
computeLinearGradientColors((float) (outerRadius * 2.0), (float) (outerRadius * 2.0),
startArgb, endArgb, angleDeg, offsetPx, gradientTmp);
arcStrokeQuad(cx, cy, radius, thickness, startAngleDeg, endAngleDeg, softness, true,
gradientTmp[0], gradientTmp[1], gradientTmp[2], gradientTmp[3]);
}
public void arcStrokeQuad(double cx, double cy, double radius, double thickness,
float startAngleDeg, float endAngleDeg, float softness, boolean caps,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
Circles2D.arcStrokeQuad(self(), cx, cy, radius, thickness, startAngleDeg, endAngleDeg, softness, caps,
cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void orbizRing(double cx, double cy,
double radius, double thickness,
float startAngleDeg, float sweepAngleDeg,
float softness, float glowRadius, float glowStrength,
int primaryArgb, int secondaryArgb,
int colorMode, float angularOffset, float angularCycles,
float trackAlpha, float bodyAlpha, float headBoost,
float trackGlow, boolean caps) {
Circles2D.orbizRing(self(), cx, cy, radius, thickness, startAngleDeg, sweepAngleDeg,
softness, glowRadius, glowStrength, primaryArgb, secondaryArgb,
colorMode, angularOffset, angularCycles, trackAlpha, bodyAlpha, headBoost, trackGlow, caps);
}
public void line(double x1, double y1, double x2, double y2, int argb) {
Lines2D.line(self(), x1, y1, x2, y2, argb);
}
public void line(double x1, double y1, double x2, double y2, RenderColor color) {
Lines2D.line(self(), x1, y1, x2, y2, color);
}
public void boxLines(double x, double y, double width, double height, int argb) {
Lines2D.boxLines(self(), x, y, width, height, argb);
}
public void quad(double x, double y, double width, double height, int argb) {
quad(x, y, width, height, argb, argb, argb, argb);
}
public void quad(double x, double y, double width, double height, int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
Rects2D.quadCorners(self(), x, y, width, height, cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void quadGradient(double x, double y, double width, double height,
int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) {
quad(x, y, width, height, cTopLeft, cTopRight, cBottomRight, cBottomLeft);
}
public void quadGradientLinear(double x, double y, double width, double height,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
computeLinearGradientColors((float) width, (float) height, startArgb, endArgb, angleDeg, offsetPx, gradientTmp);
quad(x, y, width, height, gradientTmp[0], gradientTmp[1], gradientTmp[2], gradientTmp[3]);
}
public void quadStrokeGradientLinear(double x, double y, double width, double height,
float thickness,
int startArgb, int endArgb, float angleDeg, float offsetPx) {
roundedRectStrokeGradient(x, y, width, height, 0.0f, 0.0f, thickness, startArgb, endArgb, angleDeg, offsetPx);
}
public void svg(String svgName,
double x,
double y,
double width,
double height,
SvgRenderOptions options) {
if (textured) {
throw new IllegalStateException("SVG mesh drawing is supported only on Renderer2D.COLOR.");
}
Identifier id = SvgRegistry.resolve(svgName);
if (id == null) return;
SvgMeshBackend.draw(self(), id, x, y, width, height, options);
}
public void svg(Identifier svgId,
double x,
double y,
double width,
double height,
SvgRenderOptions options) {
if (textured) {
throw new IllegalStateException("SVG mesh drawing is supported only on Renderer2D.COLOR.");
}
SvgMeshBackend.draw(self(), svgId, x, y, width, height, options);
}
public void svg(Path svgPath,
double x,
double y,
double width,
double height,
SvgRenderOptions options) {
if (textured) {
throw new IllegalStateException("SVG mesh drawing is supported only on Renderer2D.COLOR.");
}
SvgMeshBackend.draw(self(), svgPath, x, y, width, height, options);
}
public void textureQuad(GpuTextureView samplerView,
GpuSampler sampler,
double x,
double y,
double w,
double h,
int argb) {
Textures2D.textureQuad(self(), samplerView, sampler, x, y, w, h, argb);
}
public void msdfTextureQuad(GpuTextureView samplerView,
GpuSampler sampler,
double x,
double y,
double w,
double h,
int argb,
float pxRange,
int atlasWidth,
int atlasHeight) {
msdfTextureQuad(samplerView, sampler, x, y, w, h, argb, argb, argb, argb, pxRange, atlasWidth, atlasHeight);
}
public void msdfTextureQuad(GpuTextureView samplerView,
GpuSampler sampler,
double x,
double y,
double w,
double h,
int topLeft,
int topRight,
int bottomRight,
int bottomLeft,
float pxRange,
int atlasWidth,
int atlasHeight) {
Textures2D.msdfTextureQuad(self(), samplerView, sampler, x, y, w, h,
topLeft, topRight, bottomRight, bottomLeft, pxRange, atlasWidth, atlasHeight);
}
public void roundedTexRect(double x, double y, double w, double h,
float radius, float softness,
double texX1, double texY1, double texX2, double texY2,
int argb, GpuTextureView samplerView, GpuSampler sampler) {
Textures2D.roundedTexRect(self(), x, y, w, h, radius, softness, texX1, texY1, texX2, texY2,
argb, samplerView, sampler);
}
public void roundedTexMaskRect(double x, double y, double w, double h,
float radius, float softness,
double texX1, double texY1, double texX2, double texY2,
int argb, GpuTextureView samplerView, GpuSampler sampler) {
Textures2D.roundedTexMaskRect(self(), x, y, w, h, radius, softness, texX1, texY1, texX2, texY2,
argb, samplerView, sampler);
}
public void roundedTexRect(double x, double y, double w, double h,
float radius, float softness, int argb,
Identifier textureId) {
if (!textured) {
throw new IllegalStateException("Renderer2D is not configured for textures.");
}
Minecraft mc = Minecraft.getInstance();
if (mc == null || textureId == null) return;
AbstractTexture tex = mc.getTextureManager().getTexture(textureId);
if (tex == null) return;
GpuTextureView view = tex.getTextureView();
GpuSampler sampler = tex.getSampler();
if (view == null || sampler == null) return;
roundedTexRect(x, y, w, h, radius, 0.0f, 0, 0, 1, 1, argb, view, sampler);
}
public void roundedTexRect(double x, double y, double w, double h,
float radius, int argb,
Identifier textureId) {
roundedTexRect(x, y, w, h, radius, 0.0f, argb, textureId);
}
public void roundedTexMaskRect(double x, double y, double w, double h,
float radius, float softness, int argb,
Identifier textureId) {
if (!textured) {
throw new IllegalStateException("Renderer2D is not configured for textures.");
}
Minecraft mc = Minecraft.getInstance();
if (mc == null || textureId == null) return;
AbstractTexture tex = mc.getTextureManager().getTexture(textureId);
if (tex == null) return;
GpuTextureView view = tex.getTextureView();
GpuSampler sampler = tex.getSampler();
if (view == null || sampler == null) return;
roundedTexMaskRect(x, y, w, h, radius, 0.0f, 0, 0, 1, 1, argb, view, sampler);
}
public void roundedTexMaskRect(double x, double y, double w, double h,
float radius, int argb,
Identifier textureId) {
roundedTexMaskRect(x, y, w, h, radius, 0.0f, argb, textureId);
}
public void roundedTexRect(double x, double y, double w, double h,
float radius, float softness,
double texX1, double texY1, double texX2, double texY2,
int argb, Identifier textureId) {
if (!textured) {
throw new IllegalStateException("Renderer2D is not configured for textures.");
}
Minecraft mc = Minecraft.getInstance();
if (mc == null || textureId == null) return;
AbstractTexture tex = mc.getTextureManager().getTexture(textureId);
if (tex == null) return;
GpuTextureView view = tex.getTextureView();
GpuSampler sampler = tex.getSampler();
if (view == null || sampler == null) return;
roundedTexRect(x, y, w, h, radius, 0.0f, texX1, texY1, texX2, texY2, argb, view, sampler);
}
public void texQuad(double x, double y, double width, double height,
double texX1, double texY1, double texX2, double texY2,
int argb) {
Textures2D.texQuad(self(), x, y, width, height, texX1, texY1, texX2, texY2, argb);
}
}

View file

@ -5,6 +5,7 @@ import com.mojang.blaze3d.textures.GpuSampler;
import com.mojang.blaze3d.textures.GpuTextureView;
import dev.loki.lovisual.features.module.lifecycle.Modules;
import dev.loki.lovisual.features.module.modules.visuals.optimization.FpsOptimizer;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
import dev.loki.lovisual.render.engine.postprocess.post.PostProcessManager;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.renderer.renderer2d.Batch2D;
@ -41,6 +42,7 @@ public final class Blur2D {
/** Main framebuffer color texture plus the shared post-process sampler. */
public static BlurSource source() {
if (OptimizeState.isNoGlass()) return null;
FpsOptimizer fpsOptimizer = Modules.get(FpsOptimizer.class);
if (fpsOptimizer != null && fpsOptimizer.isGlassDisabled()) return null;
Minecraft mc = Minecraft.getInstance();
@ -79,44 +81,6 @@ public final class Blur2D {
Batch2D.close();
}
public static void glassBlurRect(Renderer2D r, double x, double y, double w, double h,
float radius, float quality, float brightness, float alpha, int ignoredTintRgb) {
if (w <= 0.0 || h <= 0.0) return;
if (alpha <= 0.001f) return;
r.effect(UiEffectSpec.blur(UiShape.roundedRect(x, y, w, h, radius), radius, ignoredTintRgb));
BlurSource source = source();
if (source == null) return;
DrawBatch batch = Batch2D.openBlur(r, UiBatchType.GLASS_BLUR, source.view, source.sampler,
Renderer2D.BlurQuality.HIGH, legacyKawaseOffset(quality));
if (batch == null) return;
MeshBuilder mesh = batch.mesh;
mesh.alpha = 1.0;
float finalAlpha = clamp01((float) (alpha * r.getAlpha()));
if (finalAlpha <= 0.001f) {
Batch2D.close();
return;
}
int a = Math.max(0, Math.min(255, Math.round(finalAlpha * 255.0f)));
float smoothness = 2.0f;
float rad = Math.max(0.0f, radius);
mesh.ensureQuadCapacity();
int i1 = mesh.vec2(x, y).local2(x, y).color(255, 255, 255, a)
.vec4(x, y, w, h).vec4(rad, rad, rad, rad).vec4(quality, brightness, smoothness, 0.0f).next();
int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(255, 255, 255, a)
.vec4(x, y, w, h).vec4(rad, rad, rad, rad).vec4(quality, brightness, smoothness, 0.0f).next();
int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(255, 255, 255, a)
.vec4(x, y, w, h).vec4(rad, rad, rad, rad).vec4(quality, brightness, smoothness, 0.0f).next();
int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(255, 255, 255, a)
.vec4(x, y, w, h).vec4(rad, rad, rad, rad).vec4(quality, brightness, smoothness, 0.0f).next();
mesh.quad(i1, i2, i3, i4);
Batch2D.close();
}
public static void blurChamferedRect(Renderer2D r, double x, double y, double w, double h,
double chamfer, float quality, float brightness, float alpha, int ignoredTintRgb) {
if (w <= 0.0 || h <= 0.0) return;

View file

@ -0,0 +1,23 @@
package dev.loki.lovisual.render.engine.renderer.style;
/**
* Immutable material parameters for drawing one background plate.
*
* <p>Field order: style, softness, fresnelPower, fresnelAlpha, baseAlpha,
* fresnelMix, distort, squircle, tint, strokeWidth, blurQuality.
* Fields that a style does not use are carried as zeroes; see
* {@link StyleSpecs#resolve(SurfaceStyle)}.
*/
public record StyleSpec(
SurfaceStyle style,
float softness,
float fresnelPower,
float fresnelAlpha,
float baseAlpha,
float fresnelMix,
float distort,
float squircle,
int tint,
float strokeWidth,
float blurQuality) {
}

View file

@ -0,0 +1,46 @@
package dev.loki.lovisual.render.engine.renderer.style;
/**
* Preset {@link StyleSpec} values per material. The glass numbers are lifted
* verbatim from the legacy per-site helpers (HudRenderUtil large/small plates,
* ClickGUI panel glass) so migrating call sites keeps visuals unchanged.
*/
public enum StyleSpecs {
;
/** Base RGB of the legacy {@code GLASS_BG = 0x660C0C0C} fill. */
public static final int GLASS_FILL_RGB = 0x0C0C0C;
/** Liquid-glass material for a large or small plate (HudRenderUtil numbers). */
public static StyleSpec glass(boolean large) {
return new StyleSpec(
SurfaceStyle.GLASS,
large ? 13.0f : 11.0f,
large ? -22.0f : -18.0f,
1.0f,
large ? 0.74f : 0.82f,
large ? 0.34f : 0.38f,
large ? 0.155f : 0.135f,
0.0f,
0xFFFFFFFF,
0.6f,
0.0f);
}
/** Preset for the given style; {@code AUTO} falls back to the large glass plate. */
public static StyleSpec resolve(SurfaceStyle style) {
SurfaceStyle s = style == null ? SurfaceStyle.AUTO : style;
return switch (s) {
case GLASS -> glass(true);
case BLUR -> new StyleSpec(s, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0xFFFFFFFF, 0.0f, 1.0f);
case FLAT -> new StyleSpec(s, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0xFFFFFFFF, 0.6f, 1.0f);
case OUTLINE -> new StyleSpec(s, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0xFFFFFFFF, 1.0f, 1.0f);
case NONE -> new StyleSpec(s, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0, 0.0f, 0.0f);
case AUTO -> glass(true);
};
}
}

View file

@ -0,0 +1,34 @@
package dev.loki.lovisual.render.engine.renderer.style;
import dev.loki.lovisual.config.values.mode.EnumValue;
/**
* Material used to draw an element background plate. Independent from the
* theme palette (colors) and from shape geometry (radii / strokes): it only
* answers "how is the surface drawn". {@link #AUTO} means "follow the global
* selection" and is only meaningful as a per-widget override.
*/
public enum SurfaceStyle implements EnumValue.IdProvider {
AUTO("auto"),
GLASS("glass"),
BLUR("blur"),
FLAT("flat"),
OUTLINE("outline"),
NONE("none");
private final String id;
SurfaceStyle(String id) {
this.id = id;
}
@Override
public String id() {
return id;
}
/** Global style settings never offer AUTO; it is an override-only value. */
public boolean isOverrideable() {
return this != AUTO;
}
}

View file

@ -9,6 +9,7 @@ import dev.loki.lovisual.render.engine.core.system.LoVisualRenderSystem;
import dev.loki.lovisual.render.engine.core.frame.RenderFrameContext;
import dev.loki.lovisual.render.engine.core.frame.RenderPhase;
import dev.loki.lovisual.render.engine.core.context.ViewportContext;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
import dev.loki.lovisual.render.engine.postprocess.post.PostProcessManager;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.uniform.MeshBuilder;
@ -94,10 +95,12 @@ public final class UiBlurResources {
}
public static void requestLiquidGlassBlur() {
if (OptimizeState.isNoGlass()) return;
liquidGlassBlurRequested = true;
}
public static void requestBeforeNextShapeClip() {
if (OptimizeState.isNoGlass()) return;
liquidGlassBlurRequested = true;
blurBeforeNextShapeClipRequested = true;
}

View file

@ -2,6 +2,7 @@ package dev.loki.lovisual.render.engine.text.glyph;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import dev.loki.lovisual.render.engine.color.RenderColor;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines;
import dev.loki.lovisual.render.engine.text.backend.placement.TextPlacementMode;
import dev.loki.lovisual.render.engine.text.font.Font;
@ -89,6 +90,14 @@ final class GradientTexts {
static double horizontalFade(CustomTextRenderer r, String text, double x, double y, RenderColor color,
double clipLeft, double clipRight, double fadeLeft, double fadeRight,
boolean shadow) {
// Optimize.lean_hud: plain solid text — skips the per-glyph String allocations and
// gradient lambdas of the fade run (marquee edge fade is the visual price).
if (OptimizeState.isLeanHud()) {
return r.autoRun(() -> {
r.ensureMeshStarted();
return drawText(r, text, x, y, color, shadow);
});
}
return r.autoRun(() -> {
r.ensureMeshStarted();
double glyphScale = r.scale / 1.5;

View file

@ -8,6 +8,7 @@ import net.minecraft.client.renderer.feature.FeatureRenderDispatcher;
import net.minecraft.network.chat.Style;
import net.minecraft.util.FormattedCharSequence;
import dev.loki.lovisual.render.engine.color.RenderColor;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
import dev.loki.lovisual.render.helpers.clip.ScissorFunction;
import static net.minecraft.client.Minecraft.getInstance;
@ -177,6 +178,12 @@ public class VanillaTextRenderer implements TextRenderer {
(float) Math.max(0.0, clipRight - clipLeft),
(float) Math.max(0.0, getHeight(shadow))
);
// Optimize.lean_hud: keep the clip, drop the per-glyph fade gradient allocations.
if (OptimizeState.isLeanHud()) {
double plainX = render(text, x, y, color, shadow);
flushDrawing();
return plainX;
}
int argb = color.argb();
double endX = renderGradient(text, x, y, (idx, cp, glyphX, out) -> {
String glyph = new String(Character.toChars(cp));

View file

@ -5,6 +5,7 @@ import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import dev.loki.lovisual.render.engine.core.system.LoVisualRenderSystem;
import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
import dev.loki.lovisual.features.module.modules.visuals.weather.sky.ShaderSky;
import java.nio.ByteBuffer;
@ -60,6 +61,12 @@ public enum ShaderSkyUniforms {
DATA.thunder[0] = Math.max(1.0f, thunderInterval);
DATA.thunder[1] = clamp01(thunderChance);
DATA.thunder[2] = thunderGlow;
// u_Thunder.w doubles as the Optimize.lite_sky flag: 1 = fbm runs 2 octaves instead of 4.
if (OptimizeState.isLiteSky()) {
DATA.thunder[3] = 1.0f;
} else {
DATA.thunder[3] = 0.0f;
}
LoVisualRenderSystem.uniforms().writeCached(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, 1, true, DATA);
}

View file

@ -0,0 +1,79 @@
package dev.loki.lovisual.render.helpers.material;
import dev.loki.lovisual.config.style.StyleConfig;
import dev.loki.lovisual.render.engine.animation.AnimationUtility;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
import net.minecraft.util.Util;
/**
* Cross-fade state for the global surface style. The material branch itself
* must switch instantly (styles are not blendable), so the transition fades
* the outgoing plate out during the first half of the interval and fades the
* incoming plate in during the second half — a soft hand-off instead of a pop.
* <p>
* Lives in the {@code impl/} sibling folder to keep {@code render.helpers.material}
* within the four-file-per-directory limit; package stays shared.
*/
final class StyleTransition {
/** Resolved plate state: style to draw and the alpha multiplier (0..1). */
record Display(SurfaceStyle style, float fade) {
}
private static boolean initialised;
private static SurfaceStyle from = SurfaceStyle.GLASS;
private static SurfaceStyle to = SurfaceStyle.GLASS;
private static long startMs;
private static boolean active;
private StyleTransition() {
}
/** Current display state; cheap enough to call every frame. */
static Display display() {
SurfaceStyle now = StyleConfig.get().style();
if (!initialised) {
initialised = true;
from = now;
to = now;
}
if (now != to) {
from = displayedStyle();
to = now;
startMs = Util.getMillis();
active = StyleConfig.get().animateSwitch() && StyleConfig.get().switchMs() > 0;
}
if (!active) {
return new Display(now, 1.0f);
}
int duration = StyleConfig.get().switchMs();
long elapsed = Util.getMillis() - startMs;
if (elapsed >= duration) {
active = false;
return new Display(to, 1.0f);
}
float p = progress(elapsed, duration);
if (p < 0.5f) {
return new Display(from, 1.0f - p * 2.0f);
}
return new Display(to, p * 2.0f - 1.0f);
}
/** Style visible at the current transition moment without consuming it. */
private static SurfaceStyle displayedStyle() {
if (!active) {
return to;
}
int duration = StyleConfig.get().switchMs();
long elapsed = Util.getMillis() - startMs;
if (elapsed >= duration) {
return to;
}
return progress(elapsed, duration) < 0.5f ? from : to;
}
private static float progress(long elapsed, int duration) {
float linear = duration <= 0 ? 1.0f : (float) elapsed / (float) duration;
return AnimationUtility.easeOutCubic(AnimationUtility.clamp01(linear));
}
}

View file

@ -0,0 +1,166 @@
package dev.loki.lovisual.render.helpers.material;
import dev.loki.lovisual.render.engine.animation.AnimationUtility;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.render.engine.renderer.style.StyleSpec;
import dev.loki.lovisual.render.engine.renderer.style.StyleSpecs;
import dev.loki.lovisual.render.engine.renderer.style.SurfaceStyle;
/**
* Single entry point for drawing an element background plate in the resolved
* surface style. An {@link SurfaceStyle#AUTO} override follows the global
* selection from {@code StyleConfig} with the {@link StyleTransition} fade;
* an explicit override draws that style immediately. Replaces the per-site
* glass / blur / matte / outline branches scattered across HUD and ClickGUI.
*/
public enum SurfaceRenderer {
;
/** Style an override resolves to right now (AUTO → animated global). */
public static SurfaceStyle resolvedStyle(SurfaceStyle override) {
return displayFor(override).style();
}
/** Draws a plate with a uniform corner radius. */
public static void plate(Renderer2D renderer,
double x, double y, double w, double h,
float radius,
float scale, boolean large,
float blurAlpha, float glassAlpha,
int tintArgb, SurfaceStyle override) {
plateCorners(renderer, x, y, w, h,
radius, radius, radius, radius,
scale, large, blurAlpha, glassAlpha, tintArgb, override);
}
/** Draws a plate with per-corner radii, dispatching on the resolved style. */
public static void plateCorners(Renderer2D renderer,
double x, double y, double w, double h,
float radiusTL, float radiusTR,
float radiusBR, float radiusBL,
float scale, boolean large,
float blurAlpha, float glassAlpha,
int tintArgb, SurfaceStyle override) {
if (renderer == null || w <= 0.0 || h <= 0.0) return;
StyleTransition.Display display = displayFor(override);
SurfaceStyle style = display.style();
float fade = display.fade();
float blur = AnimationUtility.clamp(blurAlpha, 0.0f, 1.0f) * fade;
float glass = AnimationUtility.clamp(glassAlpha, 0.0f, 1.0f) * fade;
float radius = (radiusTL + radiusTR + radiusBR + radiusBL) * 0.25f;
switch (style) {
case GLASS -> {
if (blur <= 0.001f && glass <= 0.001f) return;
StyleSpec spec = StyleSpecs.glass(large);
float safeScale = Math.max(0.001f, scale);
renderer.liquidGlassRectCorners(x, y, w, h,
radiusTL, radiusTR, radiusBR, radiusBL,
spec.softness() * safeScale,
tintArgb,
glass,
blur,
spec.fresnelPower(),
spec.fresnelAlpha(),
spec.baseAlpha(),
spec.fresnelMix(),
spec.distort() * glass,
spec.squircle());
}
case BLUR -> {
if (blur <= 0.001f) return;
StyleSpec spec = StyleSpecs.resolve(SurfaceStyle.BLUR);
renderer.blurRect(x, y, w, h, radius,
spec.blurQuality(), 1.0f, blur, 0xFFFFFF);
}
case FLAT -> MatteHudStyle.drawPlate(renderer, x, y, w, h, radius, glass);
case OUTLINE -> {
if (glass <= 0.001f) return;
StyleSpec spec = StyleSpecs.resolve(SurfaceStyle.OUTLINE);
renderer.roundedRectStrokeCorners(x, y, w, h,
radiusTL, radiusTR, radiusBR, radiusBL,
spec.strokeWidth(), MatteHudStyle.strokeColor(glass));
}
case NONE, AUTO -> {
// Nothing to draw; AUTO never reaches here (displayFor resolves it).
}
}
}
/**
* Draws a bespoke glass material described by {@code spec}, or the matching
* non-glass variant when the resolved style is not glass. Unlike {@link #plate},
* {@code spec.distort()} is passed through as-is (call sites pre-multiply it),
* and {@code spec.blurQuality()} > 0 requests an extra outer blur pass before
* the glass (0 = the glass pass blurs by itself).
*/
public static void plateSpec(Renderer2D renderer,
double x, double y, double w, double h,
float radiusTL, float radiusTR,
float radiusBR, float radiusBL,
StyleSpec spec,
float scale,
int tintArgb,
float glassAlpha,
float blurAlpha,
SurfaceStyle override) {
if (renderer == null || w <= 0.0 || h <= 0.0 || spec == null) return;
StyleTransition.Display display = displayFor(override);
float fade = display.fade();
float glass = AnimationUtility.clamp(glassAlpha, 0.0f, 1.0f) * fade;
float blur = AnimationUtility.clamp(blurAlpha, 0.0f, 1.0f) * fade;
float radius = (radiusTL + radiusTR + radiusBR + radiusBL) * 0.25f;
switch (display.style()) {
case GLASS -> {
if (spec.blurQuality() > 0.0f && blur > 0.001f) {
renderer.blurRect(x, y, w, h, radius,
spec.blurQuality(), 1.0f, blur, 0xFFFFFF);
}
if (glass <= 0.001f && blur <= 0.001f) return;
renderer.liquidGlassRectCorners(x, y, w, h,
radiusTL, radiusTR, radiusBR, radiusBL,
Math.max(0.001f, spec.softness() * scale),
tintArgb,
glass,
blur,
spec.fresnelPower(),
spec.fresnelAlpha(),
spec.baseAlpha(),
spec.fresnelMix(),
spec.distort(),
spec.squircle());
}
case BLUR -> {
float strength = blur > 0.001f ? blur : glass;
if (strength <= 0.001f) return;
float quality = spec.blurQuality() > 0.0f ? spec.blurQuality() : 1.0f;
renderer.blurRect(x, y, w, h, radius, quality, 1.0f, strength, 0xFFFFFF);
}
case FLAT -> MatteHudStyle.drawPlate(renderer, x, y, w, h, radius, glass);
case OUTLINE -> {
if (glass <= 0.001f) return;
renderer.roundedRectStrokeCorners(x, y, w, h,
radiusTL, radiusTR, radiusBR, radiusBL,
spec.strokeWidth(), MatteHudStyle.strokeColor(glass));
}
case NONE, AUTO -> {
// Nothing to draw; AUTO never reaches here (displayFor resolves it).
}
}
}
private static StyleTransition.Display displayFor(SurfaceStyle override) {
StyleTransition.Display base =
(override == null || override == SurfaceStyle.AUTO)
? StyleTransition.display()
: new StyleTransition.Display(override, 1.0f);
// Optimize.no_glass kill-switch: fall back to a flat plate instead of
// disabling the surface entirely (blur/glass resources are unavailable).
if (OptimizeState.isNoGlass() && base.style() != SurfaceStyle.NONE) {
return new StyleTransition.Display(SurfaceStyle.FLAT, base.fade());
}
return base;
}
}

View file

@ -13,6 +13,7 @@ import dev.loki.lovisual.features.module.lifecycle.Modules;
import dev.loki.lovisual.features.module.modules.visuals.scene.visual.ReimaginedVisual;
import dev.loki.lovisual.features.module.modules.visuals.weather.sky.ShaderSky;
import dev.loki.lovisual.render.engine.animation.AnimationUtility;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines;
import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer;
import dev.loki.lovisual.render.engine.renderer.MeshRenderer;
@ -26,6 +27,13 @@ import dev.loki.lovisual.render.engine.uniform.impl.sky.skybox.SkyboxShaderUnifo
* and the model-view stack.
*/
final class SkyboxShaderPasses {
/**
* Layer bits kept under Optimize.lite_sky: base waves/ribbons/sweeps/veil (bit 0-3)
* plus the four star grids (bit 12-15). All fbm/algebra-heavy layers are cleared so
* the shader can skip their noise blocks.
*/
static final int LITE_SKY_LAYER_MASK = 0xF00F;
private SkyboxShaderPasses() {
}
@ -48,6 +56,10 @@ final class SkyboxShaderPasses {
float yawRad = (float) Math.toRadians(-camera.yRot());
float pitchRad = (float) Math.toRadians(camera.xRot());
float shaderFov = SkyboxProjection.extractFov(worldProjection, fov);
int layerMask = visual.getSkyboxShaderLayerMask();
if (OptimizeState.isLiteSky()) {
layerMask &= LITE_SKY_LAYER_MASK;
}
SkyboxShaderUniforms.update(
visual.getShaderSkyboxColor(),
sky.skyColor & 0x00FFFFFF,
@ -71,7 +83,7 @@ final class SkyboxShaderPasses {
visual.getSkyboxShaderLargeStars(),
visual.getSkyboxShaderStarBrightness(),
visual.getSkyboxShaderTwinkleStrength(),
visual.getSkyboxShaderLayerMask()
layerMask
);
FullScreenRenderer.ensureInit();

View file

@ -202,6 +202,15 @@
"setting.main_config.backdoorAllowLocalHttpWhenServerLocal": "Allow local HTTP on local server",
"setting.main_config.backdoorAllowedTranslationPacks": "Allowed translation packs",
"setting.main_config.backdoorAllowedKeybinds": "Allowed keybinds",
"setting.style.surfaceStyle": "Surface style",
"setting.style.surfaceStyle.option.glass": "Glass",
"setting.style.surfaceStyle.option.blur": "Blur",
"setting.style.surfaceStyle.option.flat": "Flat",
"setting.style.surfaceStyle.option.outline": "Outline",
"setting.style.surfaceStyle.option.none": "None",
"setting.style.switchMs": "Style switch duration",
"setting.style.animateSwitch": "Animate style switch",
"setting.style.cycleStyle": "Cycle style bind",
"setting.common.inventory.swap_policy": "Swap policy",
"setting.common.inventory.swap_policy.option.NONE": "None",
"setting.common.inventory.swap_policy.option.GRIM_STRICT": "Grim strict",
@ -812,6 +821,7 @@
"setting.draggable.scoreboard.scoreboard_color_mode.option.Theme": "Theme",
"setting.draggable.scoreboard.scoreboard_color_mode.option.Custom": "Custom",
"setting.draggable.scoreboard.scoreboard_bg_effect": "Background effect",
"setting.draggable.scoreboard.scoreboard_bg_effect.option.Auto": "Auto",
"setting.draggable.scoreboard.scoreboard_bg_effect.option.None": "None",
"setting.draggable.scoreboard.scoreboard_bg_effect.option.Blur": "Blur",
"setting.draggable.scoreboard.scoreboard_bg_effect.option.Glass": "Glass",
@ -1923,6 +1933,7 @@
"setting.draggable.triangulator.triangulator_color_mode.option.Theme": "Theme",
"setting.draggable.triangulator.triangulator_color_mode.option.Custom": "Custom",
"setting.draggable.triangulator.triangulator_bg_effect": "Background effect",
"setting.draggable.triangulator.triangulator_bg_effect.option.Auto": "Auto",
"setting.draggable.triangulator.triangulator_bg_effect.option.None": "None",
"setting.draggable.triangulator.triangulator_bg_effect.option.Blur": "Blur",
"setting.draggable.triangulator.triangulator_bg": "Background",
@ -2122,6 +2133,7 @@
"setting.common.color_mode.option.theme": "Theme",
"setting.common.color_mode.option.custom": "Custom",
"setting.common.bg_effect": "Background effect",
"setting.common.bg_effect.option.Auto": "Auto",
"setting.common.bg_effect.option.none": "None",
"setting.common.bg_effect.option.blur": "Blur",
"setting.common.bg_effect.option.glass": "Glass",
@ -2151,6 +2163,7 @@
"setting.common.admins_bg": "Background",
"setting.common.admins_bg_alpha": "Background alpha",
"setting.common.admins_bg_effect": "Background effect",
"setting.common.admins_bg_effect.option.Auto": "Auto",
"setting.common.admins_bg_effect.option.blur": "Blur",
"setting.common.admins_bg_effect.option.none": "None",
"setting.common.admins_bg_secondary": "Secondary background",
@ -2279,6 +2292,7 @@
"setting.common.cooldowns_bg": "Background",
"setting.common.cooldowns_bg_alpha": "Background alpha",
"setting.common.cooldowns_bg_effect": "Background effect",
"setting.common.cooldowns_bg_effect.option.Auto": "Auto",
"setting.common.cooldowns_bg_effect.option.blur": "Blur",
"setting.common.cooldowns_bg_effect.option.none": "None",
"setting.common.cooldowns_bg_secondary": "Secondary background",
@ -2514,6 +2528,7 @@
"setting.common.inventory_bg": "Background",
"setting.common.inventory_bg_alpha": "Background alpha",
"setting.common.inventory_bg_effect": "Background effect",
"setting.common.inventory_bg_effect.option.Auto": "Auto",
"setting.common.inventory_bg_effect.option.blur": "Blur",
"setting.common.inventory_bg_effect.option.none": "None",
"setting.common.inventory_bg_secondary": "Secondary background",
@ -2545,6 +2560,7 @@
"setting.common.keybinds_bg": "Background",
"setting.common.keybinds_bg_alpha": "Background alpha",
"setting.common.keybinds_bg_effect": "Background effect",
"setting.common.keybinds_bg_effect.option.Auto": "Auto",
"setting.common.keybinds_bg_effect.option.blur": "Blur",
"setting.common.keybinds_bg_effect.option.none": "None",
"setting.common.keybinds_bg_secondary": "Secondary background",
@ -2614,6 +2630,7 @@
"setting.common.media_player_bg": "Background",
"setting.common.media_player_bg_alpha": "Background alpha",
"setting.common.media_player_bg_effect": "Background effect",
"setting.common.media_player_bg_effect.option.Auto": "Auto",
"setting.common.media_player_bg_effect.option.blur": "Blur",
"setting.common.media_player_bg_effect.option.glass": "Glass",
"setting.common.media_player_bg_effect.option.none": "None",
@ -2680,6 +2697,7 @@
"setting.common.module_list_bg": "Background",
"setting.common.module_list_bg_alpha": "Background alpha",
"setting.common.module_list_bg_effect": "Background effect",
"setting.common.module_list_bg_effect.option.Auto": "Auto",
"setting.common.module_list_bg_effect.option.blur": "Blur",
"setting.common.module_list_bg_effect.option.glass": "Glass",
"setting.common.module_list_bg_effect.option.none": "None",
@ -2760,6 +2778,7 @@
"setting.common.potions_bg": "Background",
"setting.common.potions_bg_alpha": "Background alpha",
"setting.common.potions_bg_effect": "Background effect",
"setting.common.potions_bg_effect.option.Auto": "Auto",
"setting.common.potions_bg_effect.option.blur": "Blur",
"setting.common.potions_bg_effect.option.none": "None",
"setting.common.potions_bg_secondary": "Secondary background",
@ -2979,6 +2998,7 @@
"setting.common.target_bg": "Background",
"setting.common.target_bg_alpha": "Background alpha",
"setting.common.target_bg_effect": "Background effect",
"setting.common.target_bg_effect.option.Auto": "Auto",
"setting.common.target_bg_effect.option.blur": "Blur",
"setting.common.target_bg_effect.option.glass": "Glass",
"setting.common.target_bg_effect.option.none": "None",
@ -3047,6 +3067,7 @@
"setting.common.tooltip_alpha": "Alpha",
"setting.common.tooltip_bg_alpha": "Background alpha",
"setting.common.tooltip_bg_effect": "Background effect",
"setting.common.tooltip_bg_effect.option.Auto": "Auto",
"setting.common.tooltip_bg_effect.option.blur": "Blur",
"setting.common.tooltip_bg_effect.option.none": "None",
"setting.common.tooltip_bg_gradient": "Background gradient",
@ -3342,6 +3363,12 @@
"setting.chinahat.head_top_offset": "Head height",
"setting.chinahat.head_forward_offset": "Forward offset",
"setting.chinahat.head_right_offset": "Right offset",
"module.optimize.name": "Optimize",
"module.optimize.description": "Manual FPS rubilnik: while it is on — no glass/blur, lighter post-process passes, no noisy procedural sky layers, no per-frame HUD animation overhead.",
"setting.optimize.no_glass": "No glass/blur",
"setting.optimize.lite_post": "Light post-process",
"setting.optimize.lite_sky": "Simple sky",
"setting.optimize.lean_hud": "Lean HUD",
"module.fpsoptimizer.name": "FPS Optimizer",
"module.fpsoptimizer.description": "Manual toggles to cut render cost: vanilla particles, menu background shader, glass/blur, bloom/glow, off-screen entity culling.",
"setting.fpsoptimizer.disable_particles": "Disable particles",

View file

@ -748,6 +748,7 @@
"setting.draggable.scoreboard.scoreboard_color_mode.option.Theme": "Тема",
"setting.draggable.scoreboard.scoreboard_color_mode.option.Custom": "Кастом",
"setting.draggable.scoreboard.scoreboard_bg_effect": "Эффект фона",
"setting.draggable.scoreboard.scoreboard_bg_effect.option.Auto": "Авто",
"setting.draggable.scoreboard.scoreboard_bg_effect.option.None": "None",
"setting.draggable.scoreboard.scoreboard_bg_effect.option.Blur": "Blur",
"setting.draggable.scoreboard.scoreboard_bg_effect.option.Glass": "Glass",
@ -1608,6 +1609,15 @@
"clickgui.hints.settings_panel.hide": "Alt+H - скрыть подсказки",
"setting.main_config.clickGuiModulesHints": "Подсказки ClickGUI",
"setting.main_config.clickGuiHudEditorHints": "Подсказки HUD-редактора",
"setting.style.surfaceStyle": "Стиль подложки",
"setting.style.surfaceStyle.option.glass": "Стекло",
"setting.style.surfaceStyle.option.blur": "Блюр",
"setting.style.surfaceStyle.option.flat": "Матовый",
"setting.style.surfaceStyle.option.outline": "Контур",
"setting.style.surfaceStyle.option.none": "Нет",
"setting.style.switchMs": "Длительность смены стиля",
"setting.style.animateSwitch": "Анимация смены стиля",
"setting.style.cycleStyle": "Бинд смены стиля",
"clickgui.hints.settings.configs.rename": "Клик по имени - переименовать конфиг",
"screen.lovisual.alt_manager.title": "Менеджер аккаунтов",
"screen.lovisual.alt_manager.account_panel": "Менеджер аккаунтов",
@ -1723,6 +1733,7 @@
"setting.draggable.triangulator.triangulator_color_mode.option.Theme": "Тема",
"setting.draggable.triangulator.triangulator_color_mode.option.Custom": "Свой",
"setting.draggable.triangulator.triangulator_bg_effect": "Эффект фона",
"setting.draggable.triangulator.triangulator_bg_effect.option.Auto": "Авто",
"setting.draggable.triangulator.triangulator_bg_effect.option.None": "Нет",
"setting.draggable.triangulator.triangulator_bg_effect.option.Blur": "Блюр",
"setting.draggable.triangulator.triangulator_bg": "Фон",
@ -1926,6 +1937,7 @@
"setting.common.color_mode.option.theme": "Тема",
"setting.common.color_mode.option.custom": "Свой",
"setting.common.bg_effect": "Эффект фона",
"setting.common.bg_effect.option.Auto": "Авто",
"setting.common.bg_effect.option.none": "Нет",
"setting.common.bg_effect.option.blur": "Блюр",
"setting.common.bg_effect.option.glass": "Стекло",
@ -1955,6 +1967,7 @@
"setting.common.admins_bg": "Фон",
"setting.common.admins_bg_alpha": "Альфа фона",
"setting.common.admins_bg_effect": "Эффект фона",
"setting.common.admins_bg_effect.option.Auto": "Авто",
"setting.common.admins_bg_effect.option.blur": "Блюр",
"setting.common.admins_bg_effect.option.none": "Нет",
"setting.common.admins_bg_secondary": "Вторичный фон",
@ -2083,6 +2096,7 @@
"setting.common.cooldowns_bg": "Фон",
"setting.common.cooldowns_bg_alpha": "Альфа фона",
"setting.common.cooldowns_bg_effect": "Эффект фона",
"setting.common.cooldowns_bg_effect.option.Auto": "Авто",
"setting.common.cooldowns_bg_effect.option.blur": "Блюр",
"setting.common.cooldowns_bg_effect.option.none": "Нет",
"setting.common.cooldowns_bg_secondary": "Вторичный фон",
@ -2318,6 +2332,7 @@
"setting.common.inventory_bg": "Фон",
"setting.common.inventory_bg_alpha": "Альфа фона",
"setting.common.inventory_bg_effect": "Эффект фона",
"setting.common.inventory_bg_effect.option.Auto": "Авто",
"setting.common.inventory_bg_effect.option.blur": "Блюр",
"setting.common.inventory_bg_effect.option.none": "Нет",
"setting.common.inventory_bg_secondary": "Вторичный фон",
@ -2349,6 +2364,7 @@
"setting.common.keybinds_bg": "Фон",
"setting.common.keybinds_bg_alpha": "Альфа фона",
"setting.common.keybinds_bg_effect": "Эффект фона",
"setting.common.keybinds_bg_effect.option.Auto": "Авто",
"setting.common.keybinds_bg_effect.option.blur": "Блюр",
"setting.common.keybinds_bg_effect.option.none": "Нет",
"setting.common.keybinds_bg_secondary": "Вторичный фон",
@ -2418,6 +2434,7 @@
"setting.common.media_player_bg": "Фон",
"setting.common.media_player_bg_alpha": "Альфа фона",
"setting.common.media_player_bg_effect": "Эффект фона",
"setting.common.media_player_bg_effect.option.Auto": "Авто",
"setting.common.media_player_bg_effect.option.blur": "Блюр",
"setting.common.media_player_bg_effect.option.glass": "Стекло",
"setting.common.media_player_bg_effect.option.none": "Нет",
@ -2484,6 +2501,7 @@
"setting.common.module_list_bg": "Фон",
"setting.common.module_list_bg_alpha": "Альфа фона",
"setting.common.module_list_bg_effect": "Эффект фона",
"setting.common.module_list_bg_effect.option.Auto": "Авто",
"setting.common.module_list_bg_effect.option.blur": "Блюр",
"setting.common.module_list_bg_effect.option.glass": "Стекло",
"setting.common.module_list_bg_effect.option.none": "Нет",
@ -2564,6 +2582,7 @@
"setting.common.potions_bg": "Фон",
"setting.common.potions_bg_alpha": "Альфа фона",
"setting.common.potions_bg_effect": "Эффект фона",
"setting.common.potions_bg_effect.option.Auto": "Авто",
"setting.common.potions_bg_effect.option.blur": "Блюр",
"setting.common.potions_bg_effect.option.none": "Нет",
"setting.common.potions_bg_secondary": "Вторичный фон",
@ -2783,6 +2802,7 @@
"setting.common.target_bg": "Фон",
"setting.common.target_bg_alpha": "Альфа фона",
"setting.common.target_bg_effect": "Эффект фона",
"setting.common.target_bg_effect.option.Auto": "Авто",
"setting.common.target_bg_effect.option.blur": "Блюр",
"setting.common.target_bg_effect.option.glass": "Стекло",
"setting.common.target_bg_effect.option.none": "Нет",
@ -2851,6 +2871,7 @@
"setting.common.tooltip_alpha": "Альфа",
"setting.common.tooltip_bg_alpha": "Альфа фона",
"setting.common.tooltip_bg_effect": "Эффект фона",
"setting.common.tooltip_bg_effect.option.Auto": "Авто",
"setting.common.tooltip_bg_effect.option.blur": "Блюр",
"setting.common.tooltip_bg_effect.option.none": "Нет",
"setting.common.tooltip_bg_gradient": "Градиент фона",
@ -3133,6 +3154,12 @@
"setting.chinahat.head_top_offset": "Высота на голове",
"setting.chinahat.head_forward_offset": "Смещение вперёд",
"setting.chinahat.head_right_offset": "Смещение вправо",
"module.optimize.name": "Оптимизация",
"module.optimize.description": "Ручной рубильник FPS: пока включён — без стекла/blur, с лёгкими пост-проходами, без шумных процедурных слоёв неба и без покадровых анимаций HUD.",
"setting.optimize.no_glass": "Без стекла/blur",
"setting.optimize.lite_post": "Лёгкий пост-процесс",
"setting.optimize.lite_sky": "Простое небо",
"setting.optimize.lean_hud": "Лёгкий HUD",
"module.fpsoptimizer.name": "Оптимизация FPS",
"module.fpsoptimizer.description": "Ручные тумблеры для снижения нагрузки рендера: ванильные частицы, фоновый шейдер меню, стекло/блюр, блум/свечение, отсечение сущностей за экраном.",
"setting.fpsoptimizer.disable_particles": "Отключить частицы",

View file

@ -273,9 +273,18 @@ void main() {
vec2 nebulaUvB = rot2(0.74) * flow * 0.58 + vec2(-t * 0.21, t * 0.33);
vec2 auroraUv = vec2(flow.x * 0.42 + sin(flow.y * 0.23 + t * 0.36) * 0.85 + t * 0.20,
rayW.y * 2.25 + sin(flow.x * 0.18 - t * 0.28) * 0.34);
float proceduralNebula = skyFbmScalar2(nebulaUvA) * 0.62 + skyFbmScalar2(nebulaUvB + 4.7) * 0.38;
float proceduralVeil = smoothstep(0.46, 0.86, skyFbmScalar2(auroraUv * 1.15 + 8.3));
float proceduralCurtain = smoothstep(0.16, 0.86, sin(auroraUv.x * 2.8 + skyFbmScalar2(auroraUv * 0.85) * 5.4) * 0.5 + 0.5);
float proceduralNebula = 0.0;
float proceduralVeil = 0.0;
float proceduralCurtain = 0.0;
// Noise detail is only consumed by the fbm-backed layers; Optimize.lite_sky clears their
// bits, so skip the four unconditional fbm evals (12 value-noise samples per pixel).
if (layerNebula > 0.5 || layerDetailCurtains > 0.5 || layerPolarArc > 0.5
|| layerWaterVeil > 0.5 || layerCaustics > 0.5 || layerRefractedAurora > 0.5
|| layerDetailStars > 0.5) {
proceduralNebula = skyFbmScalar2(nebulaUvA) * 0.62 + skyFbmScalar2(nebulaUvB + 4.7) * 0.38;
proceduralVeil = smoothstep(0.46, 0.86, skyFbmScalar2(auroraUv * 1.15 + 8.3));
proceduralCurtain = smoothstep(0.16, 0.86, sin(auroraUv.x * 2.8 + skyFbmScalar2(auroraUv * 0.85) * 5.4) * 0.5 + 0.5);
}
float proceduralStarDust = 0.0;
vec3 detailRaw = vec3(
proceduralVeil * proceduralCurtain * 0.72 + proceduralNebula * 0.12,
@ -379,39 +388,44 @@ void main() {
float largeTwinkle = starTwinkleByStrength(sin(largeTwinklePhase) * 0.5 + 0.5, 0.48, 1.43);
float largeStars = (largeDot * 0.86 + largeHalo * 0.20 + largeCross * 0.18) * largeSelect * starMask * largeTwinkle;
vec2 burstUv = rayW.xz / max(rayW.y + 1.05, 0.20);
burstUv += vec2(rawTime * 0.0018, -rawTime * 0.0011);
vec2 burstGrid = burstUv * 4.8;
vec2 burstCell = floor(burstGrid);
vec2 burstLocal = fract(burstGrid) - 0.5;
float burstSeed = hash21(burstCell + 31.6);
vec2 burstOffset = vec2(hash21(burstCell + 12.4), hash21(burstCell + 88.9)) - 0.5;
vec2 burstVec = burstLocal - burstOffset * 0.66;
float burstDist = length(burstVec);
float burstAngle = atan(burstVec.y, burstVec.x);
float burstPhase = fract(rawTime * 0.030 + burstSeed);
float burstGate = smoothstep(0.885, 0.970, burstSeed);
float burstLife = smoothstep(0.010, 0.060, burstPhase) * (1.0 - smoothstep(0.245, 0.390, burstPhase));
float burstEase = burstPhase * burstPhase * (3.0 - 2.0 * burstPhase);
float burstRadius = 0.030 + burstEase * 0.42;
float burstRing = 1.0 - smoothstep(0.010, 0.046, abs(burstDist - burstRadius));
float burstInnerRing = 1.0 - smoothstep(0.010, 0.040, abs(burstDist - burstRadius * 0.55));
float burstHalo = (1.0 - smoothstep(0.020, burstRadius * 1.42 + 0.06, burstDist)) * 0.38;
float burstCore = 1.0 - smoothstep(0.000, 0.034, burstDist);
float burstPetal = 0.5 + 0.5 * sin(burstAngle * 6.0 + burstDist * 16.0 - burstPhase * 10.0 + burstSeed * 6.2831);
burstPetal = smoothstep(0.54, 0.94, burstPetal);
float burstRay = 0.5 + 0.5 * sin(burstAngle * 11.0 - burstDist * 9.0 + burstSeed * 9.17);
burstRay = smoothstep(0.66, 0.98, burstRay) * (1.0 - smoothstep(0.06, 0.34, burstDist));
vec2 sparkGrid = burstVec * 12.0 + vec2(0.5);
vec2 sparkCell = floor(sparkGrid);
vec2 sparkLocal = fract(sparkGrid) - 0.5;
float sparkSeed = hash21(sparkCell + burstCell * 3.1);
float sparkDist = length(sparkLocal - (vec2(hash21(sparkCell + 3.4), hash21(sparkCell + 18.6)) - 0.5) * 0.55);
float sparkShell = 1.0 - smoothstep(0.055, 0.180, abs(length((sparkCell + 0.5) / 12.0) - burstRadius * 0.86));
float burstSpark = (1.0 - smoothstep(0.010, 0.044, sparkDist)) * smoothstep(0.74, 0.96, sparkSeed) * sparkShell;
float burstMask = smoothstep(-0.05, 0.50, rayW.y) * (1.0 - horizon * 0.40);
float burst = (burstRing * (0.62 + burstPetal * 0.42) + burstInnerRing * 0.32 + burstHalo + burstCore * 0.28 + burstRay * 0.24 + burstSpark * 0.42)
* burstLife * burstGate * burstMask * layerBursts;
// Burst sparkles are pure ALU and only feed `burst`; skip the whole block when off
// (Optimize.lite_sky clears this bit too).
float burst = 0.0;
if (layerBursts > 0.5) {
vec2 burstUv = rayW.xz / max(rayW.y + 1.05, 0.20);
burstUv += vec2(rawTime * 0.0018, -rawTime * 0.0011);
vec2 burstGrid = burstUv * 4.8;
vec2 burstCell = floor(burstGrid);
vec2 burstLocal = fract(burstGrid) - 0.5;
float burstSeed = hash21(burstCell + 31.6);
vec2 burstOffset = vec2(hash21(burstCell + 12.4), hash21(burstCell + 88.9)) - 0.5;
vec2 burstVec = burstLocal - burstOffset * 0.66;
float burstDist = length(burstVec);
float burstAngle = atan(burstVec.y, burstVec.x);
float burstPhase = fract(rawTime * 0.030 + burstSeed);
float burstGate = smoothstep(0.885, 0.970, burstSeed);
float burstLife = smoothstep(0.010, 0.060, burstPhase) * (1.0 - smoothstep(0.245, 0.390, burstPhase));
float burstEase = burstPhase * burstPhase * (3.0 - 2.0 * burstPhase);
float burstRadius = 0.030 + burstEase * 0.42;
float burstRing = 1.0 - smoothstep(0.010, 0.046, abs(burstDist - burstRadius));
float burstInnerRing = 1.0 - smoothstep(0.010, 0.040, abs(burstDist - burstRadius * 0.55));
float burstHalo = (1.0 - smoothstep(0.020, burstRadius * 1.42 + 0.06, burstDist)) * 0.38;
float burstCore = 1.0 - smoothstep(0.000, 0.034, burstDist);
float burstPetal = 0.5 + 0.5 * sin(burstAngle * 6.0 + burstDist * 16.0 - burstPhase * 10.0 + burstSeed * 6.2831);
burstPetal = smoothstep(0.54, 0.94, burstPetal);
float burstRay = 0.5 + 0.5 * sin(burstAngle * 11.0 - burstDist * 9.0 + burstSeed * 9.17);
burstRay = smoothstep(0.66, 0.98, burstRay) * (1.0 - smoothstep(0.06, 0.34, burstDist));
vec2 sparkGrid = burstVec * 12.0 + vec2(0.5);
vec2 sparkCell = floor(sparkGrid);
vec2 sparkLocal = fract(sparkGrid) - 0.5;
float sparkSeed = hash21(sparkCell + burstCell * 3.1);
float sparkDist = length(sparkLocal - (vec2(hash21(sparkCell + 3.4), hash21(sparkCell + 18.6)) - 0.5) * 0.55);
float sparkShell = 1.0 - smoothstep(0.055, 0.180, abs(length((sparkCell + 0.5) / 12.0) - burstRadius * 0.86));
float burstSpark = (1.0 - smoothstep(0.010, 0.044, sparkDist)) * smoothstep(0.74, 0.96, sparkSeed) * sparkShell;
float burstMask = smoothstep(-0.05, 0.50, rayW.y) * (1.0 - horizon * 0.40);
burst = (burstRing * (0.62 + burstPetal * 0.42) + burstInnerRing * 0.32 + burstHalo + burstCore * 0.28 + burstRay * 0.24 + burstSpark * 0.42)
* burstLife * burstGate * burstMask * layerBursts;
}
float detailDome = smoothstep(-0.18, 0.76, rayW.y) * (1.0 - horizon * 0.62);
float detailNebula = smoothstep(0.055, 0.42, detailWideLum) * detailDome * layerNebula;

View file

@ -58,6 +58,10 @@ float fbm(vec3 p) {
float a = 0.5;
vec3 shift = vec3(100.0);
for (int i = 0; i < 4; ++i) {
// u_Thunder.w = Optimize.lite_sky: 2 octaves instead of 4 (half the noise samples).
if (i >= 2 && u_Thunder.w > 0.5) {
break;
}
v += a * noise(p);
p = p * 2.0 + shift;
a *= 0.5;

View file

@ -58,6 +58,10 @@ float fbm(vec3 p) {
float a = 0.5;
vec3 shift = vec3(100.0);
for (int i = 0; i < 4; ++i) {
// u_Thunder.w = Optimize.lite_sky: 2 octaves instead of 4 (half the noise samples).
if (i >= 2 && u_Thunder.w > 0.5) {
break;
}
v += a * noise(p);
p = p * 2.0 + shift;
a *= 0.5;

View file

@ -0,0 +1,43 @@
package dev.loki.lovisual.features.module.modules.misc.optimize;
import dev.loki.lovisual.render.engine.optimize.OptimizeState;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public final class OptimizeTest {
@Test
void stateIsCleanUntilApplied() {
OptimizeState.reset();
assertFalse(OptimizeState.isNoGlass());
assertFalse(OptimizeState.isLitePost());
assertFalse(OptimizeState.isLiteSky());
assertFalse(OptimizeState.isLeanHud());
}
@Test
void applyTracksEachKnobIndependently() {
OptimizeState.apply(true, false, true, false);
assertTrue(OptimizeState.isNoGlass());
assertFalse(OptimizeState.isLitePost());
assertTrue(OptimizeState.isLiteSky());
assertFalse(OptimizeState.isLeanHud());
OptimizeState.reset();
assertFalse(OptimizeState.isNoGlass());
assertFalse(OptimizeState.isLiteSky());
}
@Test
void summaryListsOnlyActiveKnobsInOrder() {
assertEquals("no knobs active", Optimize.summaryOf(false, false, false, false));
assertEquals("no glass, light post", Optimize.summaryOf(true, true, false, false));
assertEquals("simple sky, lean HUD", Optimize.summaryOf(false, false, true, true));
assertEquals(
"no glass, light post, simple sky, lean HUD",
Optimize.summaryOf(true, true, true, true));
}
}

View file

@ -0,0 +1,19 @@
package dev.loki.lovisual.render.sky;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public final class SkyboxShaderPassesTest {
@Test
void liteMaskKeepsOnlyBaseLayersAndStarGrids() {
int mask = SkyboxShaderPasses.LITE_SKY_LAYER_MASK;
for (int bit : new int[] {0, 1, 2, 3, 12, 13, 14, 15}) {
assertEquals(1, (mask >> bit) & 1, "kept bit " + bit);
}
for (int bit : new int[] {4, 5, 6, 7, 8, 9, 10, 11, 16}) {
assertEquals(0, (mask >> bit) & 1, "cleared noise bit " + bit);
}
}
}