Enhanced texture dictionaries
Enhanced YTD resources use version 5. Drawables can embed dictionaries with the same texture representation. A dictionary has a sorted array of name hashes and a parallel array of texture pointers; some embedded entries have null pointers. Proven
The structural census reads all 89,813 version-5 YTD copies and embedded dictionaries in every accepted Enhanced drawable resource, with no failures. Four YTDs with other layouts (one version 2 and three version 13) and fifteen other-version YDRs are excluded. Every decoded texture’s computed mip/slice byte length equals its stored block count times block size. The proven record and storage claims below have this scope; texture lookup examples are separate observations. Proven · version-filtered full-install census
| Offset | Size | Type | Field | Confidence | Notes |
|---|---|---|---|---|---|
| 0x0 | 16 | bytes | resource base | Sourced | |
| 0x10 | 16 | bytes | unknown | Unknown | |
| 0x20 | 8 | pointer | sorted name hashes | Proven | |
| 0x28 | 2 | u16 | hash count | Proven | |
| 0x2A | 2 | u16 | hash capacity | Proven | |
| 0x2C | 4 | bytes | unknown | Unknown | |
| 0x30 | 8 | pointer | texture pointers | Proven | |
| 0x38 | 2 | u16 | texture count | Proven | |
| 0x3A | 2 | u16 | texture capacity | Proven | |
| 0x3C | 4 | bytes | unknown | Unknown |
The first 80 bytes form the texture base also used by shader references.
| Offset | Size | Type | Field | Confidence | Notes |
|---|---|---|---|---|---|
| 0x0 | 8 | bytes | unknown | Unknown | |
| 0x8 | 4 | u32 | block count | Proven | |
| 0xC | 4 | u32 | block size | Proven | |
| 0x10 | 4 | u32 | flags | Proven | |
| 0x14 | 4 | bytes | unknown | Unknown | |
| 0x18 | 2 | u16 | width | Proven | |
| 0x1A | 2 | u16 | height | Proven | |
| 0x1C | 2 | u16 | depth | Proven | |
| 0x1E | 1 | u8 | dimension | Proven | 1 2D, 2 3D, 3 cube |
| 0x1F | 1 | u8 | SGA buffer format | Proven | |
| 0x20 | 1 | u8 | tile mode | Proven | |
| 0x21 | 1 | u8 | unknown | Unknown | |
| 0x22 | 1 | u8 | mip count | Proven | |
| 0x23 | 5 | bytes | unknown | Unknown | |
| 0x28 | 8 | pointer | texture name | Proven | |
| 0x30 | 8 | bytes | unknown | Unknown | |
| 0x38 | 8 | pointer | texture data | Proven | |
| 0x40 | 4 | u32 | usage word | Proven | |
| 0x44 | 60 | bytes | unknown tail | Unknown |
Storage and formats
Section titled “Storage and formats”Texture data contains every mip of every slice, largest mip first. Each mip occupies whole compression blocks;
computed sizes from dimensions, format and mip count match blockCount * blockSize in the inspected format census.
Mip sides halve down to at least one texel. Proven
SGA format numbers partly resemble DXGI but use their own numbering. The table gives selected decoded codes, not an exhaustive list of all possible formats. Observed
| Code | Format | Confidence |
|---|---|---|
0x1C / 0x1D |
RGBA8 UNORM / sRGB | Observed |
0x38 |
R16 UNORM | Observed |
0x47 / 0x48 |
BC1 UNORM / sRGB | Observed |
0x4A / 0x4B |
BC2 UNORM / sRGB | Observed |
0x4D / 0x4E |
BC3 UNORM / sRGB | Observed |
0x50 / 0x51 |
BC4 UNORM / SNORM | Observed |
0x53 / 0x54 |
BC5 UNORM / SNORM | Observed |
0x57 / 0x5B |
BGRA8 UNORM / sRGB | Observed |
0x5F / 0x60 |
BC6H unsigned / signed float | Observed |
0x62 / 0x63 |
BC7 UNORM / sRGB | Observed |
CodeWalker’s Gen9-to-Legacy conversion can be lossy: R16 UNORM becomes A8, and unknown codes can fall back to A8R8G8B8. A converted texture’s format is therefore not evidence for its original Enhanced storage format. Sourced · CodeWalker
CodeWalker’s BC5 decoder (DDSIO.DecompressBC5Block, at commit 485d56b) decodes the second channel into red with
the first channel’s endpoints and leaves green at 255. BC5 normal maps, about 2% of the city’s normal maps, then
decode as a flat y = +1, z = 0 normal; an independent BC5 decoder gives the correct channels. Observed
Lookup
Section titled “Lookup”Texture parenting comes from live gtxd.ymt RBF data, mph4_gtxd.ymt and enabled GTXD_PARENTING_DATA XML.
CMapParentTxds/txdRelationships records name child/parent dictionary pairs; lookup can walk a parent chain.
Observed
CodeWalker also searches resident dictionaries after local and parent dictionaries. Its resident initialization
loads mapdetail, then vehshare, with later duplicate names replacing earlier resident entries.
Sourced · CodeWalker
Sampled vehicle-mod fragments obtain shared vehicle_generic_detail2, detail2_normal, detail_spec and
genericmud_car textures from vehshare; parent relationships alone do not supply them. Observed
The layout above reads dimension 2 as 3D and 3 as cube. CodeWalker, ragekit and rage-formats all read 2 as cube
and 3 as 3D, and ragekit writes its volume view kind (0xA3) only for dimension 3. Sourced[CodeWalker, ragekit,
rage-formats] Those readers share CodeWalker’s tables, so they are one source, not three. The single volume
texture of the install, cloudnoisevolume in graphics.ytd, would decide it from its depth and dimension bytes;
whether a volume’s mips halve its depth and how its slices are ordered are open with it. Unknown
Sampled blank and Tulip mesh_3a/mesh3_normal references remain unresolved after the resident lookup described
above. They do not establish permission to synthesize a replacement texture. Unknown