Site Hosted by: Logo

Support This Project

Animadead Documentation


See the Tutorials Page for example programs that gradually introduce the interface and features. Throughout the tutorials there are references to this document and where applicable, this document will refer to the example programs. Through the Tutorials and this reference documentation, you should be able to form a comprehensive understanding of how to use this library.
  1. Preface
  2. Getting Started
    1. Building the library
    2. Using Animadead in your project
    3. Basic Structure
  3. Model, the main interface
    1. Texture Loader
    2. Intended use
    3. Update function
    4. Mesh functions
      1. Loading
      2. keeping handles
      3. viewable set
      4. binding
      5. unbinding
      6. Mesh Data structure
    5. Animation Functions
      1. Loading
      2. Allocating render poses
      3. create blends
      4. create selection masks
  4. Blend
    1. BlendBase
    2. making heirarchies
    3. using blends
    4. extending blendbase
  5. AnimPlayer
    1. creating (*note, use model to manage the instance, otherwise responsible for cleaning up)
    2. setting/getting the frame
    3. updating
    4. calculate
  6. Drawing
    1. static
    2. dynamic
    3. see tutorials for shader examples
  7. Math functions
    1. Vector
    2. Matrix
    3. Quaternion
  8. File Format Specifications
    1. Mesh (adm)
    2. Animation (ada)
  9. Exporting
    1. Maya
      1. options
    2. 3DS max
      1. options

1. Preface

I often hear people say itís easier for them to rewrite a library for their own engine than try to figure out how to use an existing one. I have even felt that way when I first looked into available skeletal animation packages, well, package anyway. I felt that not only would it be easier to write it myself, but also I could do a better job, and so I wrote Animadead. No one should have to feel that way about using a library, so the goal of this guide is to make it as easy as possible to learn how to use Animadead.

2. Getting Started

2.1. Building the library

  • project files
  • dynamically-linked
  • the DLLIMPORT macro
  • statically-linked
  • directories

2.2. Using Animadead in your project

  • whatís expected of you
  • linking to the library
  • including animadead.h
  • namespace

2.3. Basic Structure

The two main components of Animadead are meshes (the geometry that makes up the look of a character or object), and animations, which contain poses for the character or object over a period of time. The skeleton is incorporated in both of these components and provides a common ground for them to work together.


In figure 2.3.1 below, you can see a mesh of some pants and a skeleton in Maya. The white areas of the mesh are influenced by the knee bone of the skeleton. The pose of a skeleton that corresponds to the pose of the mesh when it's exported is called the bind pose. When a mesh is associated with a skeleton like this, it's deformable and when it has no association with a skeleton, it's static. If a mesh is exported as deformable, a pose must be used to render it properly. A static mesh cannot be posed.

figure 2.3.1

figure 2.3.2

Figure 2.3.2 shows several meshes used to create a single character. You could create several meshes for a single area, like perhaps instead of a coat like the one that's selected, you could make some armor or maybe a shirt model. Then you can just draw the ones you want visible. Animadead has support functions for keeping track of meshes you want to draw. Details on how to use them are in section #unknown.


figure 2.3.3

For Animadead, an animation is a series of poses sampled from every frame of an animation in a modeling package. The figure 2.3.3 is an example of a set of poses for the same skeleton in figure 2.3.1.

3. Model, the main interface

This class provides interfaces for loading meshes and animations, and contains features to manage them.

3.1. Texture Loader

class TextureLoader : public ad::UserFunction
    void operator()(std::string file, void *&userdata);

You can derive a texture loader class from UserFunction and pass it to a model when it's created. When meshes are loaded, each surface read will call the texture loader and pass it the texture file name. The texture loader can then load the texture or material and return a pointer to any data you will want to access when drawing the model. The data gets stored with the surface, and each time you access the surface you can access the data. A good example of this is storing the OpenGL texture ID so you can bind to it when you draw the mesh.

void TextureLoader::operator()(string file, void *&userdata)
	// ...
	unsigned int texture=0;
	glGenTextures(1, &texture);
	// ...
	userdata = (void *)texture;
