Pulled out gobs of Sprite/Animation functionality into AbstractMedia.

Pulled out gobs of SpriteManager/AnimationManager functionality into
  AbstractMediaManager.
The big change: sprites can have their render order fine-tuned like
animations.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1787 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Ray Greenwell
2002-10-08 21:03:37 +00:00
parent e804abad30
commit a0730067ec
10 changed files with 532 additions and 659 deletions
@@ -1,15 +1,11 @@
//
// $Id: Animation.java,v 1.8 2002/09/20 21:28:20 mdb Exp $
// $Id: Animation.java,v 1.9 2002/10/08 21:03:37 ray Exp $
package com.threerings.media.animation;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.ArrayList;
import com.samskivert.util.StringUtil;
import com.threerings.media.AbstractMedia;
import com.threerings.media.Log;
/**
@@ -17,7 +13,7 @@ import com.threerings.media.Log;
* provide animation functionality. It is generally used in conjunction
* with an {@link AnimationManager}.
*/
public abstract class Animation
public abstract class Animation extends AbstractMedia
{
/**
* Constructs an animation.
@@ -26,80 +22,7 @@ public abstract class Animation
*/
public Animation (Rectangle bounds)
{
_bounds = bounds;
}
/**
* Returns the render order of this animation.
*/
public int getRenderOrder ()
{
return _renderOrder;
}
/**
* Sets the render order associated with this animation. Animations
* can be rendered in two layers; those with negative render order and
* those with positive render order. In the same layer, animations
* will be rendered according to their render order's cardinal value
* (least to greatest). Those with the same render order value will be
* rendered in arbitrary order.
*
* <p> This must be set <em>before</em> the animation is handed to the
* {@link AnimationManager} and must not change while the {@link
* AnimationManager} is managing the animation. If you wish to change
* the render order, remove the animation from the manager, change the
* order and add it back again.
*/
public void setRenderOrder (int value)
{
_renderOrder = value;
}
/**
* Sets the location at which this animation will be rendered.
*/
public void setLocation (int x, int y)
{
_bounds.x = x;
_bounds.y = y;
}
/**
* Returns a rectangle containing all pixels rendered by this
* animation.
*/
public Rectangle getBounds ()
{
return _bounds;
}
/**
* Called periodically by the {@link AnimationManager} to give the
* animation a chance to do its thing.
*
* @param tickStamp the system time for this tick.
*/
public abstract void tick (long tickStamp);
/**
* Called by the {@link AnimationManager} to request that the
* animation render itself with the given graphics context. The
* animation may wish to inspect the clipping region that has been set
* on the graphics context to render itself more efficiently. This
* method will only be called after it has been established that this
* animation's bounds intersect the clipping region.
*/
public abstract void paint (Graphics2D gfx);
/**
* This is called if the animation manager is paused for some length
* of time and then unpaused. Animations should adjust any time stamps
* they are maintaining internally by the delta so that time maintains
* the illusion of flowing smoothly forward.
*/
public void fastForward (long timeDelta)
{
super(bounds);
}
/**
@@ -120,14 +43,6 @@ public abstract class Animation
_finished = false;
}
/**
* Invalidates the bounds of this animation.
*/
public void invalidate ()
{
_animmgr.getRegionManager().invalidateRegion(_bounds);
}
/**
* Called when the animation is finished and the animation manager has
* removed it from service.
@@ -142,76 +57,20 @@ public abstract class Animation
*/
public void addAnimationObserver (AnimationObserver obs)
{
// create the observer list if it doesn't yet exist
if (_observers == null) {
_observers = new ArrayList();
}
// make sure each observer observes only once
if (_observers.contains(obs)) {
Log.info("Attempt to observe animation already observing " +
"[anim=" + this + ", obs=" + obs + "].");
return;
}
// add the observer
_observers.add(obs);
addObserver(obs);
}
/**
* Notifies any animation observers that the given animation event has
* occurred.
*/
public void notifyObservers (AnimationEvent e)
public void notifyObservers (AnimationEvent event)
{
int size = (_observers == null) ? 0 : _observers.size();
for (int ii = 0; ii < size; ii++) {
((AnimationObserver)_observers.get(ii)).handleEvent(e);
if (_observers != null) {
_mgr.queueNotification(_observers, event);
}
}
/**
* Return a string representation of the animation.
*/
public String toString ()
{
StringBuffer buf = new StringBuffer();
buf.append("[");
toString(buf);
return buf.append("]").toString();
}
/**
* Called automatically when an animation is added to an animation
* manager for management.
*/
protected void setAnimationManager (AnimationManager animmgr)
{
_animmgr = animmgr;
}
/**
* This should be overridden by derived classes (which should be sure
* to call <code>super.toString()</code>) to append the derived class
* specific animation information to the string buffer.
*/
protected void toString (StringBuffer buf)
{
buf.append("bounds=").append(StringUtil.toString(_bounds));
}
/** Our animation manager. */
protected AnimationManager _animmgr;
/** Whether the animation is finished. */
protected boolean _finished = false;
/** The animation bounds. */
protected Rectangle _bounds;
/** The render order of this animation. */
protected int _renderOrder;
/** The list of animation observers. */
protected ArrayList _observers;
}
@@ -1,17 +1,14 @@
//
// $Id: AnimationManager.java,v 1.13 2002/09/20 21:28:20 mdb Exp $
// $Id: AnimationManager.java,v 1.14 2002/10/08 21:03:37 ray Exp $
package com.threerings.media.animation;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.util.Comparator;
import java.util.ArrayList;
import com.samskivert.util.SortableArrayList;
import com.threerings.media.AbstractMediaManager;
import com.threerings.media.Log;
import com.threerings.media.MediaConstants;
import com.threerings.media.RegionManager;
/**
@@ -19,8 +16,7 @@ import com.threerings.media.RegionManager;
* manager itself is ticked and generating events when animations finish
* and suchlike.
*/
public class AnimationManager
implements MediaConstants
public class AnimationManager extends AbstractMediaManager
{
/**
* Construct and initialize the animation manager which readies itself
@@ -28,7 +24,7 @@ public class AnimationManager
*/
public AnimationManager (RegionManager remgr)
{
_remgr = remgr;
super(remgr);
}
/**
@@ -37,14 +33,7 @@ public class AnimationManager
*/
public void registerAnimation (Animation anim)
{
if (_anims.contains(anim)) {
Log.warning("Attempt to register animation more than once " +
"[anim=" + anim + "].");
return;
}
anim.setAnimationManager(this);
_anims.insertSorted(anim, RENDER_ORDER);
insertMedia(anim);
}
/**
@@ -55,43 +44,17 @@ public class AnimationManager
*/
public void unregisterAnimation (Animation anim)
{
// un-register the animation
if (!_anims.remove(anim)) {
Log.warning("Attempt to un-register animation that isn't " +
"registered [anim=" + anim + "].");
return;
}
// invalidate its bounds
_remgr.invalidateRegion(anim.getBounds());
removeMedia(anim);
}
/**
* Provides access to the region manager that the animation manager is
* using to collect invalid regions every frame. This should generally
* only be used by animations that want to invalidate themselves.
*/
public RegionManager getRegionManager ()
// documentation inherited
protected void tickAllMedia (long tickStamp)
{
return _remgr;
}
/**
* Handles updating animations and generating associated events.
*
* @param tickStamp the system clock at the time of the tick.
*/
public void tick (long tickStamp)
{
// tick all of our animations
int size = _anims.size();
for (int ii = 0; ii < size; ii++) {
((Animation)_anims.get(ii)).tick(tickStamp);
}
super.tickAllMedia(tickStamp);
// remove any finished animations
for (int ii = size - 1; ii >= 0; ii--) {
Animation anim = (Animation)_anims.get(ii);
for (int ii=_media.size() - 1; ii >= 0; ii--) {
Animation anim = (Animation)_media.get(ii);
if (anim.isFinished()) {
// let any animation observers know that we're done
anim.notifyObservers(new AnimationCompletedEvent(anim));
@@ -104,68 +67,12 @@ public class AnimationManager
}
}
/**
* If the animation manager is paused for some length of time, it
* should be fast forwarded by the appropriate number of milliseconds.
* This allows animations to smoothly pick up where they left off
* rather than abruptly jumping into the future, thinking that some
* outrageous amount of time passed since their last tick.
*/
public void fastForward (long timeDelta)
// documentation inherited
protected void dispatchEvent (ArrayList observers, Object event)
{
// fast forward all of our animations
int size = _anims.size();
for (int ii = 0; ii < size; ii++) {
((Animation)_anims.get(ii)).fastForward(timeDelta);
AnimationEvent aevt = (AnimationEvent) event;
for (int ii=0, nn=observers.size(); ii < nn; ii++) {
((AnimationObserver) observers.get(ii)).handleEvent(aevt);
}
}
/**
* Renders all registered animations in the given layer that intersect
* the supplied clipping rectangle to the given graphics context.
*
* @param layer the layer to render; one of {@link #FRONT}, {@link
* #BACK}, or {@link #ALL}. The front layer contains all animations
* with a positive render order; the back layer contains all
* animations with a negative render order; all, both.
*/
public void renderAnimations (Graphics2D gfx, int layer, Shape clip)
{
// now paint them
int size = _anims.size();
for (int ii = 0; ii < size; ii++) {
Animation anim = (Animation)_anims.get(ii);
int order = anim.getRenderOrder();
try {
if (((layer == ALL) ||
(layer == FRONT && order >= 0) ||
(layer == BACK && order < 0)) &&
clip.intersects(anim.getBounds())) {
anim.paint(gfx);
}
} catch (Exception e) {
Log.warning("Failed to render animation " +
"[anim=" + anim + ", e=" + e + "].");
Log.logStackTrace(e);
}
}
}
/** Used to accumulate dirty regions. */
protected RegionManager _remgr;
/** The list of animations. */
protected SortableArrayList _anims = new SortableArrayList();
/** Used to sort animations prior to painting. */
protected static final Comparator RENDER_ORDER = new Comparator() {
public int compare (Object o1, Object o2) {
return (((Animation)o1)._renderOrder -
((Animation)o2)._renderOrder);
}
public boolean equals (Object obj) {
return this == obj;
}
};
}