com.hdcookbook.grin.animator
Class SFAAEngine

java.lang.Object
  extended by com.hdcookbook.grin.animator.AnimationEngine
      extended by com.hdcookbook.grin.animator.SFAAEngine
All Implemented Interfaces:
java.lang.Runnable

public class SFAAEngine
extends AnimationEngine

An animation engine that draws into an instance of org.bluray.ui.SyncFrameAccurateAnimation.

If you're thinking of using this style of animation, you might want to consider using direct draw, and javax.media.Player.getMediaTime() instead. In some of SFAA using off-the-shelf players in April 2009, the execution of SFAA was found somewhat wanting, and no player seemed to do better in keeping the animation registered to the video than the sort of "best effort" result you'd get from direct draw. Additionally, SFAA makes optimized drawing impossible, because some implementations clear the SFAA buffer before each frame. This limits the on-screen size that can be covered by an SFAA if you want to maintain 24fps. In most cases you can probably achieve better results using direect draw and Player.getMediaTime.

If you do use SFAA Animator, be aware that when used with a start and stop media time, SFAA will stall the animation thread, which prevents GRIN commands from being executed. It also makes it impossible to destroy the SFAA, so you need to be sure video is playing in the time range when trying to destroy the SFAA animator instance.


Field Summary
 
Fields inherited from class com.hdcookbook.grin.animator.AnimationEngine
modelTimeSkipped, renderContext, repaintBounds, targetsCanOverlap, transparent
 
Constructor Summary
SFAAEngine(long frameNumber, boolean skipModel)
          Create a new SFAAEngine.
 
Method Summary
protected  void callPaintTargets()
          Paint the current frame into the right graphics buffer.
protected  void clearArea(int x, int y, int width, int height)
          Called from showFrame() to cause an area to be cleared in the current frame.
 void destroy()
          Destroy this animation manager, by terminating the animation thread.
protected  void finishedFrame()
          Called when the engine is finished drawing the current frame.
 javax.media.Time getAnimationFrameTime()
          Get the time of the current frame of animation.
 java.awt.Component getComponent()
          Get the component that this animation engine renders into.
 long getFrameNumber()
          Get the current frame number.
 int getHeight()
          Get the height of the area we display over
 int getSkippedFrames()
          Get the number of skipped frames over the lifetime of this animation.
 int getWidth()
          Get the width of the area we display over
 void initContainer(java.awt.Container container, java.awt.Rectangle bounds)
          Initialize this engine with its parent container and the position and size of the engine within the container.
protected  boolean needsFullRedrawInAnimationLoop()
          Tell us whether or not this style of animation requires a full redraw of everything on the screen in each pass through the animation loop.
 void pause()
          Pause the currently running animations.
protected  void runAnimationLoop()
          The inner loop for the animation thread.
 void setSFAA(org.bluray.ui.SyncFrameAccurateAnimation sfaa)
          Sets the SFAA instance to be used by this engine.
 void start()
          Start the current animations.
protected  void terminatingEraseScreen()
          Erase the screen because the AnimationManager is terminating.
 
Methods inherited from class com.hdcookbook.grin.animator.AnimationEngine
advanceModel, checkDestroy, checkNewClients, destroyRequested, getAnimationClients, getDrawTargets, getEraseTargets, getModelTimeSkipped, getNumDrawTargets, getNumEraseTargets, initClients, initialize, paintFrame, paintNextFrameFully, paintTargets, repaintFrame, resetAnimationClients, run, setAllowOverlappingTargets, setDrawTargetCollapseThreshold, setThreadPriority, showFrame
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

SFAAEngine

public SFAAEngine(long frameNumber,
                  boolean skipModel)
Create a new SFAAEngine. It needs to be initialized with the various initXXX methods (including the inherited ones).

An SFAAEngine has a public method that other engine types don't: getAnimationFrameTime(). This gives the media time of the frame of animation currently being drawn. With SFAA, it would make sense to drive all model updates from the media time, and not by counting frames (as is often done with direct draw in GRIN).

