Skip to main content

Been There, Scene That

Posted by chet on January 4, 2008 at 2:27 PM PST

(This is Part 1 of a two-part blog. It's been broken in two for no particularly good reason other
than it was getting a bit long for a single entry and I always like a bit of suspense and
tension in my technical articles - don't you?
. Look for Part 2 in the next few days)

You may have already heard about the Scene
Graph project
that we released last
month on

In case you haven't heard about it yet, here's some information about it:

We released the project last month on

Since the team was pretty busy at the time (I was at
talking about the
project, among other things, and the team was cranking away on the actual
code), we haven't really gotten around to blogging about it yet to tell people
more about the project (hey, the code's out there - does anyone need anything
more?). Fortunately for us,
seems to blog in his sleep, so there's at least been some information
out there in the blogosphere. But maybe now that the library is available, we should actually
talk about it to help everyone understand what it is, how it works, and what
you can do with it.

Hans Muller is working an
intro/overview on the subject. Chris Campbell has a blog in the works on scene graph image effects. And I was tasked with (surprise, surprise) a
discussion of animation.


I think that the best way to describe the animation engine in the scene graph
project is that it is like the next major version of the
Timing Framework
. Maybe it's because I'm a graphics geek, but I always find
it easier to understand concepts through pictures. So here's a technical diagram
illustrating how the scene graph animation engine relates to the Timing Framework.
It's a bit technical, but hopefully you'll get the point.


The similarlity between the two libraries is not, obviously, a coincidence. We started with the 1.0 version
of the Timing Framework and changed it to suit our needs for the scene graph, where "suit our needs" means that we refactored the API to improve upon various things and added functionality that has so far
been lacking in the Timing Framework.

Rather than explain how the Timing Framework works, I'd encourage you to check
out the project, the docs linked on the project site, the demos for that project, and
the copious other amounts of information on the library (including demos,
chapters in the Filthy Rich Clients
book, and so on). I'll assume that
anyone reading past here has some passing familiarity with the Timing

I'll step through the major categories of differences between the
TimingFramework and this new animation library, to give a sense of what's new
in the scene graph. I'll show some sample code along the way, although I'd encourage you to check out
the Nodes example on the
scene graph site to see animation usage in action.

Refactoring: What's Changed?

Clip is the new Animator

After living for way too long with the bureaucratically dull name
that came from the original version of the Timing Framework, we finally
renamed that class to the friendlier Animator name that the library enjoys
today in version 1.0. But now it's changed again. That
class, the most fundamental in the whole library, is now called Clip. This
was done to help people that might be familiar with the concepts covered by
that class in other toolkits and environments where the name Clip is common. It's also
closer to what the object is; yes, it animates things, but it's really just a
short, atomic animation which is meant to be strung together with other
animations in an application, much like short clips are edited together to make
an entire movie (or, in the case of the
Fantastic Four sequel, to make a travesty).

Besides, Clip saves 4 characters every time you type it. Pretty cool, huh?
That's like several milliseconds of coding time per day that we've saved you, our
user. All part of the
job, providing service and performance with a smiley.

Clip has a handful of factory methods for the common cases:

            create(int duration, double repeatCount, Object target, 
                   String property, T... keyValues)

            create(int duration, double repeatCount, Property property, T... keyValues)

            create(int duration, double repeatCount, TimingTarget target)

            create(int duration, Object target, String property,
                   T... keyValues)

            create(int duration, Property property, T... keyValues)

            create(int duration, TimingTarget target)

(The Property object will be explained later, but think of it as a replacement for
the previous PropertySetter object in the Timing Framework).

Like Animator, Clips begin running when the start() method is called (although
Clip also has more involved and powerful scheduling capabilities, discussed later):

            // Fade in myObject over a half second
            Clip clip = Clip.create(500, myObject, "opacity", 0f, 1f);

PropertySetter is now BeanProperty

The old way of having the animation engine automatically set object/property
values was through the PropertySetter class, which was constructed with a given
object and property-name pair. We felt that this was a bit too constrictive in
a world where there might be other ways that one might want to set values on
objects; what if someone has an object without JavaBean-like getter/setters on

