com.hdcookbook.grin.animator
Interface AnimationClient

All Known Implementing Classes:
SEShow, Show

public interface AnimationClient

An AnimationClient is a client of an AnimationEngine. When it's set up, an AnimationEngine calls an AnimationClient to do some amount of drawing, once per frame. An AnimationEngine may have multiple AnimationClient instances that it is managing.


Method Summary
 void addDisplayAreas(RenderContext targets)
          Tell the animation manager what areas need to be drawn to for the next frame.
 void destroy()
          Destroy this animatin client.
 java.lang.String[] getDrawTargets()
          Get the names of the draw targets used by this animation client.
 void initialize(java.awt.Component component)
          Initialize the animation client.
 void mapDrawTargets(java.util.Hashtable targets)
          Map draw target names into the numeric values that are required by the animation engine.
 void nextFrame()
          Advance the state of the show to the next frame.
 void paintDone()
          Called when the animation framework is done painting the current frame.
 void paintFrame(java.awt.Graphics2D gr)
          Paint the current frame of the animation.
 void setCaughtUp()
          Indicate to the animation client that we're not behind in the animation, so that the current frame will actually be displayed.
 

Method Detail

initialize

void initialize(java.awt.Component component)
                throws java.lang.InterruptedException
Initialize the animation client. This is called from the animation worker thread before starting the animation loop.

Parameters:
component - The component this show will eventually be displayed in. It's used for things like Component.prepareImage().
Throws:
java.lang.InterruptedException

destroy

void destroy()
             throws java.lang.InterruptedException
Destroy this animatin client. This is called from the animation worker thread before ending the animation loop.

Throws:
java.lang.InterruptedException

nextFrame

void nextFrame()
               throws java.lang.InterruptedException
Advance the state of the show to the next frame. This is called once per frame; the first time it is called can be considered "frame 0", and can monotonically increase from there.

This method can be called multiple times before any attempt is made to display the UI state. This happens when animation falls behind; the engine catches up by skipping frames. Animation clients should perform only quick updates in this method; any more time-consuming calculations should be deferred until an object is first painted for a given frame.

Throws:
java.lang.InterruptedException - if the thread has been interrupted (e.g. because the xlet is being killed)
See Also:
AnimationEngine.getModelTimeSkipped()

setCaughtUp

void setCaughtUp()
                 throws java.lang.InterruptedException
Indicate to the animation client that we're not behind in the animation, so that the current frame will actually be displayed. Clients shouldn't make any changes to the model in this call; all such changes need to happen in nextFrame()

Throws:
java.lang.InterruptedException - if the thread has been interrupted (e.g. because the xlet is being killed)
See Also:
nextFrame()

addDisplayAreas

void addDisplayAreas(RenderContext targets)
                     throws java.lang.InterruptedException
Tell the animation manager what areas need to be drawn to for the next frame. This is called just after setCaughtUp(), and just before paintFrame().

In this call, the client must indicate where it intends to draw by calling methods on RenderContext. Internally, a RenderContext keeps a number of rendering area "targets". Each target will keep track of a bounding rectangle of all of drawing operations that are considered within that target. When the call to addDisplayAreas is complete, the animation manager may merge some of these rendering areas targets, or may leave them seperate; it will then call paintFrame() as many times as it needs to, with a different clip rect each time. These clip rects will never overlap, so you don't need to worry about a Src mode drawing to the same pixel twice in the same frame.

The purpose of these targets is to try to minimize the number of pixels that will be updated on the screen in each frame of animation. Consider, for example, the case where most of the screen isn't changing, but where there's a small animation in the upper-left hand corner, and another small animation in the lower-right hand corner. If those two animations used the same target, the overall bounding rectangle would cover the whole screen. By using two different targets, the screen update can be confined to two small rectangles, one at each corner.

The number of render area targets is set up when an AnimationEngine is created, by calling mapDrawTargets() on each client. During animation, each AnimationClient is passed the same set of targets. If there are multiple AnimationClient instances attached to an AnimationEngine, it is up to the programmer to decide which render area targets should be shared between clients so as to optimize drawing performance. This can be done with appropriate naming of the targets in the mapDrawTargets() call.

Often, an AnimationClient only needs to erase or draw objects that have changed. However, under certain circumstances, the AnimationClient will be asked to redraw everything. This will happen on the first frame drawn, and possibly on others. For example, with repaint draw and platform double-buffering, the platform erases the buffer for each frame, so a full redraw is required. When this happens, the animation enginer automatically adds the full extent of the component to one of the targets. In this case, it still calls this method, so that items we draw have the opportunity to erase themselves if needed.

This method will be called exactly once for each frame displayed. Because paintFrame can be called multiple times per frame, any state maintained by the animation client to optimize display areas should be updated in this method, and not in paintFrame().

Parameters:
targets - The RenderContext that manages the set of targets the client can draw to.
Throws:
java.lang.InterruptedException - if the thread has been interrupted (e.g. because the xlet is being killed)
See Also:
RenderContext.setTarget(int), mapDrawTargets(Hashtable)

paintFrame

void paintFrame(java.awt.Graphics2D gr)
                throws java.lang.InterruptedException
Paint the current frame of the animation. This is called after addDisplayAreas(), as the last step in a cycle through the animation loop. This might be called multiple times for a given frame of animation, with a different clip rect set each time. It also might be called zero times, if no display areas were added. The callee should leave the graphics context in the same state as it was found in initially, notably:

The animation client shouldn't erase screen areas in this call. That can be handled more efficiently (for some drawing styles) via RenderArea.clearAndAddArea()

Parameters:
gr - The graphics context to draw to, set to Src drawing mode
Throws:
java.lang.InterruptedException - if the thread has been interrupted (e.g. because the xlet is being killed)
See Also:
RenderContext.addArea(DrawRecord)

paintDone

void paintDone()
Called when the animation framework is done painting the current frame. In each frame, the animation framework calls addDisplayAreas once, paintFrame zero or more times, and it is guaranteed to call paintDone() exactly once, even if the thread is interrupted. Note that if the thread is interrupted, it's possible paintDone() might be called without addDisplayAreas() having been called first.


getDrawTargets

java.lang.String[] getDrawTargets()
Get the names of the draw targets used by this animation client.

Note that GRIN uses the name "T:Default" as the name of the draw target if the GRIN show doesn't specify any.


mapDrawTargets

void mapDrawTargets(java.util.Hashtable targets)
Map draw target names into the numeric values that are required by the animation engine. This is called during initialization. By calling this on all AnimationClient instances, clients can share draw targets by giving them the same name.

The total number of different draw targets in an animation should be small, because the algorithm for combining draw targets is of cubic time complexity. One or two different draw targets might be a typical number, and more than four is questionable.

See addDisplayAreas() for a discussion of what a render area target is for.

Parameters:
targets - A hashtable mapping String names to Integer values
See Also:
RenderContext.setTarget(int), addDisplayAreas(RenderContext)