User Guide

A4 Programmer’s Manual © Conitec 2000 12
At offset
basetri = baseverts + numskinverts * sizeof(uvvert_t)
in the .MDL file you will find the
triangle list.
MDL frames
A model contains a set of animation frames, which can be used in relation with the behavior of the
modeled entity, so as to display it in various postures (walking, attacking, spreading its guts all
over the place, etc). Basically the frame contains of vertex positions and normals. Because models
can have ten thousands of vertices and hundreds of animation frames, vertex posistion are packed,
and vertex normals are indicated by an index in a fixed table, to save disk and memory space.
Each frame vertex is defined by a 3D position and a normal for each of the 3D vertices in the model.
In the MDL3 format, the vertices are always packed as bytes; in the MDL4 format that is used by the
A5 engine they can also be packed as words (unsigned shorts). Therefore the MDL4 format allows
more precise animation of huge models, and inbetweening with less distortion.
typedef struct {
byte rawposition[3]; // X,Y,Z coordinate, packed on 0..255
byte lightnormalindex; // index of the vertex normal
} mdl_trivertxb_t;
typedef struct {
unsigned short rawposition[3]; // X,Y,Z coordinate, packed on 0..65536
byte lightnormalindex; // index of the vertex normal
byte boneindex; // index of the bone this vertex belongs to
} mdl_trivertxs_t;
To get the real X coordinate from the packed coordinates, multiply the X coordinate by the X scaling
factor, and add the X offset. Both the scaling factor and the offset for all vertices can be found in the
mdl_header
struct. The formula for calculating the real vertex positions is:
float position[i] = (scale[i] * rawposition[i] ) + offset[i];
The lightnormalindex field is an index to the actual vertex normal vector. This vector is the average
of the normal vectors of all the faces that contain this vertex. The normal is necessary to calculate
the Gouraud shading of the faces, but actually a crude estimation of the actual vertex normal is
sufficient. That's why, to save space and to reduce the number of computations needed, it has been
chosen to approximate each vertex normal.
The ordinary values of lightnormalindex are comprised between 0 and 161, and directly map into
the index of one of the 162 precalculated normal vectors:
float lightnormals[162][3] = {
{-0.525725, 0.000000, 0.850650}, {-0.442863, 0.238856, 0.864188}, {-0.295242, 0.000000, 0.955423},
{-0.309017, 0.500000, 0.809017}, {-0.162460, 0.262866, 0.951056}, {0.000000, 0.000000, 1.000000},
{0.000000, 0.850651, 0.525731}, {-0.147621, 0.716567, 0.681718}, {0.147621, 0.716567, 0.681718},
{0.000000, 0.525731, 0.850651}, {0.309017, 0.500000, 0.809017}, {0.525731, 0.000000, 0.850651},
{0.295242, 0.000000, 0.955423}, {0.442863, 0.238856, 0.864188}, {0.162460, 0.262866, 0.951056},
{-0.681718, 0.147621, 0.716567}, {-0.809017, 0.309017, 0.500000}, {-0.587785, 0.425325, 0.688191},
{-0.850651, 0.525731, 0.000000}, {-0.864188, 0.442863, 0.238856}, {-0.716567, 0.681718, 0.147621},
{-0.688191, 0.587785, 0.425325}, {-0.500000, 0.809017, 0.309017}, {-0.238856, 0.864188, 0.442863},
{-0.425325, 0.688191, 0.587785}, {-0.716567, 0.681718, -0.147621}, {-0.500000, 0.809017, -0.309017},
{-0.525731, 0.850651, 0.000000}, {0.000000, 0.850651, -0.525731}, {-0.238856, 0.864188, -0.442863},
{0.000000, 0.955423, -0.295242}, {-0.262866, 0.951056, -0.162460}, {0.000000, 1.000000, 0.000000},
{0.000000, 0.955423, 0.295242}, {-0.262866, 0.951056, 0.162460}, {0.238856, 0.864188, 0.442863},
{0.262866, 0.951056, 0.162460}, {0.500000, 0.809017, 0.309017}, {0.238856, 0.864188, -0.442863},
{0.262866, 0.951056, -0.162460}, {0.500000, 0.809017, -0.309017}, {0.850651, 0.525731, 0.000000},
{0.716567, 0.681718, 0.147621}, {0.716567, 0.681718, -0.147621}, {0.525731, 0.850651, 0.000000},
{0.425325, 0.688191, 0.587785}, {0.864188, 0.442863, 0.238856}, {0.688191, 0.587785, 0.425325},