void SuperModel::Draw()
    // ... iterate viewable meshes, iterate each surface on each mesh
    glBindTexture(GL_TEXTURE_2D, (unsigned int)(surface->userData));
    // ... continue to render each surface

3.2. Intended use

Define a new class derived from the Model class and add functionality for drawing.

class SuperModel : public ad::Model
    // arguments passed to the Model constructor
    SuperModel(ad::Model::Type type, ad::UserFunction *fp);
    void Draw();


  • Load the model and optionally pass it a texture loader.
  • Load any meshes you want pre-loaded, or at least the meshes you want visible.
  • Bind the meshes you want to be visible to the model.
  • Load animations
  • call AllocateRenderPose
  • optionally create a blend hierarchy
  • optionally create a hierarchical selection mask


  • Load any additional meshes
  • Use Bind and Unbind to adjust the viewable set of meshes
  • Update relevant animations
  • Set blend weights
  • call the top level Blend Calculate
  • call GenerateRenderPose


  • Iterate the set of viewable meshes
  • Access any user defined data and the surface data to render each surface.

3.3. Update function

The default Update function iterates every loaded animation and updates it. This might be useful in very simple cases, such as constantly playing a single animation, or maybe a few animations and adjusting the blending between them. In such cases you can use the default Update function, but in most cases, you'll probably just want to call the animation update function for animations that are being used. You can always set the frame time of an animation directly, when you want to use it again.

3.4. Mesh functions

A model has an assortment of functions for meshes, including loading, binding and unbinding, with support for slots, which make it easier to swap a mesh in to replace another. All of the bound meshes can be easily accessed when you want to draw them, and the data is packed to make it easy to use in vertex arrays.

3.4.1. Loading

When loading a mesh from a filename, if the mesh has been loaded already, it will return the loaded mesh, otherwise it will load the mesh from file. The handle returned from loading a mesh is a pointer to the data structure.

3.4.2. keeping handles

You can keep track of the mesh pointers yourself for use with the binding and unbinding functions or use them directly when you want to draw the mesh. If you are going to swap the mesh frequently with other meshes, it might be useful to keep a handle of the loaded mesh, however since meshes are cached, it is not necessary. You can use LoadMesh with the file name at any time to get the Mesh pointer.

Mesh *helmet = model.LoadMesh("helmet.adm");

3.4.3. viewable set

The Model class keeps track of a set of viewable meshes (the currently bound meshes), and provides functions to alter the set. Then when you want to draw the meshes, you can simply iterate the set of viewable meshes.

3.4.4. binding

When you bind a mesh, you can optionally assign it to a slot, which can only contain one mesh at a time. If you bind another mesh to the same slot, it will remove the previous one from the viewable set. This is useful if you have a character with different sections of armor, like head, torso, legs, feet, and hands for example. You can create a slot for each one with GenSlot().

int headSlot = model.GenSlot();

Then, lets say you want to replace the normal head mesh, with one that has a helmet on, you could do:

model.BindMesh( helmet, headSlot );

The helmet mesh would be added to the viewable set, and the normal head mesh will automatically be unbound.

You can also just bind the mesh without specifying a slot, and it will simply be added to the set of viewable meshes.

3.4.5. unbinding

When you unbind a mesh, you can specify a mesh to be unbound or the slot to be unbound. If you unbind a mesh that happens to be in a slot, it will be removed from the slot. And as you might have guessed, if you unbind a slot, the slot is cleared, and the mesh in the slot is removed from the viewable set.

3.4.6. Mesh Data structure

The mesh is designed to be used in vertex arrays and therefore is organized so that it can be accessed easily. The mesh is organized into surfaces, for each texture. For each surface there is one array that contains unique combinations of normals, positions, uv-coordinates and weights and there is a separate array of indices that index into the vertex array. The indices are per triangle (each 3 indices).

See ad::Mesh

Here is an example of how you can set up vertex pointers to the data.

