Bring the graphics-dev collaborator's dpl3-revive into the repo as first-class
project code (they've handed it off; it's ours now). This is the proven
Division renderer that our in-process rt_draw has been trying to be.
What's here:
- parser/ B2Z/V2Z/SVT/SCN/SPL/BGF/BMF/BSL decoders (pure Python).
- spec/ reverse-engineered format + the definitive VelociRender wire
protocol (from the original DIVISION source, matches our live
VPX node/action tables exactly).
- source-ref/ read-only copies of the original DIVISION C (BIZREAD.C,
DPLTYPES.H, DPL.H) that define the formats.
- patha/ the "virtual VelociRender board": vrboard.py (24-action protocol
server), vrview.py (numpy software rasterizer, the reference),
vrview_gl.py (moderngl GPU backend, 832x512@60Hz), plus the
run/replay/regress tooling and evidence renders. Drives FLYK/BLADE/
Star Trek demos AND our btl4opt/rpl4opt game binaries.
- viewer/ WebGL archive generators (.py); prebuilt HTML/data regeneratable.
- samples/ small test models/textures.
- bt*.raw.bin real BTL4OPT arena wire captures (kept for offline renderer
testing/regression against OUR game).
.gitignore keeps the multi-hundred-MB demo capture dumps + debug logs +
regeneratable viewer bundles out of history (they stay on disk).
Phase 0 of the integration is validated: their board decodes our bt8 capture
with zero errors (3748 nodes, 507 instances, 4 mechs) and renders our arena
(terrain/dome/sky, correct Division DAC gamma). Plan + status in memory;
integration continues in emulator/RENDERER-COLLAB.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
64 lines
2.3 KiB
Markdown
64 lines
2.3 KiB
Markdown
# `.SPL` camera-path spline format
|
|
|
|
Reverse-engineered from `DPL3/EXAMPLES/SPLINE.C`. A `.SPL` drives a camera (or a
|
|
`DYNAMIC` object) along a smooth path. It is **plain text**:
|
|
|
|
```
|
|
N number of control points
|
|
x y z ax ay az x N -- position + euler angles (degrees)
|
|
```
|
|
|
|
`ax ay az` are rotations about X, Y, Z (same convention as `STATIC`/`LIGHT` in the
|
|
scene format). The path is a **closed loop** (the last point links back to the
|
|
first).
|
|
|
|
## Interpolation
|
|
|
|
Each of the 6 channels (x, y, z, and the three angles) is splined independently as
|
|
a **cubic Hermite** curve with **Catmull-Rom tangents**:
|
|
|
|
```
|
|
tangent at knot i (position): vel = (pos[i+1] - pos[i-1]) / 2
|
|
tangent at knot i (angle): rot = wrap(ang[i+1] - ang[i]) / 2
|
|
```
|
|
|
|
Per segment `i -> i+1`, with endpoint values `v0,v1` and tangents `d0,d1`, the
|
|
cubic `v(t) = a t^3 + b t^2 + c t + d` (`t` in 0..1) is:
|
|
|
|
```
|
|
d = v0
|
|
c = d0
|
|
a = d1 + d0 - 2*v1 + 2*v0
|
|
b = v1 - v0 - d0 - a
|
|
```
|
|
|
|
(Angle segments additionally subtract 360 from a tangent > 360 before solving, as
|
|
in the original `solve_rot_cubic`.) `walk_spline` advances `t` by a step, rolling
|
|
over to the next/previous knot at the 0..1 boundaries — a constant-`dt` walk, so
|
|
speed follows the control-point spacing (closely spaced points = slower).
|
|
|
|
## From a path sample to a camera
|
|
|
|
At parameter `t` the sampled `(pos, ang)` becomes a camera basis. Build the DPL
|
|
rotation `R = Rz(az) . Rx(ax) . Ry(ay)` (row-vector; see `SCN_FORMAT.md`), then:
|
|
|
|
```
|
|
forward = (0,0,-1) . R # the camera looks down its local -Z
|
|
up = (0,1,0) . R
|
|
eye = pos
|
|
center = pos + forward
|
|
```
|
|
|
|
The `-Z` local-forward is confirmed by `CAMERA.SPL`: it starts at `(0,310,-500)`
|
|
with `ay = 180`, which rotates local `-Z` to world `+Z` — i.e. the camera looks
|
|
into the scene, which extends toward `+Z`.
|
|
|
|
## Validation
|
|
|
|
`parser/spl.py` evaluates `CAMERA.SPL` (20 control points) into a smooth 240-frame
|
|
loop, eye path `X[-260,230] Y[-15,842] Z[-759,58519]` — matching both the file's
|
|
control points and the `RAPTOR.SCN` extent (`Z[-30000,75000]`). Rendered frames
|
|
from the path (`viewer/flythru_*.png`) show a coherent first-person flight down the
|
|
Raptor canal, banking as the euler angles interpolate. In the viewer, the fly-
|
|
through animates the full loop; dragging drops back to manual orbit.
|