GlsAnimation Library
1.0.6
Provides classes and functions to support animating GL Studio objects programmatically or with script files
|
The GL Studio animation library can help users of GL Studio create animations at runtime. There are two ways to create animation objects – use the GlsAnimation API or read in animations from a script file. There are also two ways to play back animations once they are created: manually or via the animation juggler.
The library is distributed in source code format. To use it, add the source files to your project. For loading script files, also add the files from the tinyxml and zlib folders. The library is compatible with GL Studio 4.x and newer.
The GlsAnimation API is documented in the accompanying doxygen documentation, which is extracted from the comments in the header files, and exists in the disti
namespace.
The basic unit is the GlsAnimation
class, which is an abstract interface used by the rest of the animation system such as the animation juggler. Its SetKey()
is the central function for manually animating objects. The key is usually a time value in seconds, but not always (e.g., it could be x-coordinate or miles per hour).
The GlsKeyframeAnimation
class implements the GlsAnimation
interface. It is composed of a property name, which is a string conforming to the GL Studio Resources API's format and which identifies what property to animate, and a GlsKeyframeCurve
object, which determines how to animate the property.
The GlsKeyframeCurve
class contains keyframes (keys and values) and returns what the value should be for a given key. It accepts an interpolator object to determine values in between. Interpolators for linear interpolation between keyframes, gated values (i.e., values that change only on the given key thresholds and not in between), and spherical linear interpolation (slerp) for rotation vectors and quaternions are supplied, and other interpolators such as splines can be created by implementing the GlsKeyframeInterpolator interface.
Each of these supporting classes is templated on allowable types (double
, disti::Vector
, disti::glsColor
, disti::GlsQuaternionD
, and std::string
), and the GlsKeyframeAnimation
class hides that templating. The string type can be used to animate any type not listed above (e.g., booleans, matrices, etc.), but it only supports gated interpolation since interpolation between arbitrary strings is impossible. Interpolating between vectors, quaternions, and colors interpolates between each of their components independently.
The GlsAnimationCollection
also implements the GlsAnimation
interface and represents a set of keyframe animations that are played in parallel via the SetKey()
method. The contained animations can be of different lengths and have completely different key values.
The function LoadAnimationScript()
loads a script file from disk. It returns a GlsAnimation
object which can then be used to animate objects. The script file can be generated by hand by comparing an existing XML script file or by one of the script files provided by DiSTI to export animations from Adobe After Effects or by converting a CSV file.
Script files should generally be optimized to remove redundant keyframes, which can drastically reduce their size. For speeding up load times of sets of scripts that are still large enough that disk access becomes a bottleneck, a second function called LoadAnimationZip()
loads multiple animation scripts from a zip file and decompresses them in memory. (E.g., a zip file might contain StartupAnimation.xml, MenuFlyin.xml, PageTransition.xml, and ShutdownAnimation.xml, and LoadAnimationZip()
will return a collection of GlsAnimation
objects, one for each of these files.) Because this capability introduces a dependency on the zlib library and some helper code that ships with it, it is disabled by default. To enable it, define GLS_ANIMATION_ENABLE_ZIP_LOADING
project-wide, add the helper source files from GlsAnimation/zlib to your project, and link in either the zlib library or the GL Studio runtime which includes it.
Before playing back animations, each animation needs a disti::DisplayFrame
to operate on. Usually, this is the top-level application instance or a component instance. As an aid to debugging, if the configured animation property names are not found and if GLS_DEBUG
is defined, the call to set the display frame (whether implicit or explicit) will print out a message indicating which animations will not function properly.
Given one or more GlsAnimation objects, the user can call the SetKey()
function to set the key (usually time) in the given animation. If desiring fine-grained animation, call SetKey()
with tiny changes on the key. Note that the key does not need to be monotonically increasing but can be set to any value within the range. If the user sends in a key of -10 while the minimum key is 0, the value for a key of 0 will be applied.
As an example, with three key-value pairs in our animation object like:
Key | Value |
---|---|
0 | 42 |
10 | 43 |
30 | 48 |
Then calling SetKey()
with the following keys will yield the following values:
Key | Value |
---|---|
-1 | 42 |
0 | 42 |
5 | 42.5 |
10 | 43 |
15.1 | 44.275 |
23.7 | 46.425 |
30 | 48 |
50 | 48 |
The GlsAnimationJuggler
allows the user to "fire and forget" animations, execute them immediately or at some point in the future, to play at varied speeds, and to receive a callback when the animation is started, updated, or completed. Usually there will be one juggler per application, but this is not a hard restriction (e.g., if one juggler is for time and one is for x-coordinates and one for sped-up animations).
The central function of the juggler is the Schedule()
function which schedules an animation to run. For receiving callbacks when the animation is complete, call one of the helper functions like CreateOnCompletedCallback()
, which accepts function pointers and functors (including C++11 lambdas); create an instance of GlsAnimationObserver
, passing in the callback items for starting, updating, and completing; or subclass GlsAnimationObserverBase
if the callback needs more complex behavior than the aforementioned helpers provide.
void MyCallBack( GlsAnimationJuggler::ID ); // Prototype for our callback GlsAnimationJuggler::Ptr juggler( new GlsAnimationJuggler() ); GlsAnimation::Ptr animation = LoadAnimationScript( "animation.xml" ); juggler->Schedule( animation, CreateOnCompletedCallback( &MyCallback ), myApp );
Once animations are scheduled, the user is responsible to call the Advance()
function at the appropriate time, usually in the application's Calculate()
function. Note that the parameter to advance is delta time, not absolute time, which typically means the call looks like:
juggler->Advance( time - previousTime );
The animation library provides multiple keyframe interpolators that provide intermediate values in between keyframes. These "tweeners" can be useful for getting simple animations without having to supply many keyframes. To select an interpolator in hand-written animations, create an instance of the desired interpolator and pass it into the GlsKeyframeCurve
constructor, e.g.,
auto curve1 = new GlsKeyframeCurve<double>( new GlsGatedInterpolator<double>() ); auto curve2 = new GlsKeyframeCurve<double>( new GlsSinusoidalEaseInOutInterpolator<double>() ); auto curve3 = new GlsKeyframeCurve<Vector>( new GlsSphericalLinearInterpolator<Vector>() );
As a convenience, the function CreateTweenerCurve()
can be used as follows to create a tweener curve:
auto curve4 = CreateTweenerCurve( 1.0, 325, 20, g_bounceInOutTag ); // Create a bounce in and out tweener for doubles from 1-325 over 20 seconds auto curve5 = CreateTweenerCurve( glsColor(0,0,0,0), glsColor(255,127,0,255), 10, g_quadInTag ); // Create a tweener for colors over 10 seconds
These curves can be applied to a property value in a GL Studio design by using them in an animation object:
auto animation = new GlsKeyframeAnimation( "Color bounce", "polygon1.FillColor", curve5 );
To select an interpolator in an animation script, specify it after a colon in the parameter type, e.g.,
<AnimationProperty name="Heading" type="float:quadraticInAndOut">
Additionally, the animation library provides a spherical linear interpolator (or slerp) for quaternions and rotation vectors. If the user does not supply an interpolator object to the keyframe curve or if an animation script does not have an interpolation type specified, the library assumes linear interpolation for floats, vectors, and colors; gated interpolation for strings; and spherical linear interpolation for quaternions.
Many functions in the library accept either a raw pointer or a shared pointer (reference-counted smart pointer). If the former is used, the object takes sole ownership of the object. If the latter is used, the user retains the object and can re-use it for other purposes. For instance, a single keyframe curve can be used by multiple animations by using shared pointers, and a user can re-use an animation object after it has completed playing in the juggler by passing it in as a shared pointer.
Note that some platforms may require special compiler flags or tweaks to get identical results. For instance, some GCC-based platforms require the -ffloat-store
option for the rounding of interpolated color values to work as expected.
Note that some older systems do not support std::shared_ptr
out of the box. Sometimes it may be found in the TR1 library (changing the namespace to std::tr1::shared_ptr
and possibly changing the header file from <memory>
to <tr1/memory>
or similar) or Boost which has both boost::shared_ptr
and a TR1 implementation (i.e., std::tr1::shared_ptr
) in <boost/tr1/memory.hpp>
. Any of these should suffice, though they are not all fully compatible with each other. Some versions of GCC may require the command line option –std=c++0x
or –std=c++11
to support std::shared_ptr
. For maximum compatibility, we define a namespace alias stdortr1
that points to std::tr1
by default (thus using std::tr1::shared_ptr
), but defining GLS_ANIMATION_USE_STD_SHARED_PTR
project-wide will make stdortr1
point to std
(and hence use std::shared_ptr
) instead.