CANM Format - KCreator/Earth-Defence-Force-Documentation GitHub Wiki

All offsets are relative to the beginning of their table entries.
Since the header is always at the beginning of the file, the offsets there are also absolute file offsets.

File format largely derived from EDF5, EDF4.1 might have unknown differences.

File format description

Header: 32 (0x20) bytes

Offset Size Type Description
0x00 4 String Always 'CANM'
0x04 4 UInt Always 512 0x00020000 (Version?)
0x08 4 UInt Animation Data table count
0x0C 4 UInt Animation Data table offset
0x10 4 UInt Animation Channel Data count
0x14 4 UInt Animation Channel Data offset
0x18 4 UInt BoneName table count
0x1C 4 UInt BoneName table offset

Animation Data Table: 28 (0x1C) bytes

Offset Size Type Description
0x00 4 Int Looping (1 == true)
0x04 4 UInt Name string offset
0x08 4 Float Animation duration
0x0C 4 Float Time between keyframes (0x08 / (0x10 - 1))
0x10 4 Int Keyframes in animation
0x14 4 UInt Bone Data Table Count
0x18 4 Int Bone Data Table Offset

Bone Data Table: 8 (0x08) bytes

Offset Size Type Description
0x00 2 Short Bone Name Index
0x02 2 Short Position Animation Channel Data Index (-1 if none)
0x04 2 Short Rotation Animation Channel Data Index (-1 if none) (Radians!)
0x06 2 Short Scaling Animation Channel Data Index (-1 if none)

Animation Channel Data: 32 (0x20) bytes

Offset Size Type Description
0x00 2 Short Has Keyframes (1 == True)
0x02 2 Short Keyframe Count
0x04 4 Float Base X
0x08 4 Float Base Y
0x0C 4 Float Base Z
0x10 4 Float Speed Multiplier X
0x14 4 Float Speed Multiplier Y
0x18 4 Float Speed Multiplier Z
0x1C 4 Int Keyframe Data offset (0 if 0x00 is false)

Keyframe Data: 6 (0x06) bytes

Offset Size Type Description
0x00 2 UShort X Offset
0x02 2 UShort Y Offset
0x04 2 UShort Z Offset

Bone Name Table: 4 (0x04) bytes

Offset Size Type Description
0x00 4 UInt start offset of string (UTF-16)

Strings

Note that at the end of the file, all the strings are appended. With the exception of "Scene_Root" as the first entry, all these strings are sorted in alphabetical order. Bones and Animation names, all on a pile.

Calculations:

The way animations are calculated for a frame is

X = Base X + Keyframe[i].X_offset * Speed Multiplier X
Y = Base Y + Keyframe[i].Y_offset * Speed Multiplier Y
Z = Base Z + Keyframe[i].Z_offset * Speed Multiplier Z

This is repeated for every Keyframe. The same math is used for all Animation Channel Data's. For positions this will give you relative offsets and for rotations this returns Radians. Succesfull reconstruction was done through a 4x4 Matrix. Rotation X, Y, and Z, as well as Position were made into their own 4x4 Matrices, and then multiplied in the following order:

LocalTransformMatrix = Pos @ Z Rot @ Y Rot @ X Rot

This gives a local transform matrix, which can then my multiplied with it's parents global matrix, or Identity to achieve the correct bone orientation.

Example code implementation: Blender CANM Import Script

To convert any animation curve back into data for CANM, the following math takes place:

MIN = Minimum value of all keyframes in this curve
MAX = Maximum value of all keyframes in this curve
DIFF = MAX - MIN
Base = MIN
Speed = DIFF / UShort.Max
Offset = ((KeyframeValue[i] - MIN) * UShort.Max) / DIFF

Credits:

AUK - A lot of the ground work

stafern - Making the first model viewer that had working Matrices to base further work on

Smileynator - Formatting and verification