Since I had nothing better to do today, I figured I'd see if I can figure out the animations in CASImporter.
I finally made a breakthrough, which also explains the mysterious zero-byte block in bone animations. Previously, based on Vercingetorix's work, a bone definition seemed to be like this:
Code:
[RTWBONE]
[bone_name] // name of the bone
[numFrames] // number of animation frames?
[unknown??] // ?
[...]
Now, the CAS importer never really cared about what RTWBONE numFrames data told us and just blindly used the global NumFrames to read in the animations. This worked most times, but mysteriously failed other times. This is because the global NumFrames should not be relied on when reading bone animations.
I discovered that a bone definition really looks like this:
Code:
[RTWBONE]
[bone_name] // name of the bone
[rotation_frames] // number of rotation animation frames for this bone
[movement_frames] // number of movement animation frames for this bone
[...]
What this implies, is that when we read in animation data, we must first check if the bone
actually has any rotation animation data and position rotation data.
The animation data is laid out as:
Code:
[ANIMDATA]
[num_bones]
[unknown]
[bone_hierarchy]
[num_frames]
[bone_data] // RTWBONE definitions
[rotation_anims] // rotation anims, based on each bone's rotation_frames
[movement_anims] // movement anims, based on each bone's movement_frames
[bone_positions] // default rig positions of bones
This doesn't make much sense unless we view some actual bone definitions:
Code:
Scene Root 0f 0f pos { 0.000, 0.000, 0.000 },
bone_pelvis 65f 65f pos { 0.000, 0.000, 0.000 },
bone_RThigh 65f 0f pos { 0.095, 0.001, 0.000 },
bone_Rlowerleg 65f 0f pos { 0.023, -0.465, -0.005 },
bone_Rfoot 65f 0f pos { 0.023, -0.401, -0.012 },
bone_abs 65f 0f pos { -0.000, 0.212, 0.000 },
bone_torso 65f 0f pos { -0.000, 0.212, 0.000 },
bone_head 65f 0f pos { -0.000, 0.235, 0.000 },
bone_cloak_top 65f 0f pos { 0.004, -0.084, -0.204 },
bone_cloak_mid 65f 0f pos { 0.000, -0.260, -0.070 },
bone_cloak_bottom 65f 0f pos { 0.000, -0.260, -0.070 },
bone_Rupperarm 65f 0f pos { 0.179, 0.078, -0.024 },
bone_Relbow 65f 0f pos { 0.302, 0.011, -0.014 },
bone_Rhand 65f 0f pos { 0.284, -0.003, 0.026 },
bone_Lupperarm 65f 0f pos { -0.178, 0.078, -0.024 },
bone_Lelbow 65f 0f pos { -0.302, 0.011, -0.014 },
bone_Lhand 65f 0f pos { -0.284, -0.003, 0.026 },
bone_LThigh 65f 0f pos { -0.095, 0.001, 0.000 },
bone_Llowerleg 65f 0f pos { -0.023, -0.465, -0.005 },
bone_Lfoot 65f 0f pos { -0.023, -0.401, -0.012 }
What we can see from that data is that we have: 19 rotation anims, all 65 frames long;; 1 movement anim, 65 frames long.
So the data is laid out as:
Code:
RotationsAnims[19 * 65f]
MovementAnims[1 * 65f]
This makes so much sense. If we open an ALEX model, we immediatelly notice something:
Code:
Scene Root 0f 0f pos { 0.000, 0.000, 0.000 },
bone_pelvis 68f 68f pos { 0.000, 0.000, 0.000 },
bone_RThigh 68f 68f pos { 0.095, 0.001, 0.000 },
bone_Rlowerleg 68f 68f pos { 0.023, -0.465, -0.005 },
bone_Rfoot 68f 68f pos { 0.023, -0.401, -0.012 },
bone_abs 68f 68f pos { -0.000, 0.212, 0.000 },
bone_torso 68f 68f pos { -0.000, 0.212, 0.000 },
bone_head 68f 68f pos { -0.000, 0.235, 0.000 },
bone_cloak_top 68f 68f pos { 0.004, -0.084, -0.204 },
bone_cloak_mid 68f 68f pos { 0.000, -0.260, -0.070 },
bone_cloak_bottom 68f 68f pos { 0.000, -0.260, -0.070 },
bone_Rupperarm 68f 68f pos { 0.179, 0.078, -0.024 },
bone_Relbow 68f 68f pos { 0.302, 0.011, -0.014 },
bone_Rhand 68f 68f pos { 0.284, -0.003, 0.026 },
bone_Lupperarm 68f 68f pos { -0.178, 0.078, -0.024 },
bone_Lelbow 68f 68f pos { -0.302, 0.011, -0.014 },
bone_Lhand 68f 68f pos { -0.284, -0.003, 0.026 },
bone_LThigh 68f 68f pos { -0.095, 0.001, 0.000 },
bone_Llowerleg 68f 68f pos { -0.023, -0.465, -0.005 },
bone_Lfoot 68f 68f pos { -0.023, -0.401, -0.012 }
Weird right? We have 19 rotation anims and 19 movement anims. The data is laid out as:
Code:
RotationsAnims[19 * 68f]
MovementAnims[19 * 68f]
And where does the movement anims section end? Exactly where the [bone_positions] section begins. For some reason the exporter they used for the ALEX expansion, also added movement animation data, even though there was no actual animation data stored. This perfectly explains the null bytes.
Now that I can reliably parse animation data, I can begin working on the MaxScript version to work correctly. Right now the old MaxScript just assumes we always have 19 rotation anims and 1 movement anim, which is incorrect and also the reason why the script crashes..