Files
TeslaRel410/emulator/PHASE3-PROGRESS.md
T
CydandClaude Opus 4.8 dce89a8571 Phase 3b: live OpenGL render backend in DOSBox-X (VPX_RENDER=1)
The emulated VPX board now draws frames in real time. The FIFO burst
assembler feeds an in-process DPL scene store; each vr_draw_scene publishes a
frame snapshot to a dedicated WGL window thread that renders it fixed-function.

- vpxlog.cpp: scene_burst() decode + VScene store + rt_main GL window thread;
  glFrustum from the view-node window rect, glScalef(-1,1,1) for Division's
  mirrored screen-x, action-31 camera as modelview. No build change (opengl32
  already linked).
- Validated: flyk divrgb.scn opens the "VPX VelociRender (emulated)" window
  and draws the SMPTE bars live via the real camera.spl spline camera
  (divrgb-live-gl.png), matching the offline render_capture.py decode.
- Game path (alpha1.conf) opens the window + draws background but hits the
  pre-existing production btdpl.ini vr_sync timeout (sends_wo_rcv) -- not a 3b
  issue. Remaining work tracked in PHASE3-PROGRESS.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:27:58 -05:00

6.1 KiB
Raw Blame History

Phase 3 — Render Backend: Progress

Status (2026-07-03): Phase 3a + 3b complete. 3a — the render command stream is fully captured and decoded, and a captured DIVRGB frame reconstructed to pixels offline. 3b — a live OpenGL window built into the emulated board draws each frame in real time inside DOSBox-X. First images ever produced from the Rel 4.10 VPX protocol without a real board.

decoded DIVRGB calibration screen

That is flyk divrgb.scn — Division's SMPTE color-bar calibration scene — rendered entirely from the FIFO command stream captured by the emulated VPX board: geometry, connectivity, materials, camera, viewport and background all come from the wire, none from the scene files. divrgb-frame0.png is the same capture drawn with the actual frame-0 spline camera the app sent.

3a. Full FIFO capture

vpxlog.cpp now records every FIFO burst when VPX_FIFODUMP=<path> is set (records: 'VPXM' magic, u32 length, raw bytes; one record per burst between outputData tag writes). The capture used here: divrgb.fifodump (1297 messages) from divrgb.conf.

Tools:

  • decode_fifodump.py <dump> [--hex N] [--action A] — action census + payload hexdumps.
  • render_capture.py <dump> [-o out.png] [--frame N] [--eye x,y,z] — reconstructs the scene graph and software-renders the frame each draw_scene commits.

The Rel 4.10 wire protocol (established from this capture)

One burst per message: [action:4][payload], packetized at 508 bytes. The i860 image download itself rides the FIFO in this build (actions 1820, VREND.MNG). The DPL3 vr_action enum holds for 023 but Rel 4.10 extends and re-purposes the tail:

action meaning payload
0 init args string (/device~0x150~/video~svga~…)
1 create [type][name]the host assigns node names (1,2,3…); the board's create reply node value is ignored
3 flush [name][type][node struct] (see node types below)
7 dcs_link [parent][child]
9 draw_scene [view?][0][0][1][1.0f] — commits the frame
11 list_add [parent][child]
1821 860code/data/bss/args i860 download (FIFO in this build)
23 set_geom_verts (Rel4.10; DPL3 had 22) hdr [name][0][n_verts][3][n_blocks][1][5][n_verts][1.0f], then float32 x,y,z per vertex
25 set_geom_conns (new) hdr [name][n_polys][loop_len][0], then indices; each poly a closed loop (last=first)
31 camera (new) [?][view][3×3 rotation, row-major][eye x,y,z] per frame
45 (0x2D) sync token ping (see PHASE2)

Node types (from create/flush pairs in this capture):

type node flush payload highlights
2 texture/ramp? one word, 0xFFFFFFFF / 0x0FFFFFFF
3 view window l,b,r,t (±1 × ±0.6154), window-plane distance 1.3, viewport 832×512, near 2, far 12000, background RGB
4 light
5 dcs 4×4 matrix
6 material (old-style) RGB floats
7 object
8 lod 2×4 bounds + lists
9 geogroup bounds; payload int 14 = material node name
10 geometry [geo_type][n_polys][n_verts]…[radius]
11 material floats 1012 (payload) = diffuse RGB

Graph: list_add links object→lod→geogroup→geometry (and zone-level nodes to node 0); geogroups bind materials by name. The 13 DIVRGB bars decode to the textbook SMPTE pattern — 7 color bars, the reverse strip, and the I/white/+Q PLUGE row — which validates vertices, connectivity, materials, camera and window mapping in one image. (Division screen x runs opposite to a GL-style eye space; without negating x the pattern comes out mirrored.)

3b. Live OpenGL backend (DONE)

live GL window rendering DIVRGB

VPX_RENDER=1 turns on a live render backend built into vpxlog.cpp (Windows/WGL). The same burst assembler that feeds VPX_FIFODUMP now also feeds an in-process scene store (scene_burst()struct VScene), and each vr_draw_scene publishes a frame snapshot to a dedicated OpenGL window thread (rt_main) that draws it with fixed-function GL. No build-system change was needed — opengl32 was already linked, and vpxlog.cpp is already in hardware/.

Validated: flyk divrgb.scn (divrgb.conf with VPX_RENDER=1) opens the "VPX VelociRender (emulated)" window and draws the SMPTE bars live, framed by the real camera.spl spline camera the app sends — matching the offline render_capture.py decode. The window runs on its own thread, so it keeps displaying the last frame after the DOS app exits.

Design notes:

  • Multi-burst payloads (set_geom_verts/conns continuations) are tracked with geom_active / conn_active state, same as the offline decoder.
  • Projection: glFrustum from the view-node window rect scaled by near/window_distance; a glScalef(-1,1,1) handles Division's mirrored screen-x. Camera is the row-major 3×3 from action 31 loaded as the modelview rotation, then glTranslatef(-eye).
  • Frame handoff is a critical-section-guarded VFrame + auto-reset event; the emulator thread never blocks on GL.

Game path (alpha1.conf, full BattleTech v4.10): the window opens and draws the view background, but the run hits the pre-existing production-path sync timeout (velocirender_receive timed out — sends_wo_rcv=3, then failed in vr_sync) — the btdpl.ini/netnub launch bursts several sends before its first receive, which the POLL_THRESHOLD gating stalls. This is not a 3b issue (the flyk clean-launch path renders fine); it is the same production-sync item still open from Phase 2.

Remaining

  1. Production-path vr_sync timeout (sends_wo_rcv): the game's btdpl.ini/netnub launch path. Needed before the game itself renders.
  2. Content: test.egg carries no models, so even past sync the game has no buttee.bgf/mslr.bgf geometry to draw — needs a real mission/content tree from the pod image.
  3. DOS/4GW sync variant for the CYCLE flyk yip.scn fixture (Red Planet geometry) — the older action-check sync.
  4. Texturing (set_texmap_texels, action 23-data + SVT), lighting, and depth/material niceties; current backend is flat-shaded untextured polys.