TO:R Data Map

btx: textures

Source
docs/formats/btx.md
SHA-256
0abe1b08…66fb779f

A texture: a 0x34-byte header, the texture's name, then its pixel data, ready to hand to Direct3D 11. Every texture in the game is one: the gallery and ending pictures, backgrounds, map names, Warren Report portraits, menu and font textures, and the textures of models and event sprites. A btx is a whole file's payload, a pakd entry, or sits inside another container (ARC\0, BMAR, the background archives, the fonts); it has no wrapping of its own. The engine's one texture loader reads it (How the game reads it). It's named after its magic, btx\0; Gibbed's TextureFile reads the same layout.

Based on Every btx in the game's 10,016 .dat files: 28,518 in 8,890 files (Where they are); Gibbed's TextureFile.cs, TextureFormat.cs and TextureFormatHelpers.cs (reference_tools/Gibbed.LetUsClingTogether/projects/Gibbed.Reborn.FileFormats/) and Gibbed.Reborn.ExportTexture/Program.cs, checked 2026-10-11; the unpacked executable, SHA-256 7b0230a11498f40396c9048345e7cfe0ef442cb7ca8faffc6f197920d2669599; Microsoft's DXGI_FORMAT list for the format numbers, checked 2026-10-11.
Checked 2026-10-11
Method Single-file C# programs over the decrypted files (with the toolchain's Containers library): find btx\0 at every 4-byte boundary of every payload, read every header field, work out each texture's data size the way the game does and compare it with the space the texture has. Static analysis with Ghidra 12.1.4 (the decompiled code in local/exe/decomp/) of the loader, and of the executable's format tables read by address. Not yet decoded or rebuilt by the toolchain; no in-game test.

Where they are