unsigned int offset = sizeof(ad::SuperVertex);
glVertexPointer(             3, GL_FLOAT,                  offet, &surface->superVerts[0].x);
glNormalPointer(                GL_FLOAT,                  offet, &surface->superVerts[0].a);
glVertexAttribPointerARB(pW, 4, GL_FLOAT,        GL_FALSE, offet, &surface->superVerts[0].weight[0]);
glVertexAttribPointerARB(pI, 4, GL_UNSIGNED_INT, GL_FALSE, offet, &surface->superVerts[0].bone[0]);
glVertexAttribPointerARB(pN, 1, GL_UNSIGNED_INT, GL_FALSE, offet, &surface->superVerts[0].numweights);

And here is how you'd use the index array to to draw the triangles.

glDrawElements(GL_TRIANGLES, 3*surface->numFaces, GL_UNSIGNED_INT, &surface->faces[0].indices[0]);

3.5. Animation Functions

Like meshes, a model contains functions for animations such as loading, creating blends, and creating selection masks.

3.5.1. Loading

When loading an animation from a file, the data is cached. If it has been loaded already, the previously loaded data will be used, otherwise it will load the data from file. Then an AnimPlayer is created to keep track of the current time of the animation, which uses the loaded data, and a pointer to the AnimPlayer is returned. So if you load the same animation twice, you get two AnimPlayer instances that share the same animation data.

3.5.2. Allocating render poses

The model needs to store a special pose for accumulating all of the animations and blends. But in order to make the render pose, the number of bones is needed. You can specify them directly, or the number of bones from the first animation you loaded will be used. Thus, if you don't specify the number of bones directly, you should make sure you load an animation first.

3.5.3. create blends

The model class provides an interface for creating blends between animations and other blends. The model class keeps track of all the blends and takes care of memory cleanup. The from and to poses are optional but the source poses must be set before the calculate function is called. The allocate render pose should be called before creating blends.

3.5.4. create selection masks

Create a selection mask of bones using the hierarchy.

Using the naming given for the sample skeleton, it's very easy to make selection masks using the hierarchy. The way it works is when you select a bone to be either on or off, all of its children inherit that same state unless they are set directly. The color scheme on the figure is: red is set off directly (gray is inherited off), green is set on directly (blue is inherited on). To create this mask then, one would simply need this command:

CreateMask("pelvis 1 spine1 0");

Allocate Render Pose should be called before using this function.

4. Blend

The blending system in Animadead is extremely flexible and extensible. Blends can be constructed in a hierarchy and can be set up to only only effect certain bones.

4.1. BlendBase

BlendBase provides the base abstract concept that makes the blending system in Animadead so flexible. The idea is to define a class that can calculate a Pose. The Blend class for example extends this base class, and takes two other classes derived from BlendBase. Its calculate function first calls the calculate for the two other classes, and then takes the resulting poses, and blends those together with a user-defined weight.

4.2. making heirarchies

Because of Blend's recursive nature, a blend hierarchy can be set up. A user can define a custom class derived from BlendBase that calculates a pose and use it in the hierarchy as well.

4.3. using blends

Once the hierarchy of blends is created, and the weights and selection masks are all set as desired, only the top level Calculate function needs to be called. All other Calculate functions in the hierarchy will be called automatically. When calling the top-level blend function, the render pose from the model should be used. Once the render pose has been generated, the GenerateWorldPoseMatrices function can be used to convert the resulting pose to world matrix transforms, which can be used to deform the mesh.

4.4. extending blendbase

To define a class that can be used in the blend hierarchy, extend the base class BlendBase and define void Calculate (Pose *out_pose, HiBoneMask *optionalMask=0); The calculate function should affect the out_pose parameter, and if the optionalMask is provided, only the selected bones should affect the out_pose.

5. AnimPlayer

5.1. creating

(*note, use model to manage the instance, otherwise responsible for cleaning up)

5.2. setting/getting the frame

5.3. updating

5.4. calculate

6. Drawing

6.1. static

6.2. dynamic

6.3. see tutorials for shader examples

7. Math functions

7.1. Vector

7.2. Matrix

7.3. Quaternion

8. File Format Specifications

8.1. Mesh (adm)

8.2. Animation (ada)

9. Exporting

9.1. Maya

9.1.1. options

9.2. 3DS max

9.2.1. options

© Copyright 2005 John Butterfield.
All Rights Reserved.