FSHU (File Format)
The FSHU (caFe SHader parameter animation Uber) subfile stores shader parameter animations. It appears as a subfile of a BFRES file in the 3rd index group for general parameter animations, in the 4th index group for color animations, and in the 5th index group for SRT texture animations.
An FSHU file begins with an FSHU 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.
FSHU shares many similarities with the FSKA, 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.
Every FSHU begins with an 0x34 byte FSHU header.
|0x00||4||Char||"FSHU" 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 packed as xxxxxxxx xxxxxxxx xxxxxxxx xxxxxLxB, controlling how to play the animation and what data is stored. The following flags are possible:
|0x14||2||UInt16||Material Animation count. Number of elements in the Material Animation array.|
|0x16||2||UInt16||User Data entry count.|
|0x18||4||Int32||Parameter Animation Info count, the total number of Parameter Animation Info structures in all Material Animations.|
|0x1C||4||UInt32||Curve count, the total number of Curve structures in all Material Animations.|
|0x24||4||Int32||Model offset. Points to the affected FMDL model.|
|0x28||4||Int32||Bind index array offset.|
|0x2C||4||Int32||Material Animation array offset.|
|0x30||4||Int32||User Data index group offset.|
|0x34||End of FSHU header|
The header points to an array of UInt16 elements with as many elements as specified in Material Animation count. It holds indices to materials, but an index can be 0xFFFF to reference no material. The exact purpose of this array is unknown. The end of the array is aligned to 4 bytes.
The header points to an array of Material Animation structures with as many elements as specified in Material Animation count, each of 0x20 bytes size.
|0x00||2||UInt16||Parameter Animation Info count.|
|0x04||2||UInt16||Animation Constant count.|
|0x08||4||Int32||Start Curve index, relative to the whole FSHU subfile (an array where all Material Animation Curves would be stored together, in the order of which they appear in the subfile).|
|0x0C||4||Int32||Start Parameter Animation Info index, relative to the whole FSHU subfile (an array where all Parameter Animation Infos would be stored together, in the order of which they appear in the subfile).|
|0x10||4||Int32||Animation name offset.|
|0x14||4||Int32||Parameter Animation Info array offset.|
|0x18||4||Int32||Curve array offset.|
|0x1C||4||Int32||Animation Constant array offset.|
|0x20||End of Material Animation|
Parameter Animation Info
Each Material Animation points to an array of Parameter Animation Info structures, with as many elements as specified in Parameter Animation Info count, each of 0x10 bytes size.
|0x00||2||UInt16||Start Curve index in the Curve array of the Material Animation.|
|0x02||2||UInt16||Float Curve count.|
|0x04||2||UInt16||Int Curve count.|
|0x06||2||UInt16||Start Animation Constant index in the Constant array of the Material Animation.|
|0x08||2||UInt16||Animation Constant count.|
|0x0A||2||UInt16||Sub bind index.|
|0x10||End of Parameter Animation Info|
Each Material Animation points to an array of Animation Constants, with as many elements as specified in Constant count, each of 0x08 bytes size.
|0x04||4||Int32 / Single||Value of this constant.|
|0x08||End of Animation Constant|
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 220.127.116.11, they are of 0x20 bytes size).
|0x00||2||UInt16|| Flags. Sets of bits packed as xxxxxxxx xCCCKKFF.
|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 >= 18.104.22.168|
|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|
|0x18||4||Int32||Frame array offset.|
|0x1C||4||Int32||Key array offset.|
|0x20||End of Curve|
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.
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.
The elements apparently represent the key values directly.
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.|
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.
The Curve targets which control what exactly is animated over time are not yet known.