confirmed (C# scan, all 10,016 .dat files): 28,518 btx, every one with a whole header as laid out below (version 0x103, name_offset 0x34, a known format). The pakd entry paths are as in containers.md.

Where How it's stored Files btx
Gallery/, ending/, bg/back/, ScreenShot/ The whole payload; ZIP member <name>.btx 13, 33, 99, 1 146
WarrenReport/common/, WarrenReport/<lang>/ The whole payload; member <name>.img 446 + 8 × 481 4,294
menu/mapname/<lang>/ The whole payload; member <name>.img 8 × 345 2,760
bg/*.dat pakd entries #1 on 393 2,110
bg/*.dat Inside entry #0, an untagged resource archive 394 3,827
event/scene/ Nested pakd entries (#n/0/1, #n/0/2) 364 6,344
object/ Nested pakd entries 746 1,492
worldmap/ pakd entries; and inside Worldmap.dat's BMAR 46; 1 1,796; 18
menu/texture_x4/, menu/menu_layout.dat, menu/menu_parts.dat Inside ARC\0 archives 75; 2 4,679; 634
menu/sequence/ pakd entries 10 14
Font/ Inside the payload 8 138
SaveThumb/ pakd entries 9 91
WarrenReport/WarrenReport.dat; 4 pakd files in each WarrenReport/<lang>/ pakd entries 1; 32 54; 64
battle/battle_data_release.dat Nested pakd entries 1 35
title/title.dat Nested pakd entries 1 22

0x34 bytes. Offsets are from the start of the btx (its magic), and every _offset field is an offset from there. "Not read" means the loader (0x140079db0, 0x140079de0) never reads it.

Offset Size Type Name Meaning Confidence Source
0x00 4 raw[4] magic btx\0. The loader checks it. likely 0x140079db0 (compares with 0x140bb8298); C# scan, all 28,518.
0x04 2 u16 version 0x103 in every file. The loader accepts 0x103 or lower. likely 0x140079db0; C# scan. Gibbed reads 0x04–0x07 as one u32 0x103.
0x06 1 u8 linear 0 in all but 2 files, which hold 1 (test_bg_alphamask in bg/bg_common.dat, an alpha mask). 0 lets the texture be created in an _SRGB format, so the GPU reads its colours as sRGB; 1 keeps it linear (_UNORM). likely 0x140079de0 (sets texture flag 8 when it's 0), 0x1400a5d10, 0x1400a6050; C# scan.
0x07 1 u8 unk_0x07 0 in every file. Not read. likely C# scan.
0x08 2 u16 width In pixels: 4 to 2,500 in the files. likely Gibbed Width; 0x140079de0; C# scan.
0x0A 2 u16 height In pixels: 4 to 3,528 in the files. likely Gibbed Height; 0x140079de0; C# scan.
0x0C 4 u32 row_pitch Bytes per row of level 0: the row pitch the game works out. Not read: the game computes it. confirmed Equals the computed pitch in all 28,518 (C# scan); not read by 0x140079de0. Gibbed Stride.
0x10 1 enum8 format The pixel format. See Pixel formats. The files use 13 (BC7, 21,983), 0 (R8G8B8A8, 5,298) and 7 (BC1, 1,237). likely Gibbed TextureFormat; the format table at 0x1406b0670; C# scan.
0x11 1 u8 tiling 0 in every file. When 2, the game pads every level to whole 32 × 32 pixel tiles when it sizes it; Gibbed reads 3 as Nintendo Switch swizzled data. likely 0x1401035e0; Gibbed Unknown11 and ExportTexture; C# scan.
0x12 1 u8 mip_count_minus_1 Number of mip levels, less 1: 0 in 28,498 files, 1 in 4, 2 in 16. likely Gibbed MipCount; 0x140079de0; C# scan (each texture's size matches its space with this many levels).
0x13 1 u8 unk_0x13 1 in every file. Copied into the texture's sampler settings, twice; probably the address mode for U and V (guess). — 0x140079de0; C# scan.
0x14 1 u8 unk_0x14 1 in every file. Copied into the sampler settings; probably a filter (guess). — 0x140079de0; the engine's default sampler holds the same 1, 1 and 5 (0x1400a5de0).
0x15 1 u8 unk_0x15 5 in every file. Copied into the sampler settings; probably a filter (guess). — As unk_0x14.
0x16 1 u8 unk_0x16 0 in every file. Stored in the texture at +0x118, with a "changed" bit when it differs. likely 0x140079de0, 0x14007a0a0; C# scan.
0x17 1 u8 flags 0 in every file. Bit 0: cube map (6 faces). Bit 2: volume texture of depth slices. Bit 3: never sRGB. likely 0x140079de0, 0x1400a6050, 0x140103720; C# scan.
0x18 4 u32 data_offset Start of the pixel data: a multiple of 16 in every file, 0x40 to 0x70. likely Gibbed DataOffset; 0x140079de0; C# scan.
0x1C 1 u8 unk_0x1C 0xFF in every file, read as −1; probably a clut's format, none (guess). — 0x140079de0; C# scan. Gibbed requires 255 (PaletteFormat).
0x1D 1 u8 unk_0x1D 0 in every file. Not read. likely C# scan.
0x1E 2 u16 unk_0x1E 0 in every file; probably a clut count (guess). — 0x140079de0; C# scan. Gibbed requires 0 (PaletteCount).
0x20 4 u32 unk_0x20_offset The end of the pixel data, rounded up to 64, in every file. The loader turns it into a pointer beside unk_0x1C and unk_0x1E, but doesn't pass any of the three to the texture. — 0x140079de0, 0x14007a0a0; C# scan (all 28,518). Gibbed PaletteOffset.
0x24 4 u32 name_offset The name: 0x34, right after the header, in every file. likely Gibbed NameOffset; 0x140079de0, 0x140168680; C# scan.
0x28 2 u16 depth 1 in every file: the number of slices of a volume texture. likely Gibbed Depth; 0x140079de0, 0x1400a6050; C# scan.
0x2A 2 u16 unk_0x2A 0 in every file. Not read. likely C# scan.
0x2C 4 u32 unk_0x2C_offset A u32 0 between the name and the pixel data, always 4 or 12 bytes before data_offset. Not read. likely Gibbed Unknown2COffset; C# scan.
0x30 4 u32 unk_0x30 0 in every file. Not read. likely C# scan.

Name and padding

Offset Size Type Name Meaning Confidence Source
name_offset (0x34) name + 1 raw[n] name The texture's name, NUL-terminated ASCII: the file's name for whole-payload textures, else names like bg015_00_c0_t00-85abd907d1487483 or bg015_00_c0_t00_m*.tga. The game uses it to share textures (Names). likely 0x140168180, 0x140063760; C# scan (all ASCII).
after name varies raw[n] padding Zeros to unk_0x2C_offset, then the u32 0 it points at, then zeros to data_offset. confirmed C# scan: every byte from the name's end to data_offset is 0, in all 28,518.

Pixel data

The levels follow data_offset back to back, largest first, with no padding between them. Level m is width >> m by height >> m pixels.

unk_0x20_offset points past the data, at the next 64-byte boundary; in a whole-payload btx that is past the end of the payload, since the payload ends with the data.

Pixel formats

The format codes are indexes into the engine's table of 41 formats at 0x1406b0670 (0x18 bytes each: a name pointer, bits per pixel, row alignment or block width, block height, alpha bits, a clut flag, a block-compression flag). The names below are the table's own. A format is created on the GPU as the DXGI format from the table at 0x140b9a2f0, or, when the texture is sRGB, from the one at 0x140b9a3a0 (How the game reads it). All likely (static analysis), except the file counts, confirmed by the C# scan.

Code Name Bits per pixel DXGI format (sRGB) What the game does with it btx
0 R8G8B8A8 32 28 R8G8B8A8_UNORM (29 _SRGB) Uploads it as is. 5,298
1–4 R8G8B8, R5G6B5, R5G5B5A1, R4G4B4A4 24, 16, 16, 16 — Converts it to R8G8B8A8 on the CPU first. 0
5, 6 P8, P4 8, 4 — Converts it to R8G8B8A8 through a clut, which the btx loader doesn't supply. 0
7 BC1 4 71 BC1_UNORM (72 _SRGB) Uploads it, with the GPU size rounded up to multiples of 4. 1,237
8 BC2 8 74 BC2_UNORM (75) As BC1. 0
9 BC3 8 77 BC3_UNORM (78) As BC1. 0
10, 11 BC4, BC5 4, 8 80 BC4_UNORM, 83 BC5_UNORM The table gives them block size 0, so the game can't size them: unusable. 0
12 BC6H 8 95 BC6H_UF16 Uploads it as is. 0
13 BC7 8 98 BC7_UNORM (99 _SRGB) As BC1. 21,983
14 D24S8 32 45 D24_UNORM_S8_UINT A depth format. 0
15 D15S1 16 0 (none) Fails: no DXGI format. 0
16, 17 L8, A8 8 61 R8_UNORM, 65 A8_UNORM Uploads it as is. 0
18–22 L4A4, L8A8, YUV, PVRTII_4, PVRTII_2 8, 16, 32, 4, 2 0 (none) Fails: no DXGI format. 0
23–25 U16U16, F16F16, F32 32 36 R16G16_UINT, 34 R16G16_FLOAT, 41 R32_FLOAT Uploads it as is. 0
26–28 RGBA_U32U32, R16G16B16A16F, R32G32B32A32F 64, 64, 128 17 R32G32_UINT, 10 R16G16B16A16_FLOAT, 2 R32G32B32A32_FLOAT Uploads it as is. 0
29–33 D32F, R10G10B10A2, R11G11B10, R16_UNorm, R16F 32, 32, 32, 16, 16 40 D32_FLOAT, 24 R10G10B10A2_UNORM, 26 R11G11B10_FLOAT, 56 R16_UNORM, 54 R16_FLOAT Uploads it as is. 0
34 B8G8R8A8 32 87 B8G8R8A8_UNORM (91 _SRGB) Uploads it as is. 0
35–40 A8R8G8B8, A8B8G8R8, B8G8R8, B5G6R5, B5G5R5A1, B4G4G4A4 32, 32, 24, 16, 16, 16 — Converts it to R8G8B8A8 on the CPU first. 0

Source: the format table (0x1406b0670) and the two DXGI tables (0x140b9a2f0, 0x140b9a3a0) read from the executable by address; the conversion list and the rounding in 0x1400a6050; the converter 0x140104dc0 ("pixelconv"). Gibbed's TextureFormat has the same 41 names in the same order. Codes 41 and up are past the end of the table; the game doesn't check for them.

Names

How the game reads it

Every fact here is static analysis of the unpacked executable (Ghidra 12.1.4, the decompiled code in local/exe/decomp/), so at most likely; the functions are in the names list.

Replacing a texture

What the code above says a replacement btx has to be (all likely: static analysis, no in-game test yet):

Rebuilding

To rebuild a btx byte for byte from its decoded form: write the header fields as read, the name, zeros to data_offset (the u32 at unk_0x2C_offset is 0), then the pixel data. row_pitch and unk_0x20_offset follow from the other fields (Pixel data), but are kept as read. For a new texture, place unk_0x2C_offset at data_offset − 4, as about half the files do. likely: no toolchain round trip yet.

Leads