For this reason, an SFAAEngine can be in "skip model" mode. In this mode, whenver an animation frame is skipped, the model update will be skipped, too. This way, a model that us based solely off of the media time won't waste computational resources calculating an update for a frame that's not going to be displayed anyway.

An SFAAEngine that is not in "skip model" mode will always update the model for every frame, unless animation falls behind by a substantial amount.

Note that SFAAEngine does not support optimized drawing, due to limitations in BD's SFAA API. For each frame that's displayed, the entire scene is drawn. For this reason, there's no reason to use more than one draw target in a show that's designed for SFAA.

Parameters:
frameNumber - The frame number to start with. If the SFAA instance was just created, 0 would be a reasonable value.
skipModel - Set true if this engine should be in "skip model" mode; see above. A value of true is recommended.
See Also:
getAnimationFrameTime()
Method Detail

setSFAA

public void setSFAA(org.bluray.ui.SyncFrameAccurateAnimation sfaa)
Sets the SFAA instance to be used by this engine. Calling this method is optional. If you call it, then the animation engine should still be subsequently initialized by calling initContainer(). The SFAA instance you pass in to the present method will not have any initial call to start() on it, but it will have start() and stop() called on it from the engine if the engine is paused and unpaused. The sfaa will be destroyed when the SFAAEngine is destroyed, and it will be removed from the container passed into initContainer().

This is important: SFAAEngine will not call sfaa.start() for you. If you set up the sfaa with a start and stop media time, then all is well; if you don't, you should call sfaa.start() yourself the first time.

Throws:
java.lang.IllegalStateException - if initContainer has already been called, or if the SFAA has already been set.

initContainer

public void initContainer(java.awt.Container container,
                          java.awt.Rectangle bounds)
Initialize this engine with its parent container and the position and size of the engine within the container. This should be called exactly once, before start() is called. A good time to call this would be in the animationInitialize() call within the context code passed to initialize().

The Component will be set to the specified bounds, and an internal double buffer may be created to these bounds. The container is expected to have a null layout; if it doesn't, this might change the widget's size to be different than the bounds passed in (and therefore the double buffer). The container must be visible when this is called.

Specified by:
initContainer in class AnimationEngine
Parameters:
container - The container that our SFAA instance should be put in.
bounds - The bounds of the SFAA instance we put within the container.
See Also:
setSFAA(SyncFrameAccurateAnimation)

getWidth

public int getWidth()
Get the width of the area we display over

Specified by:
getWidth in class AnimationEngine
Returns:
the width

getHeight

public int getHeight()
Get the height of the area we display over

Specified by:
getHeight in class AnimationEngine
Returns:
the height

getComponent

public java.awt.Component getComponent()
Get the component that this animation engine renders into. This is added by the engine to the container.

Specified by:
getComponent in class AnimationEngine
Returns:
the component, or null if initContainer hasn't been called yet.
See Also:
AnimationEngine.initialize(com.hdcookbook.grin.animator.AnimationContext), AnimationContext.animationInitialize()

start

public void start()
Start the current animations. The animation will start animating sometime after this method is called. This can be called while initialization is still underway in the animation thread.

By default, the manager will assume that the contents of the framebuffer wasn't changed while the manager was paused. If it might have been, it's advisable to call paintNextFrameFully().

The animation manager starts in the paused state, so this method will normally need to be called at least once.

This also calls SyncFrameAccurateAnimation.start()

Specified by:
start in class AnimationEngine
See Also:
AnimationEngine.paintNextFrameFully()

pause

public void pause()
Pause the currently running animations. The animation thread will go into a wait state, until start() or destroy() are called.

This method will return immediately, even if the animation hasn't reached the paused state yet.

When the animation framework is paused, no effort is made to output one last frame with the current state of the model.

This also calls SyncFrameAccurateAnimation.stop()

Specified by:
pause in class AnimationEngine

