diff --git a/docs/research/deepdives/r13-dynamic-lighting.md b/docs/research/deepdives/r13-dynamic-lighting.md index 91067d1..b1321a5 100644 --- a/docs/research/deepdives/r13-dynamic-lighting.md +++ b/docs/research/deepdives/r13-dynamic-lighting.md @@ -46,7 +46,7 @@ public partial class LightInfo : IDatObjType { - **Practical consequence.** For indoor cells, retail sets directional sun to zero (the cell is windowless) and relies on the baked vertex colours for the ambient "floor". Any `LightInfo` inside the cell is additive. - **No cell has a separate ambient RGB field.** The only global ambient is `SkyTimeOfDay.AmbColor` / `AmbBright`, which is only applied outdoors. -- **acdream action.** We need a `CellAmbientState` that holds the current `AmbColor * AmbBright` (outdoors, driven by sky dat) or a fixed dark RGB like `(0.10, 0.09, 0.08)` (indoors, approximating the dungeon "deep" tone) — then add active lights on top. See §12 for the C# class. +- **acdream action.** We need a `CellAmbientState` that holds the current `AmbColor * AmbBright` (outdoors, driven by sky dat) or **a flat `(0.20, 0.20, 0.20)` neutral** (indoors) — then add active lights on top. The indoor constant is taken **directly from retail**: `CellManager::ChangePosition` (0x004559B0) calls `SmartBox::SetWorldAmbientLight(0.2f, 0xFFFFFFFF)` whenever `CObjCell::seen_outside == 0`. The early-2026 guess at `(0.10, 0.09, 0.08)` was eyeballed; the retail value is both brighter and neutral. See §12 for the C# class. ## 4. Torch lights and `WeenieType.LightSource` diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index ff777f8..6f87a61 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -8319,7 +8319,13 @@ public sealed class GameWindow : IDisposable /// Derive the current sun (directional light, slot 0 of the UBO) /// from the interpolated , /// plus the cell ambient. Indoor cells force the sun intensity to - /// zero (r13 §13.7) and substitute a fixed dungeon-tone ambient. + /// zero and substitute a flat 0.2 white ambient — exact retail + /// behavior per CellManager::ChangePosition @ 0x004559B0, + /// which calls SmartBox::SetWorldAmbientLight(0.2f, 0xFFFFFFFF) + /// when the player's CObjCell::seen_outside flag is 0. + /// Indoor brightness then comes from per-cell point lights + /// (Setup.Lights on the cell's static objects, registered through + /// ). /// private void UpdateSunFromSky(AcDream.Core.World.SkyKeyframe kf, bool cameraInsideCell) { @@ -8330,7 +8336,8 @@ public sealed class GameWindow : IDisposable if (cameraInsideCell) { - // Dungeon default per r13 §3 — warm-dark ambient, no sun. + // Indoor default — retail's flat 0.2 neutral ambient, sun + // zeroed. See xref to retail decomp in the doc comment above. Lighting.Sun = new AcDream.Core.Lighting.LightSource { Kind = AcDream.Core.Lighting.LightKind.Directional, @@ -8340,7 +8347,7 @@ public sealed class GameWindow : IDisposable Range = 1f, }; Lighting.CurrentAmbient = new AcDream.Core.Lighting.CellAmbientState( - AmbientColor: new System.Numerics.Vector3(0.10f, 0.09f, 0.08f), + AmbientColor: new System.Numerics.Vector3(0.20f, 0.20f, 0.20f), SunColor: System.Numerics.Vector3.Zero, SunDirection: sunToWorld); }