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

7.6 KiB
Raw Permalink Blame History

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 (magic DIV-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_mtl means material eblu4_mtl in library STSHIPS.VMF/.BMF.

Texture sub-block 0x018 (1996+): BITSLICE — u8 plane index into a .BSL bit-slice texture pack (see SVT_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):

  • 0x047 triangle connectivity — length/12 triangles, each = 3× i32 vertex indices.
  • 0x04d polygon connectivity — u8 verts_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 odd i.
  • 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