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
+94 -4
View File
@@ -1386,7 +1386,9 @@ static const float kRetTickMajor = 0.016f; // [0x82]
static const float kRetBotX = -0.25f; // [0x84] bottom heading-ladder x0
static const float kRetBotY = 0.35f; // [0x85] heading ladder y
static const float kRetBotSpan = 0.5f; // [0x86]
static const float kRetCaret = 0.02f; // _DAT_004cd7f4 (caret triangle size) [T3]
static const float kRetCaret = 0.025f; // _DAT_004cd7f4 (caret triangle size)
// [T1] read from the binary 2026-07-24
// (was a 0.02f guess -- 20% small)
static const int kRetTicksR = 13; // [9] right ladder tick count
static const int kRetTicksB = 21; // [0xb] bottom ladder tick count
static const float kRetMaxRange = 1200.0f; // ctor param 11 (0x44960000)
@@ -1789,9 +1791,10 @@ void
// the LOCK RING [0xb7] + its SPIN [0x9d] (Execute @4cebf9-4cee54 [T1]):
// while a target is locked the ring+cross (subB9) draws at the reticle
// frame centre, spinning 4 degrees per frame; unlocked it clears. (The
// binary also hangs the PNAMEx.bgf player-name mesh on the 3D marker here
// -- the 3D marker chain remains deferred.)
// frame centre, spinning 4 degrees per frame; unlocked it clears. The SAME
// lock-change block drives the PNAMEx.bgf player NAME PLATE (the target's
// callsign under the crosshair) -- reconstructed at the end of this
// function, no longer deferred.
{
extern int gBTHudLockState;
const int locked = (gBTHudLockState == 2); // the Lock attr rule, not just a target
@@ -1856,6 +1859,93 @@ void
extern int gBTHudPrimary;
dpl2d_ExecuteList(gBTHudPrimary ? masterList : simpleXList, device);
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// THE TARGET NAME PLATE (PNAME1-8.bgf) -- the floating callsign under the
// crosshair. Reconstructed from the reticle Execute disassembly
// (reference/decomp/reticle_execute_004cdcf0.disasm.txt) [T1]:
//
// @004cdede, every frame while the full HUD is up:
// dpl_IdentityDCS (plate);
// dpl_ScaleDCS (plate, 0.12f, 0.12f, 0.12f);
// dpl_TranslateDCS(plate, K*reticlePos.x + -0.0f,
// K*reticlePos.y + -0.08f, -1.0f);
// dpl_FlushDCS (plate);
// K = the x87 long double @0x4cee64 = 0.35714286 = 1/2.8 -- the SAME
// 2.8 projection constant the hotbox uses, i.e. K converts the reticle's
// -1..+1 screen space into eye-space extents at z = -1.
// @004cec98: the plate's MESH is the target player's (see
// BTReticleTargetPlate in mech4.cpp), visibility 1; no owning player
// -> visibility 0.
// @004cdd75 / @004cddc1: reticle Off, or On-but-simple-X (PrimaryHudOn
// clear) -> visibility 0 and the cached target cleared.
// @004cebf9-@004cec47 -- THE LOCK GATE: the block is entered on a change
// of EITHER the target (Reticle+0x1c) or the LOCK attribute (the
// Scalar* at this+0x184, cached at +0x188), and when that lock value
// reads 0 it branches to the hide path (@004ced87). So the plate needs
// a real fire-control LOCK, not merely something under the crosshair --
// the same `gBTHudLockState == 2` rule the lock RING uses below.
//
// So the plate TRACKS THE AIM POINT (it is not fixed under screen centre),
// sits 0.08 eye-space units below it, and shows the TARGET'S CALLSIGN.
//
// PORT: identical placement expressed in reticle units -- dividing the
// eye-space offsets by K (i.e. x2.8) puts the plate centre at
// (reticlePos.x, reticlePos.y +/- 0.08*2.8 = 0.224)
// spanning the plate quad's own 1.0 x 0.25 extents (content/VIDEO/GEO/
// PNAME1.BGF, verified) scaled by 0.12 and back-converted: 0.336 x 0.084.
// The art is the player's callsign raster, exactly as the 1995 plate's
// `bmap:name12_mtl` material supplied it -- here the egg's 128x32 name
// texture (4:1 == the quad's aspect) via BTGetPlayerNameTexture.
//
{
extern int gBTHudPrimary;
extern int gBTHudLockState; // 2 == authentic LOCK
extern int BTReticleTargetPlate(void); // mech4.cpp
extern void *BTGetPlayerNameTexture(int index0); // L4VIDEO.cpp
extern void dpl2d_DrawTexturedRect(struct IDirect3DDevice9 *device,
void *texture, float cx, float cy, float w, float h,
unsigned long argb);
extern float gBTAimX, gBTAimY;
const float kPlateScale = 0.12f; // dpl_ScaleDCS, uniform
const float kPlateW = 1.0f; // the PNAMEx quad's x extent
const float kPlateH = 0.25f; // ... and its y extent (4:1)
const float kInvK = 2.8f; // 1/K -- eye-space -> reticle
const float kPlateDY = 0.08f * kInvK; // = 0.224 below the aim point
// The plate's own material colour: content/VIDEO/MAT/BMAP.BMF gives
// `name12_mtl` (and each sibling) a NEUTRAL (0.5, 0.5, 0.5) -- the pod's
// plate is a grey-white label, NOT phosphor green like the reticle
// glyphs. 0.5 * 255 = 128.
const unsigned long kPlateARGB = 0xFF808080;
const int plate = (gBTHudPrimary && gBTHudLockState == 2)
? BTReticleTargetPlate() : 0;
if (plate > 0)
{
void *texture = BTGetPlayerNameTexture(plate - 1);
if (texture != 0)
{
// reticle y is +DOWN on screen (dpl2d MapY), eye-space y is
// +UP, so the binary's -0.08 eye offset is +kPlateDY here.
dpl2d_DrawTexturedRect(device, texture,
gBTAimX, gBTAimY + kPlateDY,
kPlateW * kPlateScale * kInvK,
kPlateH * kPlateScale * kInvK,
kPlateARGB);
}
if (getenv("BT_HUD_LOG"))
{
static int s_plog = 0;
if ((s_plog++ % 120) == 0)
DEBUG_STREAM << "[hud] name plate: bmp=" << plate
<< " tex=" << (texture != 0)
<< " at (" << gBTAimX << "," << (gBTAimY + kPlateDY)
<< ")\n" << std::flush;
}
}
}
}
//