Files
BT411/docs/ASSET_PIPELINE.md
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.

Layout:
  engine/   MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
            work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
            models) + image codec; the minimal rp/ headers the audio HAL needs
  game/     reconstructed BT logic + surviving-original BT source + fwd shims
            + WinMain launcher
  content/  full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
  docs/     format specs + reconstruction ledgers
  reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
  tools/    MP console emulator + map/resource scanners

One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 21:03:40 -05:00

84 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Asset Pipeline — Textures, Materials & Gauges
Companion to `BGF_FORMAT.md`. Covers how a model's surface resolves to pixels, and the cockpit
gauge/HUD formats. Verified by hexdump against real content; header cites are `file:line` under
`…/CODE/RP/MUNGA_L4/libDPL/`.
## Format inventory (CONTENT/BT)
| Ext | Count | Kind | Role |
|---|---|---|---|
| `.bgf` | 1275 | `DIV-BIZ2` FILETYPE=0 | 3D geometry (see BGF_FORMAT.md) |
| `.bmf` | 2222 | `DIV-BIZ2` FILETYPE=1 | material + texture **libraries** (no pixels) |
| `.vtx` | 5 | `DIV-VTX2` | raw RGB texel image |
| `.tga` | 8 | Truevision TGA2 type-2 | 24-bit truecolor texel image |
| `.sgi` | 0 | (loader exists) | RGBA texel image (none shipped) |
| `.bsl` | 3 | `DIV-BSL2` | bit-slice / multi-image + mip container |
| `.pcc` | 434 | ZSoft PCX, 8-bit RLE | cockpit HUD/gauge **raster** bitmaps |
| `.gim` | 311 | ASCII INI | MFD/radar **vector** line-gauges (NOT raster) |
| `.gat` | 3 | ASCII INI | gauge color/attribute table |
Layout: `VIDEO/GEO/*.bgf`, `VIDEO/MAT/*.bmf`, `VIDEO/TEX/*.vtx,*.bsl` (+ `TEX/BUILD/*.tga`),
`VIDEO/BUILD/*` staging, `GAUGE/*.gim,*.gat,*.pcc`, `MODELS/*.mod` (INI tying bgf+gim+sld).
## Name-resolution chain (verified)
```
BGF geogroup SV_F_MATERIAL "library:material"
→ open library.bmf
→ MATERIAL chunk whose NAME == "material"
→ its MATERIAL_TEXTURE (0x0021): [u8 type=2 NAMED][texture-name string]
→ TEXTURE chunk whose NAME == that texture-name
→ its TEXTURE_MAP (0x0011): image basename (no ext)
→ loader appends ext, searches texmap path → .vtx/.tga/.sgi/.bsl
```
`dpfCreateMaterialName(extPath,library,mname)` `PFILE.H:821`.
## .BMF chunk layout (same TLV grammar as BGF; tags in `PFBIZTAG.H:43-62`)
**TEXTURE `0x0010`** (`dpfTEXTURE`, `__PFILE.H:120-137`): NAME `0x2008` (string); TEXTURE_MAP `0x0011`
(basename string); MINIFY `0x0012`/MAGNIFY `0x0013` (mip/filter enums, `PFILE.H:155-162`); ALPHA `0x0014`
{blend/cut/blendcut}; WRAP_U/V `0x0015/16` {repeat/clamp/select}; DETAIL `0x0017`; BITSLICE `0x0018` (u8 → .bsl slice).
**MATERIAL `0x0020`** (`dpfMATERIAL`, `__PFILE.H:152-169`): NAME `0x2008`; MATERIAL_TEXTURE `0x0021`
[`u8 type`(2=named)+name]; AMBIENT `0x0023`/DIFFUSE `0x0024` = 3×f32 RGB (verified); SPECULAR `0x0025`/
EMISSIVE `0x0026`/OPACITY `0x0027` (optional, inferred 3-4 f32); RAMP `0x0028` (ramp-name string).
**RAMP `0x0030`**: NAME + RAMP_DATA `0x0031` (float color data).
## Pixel formats (normalize all to 32-bit RGBA at load)
- **.VTX (`DIV-VTX2`):** TLV; size tag `0x2062` = two int32 (w,h, e.g. 128×128); body = **uncompressed RGB
3 B/px**, top-to-bottom. Type enum `dpiBSLTYPE` (`PIMAGE.H:104-116`): MONO0-5/BILINEAR/RGB/RGBA.
- **.TGA:** standard type-2, 24-bit BGR, TGA2 footer. `dpl_tgaRead`.
- **.SGI:** RGBA (`dpl_sgiRead`; none shipped).
- **.BSL (`DIV-BSL2`): DECODED — a BIT-SLICED multi-image container** (corpus-verified on all 66 archive
BSLs; reference = the shipping WinTesla loader `DivLoader/VGCDivLoader.cpp:323-410`
`LoadBSLFile`/`getBSLData` + Division `dsys/PIMAGE.H` `dpiBSLTYPE` + the content build scripts
`img2vtx.exe -b -mN <tga>`). Header (int32 LE): w `@0x08`, h `@0x0C`, depth `@0x10` (bits per slice,
always 4), tableBytes `@0x14` (directory length counted from the nEntries field; imageDataOffset =
`0x18 + tableBytes`), nEntries `@0x18`; directory entries `{int32 recLen; int32 sliceType; char
name[recLen-4]}`**entry names are authoring records only, read-and-discarded at runtime**; then
`w*h` little-endian 32-bit texel WORDS. Byte 0 of each word = pad (structurally unused, 0 in all 66
files); the other 3 bytes = SIX independent **4-bit GRAYSCALE slices**, nibble PAIR-SWAPPED (even slice
= HIGH nibble): slice0=bits12-15, 1=8-11, 2=20-23, 3=16-19, 4=28-31, 5=24-27 (`shift=(c+((c+1)%2)*2)*4`,
value returned `<<4` = 0x00..0xF0). sliceType 7 = **RGB444** (r=s5,g=s4,b=s3), 8 = **RGBA4444** (+a=s2);
both coexist with mono slices in one file (BDAM/BEXP/BDET). Slice SELECTION = the BMF TEXTURE record's
`BITSLICE` tag `0x18` (u8; **absent = slice 0**) — e.g. BLHSKIN.BMF blkhwk1_tex=absent(0),
blkhwk2/3/4_tex=01/02/03, all mapping image basename `blkhwk` → BLKHWK.BSL. Mono slices are colorized
downstream by material RAMP (+ diffuse tint on neutral ramps) — all mech skins, vehicle atlases
(BASEV = 6 gray sheets, NOT truecolor), logos, effects grit. ⚠ The previous "base image = trailing
w*h*bpp, pixel order [pad,R,G,B]" claim was WRONG — it overlaid 2-3 different gray slices as RGB
channels (the rainbow "graffiti" mech-skin bug); it survives as the `BT_BSL=0` diagnostic fallback in
`port/src/image.cpp decodeBSL`.
## Cockpit gauges
- **.GIM** = ASCII INI, **vector** top-down line drawing for MFD/radar: `[lods] level0=3000…`,
`[vertices] v0=x,y,z`, `[level0] linelist=<group> v0 v1 v2…`. First token = color/attr group resolved
via `.gat`. Feeds the `dpl2d_*` 2D line path. Verified `AB01_GA.GIM`.
- **.GAT** = ASCII INI: `[colors]`,`[groups] a_bld=amber1…` → group→palette-index. Verified `GAUGE.GAT`.
- **.PCC** = ZSoft **PCX**, 8-bit RLE, 256-color palette (palette after `0x0C` EOF marker); 640×480-class.
The actual HUD raster bitmaps → need 8-bit-palette → RGBA expansion. Verified `ADPAL.PCC`.
## ⚠ Dependencies / open items
1. **The retail texel raster set is NOT in this archive** — only the BUILD/logo subset of `.vtx/.tga/.bsl`
ships. The 2222 `.bmf` reference maps that aren't here. **Need the full texture content from Nick**, or
the renderer must tolerate missing maps and fall back to material DIFFUSE color.
2. **No source for the `.gim/.gat/.pcc` loaders** — inside the closed `LIBDPL.LIB`. `.pcc`(PCX) and
`.gim/.gat`(INI) are standard/simple. `.bsl` and `.vtx` are now FULLY decoded (see Pixel formats above;
the shipping `DivLoader/VGCDivLoader.cpp` turned out to carry the reference reader for both).