From 46c5f72a9d8821fe2f58428e0726ecc848eb03dc Mon Sep 17 00:00:00 2001
From: pkuzic
Date: Fri, 25 Sep 2026 04:38:01 +0100
Subject: [PATCH] MONKEY (daylight): city rooms the portal graph connects to
the sky take the interiorDaylight floor; capture knobs + torch/goldshire
scenario; LIGHTING.md
Co-Authored-By: Claude Opus 5.5
---
LIGHTING.md | 5 +
crates/benilla-app/src/capture/scenarios.rs | 5 +
crates/benilla-app/src/dynamic_interior.rs | 19 +++-
crates/benilla-world/src/lighting/daylight.rs | 101 ++++++++++++++++++
.../src/lighting/daylight/census.rs | 12 +++
crates/benilla-world/src/lighting/mod.rs | 2 +
crates/benilla-world/src/static_gx/mod.rs | 3 +
.../src/terrain_stream/spawn/assemble.rs | 6 +-
.../src/terrain_stream/spawn/mod.rs | 12 +++
9 files changed, 163 insertions(+), 2 deletions(-)
diff --git a/LIGHTING.md b/LIGHTING.md
index 2122d3df..39ba5cb4 100644
--- a/LIGHTING.md
+++ b/LIGHTING.md
@@ -20,6 +20,8 @@ behind each constant.
| Synthesised lights | torches, braziers, lanterns, campfires and lampposts emit a light in the colour of their flame, with flicker | `fireLightGain`, `fireFlicker` |
| Torch shadows | cube-map shadows from point lights onto buildings, models and terrain, with a contact-hardening penumbra and a shadow floor | `interiorShadows`, `exteriorShadows`, `torchShadowStrength`, `interiorShadowSoft` |
| Daylight and doorways | calibrated fixtures at doors, windows and open boundaries carry daylight into a room, and doorways between rooms bleed light | `interiorDaylight`, env `WOW_DAYLIGHT`, `WOW_BLEED` |
+| Terrain in torch shadows | the ground casts into an outdoor fire's cube map, so a hill or bank blocks the fire (settled exterior slots only; `torch_terrain.rs` gathers the resident MCNK chunks inside the cube's 48 yd) | `torchTerrainShadows` (default 0, High 1), env `WOW_TORCH_TERRAIN=0\|1` |
+| City day floor | `interiorDaylight`'s room floor also reaches Stormwind/Ironforge rooms that the portal graph connects to the sky (an exterior-facing portal, or one hop from one; `district_sky_rooms` in `daylight.rs`); before this no city room could take it | `interiorDaylight` (default 0, suggested High 0.10) |
| Spell and firework lights | fire, holy and fel effects light their surroundings for their lifetime; frost, nature, arcane and shadow do not | `spellLightGain`, env `WOW_SPELL_LIGHT=0` |
| Moon shadows | at night the same shadow rig re-aims at the moon and casts a faint shadow; dims only the night sky term, never point lights | `moonShadowStrength` |
| Ground-effect spells | Flamestrike, Rain of Fire, Consecration, Flare and fire traps light the ground for their duration; frost and nature areas stay dark | `spellLightGain` |
@@ -47,6 +49,9 @@ is its own module, documented in `WATER.md`.
`character_shadow.rs`, `world_shadow.rs`, `blob_shadow.rs`, `entities/carried_light.rs`,
`entities/spell_fx/lifecycle.rs`, `dynamic_interior.rs`, `debug_panel/lighting_controls.rs`, and
the cvars in `cvars.rs` / `video.rs`.
+- **Census**: `cargo test -p benilla-world --lib lighting::daylight::census -- --ignored --nocapture`
+ (`WOW_CENSUS_WMO`, `WOW_CENSUS_PLACE=map,tx,ty,uid`) prints, per interior room of a city WMO,
+ whether a daylight fixture, a bleed fixture or neither reaches it, and the sky-room count.
- **Tools**: `benilla-extract wmolights [--verts ]`, `wmolamps`, `m2firescan`
print the inputs the system works from (groups, batch classes, portals, claims, flame emitters).
diff --git a/crates/benilla-app/src/capture/scenarios.rs b/crates/benilla-app/src/capture/scenarios.rs
index ff57a2af..84f27f1a 100644
--- a/crates/benilla-app/src/capture/scenarios.rs
+++ b/crates/benilla-app/src/capture/scenarios.rs
@@ -1404,6 +1404,11 @@ pub(super) const ON_DEMAND: &[Scenario] = &[
Scenario {
name: "daylight-if-gate", map: Some(MAP_AZEROTH),
eye: [-4975.0, -895.0, 503.5], look: [-5005.0, -852.0, 506.0], minute: 720, ui: None,
+ }, // Goldshire's lamps at midnight: terrain receiving (and, with `torchTerrainShadows`, casting)
+ // torch cube shadows.
+ Scenario {
+ name: "daylight-torch-goldshire", map: Some(MAP_AZEROTH),
+ eye: [-9460.0, 70.0, 58.0], look: [-9450.0, 20.0, 61.0], minute: 0, ui: None,
},
];
diff --git a/crates/benilla-app/src/dynamic_interior.rs b/crates/benilla-app/src/dynamic_interior.rs
index e34976f6..d8385bce 100644
--- a/crates/benilla-app/src/dynamic_interior.rs
+++ b/crates/benilla-app/src/dynamic_interior.rs
@@ -104,7 +104,9 @@ fn bridge(
// MONKEY (enclosed day floor): the daylight floor rides the same bridge, but is consumed in
// the SHADER (it rides the packed `wmo_fog_params.w` fraction) rather than folded on the
// CPU — the packer's only job is to put it in the lane.
- daylight: video.interior_daylight,
+ // MONKEY (daylight): `WOW_INTERIOR_DAYLIGHT=<0..1>` overrides it in a hermetic capture,
+ // which reads no config.toml (dev builds only; read once).
+ daylight: capture_daylight().unwrap_or(video.interior_daylight),
// MONKEY (bake floor): the bake floor rides the same bridge. Half CPU, half shader: the
// packer folds `interiorGain` in and puts the product in the `sh_c16.w` fraction, and the
// two interior lanes read it from there — so `SetCVar("interiorBakeFloor", 0)` restores
@@ -116,6 +118,21 @@ fn bridge(
}
}
+/// MONKEY (daylight): the capture-only `interiorDaylight` override (see the bridge above).
+fn capture_daylight() -> Option {
+ static V: std::sync::OnceLock