vtex_idx - themeldingwars/Documentation GitHub Wiki
Virtual texture index.
static.vtex_idx is the index for the static.vtex0 .. static.vtex6 virtual texture
files. It answers two questions: which texture assets exist in the virtual texture and where
they sit in it, and where an individual tile lives inside a given static.vtexN.
010 Editor Templates
- vtex_idx.bt
- vtex_idx.tileInfo.bt - run this on a decompressed tile info block
Implementations
- FauFau reads it with
VTexIndex, including the FastLZ tables
Format
Little endian.
Header
| Field | Type | Notes |
|---|---|---|
version |
uint32 |
Always 1 |
imageInfoCount |
uint32 |
ImageInfo
imageInfoCount of these, 76 bytes each:
| Field | Type | Notes |
|---|---|---|
hash |
uint32[3] |
Three texture file hashes, see Image info hashes |
transform |
float[9] |
|
bounds |
uint16[4] |
|
offset |
uint32[4] |
|
crc |
uint32 |
The 1962 index has 4'206 of them. What transform, bounds, offset and crc mean exactly
hasn't been worked out yet.
TileInfo blocks
Exactly seven blocks follow the image infos, one for each static.vtexN, in order from 0
to 6:
| Field | Type | Notes |
|---|---|---|
compressedLength |
uint32 |
|
compressedData |
byte[compressedLength] |
FastLZ, same as CHUNK_GEOMETRY uses |
The FastLZ level is in the upper 3 bits of the first byte, plus one. All seven blocks of the 1962 index use level 2.
Each block decompresses to a flat array of 16 byte rows, with no count in front of it, so the row count is simply the decompressed length divided by 16:
| Field | Type | Notes |
|---|---|---|
offset |
uint64 |
Offset of the tile inside static.vtexN, 0xFFFFFFFFFFFFFFFF if the tile doesn't exist |
crc |
uint32 |
CRC-32 of the decoded tile, see vtex |
size |
uint32 |
Size of the tile data |
The tables are complete, level 0 has a row for each of 1024 x 1024 tiles and every level after it a quarter of that, down to 16 x 16 at level 6:
| Level | Rows | Existing tiles in 1962 |
|---|---|---|
| 0 | 1'048'576 | 732'743 |
| 1 | 262'144 | 185'318 |
| 2 | 65'536 | 46'839 |
| 3 | 16'384 | 11'765 |
| 4 | 4'096 | 2'958 |
| 5 | 1'024 | 745 |
| 6 | 256 | 192 |
So to pull a single tile out of the virtual texture, decompress the tile info block for the
mip level you want, take the row for the tile, skip it if the offset is all FF, and slice
size bytes at offset out of the matching static.vtexN. How the tile is decoded from
there is on the vtex page.
Image info hashes
Each imageinfo entry contains three hashes, each pointing to a different texture file. The
hash is a rotate-and-add over the ascii of the asset's path in the 00113000\00113473
form, i.e. the folder is the id rounded down to the nearest thousand. This is the same hash
the client uses, 113473 hashes to 4264839707:
public static uint GenerateHash(int textureAssetId)
{
string str = textureAssetId.ToString().PadLeft(8, '0');
str = str.Substring(0, str.Length - 3) + "000" + "\\" + str;
byte[] bytes = Encoding.ASCII.GetBytes(str);
uint hash = 0;
foreach (byte b in bytes)
{
hash = (hash << 7) | (hash >> (32 - 7));
hash += b;
}
return hash;
}
// assault
uint h1 = GenerateHash(113473);
uint h2 = GenerateHash(113475);
uint h3 = GenerateHash(113476);
Since the hash is over a fixed shape of string derived from a number, it can be reversed by
brute force over the plausible asset id range rather than by cracking the hash. FauFau has it
as VTexIndex.HashAssetPath.