Animation and Movie file format proposal
To summarise, an animation (.anim.binltl) is a sequence of keyframes affecting scale, rotation, position, alpha, colour and sound. But it doesn't specify what is animated, only how it is animated. It's used for animating single elements, e.g. an object in a level. A good example is rot_1fps with rotates 360 degrees every second and is used in many levels.
A movie (.movie.binltl) is basically one of the game cut-scenes (though there are a few special-case ones like end-of-level movies). It consists of a sequence of actors (images or text) each of which is animated according to an animation in the same format as above.
There's no magical encryption to these files, they're simply binary data that corresponds exactly to the structs used by the game itself. This makes it impossible for us to provide a standard "encrypt/decrypt" function for addin authors. So on the (seven hour) train ride today I spent some time perfecting my .binltl import and coming up with an XML file format describing both animations and movies.
The first thing I came up with was a direct like-for-like translation of the binary formats to XML. Check out anim_and_movie_v1.zip of both animations and movies.
Then I analysed the existing files a little more closely and came up with the following observations:
Even though a keyframe has fields for alpha, colour, angle, position, and sound strings, I have confirmed the following as true for all existing movies and animations:
- x,y are always -1 except for scale and translate transform keyframes. For those they are never -1
- angle is always -1 except for rotate transform keyframes, where it is never -1
- alpha is always -1 except for alpha keyframes, where it is never -1
- colour is always -1. On the few anims where colour keyframes exist (e.g. treeBlow_trunk) there is only one keyframe and its colour value is still -1. It's not used at all on movies, only animations. Not sure whether colour frames therefore have any purpose.
- soundStr is always 0 except for sound keyframes. 0 is an offset in the string table to a null-terminated string of length 0. Sound keyframes only ever exist in movies, not raw anims.
- For movies, there are always exactly three transforms, and they're always SCALE followed by ROTATE followed by TRANSLATE (which is of course the order you want when doing matrix multiplication)
- For anims, this isn't always the case. Specifically, ball_counter_ocd breaks this by having SCALE,SCALE,ROTATE,TRANSLATE (the first scale is 2.0,2.0) and rot_1rps breaks it by having no scale or translate keyframes at all.
For movies, there are always a matching set of transform, alpha and colour frames, each frame having the same nextframe index and same interpolation type.
This doesn't apply to anims. e.g. some only have a single alpha=255 frame for their whole duration.
This doesn't apply to sound frames in movies either, which have their own existence. The sound frames are inserted at the point when the sound needs to play, even if no other types of frame exist at this point in time. The other frame types then skip over this frame via nextframe.
Sound frames are normally (but not always) added to the last actor in a movie, but in every case there's never more than one actor with sound frames.
Interpolation is from the current item to its nextframe, not from the previous frame to this frame.
Interpolation is consistent within a movie across all keyframe types.
All these things seem to imply that anims were created by hand or script, whereas movies were probably exported from some other format.
In movies, if you take out all the sound frames and then shuffle down empty keyframes, the frames are all consecutive per actor in a movie and so nextframe is superfluous (this isn't true for anims, specifically ball_counter_ocd with its dual SCALE transforms).
All actors have a final keyframe that coincides with the movie's end time, even if nothing changes between their last "real" keyframe and the movie end. Example:
<movie length="31.571428"> <actor type="image" depth="0.0" align="center"> <image id="IMAGE_MOVIE_CHAPTER1END_BLACK32"/> <simple-animation> <keyframe time="0.0" x="547.5" y="300.0" angle="0.0" scale-x="34.218964" scale-y="18.750275" alpha="255"/> <keyframe time="31.571428" x="547.5" y="300.0" angle="0.0" scale-x="34.218964" scale-y="18.750275" alpha="255"/> </simple-animation> </actor>
The following facts are true for all movie files (I define this as "simple" animation):
// A simple animation has: // 1. No colour, and no sound. // 2. Has transforms, exactly 3 of them: SCALE, ROTATE and TRANSLATE in that order // 3. No skipped keyframes. So all frames are present for all transforms. And they're all sequential, ending with -1. // 4. Has alpha, and no skipped frames there either. And an alpha frame exists for each transform frame, and vice versa.
So to simplify the XML for the most common cases, I created an <animation> element, which has a simple list of unnumbered keyframes, all with alpha. All movies can be generated into "simple" animations.
Some but not all anims can be generated into "simple" animations. The remainder retain the original format of individual keyframes of each type, within a <complex-animation> animation.
I therefore came up with a simplified and less verbose form for the common case.
I would very much appreciate your feedback on the anim_and_movie_v2.zip file format.
Note in particular that, since sound frames only ever get "attached" to an existing actor, I've removed them from the animation entirely and seperated them out into their own "sounds" element, and removed any remaining redundant keyframes from the original element.
I'm not too happy with having both animation and complex-animation but I think it's the best way to achieve full flexibility where required, without making "normal usage" overly verbose. And at the end of the day it's only a bit more code for GooTool.
Upon consensus this will become the standard format for ".anim.xml" and ".movie.xml" in the goomod specification version 1.1 and will be implemented in GooTool in the next release.
NB NB NB Don't bother coding anything to this format yet! It's liable to change, and if we get consensus I'll document it properly.