Files
CydandClaude Fable 5 afc3fd839e Vendor dpl3-revive: the Division/DPL3 renderer, now ours
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>
2026-07-05 22:06:25 -05:00

2.3 KiB

.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.