Alamo Animation File Format

Introduction

Alamo Animation Files (extension: .ALA) in Petroglyph's games describe the transforms and changes in visibility of the bones in a 3D model. For each bone, it defines a Scale, Translation, Rotation and Visibility track for a certain number of frames. There are currently three formats for animations, each used in different games. Alamo Animation Files are an instance of Chunked Files.

Format #1

Animation files with this format are used in the game "Star Wars: Empire at War" and its expansion pack "Star Wars: Empire at War: Forces of Corruption."

Alamo Animation File

00001000h: Animation file

This chunk is the container chunk for the animation.

00001001h: Animation information

01: dword numFrames
02: float fps
03: dword numBones

This chunks contains three mini-chunks with the number of frames in the animation, the animation speed in FPS (Frames/Second) and the number of bones for which animation data is stored (i.e., the number of 1002h chunks in the file).

00001002h: Bone data

This chunk is the container chunk for the animation data of a single bone.

00001003h: Bone and animation information

04: string name
05: dword  index
06: float3 translationOffset
07: float3 translationScale
08: float3 scaleOffset
09: float3 scaleScale
10: dword  unknown

This chunk holds the bone's name and index in the model as well as the information to unpack the packed animation data. The index must be used to apply the animation to the correct bone in the model. The name can be used to validate that the animation is meant for this model.

The translations and scales for each frame are stored as triplets of 16-bit unsigned integers. Rotations are stored as packed quaternions; four 16-bit signed integers for each frame. To unpack the data, perform the following:

  • Translations: unpacked = translationOffset + float3(packed.x, packed.y, packed.z) * translationScale
  • Scales: unpacked = scaleOffset + float3(packed.x, packed.y, packed.z) * scaleScale
  • Rotations: unpacked = quaternion(packed.x / 32767.0, packed.y / 32767.0, packed.z / 32767.0, packed.w / 32767.0)

00001004h: Translation data

uint16[3 * numFrames] translations

This chunk holds an array of 16-bit unsigned integers that, in triples, define an array of packed translation vectors. Unpack them as described in the 1003h chunk. This chunk can be omitted if the bone does not translate during the animation. If omitted, the translation for the entire animation should be set to the translationOffset in the 1003h chunk.

00001005h: Scale data

uint16[3 * numFrames] scales

This chunk holds an array of 16-bit unsigned integers that, in triples, define an array of packed scale vectors. Unpack them as described in the 1003h chunk. This chunk can be omitted if the bone does not scale during the animation. If omitted, the scale for the entire animation should be set to the scaleOffset in the 1003h chunk.

00001006h: Rotation data

int16[4 * numFrames] rotations

This chunk holds an array of 16-bit signed integers that, in fours, define an array of packed rotation quaternions. Unpack them as described in the 1003h chunk.



Note: This chunk is always present and contains either numFrames or 1 quaternion. In the former case, the bone has a different rotation for each frame, in the latter case, the bone's rotation does not change during the animation and should be set to the specified rotation.

00001007h: Visibility data

bit[numFrames] visibility

This chunks contains an array of bits, one for each frame, indicating if the bone is visible at that frame. Since the lowest addressable unit is a byte, the array stores ceil(numFrames / 8) bytes, and the visibility for frame F is (visibility[F / 8] >> (F % 8)) & 1.

This chunk is optional.

00001008h: Step key track

bit[numFrames] stepped

This chunks contains an array of bits, one for each frame, indicating if the translation or rotation track contains a key at each frame. This is only kept track of if the animation originally had its mode set to "Step". Since the lowest addressable unit is a byte, the array stores ceil(numFrames / 8) bytes, and the visibility for frame F is (visibility[F / 8] >> (F % 8)) & 1.

This chunk is optional.

Format #2

Animation files with this format are used in the expansion pack "Star Wars: Empire at War: Forces of Corruption" and the game "Universe at War: Earth Assault." The format is similar to the first format, only the separate SRT data per bone are combined into three chunks. Each bone now defines indices into these chunks.

