Gitea #44: the reticle TARGET NAME PLATE (PNAME1-8) -- the target's callsign under the crosshair

Reconstructed the last deferred piece of the 1995 reticle, decoded from the
Execute disassembly @004cdcf0 [T1]:
 - selection: target_mech+0x190 (owning BTPlayer) -> player+0x1e0
   (playerBitmapIndex), 1-based into the mesh table at this+0x2e8
 - placement: re-placed every frame the aim moves -- scale 0.12 uniform,
   translate (K*retPos.x, K*retPos.y - 0.08, -1.0), K = 1/2.8 (the x87 long
   double @0x4cee64) -- so the label TRACKS THE AIM POINT, not screen centre
 - visibility: the LOCK attribute (this+0x184, cached +0x188) AND an owning
   player; reticle-off / simple-X also hide it
 - art: the plate quad UV-addresses a shared 128x64 bitslice texmap whose
   texels the pod OVERWROTE each mission with the egg's callsign rasters
   (original source commented out at L4VIDEO.cpp:5682-5710) -- the baked
   'PLAYER n' art in BMAP.BSL is only the shipped fallback.  Material colour
   is a neutral (0.5,0.5,0.5): grey-white, not phosphor green.

Port: same geometry in reticle units (0.224 below the aim point, 0.336x0.084)
drawn as the target's egg callsign texture through the reticle's own MapX/MapY
mapping, so it follows the world view in every layout and BT_SHOT captures it.
New: dpl2d_DrawTexturedRect, BTReticleTargetPlate, BTGetPlayerNameTexture.

Also: kRetCaret corrected 0.02f -> 0.025f (_DAT_004cd7f4 read from the binary;
the old value was a T3 guess, 20% small).

