Skip to content

Texture blocks ​

Every track, car and chrome file holds its textures in the same kind of block, read by read_texture_block (FUN_0046aca0) in WINPOD.EXE. A block holds a few texture pages; each page is an atlas of named sub-textures.

Reader: decoders/textures.py. Viewer: viewer/build.py. State: decoded for viewing on all 56 files that hold textures, 345 pages (measured, 2026-10-23: every page drawn and looked at in the viewer). Not yet round-trip: the bytes around the blocks are not decoded.

Layout ​

Observed in FUN_0046aca0; the sizes are register arguments, read from the disassembly at 0x46aca0–0x46ad51.

ReadSizeContent
Nu32Number of pages
—u32Read and not used by the software build
per page: ku32Number of sub-textures on the page
per page: recordsk × 0x34One record per sub-texture, below
palette0x300256 × RGB, 8-bit values; only in the 8-bit files (below)
pixelsN × page sizeThe pages, one after the other, rows top to bottom

The software build reads the palette only when the load mode is 0 or 4, and 0x10000 bytes per page (EDI at 0x46accc).

Sub-texture record (0x34 bytes) ​

A page can also hold records of all zero bytes beside its real ones: two on page 7 of POD POD's MINE.BL3 and MINE.BL4 (measured). The readers accept them on a page that has a real record too, so the block search, which looks for real records, is unchanged.

OffsetTypeMeaning
+0x00char[32]Name, zero-terminated (route2l2.TGA). Latin-1: coté.TGA in SCORP. A few names keep a stray byte after .TGA (winnight2.TGA@, mapcar5aa.TGA followed by 0x80)
+0x20i32 × 4x0, y0, x1, y1: inclusive corners on a 256 × 256 grid
+0x30u32Flags: 0 on most; 1 on the sky (meaning unknown)

The corners count to 255 even on the 128 × 128 pages: the grid is the same, the page is smaller (measured: the outlines fit the tiles at half scale).

Page formats ​

Measured by drawing the pages and by the spacing of blocks in the stream (for example the sky block in BELTANE.BL3 takes 0x300 + 0x10000 bytes, and in BELTANE.BL4 0x20000).

FilesPagePixelsPalette in the block
.BL3, .CH3256 × 2568-bit indexyes
.BV3256 × 2568-bit indexyes, the car's own; the game remaps the pages to CHROME.CH3's palette (docs/systems/render.md)
.BL4256 × 256RGB565no
.BV4, .CH4128 × 128RGB565no

Inferred: the "3" files serve the 8-bit software renderer and the "4" files the 16-bit 3D cards, which hold car textures at half size.

Where the blocks are ​

  • Tracks: three blocks. The main textures (5 pages in BELTANE), then two one-page blocks that each hold a single sky.tga. Each is preceded by a name (strings.md). The loader reads them at steps 10 and 12 (tracks.md).
  • Cars: one block of 2 pages after the car's parameters (at stream offset 0x670–0x674).
  • Chrome: one one-page block right after the header.

The scan (texture::blocks, for the viewer) finds blocks by their records: a run of .tga names with corners in range, preceded by k, N and the unused word. The car and track readers read each block where the file puts it (texture::block_at), as read_texture_block does, without checking the records. Fan files need that (measured, 2026-10-24, docs/extras.md). The fan cars F1, F2 and F3 name their first texture Pneu-pluie.TG` . The fan tracks Parc and Down name their prop textures .bmp, and Parc's sky record runs to the corner (63, 1023).

The sky ​

The sky page is not drawn as a 256 × 256 picture. Drawn 64 pixels wide and 1,024 tall it is a skyline turned on its side: inferred, a 1024 × 64 panorama stored column by column. The viewer shows it as a 256 × 256 page for now.

Open questions ​

  • What the unused second word holds (0, 1, or values like 0x328b740).
  • What the record flags mean.
  • How the sky page is mapped when drawn.

Writer ​

crates/pod-formats/src/texture.rs: a Block keeps its stored bytes (the word after the page count, each record's whole name field, the palette slot, each page's pixels). Block::encode gives them back: round-trip on all 371 pages (measured, tests/writers.rs), except one scan result in TEST.BL4 whose pages would pass the end (the scan's guess at the .BL4 sky; the track writer reads that file from the reader's own walk). Block::put draws a picture into a page: the nearest palette colour for 8-bit pages, RGB565 for 16-bit ones. Modded: Beltane's page 0 in the game (docs/modding.md).

Prose CC0 1.0, code Apache 2.0. POD: Planet of Death is © Ubi Soft; none of its files are on this site.