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

122 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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](divrgb-decoded.png)
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](divrgb-live-gl.png)
`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.