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>
5.3 KiB
.SVT texture format
Reverse-engineered from DPL3/DPL_LOAD.C : load_svt() and validated by decoding
real textures to PNG. .SVT is the texture-map format referenced by .B2Z
materials (via the texture "map filename", block 0x011 — see B2Z_FORMAT.md §7).
Layout
There is no header. The entire file is a raw, row-major array of 32-bit texels. The image is always square, and the edge length is inferred solely from the file size (exactly as the original loader does):
| File size (bytes) | Dimensions |
|---|---|
| 16384 | 64 × 64 |
| 65536 | 128 × 128 |
| 262144 | 256 × 256 |
Any other size is rejected. texel_count = edge², file_size = edge² × 4.
Texel
Each texel is 4 bytes in file order:
byte0 = pad (always 0x00, unused)
byte1 = Blue
byte2 = Green
byte3 = Red
i.e. a 0BGR layout (as a little-endian 32-bit word: 0xRRGGBB00). There is no
usable alpha channel stored in the texel — byte0 is a pad byte, not opacity. The
loader hard-codes bits_per_texel = 32. Per-material transparency comes from the
material/texture alpha mode, not from the texels.
The channel order is not stated in the source (the i860/pxpl5 hardware consumed the word directly); it was determined empirically — see Validation.
V coordinate convention
Do not flip V. The renderer indexed texture rows directly: v = 0 samples SVT
row 0, which is the image top. Verified empirically by A/B renders — the Mad Cat
cockpit canopy and missile-pod tube/vent faces, the MADCOL "08" insignia, and the
shark's back/belly shading are all correct with V passed through unchanged and all
invert if V is flipped (1-v). WebGL's texImage2D also places the first uploaded
row at t = 0, so no correction is needed anywhere in the modern pipeline.
(An earlier revision of this toolchain flipped V; that produced the "upside-down
cockpit / reversed pods" artefacts on the mechs.)
GLOMM-packed ("ALL") textures
GLOMM.EXE (source: DPL3/GLOMM.C) packs several textures into the bit-planes of
one 32-bit SVT — a texture-memory-saving trick for the pxpl5 board. From the mode
switch in load_svt():
/m: mode |
Format | Bits |
|---|---|---|
| 0 | 4-bit mono | 20–23 |
| 1 | 4-bit mono | 16–19 |
| 2 | 4-bit mono | 12–15 |
| 3 | 4-bit mono | 8–11 |
| 4 | 8-bit mono | 8–15 |
| 6 | 8-bit colour (3-3-2: r | g<<3 | b<<6) |
0–7 |
| 7 | 12-bit colour (4-4-4: r | g<<4 | b<<8) |
0–11 |
save_svt() byte-reverses each 32-bit word before writing. Files named
*ALL.SVT (MADALL, VTVALL, GENALL, …) are such packs (e.g. GLOMMAD.BAT:
glomm madall.svt /m:0 mad1 /m:1 mad2 /m:2 mad3 /m:3 mad4 /m:6 madcol) and decode
as coloured noise if read as plain RGBA. For modern rendering, use the pre-glom
per-part source textures (MAD1..4.SVT, VTVCAB.SVT, …), which sit alongside
them on the disk as ordinary full-colour SVTs.
.BSL bit-slice packs (DIV-BSL2)
The formalised successor of the GLOMM packing, used by the game-side pipeline
(1996+). Header-ed, unlike .SVT:
"DIV-BSL2" 8-byte magic
u32 version (0x100), u32 (1)
u32 bits_per_slice (4)
u32 dir_bytes
u32 n_slices
n x { u32 type (10 = 4-bit mono), u32 slice_index, cstr name }
raw 32-bit texel words (edge inferred from remaining size, as .SVT)
Slice k occupies nibble (k+2) ^ 1 of each little-endian 32-bit word:
slices fill bits 8–31 in ascending order, pair-swapped within each byte by the
writer's 32-bit byte reversal (the same save_svt reversal as GLOMM), leaving the
low byte (nibbles 0–1) for an optional 8-bit colour plane. So slices 0–5 land at
nibbles 3, 2, 5, 4, 7, 6. Materials select a slice via texture sub-block 0x018
(binary) / BITSLICE {k} (text); the 4-bit mono plane is rendered as luminance
and coloured by the material's DIFFUSE.
Verification: the pre-pack source TGAs survive in STDAVE/VIDEO/BUILD/
(STEH1–6.TGA, KLNG1–6.TGA). Correlating each TGA against all eight nibble
planes of its pack gives r ≥ 0.98 for this mapping on all twelve slices, and
near-zero for every other nibble. (A first-guess mapping of 7−k scrambled the
planes — e.g. the starship's deflector-dish glow landed on the saucer hull.)
Notes
- Textures are addressed by name from the
.B2Zmaterial; the loader resolves the name to a file via a search path (dpl_FindTextureFile). Files on the disk carry the.SVTextension. minify/magnifymodes in the material select point vs. bilinear sampling (magnify0 or 1 → point; else bilinear).wrap_u/wrap_vselect clamp vs. repeat. These live in the.B2Z, not the.SVT.- A 1-byte
.SVTappears on the disk as a placeholder/stub (e.g.WPNMECH.SVT); treat non-conforming sizes as "no texture".
Validation
parser/svt.py png <file> decodes with the 0BGR order and produced correct,
recognizable images:
| File | Dims | Result |
|---|---|---|
| FLAME64.SVT | 64² | orange/red flame (blue under the wrong order — the decisive test) |
| GROUPER.SVT | 128² | coral grouper: red body, blue spots |
| SHARK.SVT | 256² | great white shark on a blue ground |
| TANK.SVT | 128² | vehicle skin |
The flame is the disambiguator: warm colors only make sense under 0BGR; the
alternative 0RGB renders it blue.