Files
gromandClaude Opus 5 81d96af35d Everwood: the HD/OctoWoW line of benilla, imported onto upstream
This checkout had no git history at all, so this one commit carries the whole
of the Everwood work as a single import on top of chairmanpow/benilla-octo's
`main` (706cd71). The two trees have genuinely diverged — each has files the
other does not — so this is a fork point, not a catch-up.

Today's work, which is the reason a baseline exists at all:

- Booth previews no longer cast world shadows (`NO_BOOTH_SHADOW`). Portrait
  characters were entering the sun's shadow cascades, so every skinned-rig
  shadow specialization compiled live mid-frame; the hitch detector logged
  "main thread blocked 1316 ms" beside a `compiled LIVE` warning. This was
  the Fashion/Tmog stutter.
- Per-pane dress-up: each `DressUpModel` pane assembles and stages its own
  tried-on look instead of every pane mirroring the live player.
- Item template cache is append-only JSONL written on the IO pool, replacing
  an 11.6 MB whole-map JSON rewrite on the main thread every 10 s.
- `WOW_SYSTEM_TIMING` rebuilt per-thread: it took 2 mutexes per system enter
  and 4 per exit, costing 15 ms a frame (590 fps -> 60) and corrupting the
  measurements it was taken to produce.
- The visibility-churn sweep moved to its own `WOW_FLASH_CHURN` switch, so a
  frame-cost reading no longer pays 2.7 ms a frame for it.

Local state (`benilla-config/`, `logs/`, `target/`) is excluded by the
existing .gitignore; the account credential it holds is not in this commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
2026-10-15 15:01:14 -06:00

7.3 KiB

benilla-water

An optional enhanced water renderer for benilla, the Rust + Bevy reimplementation of the 1.12.1 client. It needs no data changes: everything is derived from what a 1.12 install already carries (MCLQ liquid depth and MLIQ opacity bytes, their liquid grids, the Light.dbc water and sky rows, the opaque scene depth).

It is a module on top of the reference water, not a replacement for it. The reference path (Classic) is untouched and stays byte-identical to upstream; the enhanced path only runs when the player picks it, and every part of it can be switched off.

Credits

  • Original project: WarcraftXL — the wxl-experimental-water 3.3.5a client extension.
  • Author: iThorgrim.

The WarcraftXL water module is the design reference for this one, and its author has given permission to reuse its code here on the condition that the author and the original project are named. This section is that attribution; it must travel with the module (this file, and the enhanced_water.wgsl header) wherever the module is copied or shared.

