Model (.mdl)
This documentation is incomplete.
Represents a visual model in the game, from furniture to the world, and characters.
Reading #
First read the model header, which contains some information like the data offsets:
struct ModelFileHeader {
uint32_t version;
uint32_t stackSize;
uint32_t runtimeSize;
uint16_t vertexDeclarationCount;
uint16_t materialCount;
uint32_t vertexOffsets[3];
uint32_t indexOffsets[3];
uint32_t vertexBufferSize[3];
uint32_t indexBufferSize[3];
uint8_t lodCount;
uint8_t indexBufferStreamingEnabled;
uint8_t hasEdgeGeometry;
uint8_t _unknown1;
};
Immediately after this header begins the vertex declarations which describe how vertex data is sequenced and eventually read. These structures define the basis of the vertex declarations:
enum VertexType : uint8_t {
Invalid = 0,
Single3 = 2,
Single4 = 3,
UInt = 5,
ByteFloat4 = 8,
Half2 = 13,
Half4 = 14,
};
enum VertexUsage : uint8_t {
Position = 0,
BlendWeights = 1,
BlendIndices = 2,
Normal = 3,
UV = 4,
Tangent = 5,
BiTangent = 6,
Color = 7,
};
struct VertexElement {
uint8_t stream;
uint8_t offset;
VertexType vertexType;
VertexUsage vertexUsage;
uint8_t usageIndex;
uint8_t unknown[3];
};
For every vertex declaration (the count in vertexDeclarationCount
) first read a single VertexElement
. Then keep reading a VertexElement
(and keeping these in a buffer) until VertexElement::stream
is 0xFF
(or 255 in decimal.) This implies an “end of stream” and that’s the end of that declaration. Before reading the next declaration you need to advance your cursor 17 + 8 - (elements + 1) * 8
where elements
is the amount of valid VertexElement
s you just read.