Skip to content
Lukas Dürrenberger edited this page Oct 8, 2026 · 3 revisions

CZI - Color Zone Index Maps

CZI files or Color Zone Index Maps are used to define the masked areas of a texture that the game's Atlas Builder uses to apply colors like war paints to only certain areas of a texture.

A variation is used for pattern maps too (.czip files). Patterns are saved from the patterns tab of the DDS exporter and store 2 bits per pixel.

The 1962 install has 697 .czi files (60 version 1, 32 version 2, 605 version 3) and 80 .czip files, all version 3. FauFau reads every one of them.

Format

Little endian. The whole file is a header, a table of mip levels, and then one compressed block per mip level.

Header

Field Type Notes
magic char[4] CZIM
version int32 1 to 3
width int32 Should match the texture this is paired with
height int32 Should match the texture this is paired with
isPattern uint8 Version 2 and up only. 1 for a .czip, 0 otherwise
patternUsage uint8 Version 3 only. 0 for a .czi, see Notes
numMipLevels int32 Should match the mip count of the paired texture

Note that version 1 has neither of the two bytes and version 2 only has isPattern, so the header is 20, 21 or 22 bytes long depending on the version. The client refuses version 2 files with isPattern set.

MipInfo

numMipLevels of these, one per level:

Field Type Notes
offset int32 Offset of this level in the decompressed data, i.e. the sum of all preceding size values
size int32 Decompressed size of this level

The levels are stored smallest first, the last one has the full size.

CompressedBlock

numMipLevels of these, in the same order:

Field Type Notes
length int32 Compressed length
data byte[length] zlib stream, inflates to MipInfo.size bytes

Each block is a complete zlib stream: a 2 byte header (78 9C when written by our tooling), the deflate data, and a big endian Adler-32 of the uncompressed bytes. Levels are compressed independently, so a single level can be replaced without touching the others as long as the MipInfo offsets after it are fixed up.

Mip data

In a .czip the largest level is exactly width * height / 4 bytes, i.e. 2 bits per pixel.

The .czi levels are not a plain bitmap. The largest level is somewhere between 6% and 25% of width * height bytes and varies per file, so the contents use some other encoding that hasn't been decoded yet.

Reference

  • Czi.bt - 010 Editor template, only handles version 3
  • FauFau reads and writes it
  • Client: the loader is at 0x015e6190 in build 1962.

Notes

  • The width and height should match the texture this is paired with.
  • It should have the same number of mip levels as the texture it is paired with too.
  • Creating a blank mask is just a header with numMipLevels of 0, with levels appended afterwards.
  • patternUsage is 1 in 69, 2 in 1 and 4 in 10 of the 1962 patterns. That fits a mask with one bit per slot, like the type_flags of dbvisualrecords::CziPattern (see Warpaint Pattern Usage), but it hasn't been confirmed. The SDB table also carries DisplayFlags, Style, CziTextureId and CziAssetId per pattern. See also Warpaints.

Clone this wiki locally