Incomplete Notes on Heretic II FlexModel File Format
by Gwynhala (serotonin@earthlink.net)
Last Update: 16 July, 1999


General
-------

All FlexModels seem to be called tris.fm. In general, a FlexModel file has a ".fm" suffix.

The file contains a set of chunks. Each chunk has a header. The header looks like this:

typedef struct
{
	char	ident[32];		//	The identifier of the chunk
	int		version;		//	The version number of the chunk
	int		size;			//	The size of the chunk, not including header
} header_t;

The version and size fields are each 32 bits. The value is stored in the following order:
reading from the beginning of the version field, byte values of 0x01, 0x00, 0x02, and 0x00
would indicate a version number of 0x000201.

Typicaly the following chunks are included in a Heretic II player model, in this order,
with these names and approximate sizes:

header		Some header information (40 bytes)
skin		List of paths to skin texture files (a few kbytes)
st coord	Skin texture coordinates (a few kbytes)
tris		Model triangle information (about 10 kbytes)
frames		Animation frames (about 3 megabytes)
glcmds		Model triangle information (about 20 kbytes)
mesh nodes	Model node information (about 10 kbytes)
skeleton	Model skeleton information (about 150 kbytes)
references	Other stuff (about 350 kbytes)


The Header Chunk
----------------
Version: 2
This contains information about the sizes of the other chunks in the file. Integer values
are stored in the same order as in the header_t

typedef struct
{
	int			skinwidth;		// in pixels
	int			skinheight;		// in pixels
	int			framesize;		// size of each frame (in bytes)
	int			skincnt;		// number of skins
	int			vert3dcnt;		// number of unique vertices in 3D space
	int			vertuvcnt;		// number of unique vertices in texture space
	int			tricnt;			// number of unique triangles
	int			glcmdcnt;		// # 32-bit elements in strip/fan command list
	int			framecnt;		// number of animation frames
	int			meshnodecnt;	// number of mesh nodes
} fmheader_t;


The Skin Chunk
--------------
Version: 1
This contains a list of null-terminated ASCII paths to skin names, relative the the
Heretic 2 "base" directory. Each path is null-terminated in a 64-character field.

The number of skins is given by the skincnt field of the model header.

typedef struct
{
	char	path[64];
} skinpath_t;


The St Coord Chunk
------------------
Version: 1
This contains a list of (u,v) texture coordinates. The "tris" chunk uses indeces
in this list to identify the texture coordinates associated with each vertex of
a model triangle.

The short data type takes up 2 bytes in the file. The value is stored in the
following order: reading from the beginning of the u field, byte values of 0x01,
0x00 would indicate a coordinate of 0x0001.

The number of entries is given by the vertuvcnt field of the model header.

typedef struct
{
	short	u;		//	x-coordinate in texture
	short	v;		//	y-coordinate in texture
} stcoord_t;


The Tris Chunk
--------------
Version: 1
This contains a list of triangle descriptions. For each triangle, indeces are used
to indicate the 3D space coordinates and the texture space coordinates of of each
vertex.

The number of triangles is given by the tricnt field of the model header.

typedef struct 
{
	short	index_3d[3];
	short	index_uv[3];
} triangle_t;


The Frames Chunk
----------------
Version: 1

This is a list of animation frames, each specifying the coordinates and "light normal"
index of every vertex of the model in 3D space.

For each frame there are 40 bytes of header, which specify floating-point scaling and
translation factors for the model and the name of the animation sequence (null-terminated
in a 16 byte field).

typedef struct
{
	float			scale[3];		// multiply byte verts by this
	float			translate[3];	// then add this
	char			name[16];		// frame name
} framehdr_t;

In both the scale and the translate arrays, the 1st element represents front-to-back,
the 2nd element represents right-to-left, and the 3rd element represents up-to-down.

Floating point numbers are stored in 4 bytes, in IEEE format (?). This looks something
like this: if the bytes in the file are a b c d, the floating point number is:
(a + (b<<8) + ((c|0x80)<<16)) * 2^(d-89) (??).
 
The name field indicates which animation the frame belongs to, and also the number
of the frame within the animation. Any digits at the end of the name are a frame
number within an animation; all frames with the same name up to, but not including,
any trailing digits, are part of the same animation, A name with no trailing digits
indicates a one-frame animation. For example. "foo" means the animation has one frame,
but "bar1" and "bar2" are two frames of an animation named "bar".

The header is followed by 3D vertex data structures. The number of verteces is given by
the vert3dcnt field of the model header.

typedef struct
{
	byte	v[3];					//	x, y, z scaled by header info
	byte	lightnormalindex;		//	???
} vertex3d_t;

