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

@ -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();