Files
TeslaRel410/emulator/render-bridge/gauge-ab/planes.py
T
CydandClaude Fable 5 740ef2b0a7 BT410 Phase 5.3.32: the per-head A/B -- three engineering heads now exact
The gauge framebuffer is PLANE-PACKED: L4GAUGE.CFG gives each port a bit
mask, not a rectangle, so all six heads share the same x/y and are separated
only by bit -- the packing the VDB splits into the pod's physical screens.
Comparing RGB was therefore measuring nothing useful; the "magenta artifact"
just meant the wrong heads were lit at that pixel.

New instruments (emulator/render-bridge/gauge-ab/, with a README):
  planes.py  per-head scoreboard -- shipped vs ours, missing vs extra, per
             port mask, recovering the 16-bit word from DOSBox's RGB565
  BT_VIS_LOG a complete cockpit widget map from the single dispatch every
             gauge widget is built through (MethodDescription::Execute),
             printing name + port + authored position
  ab.sh      stages the fresh build over BTL4REC.EXE and kills any running
             DOSBox before launching -- see below

The fix: the Comm page's pilot roster is the POD roster (the viewpoint mech's
ControlsMapper pilot array, mapper attributes 15/16), not the mission's
player list.  It is zero in a solo mission, so the shipped page draws empty;
ours resolved the local player and painted its icon in colour 0xff.  The gate
belongs in the row source, not PilotList::Execute -- Execute's empty branch
still has to run, because erasing is what the shipped page draws.

  head    shipped    ours   missing   extra          (was)
  Eng1      17981   17981         0       0     (0 / 1030)
  Eng2      17981   17981         0       0
  Eng3      17981   17981         0       0
  Comm      15656   13557      2099       0     (2099 / 1253)
  Heat      21374   20913       566     105     (566 / 990)

Title-band magenta 404 -> 0.  The 2099 Comm pixels we are missing were
missing before the gate, so it is a strict improvement.

Method note, which cost more than the bug: the rig's confs run BTL4REC.EXE
out of the mount while the build writes build410/btl4opt.exe, and nothing
connected the two.  Three measurements ran an hour-old binary, so a change
that "did nothing" three times had never been tested -- and the correct first
hypothesis was discarded on that evidence.  ab.sh now re-stages every launch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 12:04:43 -05:00

75 lines
2.1 KiB
Python

#
# PER-HEAD A/B scoreboard for the packed gauge framebuffer.
#
# L4GAUGE.CFG configures ten logical ports onto ONE 640x480x16 buffer, each
# port owning a BIT MASK, not a rectangle -- the VDB later splits the planes
# into the pod's separate physical heads. Comparing RGB is therefore
# meaningless; the only useful question is "which HEAD differs, and where".
#
# DOSBox presents the buffer as RGB565 with bit replication, so the original
# 16-bit word is recovered exactly by R>>3, G>>2, B>>3.
#
import sys
from PIL import Image
BOX = (8, 52, 648, 531)
PORTS = [
("sec", 0x003F), # the 3-D scene (6-bit colour)
("overlay", 0x00C0),
("Mfd1", 0x0100), ("Eng1", 0x0200),
("Mfd2", 0x0400), ("Eng2", 0x0800),
("Mfd3", 0x1000), ("Eng3", 0x2000),
("Heat", 0x4000), ("Comm", 0x8000),
]
def words(path):
im = Image.open(path).convert("RGB").crop(BOX)
w, h = im.size
px = im.load()
out = []
for y in range(h):
row = []
for x in range(w):
r, g, b = px[x, y]
row.append(((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3))
out.append(row)
return out, w, h
def main(ship_path, ours_path):
A, w, h = words(ship_path)
B, w2, h2 = words(ours_path)
if (w, h) != (w2, h2):
print("SIZE MISMATCH")
return
print("%-8s %8s %8s %8s %8s %s" %
("head", "shipped", "ours", "missing", "extra", "extra-bbox"))
for name, mask in PORTS:
sa = so = both = 0
xs = []
ys = []
for y in range(h):
ra, rb = A[y], B[y]
for x in range(w):
a = (ra[x] & mask) != 0
b = (rb[x] & mask) != 0
if a:
sa += 1
if b:
so += 1
if a and b:
both += 1
if b and not a:
xs.append(x)
ys.append(y)
bbox = ("(%d,%d)-(%d,%d)" % (min(xs), min(ys), max(xs), max(ys))
if xs else "-")
print("%-8s %8d %8d %8d %8d %s" %
(name, sa, so, sa - both, so - both, bbox))
main(sys.argv[1], sys.argv[2])