To obtain actual coordinates in 3D space, the x, y, and z members of v are scaled
by the corresponding members of scale in the frame header, and then the corresponding
values of translate in the frame header are added to each. So, if v[0] = 22, and
scale[0] = 0.5, and translate[0] = 100, the resulting x-coordinate is 22 * 0.5 + 100
or 111.


The GLCmds Chunk
----------------
Version: 1

This is a set of lists of variable-length drawing commands used to render the model.
Each command begins with a 32-bit integer. The sign of the integer determines what
kind of command, while the magnitude of the integer determines how much data follows.

A <positive> integer indicates a TRISTRIP command. Draws a connected group of
triangles. One triangle is defined for each vertex presented after the first two
vertices.  For odd n, vertices n, n+1, and n+2 define triangle n.  For even n,
vertices n+1, n, and n+2 define triangle n.  N-2 triangles are drawn, using N
verteces, where N is the value of the integer. The verteces follow the integer
immediately.

A <negative> integer indicates a TRIFAN command. Draws a connected group of
triangles.  One triangle is defined for each vertex presented after the first two
vertices.  Vertices 1, n+1, and n+2 define triangle n.  N-2 triangles are drawn,
using N verteces, where N is the absolute value of the integer.

Each vertex for either the TRISTRIP or the TRIFAN command is specified using a
floating-point U, a floating-point V, and an integer vertex index, each of which is
32 bits. The vertex index is an index into the ???? list of verteces.

A command of <zero> indicates the end of the list of commands in a group. However, the
total number of 32-bit elements in the GLCMDS chunk is given by the glcmdcnt field of
the model header. More groups follow until the specified total number of GLCMD 32-bit
elements.

NOTE: A list of drawing commands corresponds to a "node" of the model. Heretic II player
models have 16 nodes. The sets of GLCmds for each node can be arranged in any order in the
GLCMDS chunk, because the MESH NODES chunk specifies which set of GLCMDS corresponds to
each node.

typedef struct
{
	int		theCmd;		//	32-bit integer command
} glcmd_t;

typedef struct
{
	float	u;						//	Texture 's' coordinate (?)
	float	v;						//	Texture 't' coordinate (?)
	int		index_3d;				//	Index of 3D vertex coordinate in list XXX
} glvert_t;


The Mesh Nodes Chunk
--------------------
Version: 3

This is a set of bitfields indicating which triangles and verteces are members of
a given "node". The start of the GLCmds (offset into the GLCMDS chunk) and the
number of GLCmds for each node are also indicated. There are 16 "nodes" in the
model, stored in the order described above for the GLCMDS chunk.

Data for each node consists of a 2048-bit bitfield for triangles, followed by a
2048-bit bitfield for verteces, followed by a 16 bit integer indicating the
start of the GLCmds (measured in units of 32 bits), followed by a 16-bit integer
indicating the number of GLCmds (number of 32-bit entities).

Each bitfield is stored as 256 bytes of data. The LS bit of byte zero corresponds
to the zeroth element, the MS bit of byte zero to the seventh element, and so on.
A "1" indicates that the triangle or vertex with the corresponding index is part
of the current node.

NOTE: Heretic II player models have 16 nodes, each corresponding to a specific
subset of model geometry. These nodes are always stored in the following order:

enum
{
	H2MODELNODE_FRONT_TORSO = 0,	//	Front torso, shoulders, pelvis
	H2MODELNODE_BACK_TORSO,			//	Back torso, shoulders, pelvis
	H2MODELNODE_STAFF_AWAY,			//	The thingy on the right hip when the staff is stowed
	H2MODELNODE_BOW_AWAY,			//	The bow, slung over the shoulder
	H2MODELNODE_ARMOR,				//	Armor
	H2MODELNODE_RIGHT_ARM,			//	The right upper and lower arm (no hand)
	H2MODELNODE_RT_HAND_OPEN,		//	The right hand, empty and open
	H2MODELNODE_RT_HAND_STAFF,		//	The right hand, gripping the staff thingy (no staff)
	H2MODELNODE_STAFF,				//	The Durnwood Staff
	H2MODELNODE_HELLSTAFF,			//	The Hellstaff
	H2MODELNODE_LEFT_ARM,			//	The left upper and lower arm (no hand)
	H2MODELNODE_LF_HAND_OPEN,		//	The left hand, empty and open
	H2MODELNODE_LF_HAND_BOW,		//	The left hand gripping the entire bow
	H2MODELNODE_RT_LEG,				//	The right upper leg, lower leg, and foot
	H2MODELNODE_LF_LEG,				//	The left upper leg, lower leg, and bag thingy on the hip
	H2MODELNODE_HEAD				//	The head and hair
};

