Textures¶
What the qc calls
$texturegroup, and what everyone else calls materials.An mdl does not contain textures, or even material definitions. Each
mstudiotexture_tis just a name, and the engine finds the real.vmtby trying that name under each of the model’s material search paths in turn. Those paths are the cdtextures, and they are stored in the one genuinely awkward way the format has to offer.cdtextures are a double indirection.
studiohdr_t.cdtextureindexpoints at an array ofnumcdtexturesints, and each of those is itself an offset to a string. The SDK accessor is worth reading twice:inline char *pCdtexture( int i ) const { return (((char *)this) + *((int *)(((byte *)this) + cdtextureindex) + i)); };
thisis thestudiohdr_tin both halves, so unlike almost every other index in the format, both hops are relative to the file base rather than to the containing structure – there is no intermediate struct to be relative to.localnodenameindexworks the same way.The skin table is a matrix.
studiohdr_t.skinindexpoints atshort[numskinfamilies][numskinref]. A mesh’smaterialfield is not an index into the texture array directly: it is a column in this table, and the row is the skin the entity is using.numskinrefis the row width and is usually, but not necessarily, the texture count. This is how a model shows red and blu variants of one mesh without duplicating geometry.material and clientmaterial are runtime pointers, written into the mapped file image by the engine, and zero on disk. They are 4 bytes here because the on-disk layout is the 32 bit one; the
unusedarray absorbs the difference on 64 bit so that the structure stays 64 bytes on both.