feat: crack INTRFACE.FF bitmap format + render all UI assets

BitB/BitR/XPAL/STR# system fully reverse-engineered:
- BitB<id>.dat: big-endian uint16 width/height header
- BitR<id>.dat: raw 8-bit palette-indexed pixels (no header)
- XPAL<id>.dat: 256 RGB triplets, 8-bit per channel
- STR#<id>.dat: length-prefixed UI string tables
- Runtime patch: index 2 must be forced to black (0,0,0) --
  the game engine overwrites this at runtime but stored values vary

Discovery: XPAL7A12 (correct render) vs XPAL7A1C (salmon background)
differ in only 3 palette entries (0,1,2); index 2 is the canvas black.

All 32 full-screen menu backgrounds, 57 vehicle HUD icons, cockpit
windshield frames, vehicle selection screens, and button strips now
render correctly. Documented in docs/FORMATS.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
pyr0ball 2026-06-29 00:25:08 -07:00
parent aad222fd09
commit acd4057e72

View file

@ -34,8 +34,8 @@ Notes:
|---|---|---|
| `MUSIC.FF` | 116 | `WAVE<id>.DAT` PCM segments, `PLST<id>.DAT` playlists, `FFCREATE.EXE` |
| `SOUND.FF` | 65 | `WAVE<id>.DAT` sound effects, `FFCREATE.EXE` |
| `OBJECTS.FF` | 526 | `ASND<id>.DAT` (enemy/pickup models + object sounds — format TBD) |
| `INTRFACE.FF` | 547 | `BitB<id>.dat` cockpit/HUD/menu bitmaps — format TBD |
| `OBJECTS.FF` | 526 | `ASND<id>.DAT` (enemy/pickup models + object sounds — format TBD) |
| `INTRFACE.FF` | 547 | `BitB<id>.dat` headers, `BitR<id>.dat` rasters, `XPAL<id>.dat` palettes, `STR#<id>.dat` string tables, `RTbl<id>.dat` remap tables, `xpXl<id>.dat` palette variants |
## Music: `WAVE` segments + `PLST` playlists ✅
@ -53,6 +53,68 @@ Segment resolution: a playlist named `PLST<id>` has base id = `int(id, 16)`; **s
maps to wave id `base + N - 1`** (e.g. `PLST07D1` step 2 → `WAVE07D2`). Concatenating the
referenced segments' PCM reproduces the song exactly (verified by ear).
## `INTRFACE.FF` bitmap system ✅ implemented in `tools/ff_extract.py`
All entries share a 4-digit hex ID that links related assets (e.g. `797C` = main menu):
`BitB797C.dat` (dimensions) + `BitR797C.dat` (pixels) + `xpal797c.dat` (palette) + `STR#797C.dat` (strings).
### `BitB<id>.dat` — bitmap header (4 bytes)
```
uint16 width (big-endian)
uint16 height (big-endian)
```
### `BitR<id>.dat` — raw bitmap raster
Raw 8-bit palette-indexed pixels, row-major, `width * height` bytes total. No header.
### `XPAL<id>.dat` / `xpal<id>.dat` — palette (768 bytes)
256 RGB triplets, 8-bit per channel (NOT 6-bit VGA). One palette per screen/sprite group.
**Critical runtime patch:** the game engine always forces palette index 2 to `(0, 0, 0)` black
at runtime. The stored XPAL files may contain any value there (often `#e78484` salmon from the
development environment). Any renderer must override index 2 to black after loading. Index 0
and 1 are the transparency/key color (`#ff00ff` magenta in most palettes).
**Discovery method:** comparing `XPAL7A12` (correct black background) vs `XPAL7A1C` (wrong
salmon background) revealed only 3 differing entries out of 256 -- indices 0, 1, and 2.
### `STR#<id>.dat` — string table
Length-prefixed strings for the screen's UI labels. First byte = string length, then UTF-8
text. Example: `STR#797C` contains all main menu button labels and the copyright notice.
### Identified screens (640x480 full-screen bitmaps)
| ID | Content (from STR# strings) |
|---|---|
| `797C` | Main menu |
| `79E0` | Network options |
| `79AE` | Load/save game |
| `7A44` | Settings menu |
| `7A4E` | Sound/music settings |
| `7A58` | Graphics settings |
| `7A62` | Keyboard settings |
| `7A6C` | Joystick settings |
| `7ADA` | Info/help |
| `7A12` | Network client/server status |
| `79F4` | Network client options |
| `79FE` | Network server options |
### Identified sprites
| Size | Count | Content |
|---|---|---|
| 640x480 | 32 | Full-screen menu/UI backgrounds |
| 512x236, 512x230, 512x218 | 3 | Cockpit windshield frames (color variants) |
| 428x196 | 12 | Vehicle selection screens with 3D-rendered thumbnails |
| 104x432 | 3 | Cockpit side panel strips |
| 420x46, 228x46 | 29 | Button/UI strip elements |
| 48x48 | 57 | Vehicle HUD icons (monochrome green, multiple vehicles/angles) |
| 18x18 | 13 | Small UI icons |
## World data (`WORLDS/`) — TODO (3D terrain)
Per-level sets `<NN>` = 01..06 plus `N`/`N2` variants (biomes: desert, snow/ice, lava, ocean).