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

5.3 KiB
Raw Permalink Blame History

.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 2023
1 4-bit mono 1619
2 4-bit mono 1215
3 4-bit mono 811
4 8-bit mono 815
6 8-bit colour (3-3-2: r | g<<3 | b<<6) 07
7 12-bit colour (4-4-4: r | g<<4 | b<<8) 011

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 831 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 01) for an optional 8-bit colour plane. So slices 05 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/ (STEH16.TGA, KLNG16.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 7k scrambled the planes — e.g. the starship's deflector-dish glow landed on the saucer hull.)

Notes

  • Textures are addressed by name from the .B2Z material; the loader resolves the name to a file via a search path (dpl_FindTextureFile). Files on the disk carry the .SVT extension.
  • minify / magnify modes in the material select point vs. bilinear sampling (magnify 0 or 1 → point; else bilinear). wrap_u / wrap_v select clamp vs. repeat. These live in the .B2Z, not the .SVT.
  • A 1-byte .SVT appears 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.