clearArea

protected void clearArea(int x,
                         int y,
                         int width,
                         int height)
Called from showFrame() to cause an area to be cleared in the current frame.

Specified by:
clearArea in class AnimationEngine
See Also:
AnimationEngine.showFrame()

needsFullRedrawInAnimationLoop

protected boolean needsFullRedrawInAnimationLoop()
Tell us whether or not this style of animation requires a full redraw of everything on the screen in each pass through the animation loop. This is called from the animation loop.

This is always true for SFAA. Even in SFAA with one buffer, we're forced to redraw the entire buffer each time, because some implementations clear the buffer "for us" before each frame. We still have to clear the buffer, of course, because this behavior isn't required.

Note that returning true here disables optimized drawing. Alas, this is necessary with SFAA - see the class comments for this class.

Specified by:
needsFullRedrawInAnimationLoop in class AnimationEngine

callPaintTargets

protected void callPaintTargets()
                         throws java.lang.InterruptedException
Paint the current frame into the right graphics buffer. The subclass implementation of this method should call paintTargets(Graphics2D).

Specified by:
callPaintTargets in class AnimationEngine
Throws:
java.lang.InterruptedException
See Also:
AnimationEngine.paintFrame(java.awt.Graphics2D)

finishedFrame

protected void finishedFrame()
Called when the engine is finished drawing the current frame. This should flush the results to the screen, if needed. The framework guarantees that each call to callPaintTargets() will be followed by a call to finishedFrame(), even if the thread is interrupted or there's a RuntimeException that terminates the thread.

Specified by:
finishedFrame in class AnimationEngine

runAnimationLoop

protected void runAnimationLoop()
                         throws java.lang.InterruptedException
The inner loop for the animation thread. This implementation uses System.currentTimeMillis() and wait() to keep a steady frame rate. This method can be overridden for animation styles that have a different synch mechanism, like SFAA. If this is done, be sure to look inside this method, and obey the same semantic contract.

This method must call checkNewClients() outside of any synchronized block at least once per frame. This should be done at the beginning of the frame before any model updates or animation work is done.

This method must check destroyRequested() at least once per frame, and if it's true, bail out of the loop. To advance the model by one frame, it should call advanceModel(). When it wants to show a frame (and not skip it), it should call showFrame(), which will cause callPaintTargets() to be called.

Of course, the animation loop should also check Thread.interrupted() regularly.

Specified by:
runAnimationLoop in class AnimationEngine
Throws:
java.lang.InterruptedException
See Also:
AnimationEngine.destroyRequested(), AnimationEngine.advanceModel(), AnimationEngine.showFrame(), AnimationEngine.callPaintTargets()

getAnimationFrameTime

public javax.media.Time getAnimationFrameTime()
Get the time of the current frame of animation. This only works if you provide the manager with an SFAA that has a media start and stop time.

Throws:
java.lang.IllegalStateException - if the underlying SFAA isn't running and presenting video, or if it doesn't have a start/stop time set.
See Also:
setSFAA(SyncFrameAccurateAnimation)

getSkippedFrames

public int getSkippedFrames()
Get the number of skipped frames over the lifetime of this animation.


getFrameNumber

public long getFrameNumber()
Get the current frame number.


destroy

public void destroy()
Destroy this animation manager, by terminating the animation thread. It's OK to call this more than once. It should be called while the animation manager's component is still visible, and a child of a visible HScene.

This method will not return until the animation thread has terminated.

For SFAA, destroy must be called while the SFAA instance is running. For an SFAA with a start/end time, this means video must be playing and the media time must be between the start and end.

See also the class comments for this class.

Overrides:
destroy in class AnimationEngine

terminatingEraseScreen

protected void terminatingEraseScreen()
Erase the screen because the AnimationManager is terminating. This is called in the animation thread as a result of a call to destroy(), just before the animation thread terminates.

Specified by:
terminatingEraseScreen in class AnimationEngine