Hopefully that is what this thread will accomplish.
I did some poking around in the file formats today and did make some ground, but for every step forward there were 23 (approximately) steps back.
I don’t think I am going to get this format decoded on my own, so I am hoping to get others intrested in it.
Here is what we know:
Battle animation formats are the **da files stored in battle.lgp. They are fully binary and they are also the same format as the ones used in magic.lgp (for summons).
A battle enemy has an ID which can be converted into two letters, starting with “aaâ€. So enemy ID 5 is “af†and enemy ID 242 is “jiâ€.
All the files for an enemy in battle.lgp start with those first two letters. The postfix is what determines the type of file it is in relation to the enemy.
**da files are animations. **aa files are heirarchy files.
The details on these are covered in other posts and in other documents so I will move along directly to the **da files of intrest here.
The first 4 bytes of the **da file represent the numebr of animations in the file, even though some animations are blank and only 16 bytes long. They are unknown at this time.
The animations follow. Each animation has this header (this header is revised from documents you may have):
struct s_FF7AAanimHdr {
unsigned long rec_a; //0
unsigned long frames1; //4
unsigned long block_len; //8
unsigned short frames2; //12
unsigned short real_data_len; //14
unsigned char key; //15
} FF7AAanimHdr; //size = 17 bytes
frames1 and frames2 seem to always be the same number except in the dummy animations with only 16 bytes. Most likely frames2 is the actual number of frames.
block_len is the length of the block from there until the next animation set.
This length includes frames2, real_data_len, and key.
real_data_len is the actual number of bytes that are contained within this animation starting after key.
key is a compression indicator which determines if first frame is packed by 12 bits, 10 bits, or 8 bits.
key: Bits:
0 12
2 10
4 8
After this header comes the actual animation data for this animation.
A single frame has XYZ translations, XYZ rotations for the root bone, and then XYZ rotations for each of the bones in the model.
The data starts with 3 shorts, which are the translations for the first frame.
They are actually stored in reverse format of everything else in Final Fantasy® VII, for completely unknown reasons.
For all references, we use Cloud’s animation file, rtda.
The header of his first animation ends at 0x15, at which point his first frame begins (ON 0x15). You see this: 00 00 FE 2E 00 00.
These are 3 shorts in reverse (little endian) format.
Reverse the bytes in each number individually:
00 00 -> 00 00
FE 2E -> 2E FE
00 00 -> 00 00
Now they are signed shorts indicating the X Y and Z translations for Cloud’s first frame (0, -466, 0).
What comes next is a series of rotations.
Rotations are stored in the number of bits determined by “key†and each bone has 3 rotations (XYZ).
So, if key is 0, each bone requires (12 * 3 / 8) bytes, or 4.5.
If key is 2, each bone requires (10 * 3 / 8) bytes, or 3.75.
If key is 4, each bone requires (8 * 3 / 8) bytes, or 3.
To decode these, first we need to declare a ceiling. The ceiling is the total numbers that can be held by the number of bits in each bone.
Cloud’s key is 0, so each of the rotations in his bones is 12 bits.
The numbers 12 bits can hold ranges from 0 to 4095, which is 4096 total numbers. So “Ceiling†is 4096 here.
For 10 bits it is 1024 and for 8 bits it is 256.
The start of Cloud’s rotations is 0x1B.
Every 12 bits from here is an X, Y, or Z (in that order). Each XYZ triplet is a bone.
So, every 4.5 bytes is a bone. His data is as follows:
00 00 00 00 0C 00 EC E0 00 F8 2F E5…
Break this into 12-bit groups:
000 000 000 C00 ECE 000 F82 FE5…
The equation to transform the groups into angles is:
(group) * 360 / Ceiling.
So let’s do this on each rotation.
000 = (0x000) * 360 / 4096 = 0
000 = (0x000) * 360 / 4096 = 0
000 = (0x000) * 360 / 4096 = 0
C00 = (0xC00) * 360 / 4096 = 270
ECE = (0xECE) * 360 / 4096 = 333.10546875
000 = (0x000) * 360 / 4096 = 0
F82 = (0xF82) * 360 / 4096 = 348.92578125
FE5 = (0xFE5) * 360 / 4096 = 357.626953125
…
His first bone is (0, 0, 0).
His second bone is (270, 333.10546875, 0).
His third bone is (348.92578125, 357.626953125, …).
NOTE: His FIRST bone is NOT part of his skeleton. It is his root bone and it determines the facing direction of his entire body. His actual bones start on the second bone I listed here.
The number of bones is (Character’s Bones + 1), because the first bone is not part of his skeleton; it is his root bone.
Cloud’s first frame is (6 + 4.5 * (23 + 1)), or 114 bytes.
It starts at 0x15, so the next frame begins at 0x87.
Now here are the things that I know.
The next frame starts with 00 05 00.
These bytes indicate the change in translation from his first frame. His first frame’s translation was (0, -466, 0), so for this frame, it is (0, -461, 0) or (+0, +5, +0).
This seems fairly direct but it is only in this simple case.
Actually the offsets are stored in 7 bits, and those 7 bits are signed.
This means from one frame to the next, a character can move anywhere from -64 to 63 units.
So, 6F would move the character -17 units.
Each frame bases itself off the previous frame.
Unfortunately that is all I really know for sure.
The offsets for each frame after the first are only stored in 7 bits for the translations. The rotations are stored differently.
And, for the translations, I do not know what the 8th bit does.
I can set the 7 bits to whatever I want his position to be, but if I set the 8th bit he starts swirling around the map in large gaping circles.
When I mess with the data immediately after the offsets for the second frame it can cause drastic changes.
On one case his whole body started flattening. The animation (including the flattening) was smooth and repeated fine. He flattened more and more as the animation progressed and then the first frame was run again, where he was no longer flattened at all.
Other changes to only the second frame of data have resulted in a few frames where things are fine, then his arm breaks, then a few frames later his body shifts into all directions.
The data is not packed by means of compression; it is just stored in a different format.
At this point, I can not draw conclusive ideas on the formats in which they are stored.
But I know they are definitely NOT:
Compressed
Key Framed
Full Frames
I believe Cloud’s second frame is 82 bytes total, but here I have little more than poorly based calculations for that, so do not take my word for it.
Anyone want to jump in at all?
L. Spiro