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