KB: gauges-hud + open-questions corrected (the chain was filed as deferred and
mis-attributed to 'the 3D marker'); TWO PNAME consumers now distinguished (this
plate, and CameraShipHUDRenderable's ranking window which shipped 2026-07-18);
new bgf-format section on the plate atlas.

Rig-verified: 2-node relay, BT_GOTO=enemy -> '[hud] name plate: bmp=2 tex=1'
and 'Boreas' rendered under the crosshair on the locked target.  Solo clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0166KTsC7ADm7VXEi1HF1jNg
This commit is contained in:
arcattack
2026-07-24 18:36:02 -05:00
co-authored by Claude Opus 5
parent b7107b1020
commit 35c750dc7c
7 changed files with 390 additions and 10 deletions
+47
View File
@@ -71,6 +71,53 @@ A mech is not one BGF — it's a `.SKL` skeleton (a DCS tree of joints) whose ea
`Object=part.bgf` is loaded + posed, then animated by `.ANI` clips. See [[asset-formats]] /
[[locomotion]] for skeleton + animation. [T1]
## The PNAME/PLACE name-plate atlas (the only TEXT-bearing BGF geometry) [T1/T2]
`PNAME1-8.BGF` + `PLACE1-8.BGF` (`content/VIDEO/GEO/`, 235/238 bytes) are the MP
scoreboard's 16 billboard plates — each ONE flat quad (4 verts, `XYZ_UV`, `PCONN` ppf=4,
**no LOD chunk = 1 implicit LOD**, no normals, no `SV_SPECIAL`). PNAME = 1.0×0.25 m,
PLACE = 0.5×0.25 m, planar Z=0. Consumers: `FUN_00454a70` (the scoreboard, resource type
0x46) and `BTReticleRenderable` @004cc40c (PNAME only). See [[open-questions]].
**They are the only geometry in the corpus whose texture is TEXT**, which makes them the
sole asset that can prove BSL row order and slice mapping — and they CONFIRM the port's
pair-swapped nibble decode (`image.cpp:122-125`): slices 0→3 come out as "PLAYER 1/2",
"3/4", "5/6", "7/8" in exact index order. [T2 — decoded + read visually]
One shared 128×64 texmap: `bmap:``VIDEO/MAT/BMAP.BMF` → 6 `TEXTURE` records
`bmap1_tex..bmap6_tex`, all `TEXTURE_MAP=bmap` with `BITSLICE` 0..5 → `VIDEO/TEX/BMAP.BSL`
(`DIV-BSL2`, 128×64, depth 4, texels @0x70). Cell map (UVs read straight from each BGF):
| material | slice | plates → UV sub-rect |
|---|---|---|
| `name12_mtl``bmap1_tex` | 0 | PNAME1 `v[.5,1]`, PNAME2 `v[0,.5]` (full U; 128×32 cells) |
| `name34_mtl``bmap2_tex` | 1 | PNAME3 `v[.5,1]`, PNAME4 `v[0,.5]` |
| `name56_mtl``bmap3_tex` | 2 | PNAME5 `v[.5,1]`, PNAME6 `v[0,.5]` |
| `name78_mtl``bmap4_tex` | 3 | PNAME7 `v[.5,1]`, PNAME8 `v[0,.5]` |
| `place1234_mtl``bmap5_tex` | 4 | PLACE1-4 = 2×2 grid of 64×32 cells (`u[0,.5]/[.5,1]` × `v[.5,1]/[0,.5]`) |
| `place5678_mtl``bmap6_tex` | 5 | PLACE5-8 = same 2×2 grid |
**The BSL is a RUNTIME COMPOSITING TARGET, not final art [T0 engine source].**
`DPLRenderer::MakeBitSliceStorage` (L4VIDEO.cpp:9888) allocates `uint32[128*64]`;
`LoadBitSliceTexture` merges a 1bpp egg BitMap into it; `FlushBitSliceTexture`
(L4VIDEO.cpp:5682, stubbed in 2007) did `dpl_LookupTexture("bmap:bmap1_tex")` +
`dpl_TexmapTexels2D(texmap, buf, 128, 64, 4)` — one upload rewrites ALL SIX slices. So the
1995 engine painted the **egg's callsign + ordinal bitmaps** onto these plates every mission;
the baked "PLAYER n" text is only the shipped DEFAULT. Two stacked 128×32 large-name bitmaps
per slice = exactly the PNAME v-halves; two stacked 128×32 ordinal bitmaps ("1st|2nd") = exactly
the PLACE 2×2 grid. Corollaries:
- **The shipped BMAP.BSL has only 4 distinct planes** — slice4 aliases slice0 and slice5
aliases slice3 (nibble3==nibble7, nibble4==nibble6; nibbles 0/1 zero). The ordinal art was
never baked, so a naive PLACE draw shows "PLAY"/"ER 1"/… fragments. [T1 measured]
- The placeholder cells are stored **scanline-reversed** vs the compositor's top-down order
(`LoadBitSliceTexture` writes y=0..31 top-down), so a naive PNAME draw gives the RIGHT
number upside-down. Don't chase it — implement the compositor instead. [T1 / T3 fix choice]
- These 6 materials carry **no DIFFUSE/AMBIENT** — only `NAME`, `MATERIAL_TEXTURE` and an
**unhandled tag 0x0027** (12 B = {0.5,0.5,0.5}; only 41 uses in 1618 BMFs, likely SPECULAR
[T4]). `bgfload` therefore falls back to the gray placeholder `0xFFB0B0B8`; force WHITE for
these unlit text plates. And `decodeBSL` emits **alpha=255** for mono slices, so the plate
draws as an OPAQUE black rectangle — a billboard needs black→alpha-0 keying (which is exactly
what the 2D path's A4R4G4B4 `0xFFFF/0x0000` upload does).
## Key Relationships
- Detailed spec: `docs/BGF_FORMAT.md`.
- Consumed by: [[rendering]] (the D3D9 draw path), [[locomotion]] (skeleton parts).
+39 -3
View File
@@ -543,8 +543,43 @@ and every instrument is now live [T2]:**
wired task #38): lock requires a target AND your own HUD's host zone damage < **0.75** (a
shot-up targeting computer loses lock) AND the targeted zone's damage < **1.0** (whole-mech
target checks zone 0 — so a wreck's dead zone can't re-lock). The hotbox stays visible without
lock (box = HotBoxVector, ring = Lock — separate signals). The binary also hangs the PNAMEx.bgf
player-name mesh on the 3D marker here (3D chain still deferred).
lock (box = HotBoxVector, ring = Lock — separate signals). The SAME lock-change block drives the
PNAMEx.bgf **TARGET NAME PLATE** — the target's callsign floating under the crosshair.
**RECONSTRUCTED + RIG-VERIFIED 2026-07-24 (was "3D chain deferred"); awaiting live playtest.**
Mechanism, all [T1] from the Execute disassembly
(`reference/decomp/reticle_execute_004cdcf0.disasm.txt`) — the ONLY two functions that touch the
plate fields are the ctor @004cc40c and Execute @004cdcf0:
- **Mesh table** = `playerNameObject[]` at `this+0x2e8` (PNAME1 lands at +0x2ec), loaded
part_014.c:4430-4444; the array is 12 slots (`MAX_PLAYER_NAMES`), only 8 populated.
- **Selection** (@004cec98): `target_mech+0x190` (the owning BTPlayer) → `player+0x1e0`
(`playerBitmapIndex`) indexes that table **1-based** (the binary biases the base instead of
decrementing; no bounds check). Same 1-based egg `bitmapindex` the Comm pilot list uses.
- **Placement** (@004cdede): re-placed EVERY frame the aim moves — identity → scale 0.12 uniform
→ translate `(K·reticlePos.x, K·reticlePos.y 0.08, 1.0)`, `K` = the x87 long double
@0x4cee64 = **0.35714286 = 1/2.8** (the same 2.8 projection constant the hotbox uses). So the
plate **tracks the aim point**, 0.08 eye-space below it — NOT pinned under screen centre.
- **Visibility** = the **LOCK** attribute (the `Scalar*` at `this+0x184`, cached +0x188;
@004cebf9-@004cec47 branches to the hide path when it reads 0) AND the target having an owning
player. Reticle Off or simple-X (PrimaryHudOn clear) also hides it (@004cdd75/@004cddc1).
- **Art**: the plate is a bare 1.0×0.25 quad (4:1) whose material `bmap:name12_mtl` etc.
(content/VIDEO/MAT/BMAP.BMF) UV-addresses one shared 128×64 bitslice texmap —
4 materials × 2 v-halves = the 8 player slots. `content/VIDEO/TEX/BMAP.BSL` ships **baked
"PLAYER 1..8" fallback art** (decoded 2026-07-24), but the pod OVERWRITES those texels at
runtime with the egg's 1bpp CALLSIGN rasters — the original source is commented out at
`engine/MUNGA_L4/L4VIDEO.cpp:5682-5710` (`FlushBitSliceTexture` →
`dpl_TexmapTexels2D(texmap, storage, 128, 64, 4)`, with the tell-tale warning "textures for
player names not defined"). So the authentic plate shows the **operator-set callsign**, with
"PLAYER n" only as the no-bitmap fallback. Material colour is a neutral (0.5,0.5,0.5) — the
plate is grey-white, NOT phosphor green like the reticle glyphs.
- **PORT**: same placement expressed in reticle units (÷K ⇒ 0.224 below the aim point, plate
0.336×0.084), drawn as the target player's egg callsign texture
(`dpl2d_DrawTexturedRect` + `BTGetPlayerNameTexture` + `BTReticleTargetPlate`).
**Two PNAME consumers exist** — this reticle plate (PNAME only), and `FUN_00454a70`
(class key 0x46) = the engine's **`CameraShipHUDRenderable`**, the camera/broadcast seat's
followed-name banner + ranking window, which uses PNAME **and** PLACE1-8 as sorted
`[ordinal][callsign]` rows and is **already live** as screen quads (see [[multiplayer]] camera
seat). Its 1995 source is likewise commented out in `L4VIDRND.cpp:2562-2876` — the literal
`dpl_*` calls, a Rosetta stone for the binary's node API.
- **Simple-X mode** (PrimaryHudOn off, mask 0x20): the minimal reticle — a small green cross
(±0.02..0.08 arms) riding the aim translate (ctor @4689-4705 [T1]) — swapped for the full HUD
by Draw's state switch.
@@ -563,7 +598,8 @@ and every instrument is now live [T2]:**
This recovery also CONFIRMS the HUD attr-table ids 4/5/6/8/0xA/0xB/0xC/0xD name↔use pairings
(hud.hpp had flagged them uncertain; the OFFSETS were re-based 2026-07-19 — the table @5110b8
starts with id 3 FlickerRate@0x1D8, so Rotation=0x1DC…CompassHeading=0x214 Scalar; hud.hpp/
CLASSMAP corrected, names/ids unchanged). Deferred: PNAME1-8.bgf 3D marker chain. (The canopy shell
CLASSMAP corrected, names/ids unchanged). The PNAME1-8.bgf target NAME PLATE is RECONSTRUCTED
(2026-07-24, §Lock ring above) — no longer deferred. (The canopy shell
is now authentic and shows by default — see [[cockpit-view]]; `BT_HIDE_COCKPIT=1` hides it.)
Player CALLSIGN labels (kill/damage feed, radar/target tags, score display) are 1bpp name
+27 -3
View File
@@ -117,7 +117,29 @@ New unaccounted functionality no prior list knew (addresses verified absent from
(hysteresis + key-repeat), no caller found; the one hole in "gauge system complete".
Settle via vtable lookup (plausibly a config/roster scroller).
- **FUN_00454a70** (193 ln) — the PNAME1-8/PLACE1-8.bgf MP name-billboard loader (the known
"MP target identification" gap's exact function).
"MP target identification" gap's exact function). ✅ **DECODED 2026-07-24 (not yet ported)
[T1/T2]** — it is the **MP SCOREBOARD/leaderboard**, built by the L4VIDEO video-resource
factory for **resource type 0x46** (part_008.c:2902-2911, gated `res+0x28 & 0xc == 0`, alloc
0xbc). All 16 plates are ONE flat textured quad each (4 verts / 1 PCONN quad / no LOD chunk /
no normals): PNAME = 1.0×0.25 m, PLACE = 0.5×0.25 m, both planar Z=0, UNIT=metre, authored
30-Nov-1995. **PNAME1-8 are literally the words "PLAYER 1".."PLAYER 8"**; **PLACE1-8 are the
rank ordinals "1ST".."8TH"** — a row reads `[PLACE][PNAME]` because the PLACE node is
translated x=0.75 and spans ±0.25, so it ABUTS the PNAME plate's x∈[0.5,+0.5] exactly.
Update fn **FUN_004553ac** re-parents each player's PNAME plate into row node `pnameGeo[rank]`
(rank from the per-player attr at `player+0x1cc`, players indexed by `player+0x1e0`), so the
rows SORT live. Row pitch = **0.24** (double @0x004551b8), rows DCS scale 0.12 @ (0.22,0.16,0.5),
root DCS scale (0.2,0.2,1.0) @ (0,0.15,0.5). Materials/atlas map + the runtime-composite
mechanism: [[bgf-format]] §"The PNAME/PLACE name-plate atlas". The separate single-PNAME
consumer is `BTReticleRenderable` @004cc40c (no PLACE) — the in-cockpit designator label,
now **RECONSTRUCTED (2026-07-24, rig-verified)**: see [[gauges-hud]] §Lock ring.
The port's ranking display already ships the **2D** equivalent (egg ordinal+callsign bitmaps,
`CameraShipHUDRenderable::Render`), so this 3D chain is redundant for the scoreboard.
NOTE on the "PLAYER n" art: those baked words are the SHIPPED FALLBACK. The pod overwrites the
atlas texels at runtime with the egg's 1bpp callsign rasters — the original source survives
commented out at `engine/MUNGA_L4/L4VIDEO.cpp:5682-5710` (`FlushBitSliceTexture`
`dpl_TexmapTexels2D(…,128,64,4)` + the warning "textures for player names not defined"). So an
authentic plate reads the player's CALLSIGN; "PLAYER n" only appears when the egg carries no
name bitmap. [T1]
-**Explosion::SplashDamage @0042fad0 — RECONSTRUCTED (task #62, 2026-07-13) [T1/T2].** ONE call
site, **Missile::Perform (FUN_004bef78, part_013.c:10097)**, in the collision branch (fires on ANY
missile impact — mover OR world), gated on `missile+0x360`, radius = `missile+0x364`. **Radius source
@@ -266,9 +288,11 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR
executed as a D24S8 stencil cut; visible canopy = hull-minus-apertures ([[cockpit-view]]
§FINAL). All 8 mechs render connected dark frames with clear viewports (the intermediate
"frameless bhk1/loki/vulture/avatar" reading was wrong); thor matches the pod footage exactly.
Eye placement verified exact per-mech incl. Thor's +1.13 offset cockpit ([[cockpit-view]]). (b) the **3D marker
Eye placement verified exact per-mech incl. Thor's +1.13 offset cockpit ([[cockpit-view]]). (b) ~~the **3D marker
chain** ([0x31c]/[0x320] dpl objects + the PNAME1-8.bgf player-name meshes over the locked
target — matters for MP). (c) the compass rotation SIGN is derived-not-verified [T3] (turn
target — matters for MP)~~ **DONE 2026-07-24: the target NAME PLATE is reconstructed +
rig-verified (the target's callsign under the crosshair, lock-gated) — [[gauges-hud]] §Lock
ring.** (c) the compass rotation SIGN is derived-not-verified [T3] (turn
left → the stem should swing right; flip the sin sign in Draw if footage disagrees).
- **✅ StatusMessagePool / MessageBoard — LIVE (2026-07-12) [T1/T2].** Decoded: FUN_0042e580 =
the engine `Player::AddStatusMessage` (chain add at +0x1e4); FUN_0042e5a0 = `StatusMessageUpdate`