typedef struct
{
	byte	trimap[ MAX_FM_TRIS >> 3 ];		//	Bit set for each triangle part of this node
	byte	vertmap[ MAX_FM_VERTS >> 3 ];	//	Bit set for each vertex part of this node
	short	glcmdstart;						//	Offset into GLCMDS chunk to start of this node's GLCMDS
	short	glcmdcnt;						//	Number of GLCMDS for this node
} meshnode_t;


The Skeleton Chunk
------------------
Version: 1

This describes skeletal information for the model (information used to bend the model
at the neck, torso, or hips in addition to any bend or rotation caused by the current
animation). It consists of a bunch of 32-bit integers, followed by a much larger bunch
of 32-bit floats.

The integer portion is formatted as follows. The chunk begins with a "skeleton type",
which for Corvus and Kiera models is always 5. This is followed by the number of
"clusters" (spinal joints) in the skeleton, which for Corvus and Kiera is always 3.
This is followed by an integer for each "cluster", telling how many vertex indeces
are associated with that cluster. After all the counts, the vertex indeces for the
first cluster follow, then the vertex indeces for the 2nd cluster, etc. Note that
each successive cluster includes all of the preceding verteces plus its own.

These are essentially all of the verteces that must be updated if the model is bent
at the corresponding spinal joint.

The three "clusters" of the Heretic II player model skeleton (used to turn and bend
the model based on player control settings within an animation) are: head (cluster 0),
high torso with all its descendents except head (cluster 1), and low torso (cluster 2).
There is no overlap between verteces in these clusters, other than the implicit
overlap from each cluster including its predecessor.

Following all the cluster vertex info is an integer which has the value 0 or 1. If
zero, this is the end of the SKELETON chunk. If 1, skeletal positioning data for
each frame follows as 9 floating-point values per cluster per frame. First, the
positioning data for frame 0, cluster 0; then frame 0, cluster 1; then frame 0,
cluster 2 etc; then frame 1, cluster 0 and so on.

Positioning data looks like this (???):

typedef struct
{
	float	origin[3];
	float	direction[3];
	float	up[3];
} positioning_t;


typedef struct
{
	int		skeltype;		//	Skeleton type, always 5 for Corvus / Kiera
	int		numjoints;		//	Joint count, always 3 for Corvus / Kiera
	int		jointverts[1];	//	Variable length; # elements = # joints
} skelhdr_t;

enum
{
	H2CORVUS_LBJOINT = 0,	//	Lower back joint
	H2CORVUS_UBJOINT,		//	Upper back joint
	H2CORVUS_HDJOINT,		//	Head joint
	H2CORVUS_MAX_JOINTS
};



The References Chunk
--------------------
Version: 1

This chunk contains hard-coded, model-specific information on the location of important
points of the model during each animation frame. The information is used to generate
special effects such as weapon trails, shadows, etc.

The following points are important in the Corvus / Kiera models:

enum
{
	H2CORVUS_LH = 0,			//	0: Location of left hand
	H2CORVUS_RH,				//	1: Location of right hand
	H2CORVUS_LF,				//	2: Location of left foot
	H2CORVUS_RF,				//	3: Location of right foot
	H2CORVUS_STAFF,				//	4: Location of the staff
	H2CORVUS_BLADE,				//	5: Location of the blade
	H2CORVUS_HELLHEAD			//	6: Location of the head of the hellstaff
};

The data begins with a 32-bit integer identifying the type of reference information
to follow (always 0 for Corvus / Kiera / player models). Then there's another integer
which specifies ??? and has the value 1.

typedef struct
{
	int		reftype;			//	What type of reference data (0 for Corvus)
	int		idunno;				//	??? (1 for Curvus)
} refheader_t;

The rest of the data is 32-bit floating-point numbers. For each animation frame, there
are 63 floating point numbers. Each set of 63 floating points numbers contains origin,
direction-of-motion, and "up" direction information for each of the 7 "important
points" described above. The format is the same as positioning_t used in the SKELETON
chunk.

typedef struct
{
	vec3_t	origin;		//	Where the important point is
	vec3_t	direction;	//	Direction and velocity of point
	vec3_t	up;			//	Direction "up" ???
} imp_point_t;

typedef struct
{
	imp_point_t	refpoints[H2CORVUS_NUMREFPOINTS];
} refskel_t;

Note that these points are not used to determine the location of "hits" during
combat. Instead, a table of blade positions during various attack animations
is hard-coded into game source file g_weapon.c.

The locations of the reference points do not correspond to any vertex on
the model, but (we hope) they occur at a constant radius from some "joint"
in the motion capture skeleton.
