Torque Shader Engine, through resource version 140.
NOTE: this spec was originally written with Google Gemini, and later refined by implementing it into TorqueViewer and correcting against reference file data. Further fixes were added using GPT-4.6.
Atlas files are binary files used for paged terrain storage. They contain one or more Tables of Contents (TOCs), each holding chunk-reference records called stubs. The referenced chunks contain geometry, texture, or configuration payloads that may be loaded independently.
A single .atlas file can contain TOCs for geometry, opacity maps, shadow maps, and configuration data. All TOCs form a contiguous prefix, followed by the referenced chunk data. Chunk order is independent of stub order.
Highest resource payload version documented here: 140.
Geometry TOCs additionally serialize mGoalBatchSize before the common parent
TOC fields. The resource version controls stub and chunk fields such as bounds,
morph ordering, and stored normals.
This document primarily describes the multi-resource .atlas container. Section
9 separately specifies the older .chu geometry and .tqt texture formats that
can be converted into Atlas resources.
The v140 Atlas framing and layouts are confirmed by arcticBlended.atlas.
Historical format definitions establish the pre-v140 geometry layouts and the
CHU and TQT layouts.
For Atlas resource versions through 140, the generic file, TOC, stub-base, and resource-frame serialization is version-independent. Geometry payload changes occur at versions 101, 120, 130, and 140. Texture and config stubs/chunks have no known version-dependent branches through 140 and therefore retain the layouts documented in §§1b, 1c, 4, and 5.
Fields are serialized individually with no implicit C/C++ structure padding. Numeric values in the examined files and historical Torque streams are little-endian.
| Order | Type / size | Contents |
|---|---|---|
| 1 | U32 | Magic 0x534C5441 (ATLS in little-endian byte order) |
| 2 | U8 | NUM_TOCs, the number of TOCs that follow |
| 3 | Variable | TOCs 0 through NUM_TOCs-1; see §1 |
| 4 | Variable | Chunk data region, beginning after the last TOC stub; see §2 |
TOC slot indices follow the serialized TOC order and are zero-based. Chunk
frames do not have to follow stub order, be grouped by TOC, or occupy a
contiguous region. Each stub's offset and length are authoritative.
Some Atlas writers arrange chunks in a separately selected physical order to improve access locality. That ordering information is not serialized as part of a stub and cannot be reconstructed from the TOC alone.
Each TOC block is self-contained within the TOC region. The following layout applies to every TOC:
| Order | Part | Serialized layout |
|---|---|---|
| 1 | Type tag | tagLength:U8, followed by kindTag[tagLength] |
| 2 | Type-specific prefix | Zero or more fields selected by kindTag |
| 3 | Common TOC body | treeDepth:U32, stubCount:U32, csmVersion:U32, followed by stubs[stubCount] |
kindTag contains exactly tagLength bytes and has no trailing NUL. The known
canonical tag spellings are listed below.
csmVersion, formatVersion, and resourceVersion refer to the same serialized
version value.
kindTag |
Bytes between kindTag and the common TOC body |
|---|---|
Geom |
mGoalBatchSize:U32 |
Tex |
None |
Config |
None |
| Order | Type | Field | Meaning |
|---|---|---|---|
| 1 | U32 | treeDepth |
Levels numbered 0..treeDepth-1; zero for the observed Config TOC |
| 2 | U32 | stubCount |
Number of immediately following stubs |
| 3 | U32 | csmVersion |
Resource stub/chunk format version |
| 4 | Variable | stubs |
stubCount sequential type-specific entries |
Observed v140 TOC values in arcticBlended.atlas:
| Tag | Prefix | treeDepth |
stubCount |
csmVersion |
|---|---|---|---|---|
Geom |
mGoalBatchSize=1500 |
4 | 85 | 140 |
Tex |
— | 3 | 21 | 140 |
Tex |
— | 5 | 341 | 140 |
Config |
— | 0 | 1 | 140 |
The complete quadtree counts are consistent: depth 4 gives 85 stubs, depth 3
gives 21, and depth 5 gives 341. Config is not a quadtree, so its count is not
derived from treeDepth.
The file position of a stub is not stored in the stub.
| Order | Type | Field | Versions | Meaning |
|---|---|---|---|---|
| 1 | U32 | offset |
All | Absolute file offset to chunk data |
| 2 | U32 | length |
All | Complete chunk length |
| 3 | U32 | generation |
All | Modification counter |
| 4 | F32 | pos.x |
<101 |
Position X used before version 101 |
| 5 | F32 | pos.y |
<101 |
Position Y used before version 101 |
| 4 | Box3F | mBounds |
>=101 |
Six F32 values: minimum XYZ, then maximum XYZ |
| 5 | U8 | sentinel |
>=101 |
Must equal 0xD0 |
| Version | Serialized size |
|---|---|
<101 |
20 bytes |
>=101 |
37 bytes |
For version 101 and later, 0xD0 is the final byte of the geometry stub.
It does not mark the end of the referenced geometry chunk.
| Order | Type | Field | Meaning |
|---|---|---|---|
| 1 | U32 | offset |
Absolute file offset to chunk data |
| 2 | U32 | length |
Complete chunk length |
| 3 | U32 | generation |
Modification counter |
Serialized size: 12 bytes. Quadtree position and resource dependencies are derived from context rather than serialized in this record.
| Order | Type | Field | Meaning |
|---|---|---|---|
| 1 | U32 | offset |
Absolute file offset to chunk data |
| 2 | U32 | length |
Complete chunk length |
| 3 | U32 | generation |
Modification counter |
| 4 | char[8] |
name |
Fixed-width, NUL-padded identifier |
Serialized size: 20 bytes. Config TOCs are named lists rather than quadtrees.
The stub array stores complete tree levels consecutively, beginning with the
root. Within level L, coordinates are linearized with X as the major axis and
Y as the minor axis.
nodeCount(d) = 0x55555555 & ((1 << (d*2)) - 1)
= sum of 4^level for level 0..d-1
nodeID(level, x, y) = nodeCount(level) + (x << level) + y
Every stub references one framed chunk. Frames may appear in any physical order; the TOC references, rather than adjacency or stub order, locate them.
A stub's offset points at the beginning of this frame, and its length
covers the complete frame:
| Order | Type / size | Field | Meaning |
|---|---|---|---|
| 1 | U32 | outerMarker |
ATSP |
| 2 | U32 | bodySize |
Resource payload byte count only |
| 3 | U32 | typeHead |
Resource-specific head marker |
| 4 | bodySize bytes |
body |
Resource payload; see §§3–5 |
| 5 | U32 | typeTail |
Resource-specific tail marker |
Therefore stub.length == bodySize + 16. The next framed chunk can begin
immediately after typeTail; this was observed in arcticBlended.atlas.
Confirmed first geometry frame at file offset 0x1E1A:
| Bytes | Field | Decoded value |
|---|---|---|
41 54 53 50 |
outerMarker |
ATSP |
93 74 05 00 |
bodySize |
0x57493 (357523) |
61 67 63 68 |
typeHead |
agch |
| Variable | Body | Geometry resource payload |
61 67 63 74 |
typeTail |
agct |
Its TOC reference length is 0x574A3 (357539), exactly bodySize + 16.
Every Atlas chunk frame ends with its resource-specific typeTail. This tail is
the final U32 of the complete frame and is not included in bodySize. The tail
begins exactly bodySize bytes after the end of typeHead.
| Chunk kind | Frame begins with | Body begins after | Final field inside body | Frame ends with |
|---|---|---|---|---|
Geometry <120 |
ATSP |
agch |
No body sentinel; end is determined by bodySize |
agct |
Geometry >=120 |
ATSP |
agch |
U32 0xCEFEDEEF |
agct |
| Texture | ATSP |
TexH |
No body sentinel; encoded image ends at bodySize |
TexT |
| Config | ATSP |
CfgH |
No body sentinel; final entry ends at bodySize |
CfgT |
The serialized marker values are:
| Scope | Position | FourCC | U32 value |
|---|---|---|---|
| All chunks | Frame start | ATSP |
0x50535441 |
| Geometry | Body head | agch |
0x68636761 |
| Geometry | Frame end | agct |
0x74636761 |
| Texture | Body head | TexH |
0x48786554 |
| Texture | Frame end | TexT |
0x54786554 |
| Config | Body head | CfgH |
0x48676643 |
| Config | Frame end | CfgT |
0x54676643 |
Texture and config markers are confirmed by arcticBlended.atlas.
Geometry and Config resource bodies begin with previousChunk (U32), an
absolute offset to the previous chunk used for history/recovery, or zero for
the first chunk. Texture bodies begin directly with their one-byte image format
and do not contain previousChunk.
previousChunk is the first U32 in the payload. Stub offset and length are
stored in the TOC and are not repeated in the body.
| Order | Type / size | Field | Versions |
|---|---|---|---|
| 1 | U32 | previousChunk |
All |
| 2 | Box3F (24 bytes) | mBounds |
>=120 |
| 3 | U32 | mIndexCount |
All |
| 4 | U32 | mSkirtSkipCount |
All |
| 5 | mIndexCount × U16 |
mIndex |
All |
| 6 | U32 | mVertCount |
All |
| 7 | Version-dependent | Vertices | All |
| 8 | Box3F (24 bytes) | mBounds |
101–119 only |
| 9 | U8 | colFlag |
>=120 |
| 10 | Conditional | Collision data | >=120 and colFlag == 0xDF |
| 11 | U32 | postColSentinel |
>=120; must equal 0xCEFEDEEF |
Versions below 101 do not serialize chunk bounds; they must be calculated from the decoded mesh.
For version 120 and later, postColSentinel is the final four bytes of the
geometry body, whether or not collision data is present. The geometry frame
tail agct follows immediately after it. Geometry bodies before version 120
have no internal ending sentinel; bodySize locates the following agct tail.
| Type / count | Field | Meaning |
|---|---|---|
| U32 | mIndexCount |
Number of U16 indices |
| U32 | mSkirtSkipCount |
Number of trailing skirt indices |
mIndexCount × U16 |
mIndex |
Triangle-list vertex indices |
mIndexCount - mSkirtSkipCount is the non-skirt index count. The remaining
indices are skirt triangles used for LOD blending.
Every vertex begins with these fields:
| Order | Type | Field |
|---|---|---|
| 1 | 3 × F32 | point.x, point.y, point.z |
| 2 | 2 × F32 | texCoord.x, texCoord.y |
Morph-field order depends on the version:
| Version | Following fields, in serialized order |
|---|---|
<130 |
pointMorphOffset.x/y/z, then texMorphOffset.x/y |
130–139 |
texMorphOffset.x/y, then pointMorphOffset.x/y/z |
>=140 |
texMorphOffset.x/y, pointMorphOffset.x/y/z, then normal.x/y/z |
| Version | Bytes per vertex | Notes |
|---|---|---|
<101 |
40 | Point, texture coordinate, and both morph offsets |
101–119 |
40 | Bounds remain per chunk, not per vertex |
120–129 |
40 | Collision data follows the complete vertex array |
130–139 |
40 | Morph order swapped; same size |
>=140 |
52 | Adds three normal floats |
For versions below 140, normals are not serialized and normalize to (0,0,1).
mTCBounds is not serialized.
colFlag |
Meaning |
|---|---|
0xDF |
Collision block is present |
0x0F |
No collision block |
When collision is present:
| Order | Type / count | Field | Meaning |
|---|---|---|---|
| 1 | U32 | mColTreeDepth |
Collision quadtree depth, commonly 4 |
| 2 | nodeCount(mColTreeDepth) × {F32,F32} |
mColTree |
Per-node minimum and maximum triangle Z |
| 3 | U32 | mColOffsetCount |
Number of bin offsets |
| 4 | mColOffsetCount × U16 |
mColIndicesOffsets |
Offsets into mColIndicesBuffer |
| 5 | U32 | mColIndexCount |
Number of collision-index entries |
| 6 | mColIndexCount × U16 |
mColIndicesBuffer |
Triangle offsets into mIndex; each offset selects three consecutive vertex indices |
Triangle lists within each bin are terminated by 0xFFFF; these values end
individual collision-bin lists, not the chunk. Regardless of colFlag, every
version-120+ geometry body ends with U32 0xCEFEDEEF, followed by the outer
frame tail agct.
| Order | Type / size | Field | Meaning |
|---|---|---|---|
| 1 | U8 | mFormat |
Image encoding identifier |
| 2 | Remaining body bytes | Image data | Complete encoded image stream |
The encoded image occupies every remaining byte of the declared body. There is
no texture-body footer or sentinel. The frame-ending U32 TexT follows at the
first byte after the body.
mFormat |
Encoding | Payload |
|---|---|---|
| 0 | JPEG | Lossy image without stored mipmaps |
| 1 | PNG | Lossless image without stored mipmaps |
| 2 | DDS | DDS magic, DDS_HEADER, optional DX10 extension, pixels and mipmaps |
A double-sized tile may contain both an opacity map and lightmap, as identified by the owning texture TOC.
JPEG and PNG retain their standard encoded channel definitions. However, some Atlas content was produced from bitmap data using BGR or BGRA component order. A standard decoder still returns components in RGB or RGBA positions, but the decoded red and blue values may therefore be semantically reversed for that Atlas content.
| Encoded payload | Channel interpretation after decoding |
|---|---|
| JPEG/PNG with normal RGB source order | Use decoded R,G,B[,A] directly |
| JPEG/PNG produced from BGR/BGRA bitmap data | Convert decoded B,G,R[,A] to R,G,B[,A] |
| DDS | Use the DDS pixel-format masks or DXGI format; do not infer BGR order from the Atlas convention |
This is an Atlas content convention rather than a change to the JPEG or PNG formats. An incorrect interpretation is readily visible as a red/blue swap, often giving terrain an excessive blue tint.
Atlas texture placement reflects one tree axis relative to terrain geometry. The reflection applies to the complete virtual texture, not independently to the contents of arbitrary tiles.
For texture level L, let N = 2^L. If a geometry node maps to coordinates
(xL,yL) at that texture level, its texture stub and local coordinates are:
| Value | Mapping |
|---|---|
| Texture stub X | N - 1 - xL |
| Texture stub Y | yL |
| Local U | N * texCoord.x - yL |
| Local V | N * texCoord.y + xL + 1 - N |
When geometry and texture levels differ, xL and yL are the geometry-node
coordinates projected to level L. The stub-X and local-V relations describe
the same reflected tree axis.
| Order | Type / size | Field | Meaning |
|---|---|---|---|
| 1 | U32 | previousChunk |
Previous chunk offset, or zero |
| 2 | U32 | entryCount |
Number of key/value pairs |
| 3 | Repeated entryCount times |
Entries | Each entry uses the layout below |
| Entry order | Type / size | Field | Meaning |
|---|---|---|---|
| 1 | U32 | keyLength |
Key byte count |
| 2 | keyLength bytes |
key |
Key bytes; no trailing NUL is included |
| 3 | U32 | valueLength |
Value byte count |
| 4 | valueLength bytes |
value |
Value bytes; no trailing NUL is included |
Notes:
- Config chunks are not quadtrees and have no level/position.
- Entries are stored newest first.
- Config bodies have no internal footer or sentinel. After the final value (or
after
entryCountwhen it is zero), the frame-ending U32CfgTfollows at the declared body boundary.
The stub array is divided into consecutive level ranges. Level L contains
4^L entries, and its first entry follows every entry from levels 0 through
L-1. Coordinates within the level use x * 2^L + y; coordinate bits are not
interleaved.
totalStubs = 0x55555555 & ((1 << (d*2)) - 1)
base = 0x55555555 & ((1 << (level*2)) - 1)
index = base + (x << level) + y
Depth-5 example:
| Level | Nodes at level | Cumulative stubs |
|---|---|---|
| 0 | 1 | 1 |
| 1 | 4 | 5 |
| 2 | 16 | 21 |
| 3 | 64 | 85 |
| 4 | 256 | 341 |
The root (0,0,0) has index 0. At the highest level, use
base + (x << (treeDepth-1)) + y.
The chunk for stub index i is located through its TOC entry:
| Type | Field | Meaning |
|---|---|---|
| U32 | offset |
Absolute file offset to the chunk |
| U32 | length |
Complete chunk byte length |
The referenced data begins at offset, spans length bytes, and includes the
complete outer frame described in §2.
| Version | Geometry format change |
|---|---|
| 101 | Adds mBounds to geometry stubs and adds chunk bounds after the vertex array. Earlier stubs contain two position F32 values, and earlier chunks calculate bounds from mesh data. |
| 120 | Moves chunk bounds after previousChunk; adds collision flag/data and mandatory 0xCEFEDEEF footer. |
| 130 | Swaps the serialized order of point- and texture-morph offsets. |
| 140 | Adds three F32 normal components per vertex. |
The following rules describe the data implied by fields omitted from earlier versions. They allow every documented version to be represented with the v140 geometry field set without changing the serialized layout.
| Source version | Canonical interpretation |
|---|---|
| All through 140 | The common ATSP framing and resource markers apply unchanged. |
<101 |
Bounds are derived from the vertices; the derived bound supplies both the canonical stub bound and chunk bound. |
101–119 |
The chunk bound is the value serialized after the vertex array. |
<120 |
Collision data is absent. The v120 footer has no serialized counterpart. |
<130 |
The first morph vector is pointMorphOffset; the second is texMorphOffset. |
<140 |
The canonical normal for the omitted field is (0,0,1). |
| Texture/config through 140 | Their serialized layouts are version-independent. |
Confirmed prefix of arcticBlended.atlas (4 TOCs):
| Offset | Contents |
|---|---|
0x0000 |
Magic ATLS |
0x0004 |
U8 NUM_TOCS = 4 |
0x0005 |
tagLength=4, kindTag="Geom" |
0x000A |
mGoalBatchSize=1500, treeDepth=4, stubCount=85, formatVersion=140 |
0x001A |
First geometry stub |
0x0C63 |
End of 85 v140 geometry stubs; tagLength=3, kindTag="Tex" |
0x0C67 |
treeDepth=3, stubCount=21, formatVersion=140; no geometry prefix |
0x0C73 |
First texture stub |
0x0D6F |
End of 21 12-byte texture stubs; tagLength=3, kindTag="Tex" |
0x0D73 |
treeDepth=5, stubCount=341, formatVersion=140 |
0x0D7F |
First texture stub |
0x1D7B |
End of 341 12-byte texture stubs; tagLength=6, kindTag="Config" |
0x1D82 |
treeDepth=0, stubCount=1, formatVersion=140 |
0x1D8E |
Config ChunkRef, followed by fixed char[8] name schema |
0x1DA2 |
End of all confirmed TOCs |
All four TOCs and all 448 referenced frames in this sample are structurally consistent. Their current chunk references form a contiguous region from the first chunk through the exact end of the file. Contiguity is an observed property of this file, not a requirement imposed on every Atlas file.
CHU and TQT are standalone import formats. They are not older revisions of the Atlas container, and CHU version 400 is unrelated to Atlas resource version 140. All numeric fields below are little-endian and tightly serialized.
| Bytes | Format | Contents |
|---|---|---|
41 54 4C 53 |
Atlas (ATLS) |
Multi-resource TOCs and ATSP chunks |
43 48 55 33 |
CHU (CHU3) |
One quantized geometry tree |
74 71 74 00 |
TQT (tqt\0) |
One DDS texture tree |
CHU/TQT have no Atlas TOCs, ATSP frames, generation counters, or history
links. Their offsets refer directly to CHU chunks or TQT tiles and are not Atlas
chunk-frame offsets.
CHU contains one geometry hierarchy and no texture/config data.
CHU header — 28 bytes:
| Offset | Type | Field | Meaning |
|---|---|---|---|
0x00 |
U32 | fourCC |
CHU3 |
0x04 |
S16 | version |
Must be 400 |
0x06 |
S16 | treeDepth |
Geometry-tree levels |
0x08 |
F32 | baseMaxError |
Probable LOD-error value; exact use is unconfirmed |
0x0C |
F32 | verticalScale |
World Z units per quantized unit |
0x10 |
F32 | leafDimensions |
World X/Y width of one leaf chunk |
0x14 |
U32 | chunkCount |
Number of following stubs |
0x18 |
U32 | colTreeDepth |
Collision-tree depth used by flagged chunks |
Expected relationships:
| Value | Formula / rule |
|---|---|
chunkCount |
nodeCount(treeDepth) for a complete tree |
| Terrain width/height | leafDimensions * 2^(treeDepth-1) |
leafDimensions |
Finite and positive |
verticalScale |
Normally finite and positive |
CHU stub — 37 bytes, repeated chunkCount times immediately after the header:
| Relative offset | Type | Field | Meaning |
|---|---|---|---|
0x00 |
U32 | sentinel |
Must be 0xDEADBEEF |
0x04 |
S32 | label |
Logical node label |
0x08 |
4 × S32 | neighbors |
Inferred same-level neighbor labels; direction order unknown |
0x18 |
U8 | level |
Root is level 0 |
0x19 |
S16 | x |
Node X coordinate |
0x1B |
S16 | y |
Node Y coordinate |
0x1D |
S16 | min |
Inferred quantized conservative minimum Z |
0x1F |
S16 | max |
Inferred quantized conservative maximum Z |
0x21 |
U32 | chunkOffset |
Absolute offset to 0xBEEF1234 chunk sentinel |
Stub records may be physically unordered. Labels identify logical tree nodes and
must be unique across the complete tree. Negative neighbor values most likely
mean “no neighbor”; the direction represented by each neighbor-array position
is not established. Stub min and max most likely contain conservative Z
bounds in units scaled by verticalScale.
CHU chunk — structurally sized, with no length prefix:
| Order | Type/count | Field | Rule |
|---|---|---|---|
| 1 | U32 | sentinel |
Must be 0xBEEF1234 |
| 2 | U16 | vertCount |
Number of quantized vertices |
| 3 | vertCount × 4 × S16 |
vertices |
Per vertex: x,y,z,morph |
| 4 | S32 | indexCount |
Must be non-negative |
| 5 | indexCount × U16 |
indices |
Geometry indices |
| 6 | U32 | triCount |
Probable source triangle count; exact use is unconfirmed |
| 7 | U8 | colDataFlag |
Must be 0 or 1 |
| 8 | conditional | Collision block | Present only when flag is 1 |
| 9 | U32 | footer |
Must be 0xB1E2E3F4 |
The U32 footer 0xB1E2E3F4 is always the final field of a CHU chunk. It follows
colDataFlag directly when the flag is zero, or follows the complete collision
block when the flag is one. CHU chunks have no length field and no additional
tail after this footer.
CHU collision block (colDataFlag == 1):
| Order | Type/count | Field | Rule / likely meaning |
|---|---|---|---|
| 1 | nodeCount(colTreeDepth) × {S16,S16} |
colTreeNodes |
Inferred quantized min/max Z |
| 2 | U32 | collisionMark |
Must be 0xB33FD34D |
| 3 | colGridCount × U16 |
colOffsets |
Likely U16-element offsets into the buffer |
| 4 | U32 | bufferSize |
Number of following U16 entries |
| 5 | bufferSize × U16 |
colIndexBuffer |
Likely triangle IDs; 0xFFFF probably terminates a cell |
0xB33FD34D separates the collision-tree nodes from the collision-grid data;
it does not end the CHU chunk. Likewise, any 0xFFFF values terminate
individual collision-grid lists rather than the chunk itself. The enclosing CHU
chunk still ends only at footer 0xB1E2E3F4.
| Derived collision value | Expression |
|---|---|
| Collision-node count | nodeCount(colTreeDepth) |
| Collision-grid width | 2^(colTreeDepth-1) |
| Collision-grid cell count | 2^(2*(colTreeDepth-1)) |
When colDataFlag is 1, colTreeDepth must be nonzero so that the derived
collision dimensions are defined. The exact token semantics of colOffsets
and colIndexBuffer, and their direct equivalence to Atlas collision data, are
not established.
The CHU hierarchy maps to one Atlas geometry TOC. Atlas node (level,x,y) uses
CHU label nodeID(level,y,x), preserving the CHU/Atlas X/Y transpose.
| Atlas geometry property | CHU source or mapping |
|---|---|
treeDepth |
CHU treeDepth |
stubCount |
CHU chunkCount |
mGoalBatchSize |
No CHU equivalent; selected when an Atlas file is written |
| Terrain width and height | leafDimensions * 2^(treeDepth-1) |
Chunk width at level L |
leafDimensions * 2^((treeDepth-1)-L) |
| Chunk origin | Chunk width multiplied by stub X and Y |
generation and previousChunk |
No CHU equivalent; initialize to zero |
For each vertex, let size be the chunk width and origin its world-space XY
origin:
| Atlas vertex field | CHU mapping |
|---|---|
point.x |
((x / 16384)*0.5 + 0.5)*size + origin.x |
point.y |
((y / 16384)*0.5 + 0.5)*size + origin.y |
point.z |
z * verticalScale |
texCoord.x |
point.y / terrainHeight |
texCoord.y |
1 - point.x / terrainWidth |
pointMorphOffset |
(0, 0, morph*verticalScale) |
texMorphOffset |
(0, 0) |
normal |
(0, 0, 1) |
Quantized X/Y values outside [-16384,+16384] are retained because they may
represent skirts or overlap. Geometry indices map directly and must refer to
existing vertices. CHU has no confirmed Atlas mSkirtSkipCount equivalent, so
the canonical mapping uses zero.
Each mapped chunk bound contains its own decoded vertices and the bounds of its
four children. Consequently, bounds are derived from the leaves toward the
root, then stored identically in the Atlas stub and chunk. The mapped stub uses
sentinel 0xD0. CHU collision is not field-compatible with Atlas collision; a
mapping either regenerates Atlas collision from geometry or represents the
chunk without Atlas collision data.
TQT contains one texture hierarchy and no geometry/config data.
TQT header — 16 bytes:
| Offset | Type | Field | Meaning |
|---|---|---|---|
0x00 |
U32 | fourCC |
tqt\0 |
0x04 |
U32 | version |
TQT format version; no version-dependent layouts are known |
0x08 |
U32 | treeDepth |
Texture-tree levels |
0x0C |
U32 | tileSize |
Inferred intended square top-mip size |
The header is followed immediately by:
| Type/count | Field | Meaning |
|---|---|---|
nodeCount(treeDepth) × U32 |
offsets |
Absolute tile offsets |
The offset table is ordered by tree level and uses transposed horizontal
coordinates: logical node (level,x,y) uses entry nodeID(level,y,x).
TQT tile at each referenced offset:
| Relative offset | Type/count | Field | Meaning |
|---|---|---|---|
0x00 |
U32 | chunkSize |
DDS byte count; excludes this U32 |
0x04 |
chunkSize bytes |
ddsBytes |
Complete stream beginning with DDS |
A TQT tile is length-delimited and has no ending sentinel. Its final byte is
the final byte of ddsBytes, so the complete tile range is
[tileOffset, tileOffset + 4 + chunkSize).
The DDS header supplies dimensions, pixel format, mip count, and payload bounds.
tileSize most likely describes the intended square top-mip dimension; the DDS
header is authoritative if the values disagree.
TQT maps to one Atlas texture TOC. It contains no field identifying the tree as an opacity or shadow map, so the default mapping is a base-terrain texture tree.
| Atlas texture property | TQT source or mapping |
|---|---|
treeDepth |
TQT treeDepth |
stubCount |
nodeCount(treeDepth) |
Stub (level,x,y) |
Logical tree position after the table-coordinate transpose |
| Texture encoding | DDS (mFormat=2) |
| Texture payload | Exact TQT ddsBytes |
Stub generation |
No TQT equivalent; initialize to zero |
CHU and TQT contain no serialized cross-reference to each other. By convention, a same-directory TQT with the same filename stem supplies textures for a CHU; extension matching is case-insensitive. The pair maps to one Atlas geometry TOC and one Atlas texture TOC. Either file remains independently meaningful when no companion exists.
The TQT DDS stream maps directly to an Atlas texture chunk with mFormat=2.
Transcoding it to JPEG or another Atlas texture encoding is optional and is not
part of either source format.
The following conditions make the serialized structure invalid:
| Condition | Requirement |
|---|---|
| Magic and sentinels | Must equal their values specified above |
CHU indexCount |
Must be non-negative |
CHU colDataFlag |
Must be 0 or 1 |
| Counts and referenced ranges | Every implied byte range must lie wholly within the file |
| CHU logical labels | Must be unique and cover the complete declared tree |
| TQT tile payload | Must begin with DDS and contain a complete DDS stream |
| Distinct TQT tile ranges | Must not partially overlap |
Multiple nodes may contain identical offsets, in which case they reference the same chunk or tile. Physical order, monotonic offsets, adjacency, and complete coverage through EOF are not format requirements.
The following are consistency checks rather than structural requirements, because the exact semantics of these fields are not fully established:
| Comparison | Interpretation |
|---|---|
CHU stub min/max versus decoded bounds |
A difference may indicate conservative bounds or an incorrect interpretation |
CHU triCount versus the index-derived triangle count |
A difference may indicate CHU-specific triangle accounting |
TQT tileSize versus DDS dimensions |
The DDS header defines the encoded image dimensions |
| Type | Definition |
|---|---|
| U8 | 8-bit unsigned integer |
| U16 | 16-bit unsigned integer |
| U32 | 32-bit unsigned integer |
| S16 | 16-bit signed integer |
| S32 | 32-bit signed integer |
| F32 | 32-bit IEEE-754 floating-point value |
| Type | Fields | Meaning |
|---|---|---|
Point2F |
x:F32, y:F32 |
Floating-point 2D point |
Point2I |
x:S32, y:S32 |
Integer 2D point |
Point3F |
x:F32, y:F32, z:F32 |
Floating-point 3D point |
Box3F |
min:Point3F, max:Point3F |
3D bounding box |
RectF |
point:Point2F, extent:Point2F |
2D region |
These are the logical geometry-vertex fields represented by the versioned
serialization in §3. Earlier versions omit normal but otherwise represent
the same fields in a different order where noted.
| Field | Type | Meaning |
|---|---|---|
point |
Point3F | 3D vertex position |
texCoord |
Point2F | Texture coordinate |
texMorphOffset |
Point2F | Texture-coordinate morph offset |
pointMorphOffset |
Point3F | Position morph offset |
normal |
Point3F | Surface normal, serialized from v140 |