Rule for contributors: a file that ports code or a technique from WarcraftXL says so in its header (Ported from WarcraftXL (https://github.com/WarcraftXL) by iThorgrim — module <module>, <source files>.; blocks inside a file keep their Portions derived from WarcraftXL ... line), the technique is listed in the table below, and the file is listed in THIRD-PARTY.md, the one table of every WarcraftXL-derived file across the fork. Do not remove any of them.

Technique Status here From WarcraftXL
Visual-only wave riding for swimmers (authoritative position never moves) shipped (water_fx/bob.rs) same principle as world/Ride.cpp, implemented independently
Shore surf limited by the TERRAIN column, so objects in the water never foam shipped (authored depth gate, on_bed) principle from sea/Shore.hpp
Per-channel extinction + scene-copy refraction shipped (enhanced_water.wgsl DEPTH LOOK; bent samples landing on anything in front of the water are refused via the scene depth) ported from shaders/Surface.ps.hlsl, render/Refraction.cpp
Caustics, two layers at incommensurate scales/rates shipped (floor web; built from animated cell edges, not value noise) ported from shaders/Surface.ps.hlsl, render/Noise.cpp
Screen-space reflection of the scenery shipped on High (a bisected march against the scene depth, not WXL's single probe) principle from shaders/Surface.ps.hlsl
Gerstner trains + breaker index, crest-fold foam planned sea/Spectrum.*, sea/Shore.hpp, shaders/Wave.hlsli
Specular lobe widened by the normal's screen derivative, distance glints shipped / planned shaders/Surface.ps.hlsl

What it does

Lane What you see Main switch
Quality tiers Classic = the reference water, Enhanced, High (= Enhanced + scenery reflections) Video options → Water Quality, cvar waterQuality, env WOW_WATER=0|1|2
Procedural waves multi-band analytic waves with exact normals; the long swell moves ocean vertices tier
Open-sea whitecaps High adds Gerstner crest gathering and fold-thresholded foam; calm canals remain clear. The fold mask adds the next two wave bands, a slow domain-warped gust field moves the break threshold and calms patches, and ~6 yd segments break each crest into short runs, so the caps do not form a lattice (whitecap_fold, enhanced_water.wgsl) tier
Near mesh refinement High builds a transient 4x liquid lattice within 64 yd, with an 80 yd release ring tier
Ocean / inland profiles the sea and lakes/rivers have their own colour, energy and reflectivity tier
WMO pools exterior canals use a calm drifting profile with outdoor glints; interiors use their authored MOMT colour and room-fog reflection tier
Depth look light fades per channel over the real path through the water; the bed is seen through it, bent by the waves; sunlit shallows carry a caustic web tier
Reflection and glints Fresnel sky reflection from the zone's sky rows, sun path, moon path, point-light glints tier
Beach surf a travelling wave front, a lace of foam that dissolves behind it, a swash sheet on the sand tier
Swimmers wake foam, treading rings and a visual-only bob with the swell tier
Lava glow magma surfaces emit warm point lights through the lighting module Advanced Graphics → Lava Glow, lavaLightGain
Lava HDR magma partially resists distance fog and feeds the screen-space halo Advanced Graphics → Bloom, bloom (Off/Low/High)

Rivers deliberately have NO flow effect: a derived current was tried and removed at the owner's request. If it ever returns it should read the authored MCLQ flow records, not derive one.

Where the code lives

  • Shader: crates/benilla-assets/src/shaders/enhanced_water.wgsl - the whole module on the GPU side, an importable library (benilla::enhanced_water) with its own bindings: 103 scene depth, 104 WaterParams (benilla_assets::WaterUniform), 105 the shared light buffer (a second read-only view of upstream's binding 90), 106 the scene colour (for refraction and reflection). Upstream's liquid.wgsl carries three hooks only: the #import, water_swell in its vertex stage, and the water_active() branch at the top of its fragment stage, which returns the module's result as-is (the module fogs its own surface terms only: the scene it refracts and reflects is already fogged). Keep it that way: new water code goes in the module, not in liquid.wgsl.
  • Assets (crates/benilla-assets/src): water_depth.rs (WaterUniform, the scene-depth image), materials.rs (LiquidExt fields 103-106, shader registration), lib.rs (WaterQuality).
  • World (crates/benilla-world/src): liquid/scene_depth.rs (copies the opaque depth AND colour after the main opaque pass), liquid/waves.rs (the CPU mirror of the vertex swell), liquid/surface.rs (per-kind material parameters and the opt-in WOW_WATER_PROBE WMO classification/depth log), liquid/lod.rs (High-only 4x near-grid swap), water_fx/bob.rs (swimmer bob), lighting/lava_light.rs.
  • App (crates/benilla-app/src): the setting in cvars.rs / video.rs, the options rows in assets/ui/OptionsFrame.xml, the capture scenes water-* and lava-* in capture/scenarios.rs.

Invariants worth knowing before editing

  • Classic must stay byte-identical: capture water-noon with WOW_WATER=0 and compare with the baseline before and after any edit.
  • The CPU swell (liquid/waves.rs) and the shader's WATER_WAVES table are one contract.
  • MLIQ's per-vertex byte is an opacity-ramp coordinate, not water depth; enhanced WMO water uses reconstructed scene depth for its column measurement.
  • Every screen derivative in enhanced_water() is taken at the top of the function (WGSL uniformity); WGSL only fails at pipeline creation, so verify by running a water-* scene.
  • Never rotate a noise domain by a per-pixel angle at world coordinates (~1e4 yd): it shears.
  • The temporary water wind is WATER_WIND_DIR; all wind-aligned shader terms derive from it until the weather lane supplies shared wind.
  • Run one GPU capture at a time, and run cargo test in a shell WITHOUT WOW_DATA exported.