docs(N.3): mark Phase N.3 shipped + commit implementation plan

Roadmap: N.3 row added to shipped table; sub-phase block updated from
ahead-estimate to shipped summary. Document header date bumped.

Plan: docs/superpowers/plans/2026-05-08-phase-n3-texture-decode-via-wb.md
captures the audit + per-format substitution strategy + A8 isAdditive
divergence resolution that drove this phase.

No ISSUES.md update — visual verification at Holtburg is the remaining
gate; if the A8 non-additive change produces a visible delta on entity
textures, an issue gets filed there.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-08 11:37:52 +02:00
parent d467c4cf24
commit 8d166afc62
2 changed files with 736 additions and 8 deletions

View file

@ -1,6 +1,6 @@
# acdream — strategic roadmap
**Status:** Living document. Updated 2026-05-02 for Phase M network-stack conformance planning.
**Status:** Living document. Updated 2026-05-08 for Phase N.3 (texture decode via WB TextureHelpers) shipping.
**Purpose:** One source of truth for where the project is and where it's going. Every observed defect or missing feature has a named phase that owns it; when something looks wrong in-game, look here to find the phase that'll address it. Implementation details live in per-phase specs under `docs/superpowers/specs/`, not in this file.
---
@ -58,6 +58,7 @@
| L.0 | Full retail-style Settings interface — F11 tabbed panel with 6 tabs (Keybinds + Display + Audio + Gameplay + Chat + Character). `settings.json` at `%LOCALAPPDATA%\acdream\`, per-toon `Character` keying (swapped on EnterWorld). Display GL knobs (Resolution / Fullscreen / VSync / FOV / ShowFps) + Audio (Master / SFX) live-wired; Gameplay / Chat / Character settings persist for server-sync wiring later. Tab API extension to `IPanelRenderer`; chat Copy mode (read-only multi-line); per-panel layout reset; FramebufferResize handler keeps GL viewport + camera aspect + panel positions in sync. | Live ✓ |
| C.1 | PES particle system + sky-pass refinements — retail-faithful `ParticleEmitterInfo` unpack with all 13 motion integrators (`Particle::Init`/`Update` ports of `0x0051c290`/`0x0051c930`), `PhysicsScriptRunner` with `CallPES` self-loop semantics, `ParticleHookSink` with `EmitterDied` cleanup, instanced billboard `ParticleRenderer` with material-derived blend (DAT emitters never default additive — pulled from particle GfxObj surface), global back-to-front sort, BC clipmap alpha-keying, AttachLocal `is_parent_local=1` live-parent follow via `UpdateEmitterAnchor`. Sky pass: `Translucent+ClipMap` → alpha-blend cloud sheet (matches `D3DPolyRender::SetSurface` `0x0059c4d0`), raw-`Additive` fog-skip (matches `0x0059c882`), per-keyframe `SkyObjectReplace` Translucency/Luminosity/MaxBright divide-by-100, bit `0x01` pre/post-scene split (matches `GameSky::CreateDeletePhysicsObjects` `0x005073c0`), Setup-backed (`0x020xxxxx`) sky objects via `SetupMesh.Flatten`, persistent GL sampler objects (Wrap + ClampToEdge) replace per-frame wrap-mode mutation (ported from WorldBuilder's `OpenGLGraphicsDevice`), post-scene Z-offset gated on `(Properties & 4) != 0 && (Properties & 8) == 0` per `GameSky::UpdatePosition` `0x00506dd0`. Sky-PES playback disabled by default (named-retail proves `GameSky` drops `pes_id`); `ACDREAM_ENABLE_SKY_PES=1` opens the experimental path. 1325 → 1331 tests. | Live ✓ |
| N.1 | WorldBuilder-backed scenery (Chorizite/WorldBuilder fork as submodule, SceneryHelpers + TerrainUtils replace our inline ports) | Live ✓ |
| N.3 | WorldBuilder-backed texture decode — `SurfaceDecoder` delegates INDEX16 / P8 / A8R8G8B8 / R8G8B8 / A8(+Additive) to `TextureHelpers.Fill*`; `isAdditive` threaded through (terrain alpha → `FillA8Additive`, non-additive entity surfaces → `FillA8`). R5G6B5 + A4R4G4B4 newly handled (previously magenta). X8R8G8B8, DXT1/3/5, SolidColor remain ours (no WB equivalent). 9 conformance tests prove byte-identical equivalence per format. | Tests ✓ |
Plus polish that doesn't get its own phase number:
- FlyCamera default speed lowered + Shift-to-boost
@ -577,13 +578,19 @@ for our deletions/additions; merge upstream `master` periodically.
`SampleNormal` / `SampleSurface` to call WB's `TerrainUtils.GetHeight`
/ `GetNormal` internally. ~1-2 days. Smallest remaining N phase, low
risk after N.1's conformance proof on GetNormal.
- **N.3 — Texture decoding.** Replace our `TextureCache` decode
pipeline (`src/AcDream.App/Rendering/TextureCache.cs`) with WB's
`TextureHelpers` (INDEX16, P8, BGRA, DXT, alpha). Touches every
texture path. **Realistic estimate: 3-5 days** (was 2-3) — the GL
upload path needs adapting and we'll need conformance tests per
texture format. Handoff doc:
`docs/research/2026-05-08-phase-n3-handoff.md`.
- **✓ SHIPPED — N.3 — Texture decoding.** Shipped 2026-05-08. `SurfaceDecoder`
now delegates INDEX16 / P8 / A8R8G8B8 / R8G8B8 / A8 to WB's
`TextureHelpers.Fill*`. The A8 divergence (our old code did R=G=B=A=val
always; WB splits additive vs non-additive) was resolved by threading an
`isAdditive` parameter through `DecodeRenderSurface`: terrain alpha masks
pass `isAdditive: true` (matches our prior behavior, preserves the
shader's `.r` blend-weight read), entity surfaces pass
`surface.Type.HasFlag(SurfaceType.Additive)`. Bonus: R5G6B5 + A4R4G4B4
formats now decode (previously fell to magenta). X8R8G8B8, DXT1/3/5, and
SolidColor remain ours (no WB equivalent). **9 conformance tests prove
byte-identical equivalence per format** before substitution; updated
`SurfaceDecoderTests` to match the new A8 split semantics. Visual
verification at Holtburg pending.
- **N.4 — Object meshing.** Replace `SetupMesh.cs` + `GfxObjMesh.cs`
with calls to WB's `ObjectMeshManager`. Character-appearance
behaviors (CreaturePalette / GfxObjRemapping / HiddenParts) remain