Difference between revisions of "FSKA (File Format)"
(Documenting unknown fields for now, keys and flags later.) |
(Rewamp format documentation and reuse the Curve structures) |
||
Line 1: | Line 1: | ||
{{Under-construction}} | {{Under-construction}} | ||
− | The '''FSKA''' (ca'''F'''e '''SK'''eletal '''A''' | + | The '''FSKA''' (ca'''F'''e '''SK'''eletal '''A'''nimation) subfile stores animations which control how to transform bones of a model over time. It appears as a subfile of a '''[[BFRES (File Format)|BFRES file]]''' in the '''2nd''' [[index group]]. |
+ | |||
+ | __TOC__ | ||
+ | |||
+ | = Format = | ||
+ | |||
+ | An '''FSKAfile''' begins with an '''FSKA header'''. This is then followed by a number of sections pointed to by the header, many of which can occur multiple times. The purpose of these sections is described in the table below. | ||
+ | |||
+ | '''FSKA''' shares many similarities with the '''[[FSHU]]''', '''[[FTXP]]''', '''[[FVIS]]''', '''[[FSHA]]''' and '''[[FSCN]]''' subfiles, which mostly only differ in the structure describing what is changed by animations over time, but reusing the same animation curve and key structures, and even headers being very similar to one another. | ||
== Header (FSKA) == | == Header (FSKA) == | ||
− | + | ||
+ | Every FSKA begins with an 0x30 byte '''FSKA header'''. | ||
{|class="wikitable" | {|class="wikitable" | ||
|- | |- | ||
− | ! Offset !! Type !! Description | + | ! Offset !! Size !! Type !! Description |
|- | |- | ||
− | | 0x00 || | + | | 0x00 || 4 || Char[4] || "'''FSKA'''" file identifier, ASCII string. |
|- | |- | ||
− | | 0x04 || Int32 || '''File name''' offset | + | | 0x04 || 4 || Int32 || '''File name''' offset (without file extension). |
|- | |- | ||
− | | 0x08 || Int32 || ''' | + | | 0x08 || 4 || Int32 || '''File path''' offset, the path of the file this data was originally created from. Stripped in [[Mario Kart 8]] files, always pointing to an empty string at the end of the BFRES [[BFRES (File Format)#String Table|string table]]. |
|- | |- | ||
− | | 0x0C || UInt32 || '''Flags'''. | + | | 0x0C || 4 || UInt32 || '''Flags'''. Set of bits controlling how data is stored, packed as '''xxxxxxxx xxxxxxxx xxxRxxSS xxxxxPxC'''. |
− | * C determines whether curves | + | * '''C''' determines whether curves are baked. |
− | * P controls the | + | * '''P''' controls whether the animation is looping. |
− | * SS controls how to perform scaling: | + | * '''SS''' controls how to perform scaling: |
{| class="wikitable" | {| class="wikitable" | ||
! Value !! Description | ! Value !! Description | ||
Line 30: | Line 39: | ||
| 3 || Softimage scaling | | 3 || Softimage scaling | ||
|} | |} | ||
− | * R controls the rotation mode, either euler XYZ rotation (bit set) or quaternion (bit unset). | + | * '''R''' controls the rotation mode, either euler XYZ rotation (bit set) or quaternion (bit unset). |
|- bgcolor="#AAFFAA" | |- bgcolor="#AAFFAA" | ||
− | | colspan=" | + | | colspan="4" align="center" | '''if BFRES version >= 3.4.0.0''' |
|- bgcolor="#DDFFDD" | |- bgcolor="#DDFFDD" | ||
− | | 0x10 || UInt32 || '''Frame count'''. | + | | 0x10 || 4 || UInt32 || '''Frame count'''. |
|- bgcolor="#DDFFDD" | |- bgcolor="#DDFFDD" | ||
− | | 0x14 || UInt16 || '''[[#Bone Animation|Bone Animation]] count'''. | + | | 0x14 || 2 || UInt16 || '''[[#Bone Animation|Bone Animation]] count'''. |
|- bgcolor="#DDFFDD" | |- bgcolor="#DDFFDD" | ||
− | | 0x16 || UInt16 || '''[[ | + | | 0x16 || 2 || UInt16 || '''[[User Data]] entry count'''. |
|- bgcolor="#FFAAAA" | |- bgcolor="#FFAAAA" | ||
− | | colspan=" | + | | colspan="4" align="center" | '''else''' |
|- bgcolor="#FFDDDD" | |- bgcolor="#FFDDDD" | ||
− | | 0x10 || UInt16 || '''Frame count'''. | + | | 0x10 || 2 || UInt16 || '''Frame count'''. |
|- bgcolor="#FFDDDD" | |- bgcolor="#FFDDDD" | ||
− | | 0x12 || UInt16 || '''[[#Bone Animation|Bone Animation]] count'''. | + | | 0x12 || 2 || UInt16 || '''[[#Bone Animation|Bone Animation]] count'''. |
|- bgcolor="#FFDDDD" | |- bgcolor="#FFDDDD" | ||
− | | 0x14 || UInt16 || '''[[ | + | | 0x14 || 2 || UInt16 || '''[[User Data]] entry count'''. |
|- bgcolor="#FFDDDD" | |- bgcolor="#FFDDDD" | ||
− | | 0x16 || — || | + | | 0x16 || 2 || — || Padding. |
|- | |- | ||
− | | 0x18 || UInt32 || '''Curve''' | + | | 0x18 || 4 || UInt32 || '''[[#Curve|Curve]] count''', the total number of Curve structures in all Material Animations. |
|- | |- | ||
− | | 0x1C || UInt32 || '''Baked | + | | 0x1C || 4 || UInt32 || '''Baked length'''. |
|- | |- | ||
− | | 0x20 || Int32 || '''[[#Bone Animation|Bone Animation]]''' array offset. | + | | 0x20 || 4 || Int32 || '''[[#Bone Animation|Bone Animation]]''' array offset. |
|- | |- | ||
− | | 0x24 || Int32 || '''Skeleton | + | | 0x24 || 4 || Int32 || '''[[FSKA|Skeleton]]''' offset. Points to the affected FSKA skeleton. |
|- | |- | ||
− | | 0x28 || Int32 || ''' | + | | 0x28 || 4 || Int32 || '''[[#Bind Indices|Bind index]] array''' offset. |
|- | |- | ||
− | | 0x2C || Int32 || '''[[ | + | | 0x2C || 4 || Int32 || '''[[User Data]] [[index group]]''' offset. |
|- | |- | ||
− | | 0x30 || colspan=" | + | | 0x30 || colspan="3" {{Unknown|End of FSKA header}} |
|} | |} | ||
− | + | === Bind Indices === | |
+ | The header points to an array of UInt16 elements with as many elements as specified in ''Bone Animation count''. It holds indices to bones, but an index can be 0xFFFF to reference no bone. The exact purpose of this array is unknown. | ||
+ | The end of the array is aligned to 4 bytes. | ||
== Bone Animation == | == Bone Animation == | ||
− | + | The header points to an array of Bone Animation structures with as many elements as specified in ''Bone Animation count'', each of 0x18 bytes size. | |
− | {|class="wikitable" | + | {| class="wikitable" |
+ | |- | ||
+ | ! Offset !! Size !! Type !! Description | ||
+ | |- | ||
+ | | 0x00 || 4 || UInt32 || '''Flags'''. Sets of bits packed as '''xxxxSSSS Sxxxxxxx CCCCCCCC CCBBBxxx''' determining if initial transformational values exist. | ||
+ | * '''BBB''' are combinable flags determining if data is available in the Base Transformation Data array to reset specific transformations: | ||
+ | {| class="wikitable" | ||
+ | ! Value !! Data Type | ||
+ | |- | ||
+ | | 1 || Scale, stores a 3-component Single vector | ||
|- | |- | ||
− | + | | 2 || Rotate, stores a 4-component Single vector (quaternion) | |
|- | |- | ||
− | | | + | | 4 || Translate, stores a 3-component Single vector |
+ | |} | ||
+ | * '''CC CCCCCCCC''' are combinable flags apparently describing what kind of Curves are available. | ||
+ | {| class="wikitable" | ||
+ | ! Value !! Description | ||
|- | |- | ||
− | | | + | | 1 || Scale X |
|- | |- | ||
− | | | + | | 2 || Scale Y |
|- | |- | ||
− | | | + | | 4 || Scale Z |
|- | |- | ||
− | | | + | | 8 || Rotate X |
|- | |- | ||
− | | | + | | 16 || Rotate Y |
|- | |- | ||
− | | | + | | 32 || Rotate Z |
|- | |- | ||
− | | | + | | 64 || Translate X |
|- | |- | ||
− | | | + | | 128 || Translate Y |
|- | |- | ||
− | | | + | | 256 || Translate Z |
|} | |} | ||
− | + | * '''S SSSS''' are additional combinable flags which apparently describe how bones affect transformations. | |
− | + | {| class="wikitable" | |
− | + | ! Value !! Description | |
− | |||
− | {|class="wikitable" | ||
|- | |- | ||
− | + | | 1 || Segment Scale Compensate | |
|- | |- | ||
− | | | + | | 2 || Scale Uniform |
|- | |- | ||
− | | | + | | 4 || Scale Volume One |
|- | |- | ||
− | | | + | | 6 (2 + 4) || Scale One |
− | |||
|- | |- | ||
− | + | | 8 || Rotate Zero | |
|- | |- | ||
− | | | + | | 16 || Translate Zero |
|- | |- | ||
− | | | + | | 24 (8 + 16) || Rotate Translate Zero |
|- | |- | ||
− | | | + | | 30 (2 + 4 + 8 + 16) || Identity |
+ | |} | ||
|- | |- | ||
− | | | + | | 0x04 || 4 || Int32 || '''Bone name''' offset of the bone to be transformed. |
|- | |- | ||
− | | | + | | 0x08 || 1 || Byte || '''Start rotation''', exact purpose unknown. |
|- | |- | ||
− | | | + | | 0x09 || 1 || Byte || '''Start translation''', exact purpose unknown. |
|- | |- | ||
− | | | + | | 0x0A || 1 || Byte || '''[[#Curve|Curve]]''' count. |
|- | |- | ||
− | | | + | | 0x0B || 1 || Byte || '''Base Transformation Data translate offset''', an offset into the Base Transformation Data to retrieve the initial bone translation when resetting their transform. |
|- | |- | ||
− | | | + | | 0x0C || 1 || Byte || '''Start [[#Curve|Curve]]''' index, relative to the whole FSKA subfile (an array where all Bone Animation Curves would be stored together, in the order of which they appear in the subfile). |
− | | | ||
|- | |- | ||
− | | | + | | 0x0D || 3 || — || Padding. |
|- | |- | ||
− | | | + | | 0x10 || 4 || Int32 || '''[[#Curve|Curve]] array''' offset. |
|- | |- | ||
− | | | + | | 0x14 || 4 || Int32 || '''[[#Base Transformation Data|Base Transformation Data]]''' offset. |
|- | |- | ||
− | + | | 0x18 || colspan="3" {{Unknown|End of Bone Animation}} | |
− | |||
− | |||
− | |||
− | | 0x18 | | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | | colspan="3 | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|} | |} | ||
− | === | + | === Base Transformation Data === |
+ | |||
+ | The Bone Animation header points to an array of float values, which have to be interpreted as 3- or 4-component vectors, depending on which base transformations are available in a bone as described in the Bone Animation '''Flags'''. It is used to reset transformations on a bone. | ||
+ | |||
+ | Vectors are stored in the following order: | ||
+ | * Scale, a 3-component Single vector | ||
+ | * Rotation, a 4-component Single vector (quaternion) | ||
+ | * Translate, a 3-component Single vector | ||
− | + | {{NW4FCurve}} | |
− | { | + | === Target === |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | The following Curve targets are possible, making the Curve control a specific transformation on the bone: | |
− | |||
{|class="wikitable" | {|class="wikitable" | ||
|- | |- | ||
− | ! | + | ! Value !! Description |
|- | |- | ||
− | | | + | | 0x04 || X Scale |
|- | |- | ||
− | | | + | | 0x08 || Y Scale |
|- | |- | ||
− | | | + | | 0x0C || Z Scale |
|- | |- | ||
− | | | + | | 0x10 || X Translate |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
− | + | | 0x14 || Y Translate | |
|- | |- | ||
− | | | + | | 0x18 || Z Translate |
|- | |- | ||
− | | | + | | 0x20 || X Rotate |
|- | |- | ||
− | | | + | | 0x24 || Y Rotate |
|- | |- | ||
− | | | + | | 0x28 || Z Rotate |
|} | |} | ||
Revision as of 17:25, 30 May 2017
The FSKA (caFe SKeletal Animation) subfile stores animations which control how to transform bones of a model over time. It appears as a subfile of a BFRES file in the 2nd index group.
Format
An FSKAfile begins with an FSKA header. This is then followed by a number of sections pointed to by the header, many of which can occur multiple times. The purpose of these sections is described in the table below.
FSKA shares many similarities with the FSHU, FTXP, FVIS, FSHA and FSCN subfiles, which mostly only differ in the structure describing what is changed by animations over time, but reusing the same animation curve and key structures, and even headers being very similar to one another.
Header (FSKA)
Every FSKA begins with an 0x30 byte FSKA header.
Offset | Size | Type | Description | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x00 | 4 | Char[4] | "FSKA" file identifier, ASCII string. | ||||||||||
0x04 | 4 | Int32 | File name offset (without file extension). | ||||||||||
0x08 | 4 | Int32 | File path offset, the path of the file this data was originally created from. Stripped in Mario Kart 8 files, always pointing to an empty string at the end of the BFRES string table. | ||||||||||
0x0C | 4 | UInt32 | Flags. Set of bits controlling how data is stored, packed as xxxxxxxx xxxxxxxx xxxRxxSS xxxxxPxC.
| ||||||||||
if BFRES version >= 3.4.0.0 | |||||||||||||
0x10 | 4 | UInt32 | Frame count. | ||||||||||
0x14 | 2 | UInt16 | Bone Animation count. | ||||||||||
0x16 | 2 | UInt16 | User Data entry count. | ||||||||||
else | |||||||||||||
0x10 | 2 | UInt16 | Frame count. | ||||||||||
0x12 | 2 | UInt16 | Bone Animation count. | ||||||||||
0x14 | 2 | UInt16 | User Data entry count. | ||||||||||
0x16 | 2 | — | Padding. | ||||||||||
0x18 | 4 | UInt32 | Curve count, the total number of Curve structures in all Material Animations. | ||||||||||
0x1C | 4 | UInt32 | Baked length. | ||||||||||
0x20 | 4 | Int32 | Bone Animation array offset. | ||||||||||
0x24 | 4 | Int32 | Skeleton offset. Points to the affected FSKA skeleton. | ||||||||||
0x28 | 4 | Int32 | Bind index array offset. | ||||||||||
0x2C | 4 | Int32 | User Data index group offset. | ||||||||||
0x30 | End of FSKA header |
Bind Indices
The header points to an array of UInt16 elements with as many elements as specified in Bone Animation count. It holds indices to bones, but an index can be 0xFFFF to reference no bone. The exact purpose of this array is unknown. The end of the array is aligned to 4 bytes.
Bone Animation
The header points to an array of Bone Animation structures with as many elements as specified in Bone Animation count, each of 0x18 bytes size.
Offset | Size | Type | Description | ||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x00 | 4 | UInt32 | Flags. Sets of bits packed as xxxxSSSS Sxxxxxxx CCCCCCCC CCBBBxxx determining if initial transformational values exist.
| ||||||||||||||||||||||||||||||||||||||||||||||
0x04 | 4 | Int32 | Bone name offset of the bone to be transformed. | ||||||||||||||||||||||||||||||||||||||||||||||
0x08 | 1 | Byte | Start rotation, exact purpose unknown. | ||||||||||||||||||||||||||||||||||||||||||||||
0x09 | 1 | Byte | Start translation, exact purpose unknown. | ||||||||||||||||||||||||||||||||||||||||||||||
0x0A | 1 | Byte | Curve count. | ||||||||||||||||||||||||||||||||||||||||||||||
0x0B | 1 | Byte | Base Transformation Data translate offset, an offset into the Base Transformation Data to retrieve the initial bone translation when resetting their transform. | ||||||||||||||||||||||||||||||||||||||||||||||
0x0C | 1 | Byte | Start Curve index, relative to the whole FSKA subfile (an array where all Bone Animation Curves would be stored together, in the order of which they appear in the subfile). | ||||||||||||||||||||||||||||||||||||||||||||||
0x0D | 3 | — | Padding. | ||||||||||||||||||||||||||||||||||||||||||||||
0x10 | 4 | Int32 | Curve array offset. | ||||||||||||||||||||||||||||||||||||||||||||||
0x14 | 4 | Int32 | Base Transformation Data offset. | ||||||||||||||||||||||||||||||||||||||||||||||
0x18 | End of Bone Animation |
Base Transformation Data
The Bone Animation header points to an array of float values, which have to be interpreted as 3- or 4-component vectors, depending on which base transformations are available in a bone as described in the Bone Animation Flags. It is used to reset transformations on a bone.
Vectors are stored in the following order:
- Scale, a 3-component Single vector
- Rotation, a 4-component Single vector (quaternion)
- Translate, a 3-component Single vector
Curve
Curves store how animations are performed over time and store the required keys and values for this. They appear in multiple animation subfiles, and their header is of 0x24 bytes size (for BFRES versions earlier than 3.4.0.0, they are of 0x20 bytes size).
Offset | Size | Type | Description | ||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x00 | 2 | UInt16 | Flags. Sets of bits packed as xxxxxxxx xCCCKKFF.
| ||||||||||||||||||||||||||||||||||||||||||||||||
0x02 | 2 | UInt16 | Key count. | ||||||||||||||||||||||||||||||||||||||||||||||||
0x04 | 4 | UInt32 | Target Offset, an offset in bytes into the corresponding Animation Data structure to animate the field at that relative address. | ||||||||||||||||||||||||||||||||||||||||||||||||
0x08 | 4 | Single | Start frame, the first frame at which a key is placed. | ||||||||||||||||||||||||||||||||||||||||||||||||
0x0C | 4 | Single | End frame, the last frame at which a key is placed. | ||||||||||||||||||||||||||||||||||||||||||||||||
0x10 | 4 | Int32 / Single | Data scale, multiplier to the raw key values to get the final result. Together with Data offset, it is chosen carefully to consider an optimal granularity between the stored values. | ||||||||||||||||||||||||||||||||||||||||||||||||
0x14 | 4 | Single | Data offset, added to the raw values (after multiplying them with Data scale) to get the final key value. | ||||||||||||||||||||||||||||||||||||||||||||||||
if BFRES version >= 3.4.0.0 | |||||||||||||||||||||||||||||||||||||||||||||||||||
0x18 | 4 | Single | Data delta, stores the difference between the first and last key value. | ||||||||||||||||||||||||||||||||||||||||||||||||
0x1C | 4 | Int32 | Frame array offset. | ||||||||||||||||||||||||||||||||||||||||||||||||
0x20 | 4 | Int32 | Key array offset. | ||||||||||||||||||||||||||||||||||||||||||||||||
0x24 | End of Curve | ||||||||||||||||||||||||||||||||||||||||||||||||||
else | |||||||||||||||||||||||||||||||||||||||||||||||||||
0x18 | 4 | Int32 | Frame array offset. | ||||||||||||||||||||||||||||||||||||||||||||||||
0x1C | 4 | Int32 | Key array offset. | ||||||||||||||||||||||||||||||||||||||||||||||||
0x20 | End of Curve |
Frames
The Curve header points to a Frame array which stores values controlling at which frame a Key from the Key array is placed. Thus, the array has as many elements as specified in Key count. The data type of the frames is given in the Curve's Flags.
The end of the array is aligned to 4 bytes.
Keys
The Curve header points to a Key array which stores the key values and additional values to interpolate the curve from one point to the next. Thus, the array has as many elements as specified in Key count, multiplied by the number of elements stored per key (depending upon the CCC Curve Type bits in the Curve Flags as described above). The data type of each element is given by the KK Key Type bits in the Curve Flags.
The end of the array is aligned to 4 bytes.
Step Curves
The elements apparently represent the key values directly.
Linear Curves
For linearly interpolated curves, 2 elements are stored per key:
- Value at which the key is set. To get the final value, scale and then offset it.
- Delta to value at next frame to which the curve linearly runs. To get the final value, scale it. If there is no next frame, this is always 0.
A key can be discarded by the next key if that one is stored at the same frame. In that case, only the value of the next key is stored, and the delta of the previous key is adjusted to run to the value of the now discarded key.
This example curve's keys are stored as SByte elements. The curve scale was computed as 2, the offset as 200 and the curve delta (if available in the BFRES version) as 300. Due to the lower key in frame 20 being discarded in favor of the higher key, only 3 keys are stored in 6 elements as follows.
Point | Array Index | Raw Value | *2 (Scale) | +200 (Offset) | Notes |
---|---|---|---|---|---|
0,0 | 0 | -100 | -200 | 0 | Initial key with value 0. |
(20,254) | 1 | 127 | 254 | - | Delta to end value of initial key at next frame. |
20,254 | - | - | - | - | This key is discarded in favor of the next. |
20,400 | 2 | 100 | 200 | 400 | Overrides previous key. |
(30,300) | 3 | -50 | -100 | - | End value of overriding key at next frame. |
30,300 | 4 | 50 | 100 | 300 | Value of fourth (but third stored) key. |
(end) | 5 | 0 | 0 | - | Since no frame follows, always 0. |
Hermite Curves
For hermite curves, 4 elements are stored for each key. It is unclear how to exactly interprete them to form the curve out of it.
Target
The following Curve targets are possible, making the Curve control a specific transformation on the bone:
Value | Description |
---|---|
0x04 | X Scale |
0x08 | Y Scale |
0x0C | Z Scale |
0x10 | X Translate |
0x14 | Y Translate |
0x18 | Z Translate |
0x20 | X Rotate |
0x24 | Y Rotate |
0x28 | Z Rotate |
Tools
The following tools can handle FSKA files:
- ModelThingy, by Ploaj (can animate models)