So we defined a new interface, Property, that abstracts out the concepts and methods for getting and setting the value of some property.

            public interface Property<T> {
                public <T> getValue();
                public void setValue(T value);

Then we refactored the old PropertySetter class as the new class
which is an implementation of that interface that specifically defines
properties in terms of JavaBean objects/name pairs.

            public class BeanProperty<T> implements Property<T> {
public BeanProperty(Object object, String propertyName);

                public <T> getValue();
                public void setValue(T value);

Also, note that we separated the functionality of setting values on a Property object
from animating those values. These concepts overlapped in the previous
PropertySetter object, which was an implementation of TimingTarget and handled
both animating the value in question as well as setting it on the specified
object. Now, the new KeyFrames object handles animating a property, and the
resulting value is then sent into the appropriate Property object.


One of my favorite refactorings from the TimingFramework was the change that Chris
Campbell made to interpolators. The base interface, Interpolator, is the same:

            public interface Interpolator {
                public float interpolate(float fraction);

The change is that there used to be several implementation classes of
Interpolator (LinearInterpolator, DiscreteInterpolator, and
SplineInterpolator), and now there is just one class, Interpolators,
that provides five factory
methods for different types of interpolators:

            public class Interpolators {
                static Interpolator getLinearInstance();
                static Interpolator getDiscreteInstance();
                static Interpolator getSplineInstance(float x1, float y1, float x2, float y2);

                static Interpolator getEasingInstance();
                static Interpolator getEasingInstance(float acceleration, float deceleration);

The linear, discrete, and spline interpolators are virtually the same as
before, in both construction and
operation. But there is now an additional "easing" variety that takes the place
of the setAcceleration()/setDeceleration() behavior in the old Animator class.
This simplifies the use of acceleration/deceleration, and makes it more
consistent with the use of other interpolator functionality.

Also, note that Clip uses an easing interpolator by default (with the default factors
of .2f/.2f), as opposed
to the old linearly-interpolated Animator object. Linear interpolation makes
more sense as a default from an analytical standpoint (it seems less arbitrary
than some particular choice of easing factors), but frankly most of the animations that
you'll create should be non-linearly interpolated, which means that you would either not get the behavior you should if you used the linear
default or (as in all of my animation demos) you'd have to keep writing the same
boilerplate code to set the easing factors to get the behavior right.


The previous structure of KeyFrames was closely modeled on the
where there was a list of n KeyTimes, a list of n
KeyValues which corresponded
to the times in KeyTimes, and an optional list of (n-1) Interpolators for the
intervals between the times in KeyTimes. The basic functionality of that system
is unchanged, but it has been reorganized in a way that we think makes more
sense for the API.

Now there is a KeyFrame object which holds a time/value pair as well as an optional Interpolator. The Interpolator is used for the interval between the previous
KeyFrame and this one (which is ignored if this is the first
KeyFrame, since there is no preceding interval). A KeyFrames object in the new system is just a
collection of these individual KeyFrame objects. There is also more latitude now for
creating animations without start/end values. For example, if a KeyFrames
object is defined without a KeyFrame object at time t=0,
then the animation
derives the value at t=0 when the animation is started. Additionally, if there is no KeyFrame at time t=1, then the animation simply holds the value set by the
preceding KeyFrame.

KeyFrames implement the TimingTarget interface, and are used as targets of an
animation to animate a value and then set it on the Property object with
which they were constructed.
Note that KeyFrames objects are created either with an explicit Property object
or with the object/property
pair that is used to construct a BeanProperty object internally:

            static KeyFrames<T> create(Object target, String propertyName, KeyFrame<T>... keyFrames);
            static KeyFrames<T> create(Object target, String propertyName, T... keyValues);
            static KeyFrames<T> create(Property<T> property, KeyFrame<T>... keyFrames);
            static KeyFrames<T> create(Property<T> property, T... keyValues);

Evaluator is now Composer

The system in TimingFramework to handle interpolation between values of various
types uses the Evaluator class (or, rather, subclasses of Evaluator). Each Evaluator subclass is defined to take values of a certain type, a fraction
to interpolate between then, and would linearly interpolate between those values.
abstracted this functionality another level and created the Composer class. It
performs similar functionality, but only requires from its subclasses the
work of breaking down a type into component pieces that are stored in
double values. That is, the Evaluator class internally handles the simple
parameteric calculation that interpolates between two double values. All that
Composer and its subclasses need to do is to marshall values between their
native representation and a representation in a series of doubles.

As in the TimingFramework, most types that you would care about animating are
already handled by the system. But if you do need to animate a variable of a type
that is unknown to the system, then you need to create your own Composer subclass and register it
with the system. It will then be used whenever the system encounters that type
and looks for an appropriate Composer. Instead of putting sample code for a here, I'll just defer to the JavaDocs
and the source code, which do a good job of showing what any new subclass would
need to do in order to work within this system. But assuming you've defined some
custom Composer, MytypeComposer, registration is easy:

            Composer.register(new MytypeComposer());

TimingTrigger is replaced by Clip dependency scheduling

One piece of functionality that is completely gone is the old
This class is the mechanism for sequencing animations in the Timing Framework;
you daisy-chain animations by triggering one animation to start when
another ended. But now, the Clip class has this capability built-in, with more
bells and whistles. Instead of going through a Trigger to sequence animations,
you can tell the animations directly that you want to sequence them on each
other. Also, there is more flexibility in how the animations are sequenced; you
can schedule an animation to start on another animation's start or end, and can
do either one with a specified offset value.

            addBeginAnimation(Animation anim);
            addBeginAnimation(Animation anim, long offset);

            addEndAnimation(Animation anim);
            addEndAnimation(Animation anim, long offset);         

(where Animation is the superclass
of both Clip and the as-yet-undiscussed Timeline class).

So, for example, you can have
clipB start 100 ms after clipA ends with the following call:

clipA.addEndAnimation(clipB, 100);

Minor Changes

There are various minor changes to the system that you will notice as you try it
out. It's not worth going through all of these (because it'd take me a long
time to go over the API to catch all of these changes, for one thing), but they
should be fairly self-explanatory when you encounter them. For example, the old
Animator.INFINITE constant, which was used, for example, to define unending
animations has become Clip.INDEFINITE. Not a big change, but it seemed more
semantically correct.

(That's it for this entry - check back next week for the gripping conclusion to this discussion, as we go over some of the new bits in the scene graph animation library that are not now part of the Timing Framework)

Related Topics >>


psychostud: AnimTrans is complementary to the scene graph animation engine for now, just like it's complementary with the Timing Framework. The "animation engine" is all about providing the fundamental support for timing behavior plus the ability to interpolate values of different types. AnimTrans, however, is about providing a layer on top of that to make animated seques, in particular, much easier. Maybe something like this makes sense to include in the scene graph engine eventually, but for now it's a separate piece of functionality.


Finally or too late?
1. Sun has been pushing 20 years old technology (Swing) for too long. Macromedia has shown the way forward with Flash, Microsoft followed with WPF (aka Silverlight) and now Sun is reimplementing this concept (animated scenegraph) with Java FX. Finally! But this is only the first step in the right direction. 2. Flash is not successful because Flash Player (or Actionscript) is a great technology (they both suck), but because they have a great IDE targeted at designers. Remember, great GUIs are made by designers not developers. Most developers hate designing GUIs and they suck at it. What Java needs is a GUI design tool that bridges the gap between designers and developers (you know what I mean when you yet again start transforming HTML design into XML/XSLT/Velocity/whatever template). A tool that lets us developers easily pick up where designers left off. Microsoft learned that lesson as we can see by their Expression series. Hope Sun has learned that lesson too. Or is it too late? 3. And finally: Sun, I hope you don't think that you can make a breakthrough GUI technology (Web or RIA) without supporting at least an industry-standard video playback, preferably also recording. Codec that is going to rule the next decade is H.264. If we can't create a YouTube rip-off in Java, don't bother developing this technology, because it's not going to make us competitive versus Flash or Silverlight.

thats great chet,
does the scenegraph also have something similar to the animatedTransitions Library or would they work complementing each other ?

psychostud: You've cleverly anticipated part of what I cover in Part 2 - I'll be posting that later today or tomorrow... (no problem about the typo - I've been called worse...)


Yes, Chet is actually The Cheat of HomeStarRunner fame. Long Live Da Cheat!

sorry for the typo Chet

So Cheat ,
does this mean we put away the timing Framwork at 1.0 and start using the animation engine in the scene graph in future?

Well, what can I say. It's cold and grey and rainy here in Oregon. Blogging is way more fun than sleeping. :)

What is the relationship between the Property and BeanProperty classes in the Scene graph project and the Property and BeanProperty classes in the Beans Binding project? It seems like they are practically identical. Have you guys spoken to Scott Violet and Shannon Hickey about how the binding framework and scene graph timing framework will integrate?