Alamo Animation File

00001000h: Animation file

This chunk is the container chunk for the animation.

00001001h: Animation information

01: dword numFrames
02: float fps
03: dword numBones
11: dword rotationBlockSize
12: dword translationBlockSize
13: dword scaleBlockSize

This chunks contains six mini-chunks with the number of frames in the animation, the animation speed in FPS (Frames/Second), the number of bones for which animation data is stored (i.e., the number of 1002h chunks in the file), and the number of 16-bit words in each frame for the rotation translation and scale tracks, respectively.

00001002h: Bone data

This chunk is the container chunk for the animation data of a single bone.

00001003h: Bone and animation information

04: string name
05: dword  index
06: float3 translationOffset
07: float3 translationScale
08: float3 scaleOffset
09: float3 scaleScale
10: dword  unknown
14: dword  translationIndex
15: dword  scaleIndex
16: dword  rotationIndex
17: word4  defaultRotation

This chunk holds the bone's name and index in the model as well as the information to unpack the packed animation data. The index must be used to apply the animation to the correct bone in the model. The name can be used to validate that the animation is meant for this model.

The translations and scales for each frame are stored as triplets of 16-bit unsigned integers. Rotations are stored as packed quaternions; four 16-bit signed integers for each frame. To unpack the data, perform the following:

  • Translations: unpacked = translationOffset + float3(packed.x, packed.y, packed.z) * translationScale
  • Scales: unpacked = scaleOffset + float3(packed.x, packed.y, packed.z) * scaleScale
  • Rotations: unpacked = quaternion(packed.x / 32767.0, packed.y / 32767.0, packed.z / 32767.0, packed.w / 32767.0)
The translation, scale and rotation indices point to the base word in the track data blocks for this bone. If any index is -1, this bone does not have that track and the default value (offset for translation and scale, defaultRotation for rotation) should be used for all frames instead.

00001007h: Visibility data

bit[numFrames] visibility

This chunks contains an array of bits, one for each frame, indicating if the bone is visible at that frame. Since the lowest addressable unit is a byte, the array stores ceil(numFrames / 8) bytes, and the visibility for frame F is (visibility[F / 8] >> (F % 8)) & 1.

This chunk is optional.

00001008h: Step key track

bit[numFrames] stepped

This chunks contains an array of bits, one for each frame, indicating if the translation or rotation track contains a key at each frame. This is only kept track of if the animation originally had its mode set to "Step". Since the lowest addressable unit is a byte, the array stores ceil(numFrames / 8) bytes, and the visibility for frame F is (visibility[F / 8] >> (F % 8)) & 1.

This chunk is optional.

0000100bh: Scale data

word3[numFrames * scaleBlockSize] scales

This chunks holds an array of packed vectors for each frame for each animated bone. The scaleIndex in the 1003h chunk indexes into this array. Note that the index is a word-index, not a whole packed vector index. The scaleBlockSize in the 1001h chunk defines the size of each frame's worth of data, in words. As such, the packed vector for frame F, bone B starts at word (F * scaleBlockSize + bones[B].scaleIndex)

0000100ah: Translation data

word3[numFrames * translationBlockSize] translations

This chunks holds an array of packed vectors for each frame for each animated bone. The translationIndex in the 1003h chunk indexes into this array. Note that the index is a word-index, not a whole packed vector index. The translationBlockSize in the 1001h chunk defines the size of each frame's worth of data, in words. As such, the packed vector for frame F, bone B starts at word (F * translationBlockSize + bones[B].translationIndex)

00001009h: Rotation data

word4[numFrames * rotationBlockSize] rotations

This chunks holds an array of packed quaternions for each frame for each animated bone. The rotationIndex in the 1003h chunk indexes into this array. Note that the index is a word-index, not a whole packed quaternion index. The rotationBlockSize in the 1001h chunk defines the size of each frame's worth of data, in words. As such, the packed quaternion for frame F, bone B starts at word (F * rotationBlockSize + bones[B].rotationIndex)