Repository navigation
ANIMATION
Jocelyn Beedie edited this page Oct 9, 2021
·
8 revisions
This is the very first file type to be structured using decompilation!
struct Animation {
float length;
uint16_t unk;
uint32_t numAnimationMeshes;
AnimationMesh animationMeshes[numAnimationMeshes];
uint32_t numAnimationNodes;
AnimationNode animationNodes[numAnimationNodes];
uint32_t numAnimationMaterials;
AnimationMaterial animationMaterials[numAnimationMaterials];
}struct AnimationMesh {
int32_t name;
uint16_t unk;
KeyFramerFloat track;
}struct AnimationNode {
int32_t name;
uint16_t unk;
KeyFramerVec3fComp track1;
KeyFramerRot track2;
KeyFramerVec3fComp track3;
KeyFramerMessage track4;
}struct AnimationMaterial {
int32_t name;
uint16_t unk;
KeyFramerFloat track1;
KeyFramerFloat track2;
KeyFramerFloat track3;
KeyFramerFloat track4;
KeyFramerFloat track5;
KeyFramerVec3fComp track6;
KeyFramerVec3fComp track7;
KeyFramerFloat track8;
}struct KeyFramerFloat {
uint16_t interp;
uint32_t num_frames;
struct KeyFloat {
uint16_t frame;
uint16_t junk;
Vector3 data;
}
KeyFloat frames[num_frames];
}struct KeyFramerVec3fComp {
uint16_t interp;
uint32_t num_frames;
struct KeyVec3fComp {
uint16_t frame;
int16_t pos[3];
int16_t handle_left[3];
int16_t handle_right[3];
}
KeyVec3fComp frames[num_frames];
}To convert a point in KeyVec3fComp to a Vector3, just convert each component to a float and multiply by 0.001.
For example:
KeyVec3fComp v;
Vector3 pos = Vector3(v.pos[0], v.pos[1], v.pos[2]) * 0.001;struct KeyFramerRot {
uint16_t interp;
uint32_t num_frames;
struct KeyRot {
int16_t frame;
int16_t quat[4];
iint16_t junk;
float omega;
float sinom;
}
KeyRot frames[num_frames];
}Converting to a quaternion
float convertQuatComponent(int16_t value) {
// keep only 12 bits of `value`, that way it stays close to the range [-1, 1]
return (float)(val & 0x0FFF) * 0.0005;
}
Quatf convertQuat(KeyRot key) {
return Quatf (
convertQuatComponent(key.quat[0]),
convertQuatComponent(key.quat[1]),
convertQuatComponent(key.quat[2]),
convertQuatComponent(key.quat[3]),
);
}Interpolating Quaternions is fairly straightforward, and any old slerp function should work fine. However, the game also includes precomputed omega/sinom values for the slerp function, for a small performance boost. For completion's sake, here is (roughly) how the game interpolates quaternions:
Quatf interp(KeyRot from, KeyRot to, float t) {
if (from.omega == 0.0) {
return convertQuat(from);
}
else {
Quat fromq = convertQuat(from);
Quat toq = convertQuat(to);
if (from.omega > 2 * PI) {
from.omega = from.omega - 2 * PI;
toq = -toq;
}
float t1 = sin(t * from.omega);
float t2 = sin((1.0 - t) * from.omega);
return from.sinom * (from1 * t1 + toq * t2);
}
}struct KeyFramerMessage {
uint16_t interp;
uint32_t num_frames;
struct Message {
uint32_t unk1;
uint32_t unk2;
// if unk1 in [0x11, 0x12, 0x13]:
uint32_t strlen; // will create a buffer overflow if >= 144
char data[strlen];
int32_t name;
}
struct KeyMessage {
uint16_t frame;
uint16_t junk;
uint32_t num_messages;
Message messages[num_messages];
}
KeyMessage frames[num_frames];
}