HUD phase 1: full dpl2d API recovered + opcode-faithful 2D layer rework

Every dpl2d_ recorder in the binary self-identifies via its debug-name string
(part_010.c 0x487f34..0x4888c0) -- the complete API + opcode map is recorded
in phases/phase-02-dpl2d-reticle.md: point sets (2/3), closed polylines (4/5),
open line strips (6/7), AddPoint (8), AddCircle (9), SetColor (0xF),
Set/ConcatMatrix (0x10/0x11, 2x3 affine), Push/PopState (0x12/0x13),
SetLineWidth (0x15), CallDisplayList (nested glyphs), FullScreenClipRegion.

dpl2d.cpp reworked to that model: command-stream recorder (open-primitive
vertex runs, state commands, nested list calls) + a recursive ExecuteList
rasteriser (XYZRHW points/strips/loops/circles, 2x3 transform + state stacks,
save/restore).  CORRECTION: the old "PushMatrix/MoveTo/PopMatrix" trio was a
misreading of OpenPolypoint/AddPoint/ClosePolypoint ("draw a point") -- kept
as aliases mapping to the true semantics.

Reticle findings recorded: the ctor (@004cc40c) builds ~15 display lists (the
dotted-cross reticle, tick ladders via FUN_004cd938, side arrows, arcs) plus a
3D marker chain and the PNAME1-8.bgf pip meshes (all ship).  Next: transcribe
ctor+Execute, wire the 1996 caller's AddWeapon arguments, hook the draw.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-08 19:32:36 -05:00
co-authored by Claude Fable 5
parent 56f02b2176
commit 1cd8ca1a80
3 changed files with 467 additions and 161 deletions
+70
View File
@@ -0,0 +1,70 @@
# Phase 02 — dpl2d API recovery + BTReticleRenderable reconstruction (task #35)
**Goal:** the main-view HUD (targeting reticle + up to 10 per-weapon pips).
**Status:** API fully recovered [T1]; ctor/Execute transcription + wiring IN PROGRESS.
## The recovered dpl2d recorder API (libDPL 2D display lists) [T1]
Every recorder self-identifies via its `FUN_0049a300(1, s_dpl2d_...)` debug-name string
(part_010.c). Opcodes are the first word written into the list's command buffer.
| FUN @ | dpl2d name | opcode | args |
|---|---|---|---|
| 00487f34 | NewDisplayList | — | → list handle |
| 00487fbc | OpenDisplayList (Begin) | — | (list, mode) |
| 00488030 | CloseDisplayList (End) | — | (list) |
| 00488054 | FlushDisplayList (Compile) | — | (list) |
| 004880e8 | AddOpenPolyline | 4 | closed-loop polyline begin |
| 0048814c | AddClosePolyline (loop end) | 5 | |
| 00488278 | AddOpenLines | 6 | open line-strip begin |
| 004882dc | AddClosePolyline (strip end) | 7 | |
| 00488340 | AddOpenPolypoint | 2 | point-set begin |
| 004883a4 | AddClosePolypoint | 3 | |
| 00488408 | AddPoint | 8 | (x, y) — vertex of the open primitive |
| 0048847c | AddCircle | 9 | (x, y, r, fill) |
| 00488500 | AddSetLineWidth | 0x15 | (w) — 1.0/2.0/3.0 used |
| 0048856c | AddPushState | 0x12 | |
| 004885cc | AddPopState | 0x13 | |
| 00488630 | AddSetColor | 0xf | (r, g, b) floats |
| 004886ac | AddSetColor (packed) | 0x16 | (argb?) |
| 00488718 | AddSetMatrix | 0x10 | 6 floats (2x3 affine) |
| 004887b0 | AddConcatMatrix | 0x11 | 6 floats + flag |
| 00488850 | AddCallDisplayList | (nested) | (list) — glyph reuse |
| 004888c0 | AddFullScreenClipRegion | | |
| 00488b80 / 00488bac | 2x3 matrix build: identity / set-translate(x,y) | — | local helpers feeding AddSetMatrix |
⚠ CORRECTION to the earlier AddWeapon recon comments: the "PushMatrix/MoveTo/PopMatrix"
triple is actually **AddOpenPolypoint / AddPoint / AddClosePolypoint** = "draw a POINT" —
`game/reconstructed/dpl2d.cpp`'s current Push/Move/Pop interpretation must be reworked to
this opcode model (points, open/closed polylines, circles, width, color, push/pop state,
set/concat matrix, nested list calls) and its `dpl2d_ExecuteList` renderer extended to draw
them (XYZRHW screen-space lines/points/fans; state save/restore already present).
## BTReticleRenderable — what the ctor builds (@004cc40c, part_014.c:4362) [T1 read]
- Calibration from ctor params/templates: pip origin/bias/scale (+0x1fc..0x234 in class
terms), min/max range from templates, `rangeScale = (clamped - lo) / (hi - lo)`.
- Loads **PNAME1-8.bgf** (all ship in VIDEO/GEO) — pip/number meshes — plus a 3D
renderable chain (FUN_00489708/489724/48ab0c/491cc4... — the dpl *3D* overlay object at
0.12 scale) — the reticle has BOTH a 3D marker component and the 2D display lists.
- Builds ~15 display lists: the master list (param_1[0x98]) composed of nested glyph lists
via AddCallDisplayList: crosshair dot cluster (AddPoint xy at ±0.04/±0.1 = the dotted
cross), heavier ±0.1..0.16 tick cross at width 3, two tick-LADDERS via FUN_004cd938
(count 0xd=13 / 0x15=21 ticks, spacing/geometry from the calibration constants at
[0x7f..0x88]: 0.35/0.25/0.5/±0.008/0.016...), side arrow polylines (the 4-vertex
closed arrows at the ladder ends), an arc segment (AddCircle partial at 0.03?), and the
heading/aim sub-lists ([0x9a..0xa1, 0xb6..0xba]) positioned by AddSetMatrix translates.
- FUN_004cd938 = the tick-ladder builder (count, flag, scale, x, y, step, minor/major
tick half-lengths) — transcribe next.
## Remaining steps
1. Rework dpl2d.cpp to the opcode model + extend ExecuteList (lines/points/polys/matrix/call).
2. Transcribe the ctor's glyph program into BTReticleRenderable::BTReticleRenderable
(+ FUN_004cd938 helper) with the authentic constants.
3. Read + transcribe Execute (vtable PTR_LAB_0051db44 — find the Execute slot; per-frame:
withinRange attr reads → pip list visibility/colors, aim/heading matrix updates).
4. Read the 1996 caller wiring (FUN_004cef28's inside path: the ctor's 15 args + the
AddWeapon per-weapon argument sourcing) and reproduce in MakeMechRenderables.
5. Draw hook: the engine already calls mReticle->Execute() per frame (L4VIDEO ~6562);
or execute from the BT renderer after the 3D scene; dpl2d_ExecuteList(device).
6. The cockpit canopy shell (blx_cop, punch cutout) black-enclosure fix (BT_INSIDE_COCKPIT=1).