The Holtburg meeting-hall facade washed out warm/bright vs retail. The round-1 checkpoint blamed torch REACH (acdream Falloff 6×1.3=7.8m vs a supposed retail Falloff 4). That theory is WRONG, and this commit fixes the real cause. Empirical (HoltburgTorchFalloffProbeTests, headless dat dump via the production LightInfoLoader): the orange entrance torch (setup 0x020005D8) is raw dat Falloff 6 and acdream reads it FAITHFULLY — there is no Falloff-4 torch anywhere in Holtburg. Both clients read the same dat float, so reach was never inflated. Decomp (read verbatim + corroborated by an independent adversarial workflow): retail's per-object torch binder minimize_object_lighting (0x0054d480) is gated in RenderDeviceD3D::DrawMeshInternal (0x0059f398) by `if (Render::useSunlight == 0)`. The outdoor landscape stage runs useSunlightSet(1) (PView::DrawCells 0x005a485a, before LScape::draw), so the building EXTERIOR shell — drawn via DrawBlock→DrawSortCell→DrawBuilding→CPhysicsPart::Draw→DrawMeshInternal — is lit by SUN + ambient ONLY; torches are SKIPPED. The static bake (SetStaticLightingVertexColors 0x0059cfe0) is EnvCell-only. So retail NEVER torch-lights outdoor objects. This exactly explains the isolation test (object point lights OFF → building matches retail). Fix: WbDrawDispatcher.ComputeEntityLightSet gates per-object torch selection on the object being INDOOR (ParentCellId is an EnvCell, (id&0xFFFF)>=0x0100) via the pure predicate IndoorObjectReceivesTorches. Outdoor objects (building shells with null ParentCellId, outdoor scenery, outdoor creatures) keep the all-(-1) light set ⇒ sun + ambient only = retail. The indoor "no sun" half is already handled by the global sun-kill when the player is inside a cell (UpdateSunFromSky). No dungeon regression: EnvCell statics get ParentCellId set (keep torches). Divergence register: AP-37 (residual: acdream keys sun/torch on the object's own cell + a per-frame player-inside sun-kill, vs retail's per-draw-stage useSunlight; only matters for through-doorway look-ins). The round-1 CHECKPOINT got a RESOLVED banner correcting the reach theory. Tests: WbDrawDispatcherTorchGateTests (7), HoltburgTorchFalloffProbeTests (dat dump). App 280/1skip, Core 1486/2skip green. Held at the visual gate — not merged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
42 lines
1.7 KiB
C#
42 lines
1.7 KiB
C#
using AcDream.App.Rendering.Wb;
|
|
using Xunit;
|
|
|
|
namespace AcDream.App.Tests.Rendering.Wb;
|
|
|
|
/// <summary>
|
|
/// A7 Fix D round 2 — pins retail's <c>useSunlight</c> gate for per-object torch
|
|
/// lighting (<c>WbDrawDispatcher.IndoorObjectReceivesTorches</c>). Retail enables
|
|
/// the static wall-torches on an object ONLY in the indoor stage
|
|
/// (<c>DrawMeshInternal</c> 0x0059f398: <c>if (useSunlight == 0) minimize_object_lighting()</c>),
|
|
/// so OUTDOOR objects — building exterior shells (null ParentCellId) and outdoor
|
|
/// scenery (land sub-cell 0x0001..0x00FF) — get the sun, never torches. Only
|
|
/// EnvCell-parented (indoor, low word >= 0x0100) objects receive torches.
|
|
/// </summary>
|
|
public sealed class WbDrawDispatcherTorchGateTests
|
|
{
|
|
[Fact]
|
|
public void BuildingShell_NullParent_IsOutdoor_NoTorches()
|
|
{
|
|
// Building exterior shells are top-level landblock stabs with no
|
|
// ParentCellId (LandblockLoader sets BuildingShellAnchorCellId, not Parent).
|
|
Assert.False(WbDrawDispatcher.IndoorObjectReceivesTorches(null));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0xA9B4_0001u)] // outdoor land sub-cell
|
|
[InlineData(0xA9B4_0020u)] // outdoor land sub-cell
|
|
[InlineData(0xA9B4_0040u)] // last outdoor land sub-cell (0x40)
|
|
public void OutdoorLandCell_NoTorches(uint parentCellId)
|
|
{
|
|
Assert.False(WbDrawDispatcher.IndoorObjectReceivesTorches(parentCellId));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0xA9B4_0100u)] // first EnvCell
|
|
[InlineData(0xA9B4_0164u)] // interior EnvCell
|
|
[InlineData(0x0007_0143u)] // dungeon EnvCell
|
|
public void IndoorEnvCell_GetsTorches(uint parentCellId)
|
|
{
|
|
Assert.True(WbDrawDispatcher.IndoorObjectReceivesTorches(parentCellId));
|
|
}
|
|
}
|