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>
7.6 KiB
DIV-BIZ2 (.B2Z / .V2Z) binary geometry format
The format family is wider than its extensions. The game-side pipeline uses the same two encodings under different names:
.BGF= binary geometry (magicDIV-BIZ2),.VGF= its text twin (DIV-VIZ2),.BMF= binary material library (a BIZ2 file with only material/texture/ramp blocks, no geometry),.VMF= its text twin. Everything below applies to all of them. Game-side material references are namespaced:stships:eblu4_mtlmeans materialeblu4_mtlin librarySTSHIPS.VMF/.BMF.Texture sub-block
0x018(1996+): BITSLICE — u8 plane index into a.BSLbit-slice texture pack (seeSVT_FORMAT.md). Absent = slice 0.
Reverse-engineered from DPL3/BIZREAD.C (© DIVISION Ltd 1994, author PJA) and
validated against real models on drive SDA4. This is the object/geometry format
consumed by the DPL3 renderer used in Virtual World Entertainment's BattleTech /
Red Planet pods. .B2Z and .V2Z share this format.
All multi-byte values are little-endian. Floats are IEEE-754 single precision (the header rejects double-precision files). There is no compression — the stream is a flat sequence of length-delimited, tagged blocks.
1. File layout
"DIV-BIZ2" 8-byte ASCII magic
<block>* sequence of top-level blocks
Parsing stops at the trailer block (type 0x005).
2. Block header
Every block begins with a 16-bit header, followed by a length field whose width is encoded in the top nibble of the header:
hdr = u16
sel = (hdr >> 12) & 0xC
sel == 0x0 -> length = u8 (1 byte) top nibble 0,1,2,3
sel == 0x4 -> length = u16 (2 bytes) top nibble 4,5,6,7
sel == 0x8 -> length = u32 (4 bytes) top nibble 8,9,A,B
length counts the block body only (everything after the length field). The
record type is hdr & 0xFFF; the top nibble is purely the length-encoding
flag. That is why the source lists each type three times (0x0NNN / 0x4NNN /
0x8NNN) — same record, three body sizes.
3. Top-level block types (hdr & 0xFFF)
| Type | Meaning | Body |
|---|---|---|
| 0x003 | Header | sub-blocks (§4) |
| 0x004 | Comment | opaque, skip |
| 0x005 | Trailer | end of file |
| 0x010 | Texture | sub-blocks (§7) |
| 0x020 | Material | sub-blocks (§7) |
| 0x030 | Ramp | sub-blocks (§7) |
| 0x040 | Object | sub-blocks (§5) |
4. Header sub-blocks
| Type | Name | Body |
|---|---|---|
| 0x002 | version | skip |
| 0x003 | date | skip |
| 0x004 | time | skip |
| 0x005 | scale | f32 |
| 0x006 | precision | u8 (must be 0 = single) |
| 0x007 | filetype | skip |
| 0x009 | unit | u8: 0 = model units, 1 = inches (scale by 1/25.4) |
5. Object sub-blocks
| Type | Name | Body |
|---|---|---|
| 0x008 | object name | NUL-terminated string |
| 0x030 | front material | material-ref (§6) |
| 0x031 | back material | material-ref (§6) |
| 0x036 | vertex format | u8 draw_mode (inherited by patches) |
| 0x041 | LOD | payload skipped by original loader |
| 0x042 | patch | sub-blocks (§8) — one geogroup |
| 0x032/33/34/35/37 | plane / draw-mode / decal / facet / voodoo | skip |
| 0x000/001 (+comment tags) | comment | skip |
6. Material reference (used by 0x030 / 0x031)
type = u8
0 -> none (NULL)
1 -> named: NUL-terminated material name follows
2 -> DEFAULT material
3 -> (back only) same as front
7. Material / Texture / Ramp sub-blocks
Material (top-level 0x020):
| Type | Name | Body |
|---|---|---|
| 0x008 | name | string |
| 0x00a | scope | u8 |
| 0x021 | texture | u8 mode; if mode==2, NUL-terminated texture name |
| 0x023 | ambient | 3×f32 |
| 0x024 | diffuse | 3×f32 |
| 0x025 | specular | 4×f32 |
| 0x026 | emissive | 3×f32 |
| 0x027 | opacity | 3×f32 |
| 0x028 | ramp | NUL-terminated ramp name |
Texture (top-level 0x010): 0x008 name, 0x00a scope, 0x011 map filename
(string), 0x012 minify, 0x013 magnify, 0x014 alpha, 0x015 wrap_u, 0x016 wrap_v,
0x017 detail — the mode fields are each a u8. The bitmap itself lives in an
external .SVT file named by 0x011. 0x037 is the SPECIAL hook, a NUL-terminated
free-text string mirroring the text source's SPECIAL="..." header field — in
practice " SCROLL u0 v0 du dv " UV-drift rates (see SCN_FORMAT, Scrolling
textures).
Ramp (top-level 0x030): 0x008 name, 0x00a scope, 0x031 ramp data (color0 = 3×f32, color1 = 3×f32).
8. Patch (geogroup) sub-blocks
| Type | Name | Body |
|---|---|---|
| 0x008 | patch name | string |
| 0x030 | front material | material-ref (§6) |
| 0x031 | back material | material-ref (§6) |
| 0x036 | vertex format | u8 draw_mode |
| 0x043 | polygon | vertex-list (§9), type = polystrip |
| 0x044 | tristrip | vertex-list (§9), type = tristrip |
| 0x045 | polystrip | vertex-list (§9), type = polystrip |
| 0x046 | pmesh | vertex-list (§9), type = pmesh |
| 0x048/04a/04b | sphere / line / text | not implemented in original; skip |
| 0x032/33/34/35/37 | plane / draw-mode / decal / facet / voodoo | skip |
draw_mode bits (from dpltypes.h): 0x01 smooth, 0x02 colored, 0x04 luminance,
0x08 textured, 0x10 3d-textured, 0x200 front, 0x400 back.
9. Vertex-list sub-blocks
A primitive's body is itself a sequence of blocks: zero or more connectivity
blocks (pmesh only) plus exactly one vertex block. A vertex block's length
gives n_floats = length / 4; n_vertices = n_floats / floats_per_vertex.
Each vertex is floats_per_vertex consecutive f32s; components live at fixed
offsets by format:
| Type | f/vert | position | normal | rgba | lum(la) | uv(2) | uvw(3) |
|---|---|---|---|---|---|---|---|
| 0x080 | 3 | 0 | – | – | – | – | – |
| 0x081 | 6 | 0 | 3 | – | – | – | – |
| 0x082 | 7 | 0 | – | 3 | – | – | – |
| 0x083 | 10 | 0 | 3 | 6 | – | – | – |
| 0x084 | 5 | 0 | – | – | 3 | – | – |
| 0x085 | 8 | 0 | 3 | – | 6 | – | – |
| 0x088 | 5 | 0 | – | – | – | 3 | – |
| 0x089 | 8 | 0 | 3 | – | – | 6 | – |
| 0x08a | 9 | 0 | – | 3 | – | 7 | – |
| 0x08c | 7 | 0 | – | – | 3 | 5 | – |
| 0x090 | 6 | 0 | – | – | – | – | 3 |
| 0x091 | 9 | 0 | 3 | – | – | – | 6 |
| 0x092 | 10 | 0 | – | 3 | – | – | 7 |
| 0x094 | 8 | 0 | – | – | 3 | – | 5 |
Connectivity (pmesh only):
0x047triangle connectivity —length/12triangles, each = 3× i32 vertex indices.0x04dpolygon connectivity — u8verts_per_poly, then(length-1)/(vpp*4)polygons, each =vpp× i32 indices.
Triangulation for export:
tristrip: triangles(i, i+1, i+2), flipping winding on oddi.pmesh: fan each face(f0, fk, fk+1).polygon/polystrip: current parser fans the block's vertices — adequate for simple patches; a faithful polystrip walk is a known refinement (see README).
10. Validation
parser/b2z.py decodes the samples with no unrecognized blocks and clean
trailers. Semantic checks that confirm correctness:
| File | Result |
|---|---|
| PT_RED.B2Z | material diffuse = (1,0,0) → red; no geometry (a colored point) |
| PT_WHITE.B2Z | material diffuse = (1,1,1) → white |
| BALL.B2Z | 50 verts / 40 tris, bounds ≈ unit sphere at origin, has normals |
| TESTBOX.B2Z | 5 pmesh parts (blue/red/black/green/yellow), 202 tris, boxy bounds |
| CANDA_S1.B2Z | Red Planet terrain tile: redrock/water materials, inch units, UV coords |