From ccc6ee6914e2d45a33e9739ffc47c4c5d18003b3 Mon Sep 17 00:00:00 2001 From: Cyd Date: Tue, 21 Jul 2026 15:46:03 -0500 Subject: [PATCH] Fix HUD vertical flip: dpl2d Y grows DOWN, not up User-reported live: the torso-twist tape appeared at the TOP of the reticle (should be bottom) and the range ladder filled the wrong direction. I had assumed dpl2d used a standard math y-up convention (y0=bottom, y1=top) and inverted accordingly. Found the exact, already-solved answer in vrview_gl.py's own HUD vertex shader comment: "dpl2d Y grows DOWN (screen convention): period VHS footage shows the twist dial UNDER the reticle and the range bar filling top-to- bottom; mapping straight onto GL's Y-up NDC rendered the whole HUD flipped" -- the exact same bug, already diagnosed and fixed there. y0 (the smaller raw view-rect value) is the TOP of screen, y1 the bottom -- direct mapping, no inversion needed. Verified offline: the composited reticle now shows the twist tape (with its bowtie shape) at the bottom and the range ladder/pips reading top-to-bottom, matching BT411's documented layout. Co-Authored-By: Claude Opus 4.8 --- .../firmware-decomp/emu860c/hud2d_overlay.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/emulator/firmware-decomp/emu860c/hud2d_overlay.py b/emulator/firmware-decomp/emu860c/hud2d_overlay.py index 5c96bbe6..871318b3 100644 --- a/emulator/firmware-decomp/emu860c/hud2d_overlay.py +++ b/emulator/firmware-decomp/emu860c/hud2d_overlay.py @@ -28,7 +28,8 @@ _EDGE_OP = {6: 'nest', 7: 'link', 8: 'prune', 11: 'list_add', 12: 'list_remove'} class HudTracker: """Incremental wire-record feed -> the view's live dpl2d overlay - primitives, in view-rect space (x0..x1, y0..y1, y up). + primitives, in view-rect space (x0..x1, y0..y1, y grows DOWN -- + y0 is the top of screen, y1 the bottom; see composite_hud's to_px). Only tracks what hud2d_root/hud2d_prims need: node type+body (create/ flush), the dcs->view list_add edge, and the dl2d display-list words @@ -101,8 +102,9 @@ class HudTracker: def composite_hud(img, tracker, W, H): """Draw the tracker's current HUD primitives onto img (HxWx3 uint8, - modified in place). view-rect (x0..x1, y0..y1, y UP) -> pixel space - (0..W, 0..H, y DOWN): px = (x-x0)/(x1-x0)*W, py = (1-(y-y0)/(y1-y0))*H. + modified in place). view-rect (x0..x1, y0..y1, y grows DOWN -- confirmed + live, see to_px) -> pixel space (0..W, 0..H, y down, same direction): + px = (x-x0)/(x1-x0)*W, py = (y-y0)/(y1-y0)*H, no inversion. No-op (returns False) if the view rect or display list isn't resolved yet -- callers should keep showing the last good frame, same as the 3D render's own "skip if not ready" convention.""" @@ -121,7 +123,13 @@ def composite_hud(img, tracker, W, H): def to_px(pt): x, y = pt - return ((x - x0) / dx * W, (1.0 - (y - y0) / dy) * H) + # dpl2d Y grows DOWN (screen convention), confirmed both by the user + # (live: horizontal/twist tape appeared at top instead of bottom, the + # range ladder filled the wrong direction) and by vrview_gl.py's own + # comment/fix for the identical symptom ("mapping straight onto GL's + # Y-up NDC rendered the whole HUD flipped") -- y0 (the smaller raw + # value) is the TOP of screen, y1 the bottom. No inversion needed. + return ((x - x0) / dx * W, (y - y0) / dy * H) for kind, col, width, pts in prims: if len(pts) < 1: