fix(rendering): carry retail SetSurface state to detail draws
Resolve exact SetSurface blend, alpha-test, and fog state once during extraction and preserve it through recipe-10 prepared payloads, Wb/EnvCell command data, Vulkan pipelines, push constants, and both ordinary/atmospheric one-pass shaders. Preserve AP-240 Wb pure-Clip immediate opaque/A2C while EnvCell uses retail premultiplied Clip; detail-off routing remains unchanged. Correct AP-232 and register the remaining detail-off state divergence. Mutation first failures (all restored): - raw Add->SRCALPHA/ONE: WalkStaticStreamPopulatorTests.ImmediateBuildingDetail_UsesExactResolvedSetSurfaceState line 1278, expected wb-mesh-raw-additive-1x. - inverse-add->alpha-add: same test line 1278, expected wb-mesh-inverse-additive-1x. - remove Env inverse: EnvCellAlphaDrawSourceTests.DetailOn_EveryEnvCellFamilyDrawsOnceInPlaceWithAuthoredOpacity line 132, expected envcell-inverse. - raw IsAdditive precedence: same test line 132, Translucent|Clip|Additive expected envcell-alpha. - Wb paletted ParamB=0: OrderPreservingSubmitterTests line 333, expected 0.392156869. - Wb DDS ParamB=0.05: same test line 333, expected 0.784313738. - disable Alpha+Clip test: WalkStaticStreamPopulatorTests line 1286, expected 0.784313738. - always fog raw Add: same test line 1287, expected no-fog true. - disable fog non-Add: same test line 1287, expected no-fog false. - X=a*qA: RetailDetailTextureContractTests line 261, shared squared-alpha substring absent. - X includes base alpha: same test line 262, forbidden baseTexel.a present. - CLIP uses 0.05: EnvCellAlphaDrawSourceTests.ClipShaders_UseGreaterEqualForThePerRangeReference line 367. - second detail draw: EnvCell detail-on line 131, collection contained 2 draws. - straight-alpha substitute: Wb immediate line 1278, expected wb-mesh-additive-1x. - omit ordered detail arm: OrderPreservingSubmitterTests line 318, expected (77,3.5), got (0,0). - omit atmospheric combine: RetailDetailTextureContractTests line 260, shared include absent. - drop serialized opacity: ObjectMeshDataSerializerTests line 292, expected opacity bits, got 1.0. - stale detail arm: atmospheric adjacency line 402, expected slot 0, got 77. - per-frame surface map: EnvCell warmed allocation line 285, expected 0 B, got 204800 B.
This commit is contained in:
parent
75664805f8
commit
15ed57a1e7
44 changed files with 1154 additions and 187 deletions
|
|
@ -259,8 +259,22 @@ heading/velocity/parent state, arms no teleport hook, and still acknowledges
|
|||
immediately. The long AP-148 row below is retained only as historical filing
|
||||
research and is no longer active.
|
||||
|
||||
**S5-c4 fix-round-1 AP-232 correction (2026-09-05):** AP-244 below raises
|
||||
the active total to **161**; the historical heading's 160 is superseded.
|
||||
AP-232's retirement remains valid for the old two-draw/detail-weight
|
||||
deviation, with this corrected scope: recipe 10 carries extraction-resolved
|
||||
SetSurface blend, alpha-test/reference, and fog state through both real command
|
||||
owners. Detail-active Wb and EnvCell select raw Additive, Alpha+Additive,
|
||||
inverse, inverse-additive, combined/pure ClipMap, late Translucent override,
|
||||
final-X reference, and raw-Additive fog-disable state exactly. Wb pure Clip
|
||||
retains AP-240's immediate opaque/A2C pipeline while gaining final-X ParamB;
|
||||
only EnvCell pure Clip uses `ONE/INVSRCALPHA`. The retired row's recipe-9-only
|
||||
and `None` residual wording is superseded by this correction and AP-244;
|
||||
AP-238/AP-239/AP-240 remain separate queue/token/raw-mask/placement residuals.
|
||||
|
||||
| # | Divergence | Where (file:line) | Why it is safe / justified | Risk if assumption breaks | Retail oracle |
|
||||
|---|---|---|---|---|---|
|
||||
| AP-244 | **Filed 2026-09-05 at Campaign OVERHAUL S5-c4 fix round 1.** The new exact resolved SetSurface state is deliberately selected only when a Wb/EnvCell command has active building detail, preserving §23's bounded detail-off behavior. With detail off, Wb still collapses raw Additive and InvAlpha+Additive through `TranslucencyKind.Additive` to `SRCALPHA,ONE`; EnvCell additionally selects raw `IsAdditive` before the late `Translucent\|ClipMap` override and has no detail-off inverse pipeline. Both shader families retain the existing non-detail 0.05 discard rather than every combined ClipMap's palette/DDS reference, and fixed-function fog remains enabled for raw-Additive detail-off rows. AP-240 separately covers Wb pure-Clip placement/A2C. | `src/AcDream.App/Rendering/Wb/WbDrawDispatcher.Rhi.cs` (`PipelineForBlend`, detail gates); `src/AcDream.App/Rendering/Wb/EnvCellRenderer.cs` (`ResolveBatchGroupIndex`); `src/AcDream.App/Rendering/Wb/EnvCellRenderer.Rhi.cs` (detail-active exact selection versus retained range buckets); `src/AcDream.App/Rendering/Shaders/mesh_modern.frag`; `src/AcDream.App/Rendering/Shaders/mesh_atmospheric.frag` | Fix round 1 was expressly bounded to detail-active one-pass material truth. The immutable state is already present end-to-end, so a later dedicated detail-off correction can select it without DAT lookup or new ownership, but must re-gate FIFO/routing/order and visual behavior together. | Detail-off raw Additive/inverse-additive brightness, inverse EnvCell compositing, combined ClipMap cutout threshold, late Translucent override, and raw-Additive fog can differ from retail. | `D3DPolyRender::SetSurface @0x0059C4D0` lines 425083–425303; Campaign OVERHAUL S5-c4 §23.2 |
|
||||
| AP-235 | **Filed 2026-08-25 at the Campaign CT4 fix round.** Retail resolves gender display text via `AppraisalSystem::InqGenderDisplayName @0x005b47c0` and heritage via `InqHeritageGroupDisplayName @0x005b4710`, both through the static `EnumMapper::GetString(uint32_t enumValue, uint32_t queryId, PStringBase<char>*) @0x0041ac40` overload — `DBObj::GetDIDByEnum(&did, enumValue, 1)` (master map `0x25000000` → category-1 sub-map `0x25000001` → `ClientEnumToID[0x10000001]`/`[0x10000002]` → EnumMapper DIDs `0x2200000A`/`0x2200000B`) — reading each id's `IdToStringMap` entry live, with heritage ids 2/5/0xd hardcoded to `"Gharu'ndim"`/`"Umbraen"`/`"Olthoi"` in place of the raw internal names `"Gharundim"`/`"Shadowbound"`/`"OlthoiAcid"`. `CharacterIdentityText.GenderDisplayName`/`HeritageGroupDisplayName` are hardcoded C# `switch` tables instead — a mechanism divergence (compile-time constant vs. live DAT read), not a content one: `CharacterPanelLiveDatTests.GenderHeritageDisplayNameTables_MatchTheRetailEnumMapperChain` (filed the same round) walks the live EnumMapper chain and asserts every table entry byte-exact, including the two entries (10 "Penumbraen", 12 "Olthoi") the CT4 review had flagged as unverified guesses — both are correct. | `src/AcDream.App/UI/Layout/CharacterIdentityText.cs` (`GenderDisplayName`, `HeritageGroupDisplayName`); `src/AcDream.App/UI/Layout/RetailAppraisalNameResolver.cs` (`ResolveHeritage` — CT5 fix round 2026-08-25 deleted its independent re-implementation of the same 2/5/13 overrides; it now delegates straight to `CharacterIdentityText.HeritageGroupDisplayName`, so this row's divergence has exactly ONE owner, not two) | `RetailDataIdResolver.Resolve` (`src/AcDream.Content/RetailDataIdResolver.cs`) already ports the generic two-level `GetDIDByEnum` chain (used today for layout/material DIDs); unifying gender/heritage onto it needs only `Resolve(dats, enumValue: 0x10000001u/0x10000002u, enumCategory: 1u)` plus an `EnumMapper.IdToStringMap` read — a live-DAT-only path with no bespoke traversal code to write, which is why the tables stayed hardcoded this round rather than porting live-read on the spot; CT5 is the natural landing slot since it already owns this same DAT-lookup family for the Titles page | A future DAT/game update that renames or reorders a heritage/gender enum entry would silently desync acdream's hardcoded tables from retail's live text with no build-time or runtime signal — the CT5 fix round retired the second-copy drift risk (`ResolveHeritage` now reads the same single table), but the core hardcoded-vs-live-DAT divergence itself remains open | `AppraisalSystem::InqGenderDisplayName @ 0x005B47C0`; `InqHeritageGroupDisplayName @ 0x005B4710`; `EnumMapper::GetString @ 0x0041AC40`; `DBObj::GetDIDByEnum @ 0x004153A0` |
|
||||
| AP-233 | **Filed 2026-08-23 at the Holtburg windmill fix (row owed since the R1-P5 sequencer cutover).** `AnimationSequencer.BuildBlendedFrame` blends each part between `floor(FrameNumber)` and the next frame in the playback direction using the retail slerp (`SlerpRetailClient`). Retail never blends animation frames: `CPartArray::UpdateParts` applies `CSequence::get_curr_animframe` = `get_part_frame(floor(frame_number))`, holding every authored 30 fps frame for its whole interval. Since 2026-08-23 the blend holds the boundary frame at BOTH ends of a node's window — including the cyclic seam — so a cycle's last→first transition is retail's hard cut, not a blend. | `src/AcDream.Core/Physics/AnimationSequencer.cs` (`BuildBlendedFrame`); tests `AnimationSequencerTests.Advance_LinkTailDoesNotBlendIntoLinkFrame0` (#61), `Advance_CyclicSeamHoldsLastFrameInsteadOfBlendingIntoFrame0` (windmill) | The blend only smooths between authored interior frames of one node; at every seam the pose is exactly retail's held frame. Authored cycles that loop by symmetry (the Holtburg windmill's 60-frame quarter turn, `0x0300061B`) or by design read identically at the seam; link tails hold their end pose (#61). The owner chose this over dropping the blend (retail's 30 fps stepping) on 2026-08-23. | Any two adjacent authored frames that are NOT meant to be traversed smoothly (a deliberate authored pop inside a node) would be smoothed where retail pops; none known. A per-frame hitch of one held 33 ms interval at each cycle seam is the price of the cut (1.5° on the windmill). | `CPartArray::UpdateParts @0x005190F0`; `CSequence::get_curr_animframe @0x00524970`; `CSequence::get_curr_frame_number @0x005249D0` |
|
||||
| ~~AP-232~~ | **RETIRED 2026-09-04 at Campaign OVERHAUL S5-c4.** The acdream-only base-plus-detail replay is deleted. `TextureBatchData.SurfaceOpacity` carries exact `1-Surface.Translucency` from `MeshExtractor` through recipe-9 prepared serialization, `ObjectRenderBatch`, and the unchanged 16-byte GPU batch ABI. `mesh_modern` and `mesh_atmospheric` share `retail_detail_material.glsl` and emit one pre-fog fragment per detail-active subset: `w=a*qA`, `C=q*w+(B*D)*(1-w)`, `X=a*qA*qA`, where `a=authoredOpacity*liveFade`; base texture alpha is excluded. The final `X` drives pure CLIP at 100/255 or 200/255 with equality surviving. Classic grouped, walk-ordered (#471), immediate alpha, delayed alpha, and EnvCell paths keep their original draw position and pipeline family; the separate RetailDetail pipelines, replay helpers, shaders, SPIR-V, and manifest entry are gone. | `src/AcDream.Content/MeshExtractor.cs`; `src/AcDream.Content/Pak/ObjectMeshDataSerializer.cs`; `src/AcDream.App/Rendering/Shaders/retail_detail_material.glsl`; `src/AcDream.App/Rendering/Shaders/mesh_modern.frag`; `src/AcDream.App/Rendering/Shaders/mesh_atmospheric.frag`; `src/AcDream.App/Rendering/Wb/WbDrawDispatcher.Rhi.cs`; `src/AcDream.App/Rendering/Wb/EnvCellRenderer.Rhi.cs` | Exact retail single-pass stage arithmetic, authored-alpha provenance, framebuffer-family/CLIP CPU fixtures, shader ABI pins, deterministic recipe-9 round trips and rejection of recipe 8, one-draw command transcripts, shader/SPIR-V validation, and 0-B warmed-path proof. | None for the former weight/draw-count deviation. AP-238/AP-239/AP-240 remain separate queue/token/raw-mask placement residuals and are not changed by this retirement. | `D3DPolyRender::SetSurface @0x0059C4D0`; `RenderMeshSubset @0x0059CA10`; `DrawMesh @0x0059D4A0`; VM2 cdb note `docs/research/2026-08-22-vm2-retail-detail-path-cdb.md`; Campaign OVERHAUL S5-c4 §22 |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue