Need help understanding ANS files

pmobley

Member
Joined
Jan 22, 2022
Messages
34
Hello all,

I need some assistance in understanding the ans data format. I do know that the file contains a list of bones and what appears to be the coordinate translations for the animation of the bones. I specially am looking for information regarding the QCHN catergory. Please let me know if there is anything out there that can assist me in understanding the format of the data.
 

Borrie BoBaka

Local Bothan
Staff member
Super Moderator
Joined
Mar 16, 2014
Messages
91
Location
Dark Rebellion RP
It's an interesting file format, to be sure. Unfortunately I can't write about it in full detail right now but I thought I'd leave you with some information before I can come back here and post additional info.

The QCHN stands for "Quaternon Channel/Change" You have to keep in mind three things. 1. Animations are going to be mostly quaterinon movements, 2. Animations are broken up into frames with instructions to move certain bones at certain times, and 3. SWG files like these are designed to reuse data whenever possible to conserve space.

So what an animation file does is runs through a list of ID's for each bone for each frame. This is something I'll have to look up later, but off the top of my head, I know that each frame has an ID for a Quaternion referenced, so an animation for the root bone might be Frame 1: ID 2, Frame 2: ID 45, Frame 3: ID 91 and the ID references which Quaternion values should be used on that frame.

NOTE HOWEVER: CKAT animations are compressed. The Quaternion values aren't straightforward 1:1 quaternions, and have to be decompressed. However, the game can swap between CKAT and KFAT (uncompressed) animations without issue. In these modern times, there's no need to compress animations anymore.
 

pmobley

Member
Joined
Jan 22, 2022
Messages
34
Ok so here is some sample of the hex values for the acklay_cbt_attack_ranged animation

1A 00 E8 A0 9F 00 00 FF FC 17 E7 01 00 FF 57 DD 02 00 FF FC B7 C5

There is more to the file but will get that in a little. For the sake of discussion, this amount of info should be fine.

I have been comparing this with the other animations inside of the game (and to the same creature animations). What I have been finding out is that there is a section of 4 numbers (FF FC 17 E7 in the example) I believe that these are the Quaternion that you are referencing. These numbers are followed by a fifth number (01 above) Which I am fairly confident is the frame. Then the frame number is followed by the 00 which I believe is a delimiter and then this repeats. In the file above, There are 20 frames because the last one is 0x19 (remember, the numbers here are hex). Now this theory breaks down a little bit becuase at the start, we have only 3 bytes (E8 A0 9F) followed by a frame ID of 0. My guess is that this would be the initial position of the bones.

I do not think that these numbers (FF FC 17 E7) are references but the values. The reason being is that I do not see any reference to other files. Typically there would be some sort of table associated with the file. For example see the LAT (Logical Animation Table) However, since these are 4 bytes long, it is possible that is it a reference because an int is 4 bytes long. Need to look into what a Quaternion is and how to use. This is the first time I heard of it.

Besides that, the other thing that is tripping me up is how the program associates the bone to the specific animation. What I gather is that each XFIN stores the info for the animation. Or at least it should. It should store which bone is being reference and where the bone is for each frame of the animation. So far I have been half correct. But when I try to associate a bone to the frame or the animation, I am not clear on how the program is doing it. I thought that there would be some kind of ID but so far I have not found the hex value spot that is consistant across all animations. (At first, I thought it would be at the beginning of the file but I am not sure)

In the FBX SDK, you have to have animation curves (Currently working on converitng the animation to FBX for exporting/importing into UE) Inside of UE, I see that 1 animation curve can be linked to an array of bones so there is that. It is possible that SWG is going the same thing here.
 

pmobley

Member
Joined
Jan 22, 2022
Messages
34
Ok so I modified my program a little bit and had it go through the every single ans file. It did not find a single KFAT. Only has CKAT so I think that we have to only deal with one format. If your version of SWG has KFAT, can you tell me which file it is so that I can check my version?
 

Borrie BoBaka

Local Bothan
Staff member
Super Moderator
Joined
Mar 16, 2014
Messages
91
Location
Dark Rebellion RP
You won't find many KFAT files typically. You can browse through the beta files found within the TRE repository here on MTG for uncompressed versions of the animations for an easier approach. It would seem before release of the game, SOE compressed all the animations, but not before.

The numbers you're looking at, i.e. "FF FC 17 E7 " are bytes. Bytes are a value between 0 and 255, which when combined together can create values. I apologize if this is something you know, but just incase you don't: every value is made up of bytes. The most common value types you're going to find are floats (floating decimals like 4.2918), and 32 and 16 bit integers. Floats and 32 bit integers use four bytes, 16 bit integers use two, etc. Quaternions are four floats long (x, y, z, w). Which means that every Quaternion is going to be 16 bytes in length in a KFAT file. In a CKAT, I believe it's compressed down to four bytes.

Typically at the start of many nodes within IFF files, you have a single value like a 32 bit integer at the head of the file that references how many values are within that node, with every value afterward referencing the data itself.

As for matching up with skeletons, it literally is just a string match. It does look for a bone with the name being referenced in the animation, and will work on an animation in game even if the bone is not found. It's very robust in the fact that it won't crash if it doesn't find the needed bone. So if the XFIN says "chest3" then its going to manipulate any bone named "chest3." That is the only connection between skeletons and animations within SWG.

If you have more questions, I'll do my best to answer them as soon as I can. The ANS file is an interesting format and tricky to work with, but a bit straight forward when you know what you're looking at. I've done some work with ANS editing and have even been able to import some work into other games but because of my lack of good math skills, my success has been limited =D
 

pmobley

Member
Joined
Jan 22, 2022
Messages
34
Thank you for the brief on the what the byte is. If a Quaternion is a 4 byte number, then I believe that the length in bits will be 16 bits. Each value in hex (1, 2, A, B, etc.) is 4 bits long. So 2 values in hex is 8 bits long which is 1 Byte. So the question comes, how is it that the values FF FC 17 E7 are Quaternions values?

It is simple, to compress the animation, you can take the float value and multiply it by 255 (the max value for a byte). From there, this will essentially convert every float to an 1 byte long. (Assuming the value is not too big. All of the quaterions will need to be less then 1 for this trick to work).

As for the reference to the bones, in the XFIN files, I see the string name. However in the QCHN files, there is no string reference. At first I thought that the order of the QCHN files will match with the order of the bones so it is a one to one match. I think that it did not work out exactly but will need to double check that. Right now, I do not see an identifier within the QCHN files
 

pmobley

Member
Joined
Jan 22, 2022
Messages
34
I have a function that can convert the Quaternion to Euler. I will just need to know which order the Quaternion is in the ans file.
 

pmobley

Member
Joined
Jan 22, 2022
Messages
34
Ok so after a couple of hours toying around, this is my first shot at converting the animation. Not much to go by. Poor acklay, can't even get up.

I made many assumptions here. Good news is is that I was able to successfully export the model! Not so good news is that I need to refine the algorithm a little more for the animation. At least something is moving. Not sure what it is though.

Also, I used the low poly count model so that it can import/export faster
 

Attachments

Rabiator

New Member
Joined
Dec 1, 2016
Messages
27
QCHN
Code:
struct[DataType]{short[FrameNumber], uint[CompressedRotation]}

short[Keyframe Count]
byte[X Format]
byte[Y Format]
byte[Z Format]
DataType[stuff, -1]
793

Dont ask me what exactly is in the compressed part/byte part. i never looked deeper into that.
 

pmobley

Member
Joined
Jan 22, 2022
Messages
34
The compressed part I believe is the series of bytes that make up the Quaternion. The compressed part is a series of 4 bytes where 1 byte is one Quaternion. It is scaled to fit into 1 byte.

Any idea what the X, Y, and Z Format are?
 

pmobley

Member
Joined
Jan 22, 2022
Messages
34
Code:
struct[DataType]{short[FrameNumber], byte[CompressedX], byte[compressedY], byte[compressedZ], byte[compressedW]}

short[Keyframe Count]
byte[X Format]
byte[Y Format]
byte[Z Format]
DataType[stuff, -1]
So here is the breakdown of each one. I am guessing the order of the X, Y, Z, and W. I wonder if you have to divide these numbers by the format?
 

Attachments

Rabiator

New Member
Joined
Dec 1, 2016
Messages
27
i dont think there is a W value, else the framecount and the counters of the frames below would not fit, but they do fit
795
 

pmobley

Member
Joined
Jan 22, 2022
Messages
34
Right so if you look at the bytes in the main viewer, you will see for example 01 00 45 67 A4 89 02 00 ... and repeat. The 01 is the frame number, 00 is well 0, and the 45 67 A4 89 are what makes up the compressedrotation value (again, this is an example). Notice that there are 4 bytes.

Now I believe that these 4 bytes do not make up 1 number but rather are 4 individual numbers. X, Y, Z, and W.

Obviously the float values for the coordinate positions are not able to fit into 1 byte. 1 float is 4 bytes long! However, if the float is less then 1, then you can normalize everything with ints.

For example, 0x45 = 69 (dec). Take this and divide by 255 (max size of 1 byte) and you get 0.2706, this is a float and will be stored in memory as 4 bytes long. Conversely, you and do the opposite way. Take a float, multiply by 255 and then you can store that value as a byte in memory. A crude method of compression but it works.

If you look at the above screenshot that I posted, or if you run the script that I also posted, you will notice that the single value for compressrotation can be broken into 4 individual bytes with the frames still matching up
 

pmobley

Member
Joined
Jan 22, 2022
Messages
34
Did i miss something ? Not seen any script ...


Code:
struct[DataType]{short[FrameNumber], byte[CompressedX], byte[compressedY], byte[compressedZ], byte[compressedW]}

short[Keyframe Count]
byte[X Format]
byte[Y Format]
byte[Z Format]
DataType[stuff, -1]
This guy right here. I called it a script but it is for formatting the output window. I apologize for any confusion
 
Top Bottom