Files
TeslaRel410/emulator/render-bridge/phase0_hero.py
T
CydandClaude Fable 5 0f5b2e28da Renderer: vendor live-bridge scripts; GPU backend unblocked (60fps)
- emulator/render-bridge/: the pod->Dave's-renderer live bridge (rescued
  from session scratchpad): live_bridge.py (first-person cam from the 0x1f
  pose, arrow-key eye-height trim), fp/chase offline renders, fifobridge,
  diagnostics, gauge_arena[_sound].conf, and launch_pod.ps1 (one-command
  pod+bridge restart: pentapus VPX_EXPLODE + AWE32 sound + GL bridge).
- _backend.py: renderer selection -- vrview_gl.GLRenderer (moderngl) by
  default, VRVIEW_SOFT=1 for the software reference; backend-agnostic
  frame save via last_frame.
- GPU backend runs on side-by-side CPython 3.13 (moderngl/glcontext cp313
  wheels; no MSVC needed): 63fps headless / 60.7 windowed vs 21fps software
  on the same scene, and the GL path also draws the vertex-alpha cloud dome.
- vrview.py: VRVIEW_GAMMA env selects DAC gamma (1.25 live-renderer legacy
  vs 1.7 per the original GAMMA.C) for A/B against the real pod.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 13:34:02 -05:00

59 lines
2.0 KiB
Python

#!/usr/bin/env python3
"""Phase 0 hero shot: replay a BTL4OPT capture, aim a synthetic camera at the
decoded animated mechs (anim_abs), lift the far-clip so the whole arena shows."""
import os, sys, struct
sys.path.insert(0, r'C:\VWE\TeslaRel410\dpl3-revive\patha')
os.environ.setdefault('SDL_VIDEODRIVER', 'dummy')
import numpy as np
from vrboard import VirtualBoard, Assembler
from decode_anim import find_framed_start
from vrview import Renderer
cap = sys.argv[1]
upto = int(sys.argv[2])
out = sys.argv[3]
dist = float(sys.argv[4]) if len(sys.argv) > 4 else 900.0
high = float(sys.argv[5]) if len(sys.argv) > 5 else 350.0
data = open(cap, 'rb').read()
board = VirtualBoard()
asm = Assembler(); asm.feed(data[find_framed_start(data):])
for m in asm:
try: board.handle(m)
except Exception: pass
if board.frames >= upto: break
r = Renderer(w=832, h=512)
r.cache.maybe_rebuild(board)
c = r.cache
# aim at the centroid of the animated vehicles (the mechs)
pts = np.array([np.array(f[9:12]) for f in board.anim_abs.values()])
target = pts.mean(0)
print('mech positions:'); print(pts.round(1))
print('target', target.round(1))
# camera: pulled back (+z), raised (-y is up in this y-down world)
eye = target + np.array([dist*0.4, -high, dist])
fwd = target - eye; fwd /= np.linalg.norm(fwd)
back = -fwd
worldup = np.array([0.0, -1.0, 0.0])
right = np.cross(worldup, back); right /= np.linalg.norm(right)
up = np.cross(back, right)
M = np.eye(4)
M[0,:3], M[1,:3], M[2,:3], M[3,:3] = right, up, back, eye
r.cam_matrix = lambda _b, _M=M: _M
# lift the far clip (yon = view-body float idx 13 -> byte offset 52) so the
# whole arena renders instead of being culled at the fog wall
if c.view is not None and c.view in board.nodes:
vb = bytearray(board.nodes[c.view].get('body') or b'')
if len(vb) >= 56:
struct.pack_into('<f', vb, 52, 1.0e6) # yon
board.nodes[c.view]['body'] = bytes(vb)
print('patched yon -> 1e6')
r.draw(board)
r.pygame.image.save(r.screen, out)
print('wrote', out)