diff --git a/src/java/com/threerings/media/AbstractMedia.java b/src/java/com/threerings/media/AbstractMedia.java new file mode 100644 index 000000000..92236153e --- /dev/null +++ b/src/java/com/threerings/media/AbstractMedia.java @@ -0,0 +1,184 @@ +// +// $Id: AbstractMedia.java,v 1.1 2002/10/08 21:03:37 ray Exp $ + +package com.threerings.media; + +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.util.ArrayList; + +import com.samskivert.util.StringUtil; + +/** + * Something that can be rendered on the media panel. + */ +public abstract class AbstractMedia +{ + /** + * Instantiate an abstract media object. + */ + public AbstractMedia (Rectangle bounds) + { + _bounds = bounds; + } + + /** + * Called periodically by this media's manager to give it + * a chance to do its thing. + * + * @param tickStamp the system time for this tick. + */ + public abstract void tick (long tickStamp); + + /** + * Called by the appropriate manager to request that the + * media render itself with the given graphics context. The + * media 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 + * media's bounds intersect the clipping region. + */ + public abstract void paint (Graphics2D gfx); + + /** + * Called when the appropriate media manager has been paused for some + * length of time and is then unpaused. Media should adjust any time stamps + * that are maintained internally forward by the delta so that time + * maintains the illusion of flowing smoothly forward. + */ + public void fastForward (long timeDelta) + { + } + + /** + * Invalidate the media's bounding rectangle for later painting. + */ + public void invalidate () + { + if (_mgr != null) { + _mgr.getRegionManager().invalidateRegion(_bounds); + } + } + + /** + * Set the location. + */ + public void setLocation (int x, int y) + { + _bounds.x = x; + _bounds.y = y; + } + + /** + * Returns a rectangle containing all the pixels rendered by this media. + */ + public Rectangle getBounds () + { + return _bounds; + } + + /** + * Sets the render order associated with this media. Media + * can be rendered in two layers; those with negative render order and + * those with positive render order. In the same layer, they + * 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. + * + *
This must be set before the media is added to the
+ * appropriate manager and must not change while the manager is
+ * managing it. If you wish to change the render order, remove the
+ * media from the manager, change the order and add it back again.
+ */
+ public void setRenderOrder (int renderOrder)
+ {
+ _renderOrder = renderOrder;
+ }
+
+ /**
+ * Returns the render order of this media element.
+ */
+ public int getRenderOrder ()
+ {
+ return _renderOrder;
+ }
+
+ /**
+ * Initialize the media.
+ */
+ protected final void init (AbstractMediaManager manager)
+ {
+ _mgr = manager;
+
+ init();
+ }
+
+ /**
+ * Called when the media has had its manager set.
+ * Derived classes may override this method, but should be sure to
+ * call super.init().
+ */
+ protected void init ()
+ {
+ }
+
+ /**
+ * Called by the media manager after the media is removed from service.
+ * Derived classes may override this method, but should be sure to
+ * call super.shutdown().
+ */
+ protected void shutdown ()
+ {
+ _mgr = null;
+ }
+
+ /**
+ * Add the specified observer to this media element.
+ */
+ protected void addObserver (Object obs)
+ {
+ if (_observers == null) {
+ _observers = new ArrayList();
+
+ } else if (_observers.contains(obs)) {
+ Log.info("Attempt to observe media already observing " +
+ "[media=" + this + ", obs=" + obs + "].");
+ return;
+ }
+
+ _observers.add(obs);
+ }
+
+ /**
+ * Dumps this media to a String object.
+ */
+ public String toString ()
+ {
+ StringBuffer buf = new StringBuffer("[");
+ toString(buf);
+ return buf.append("]").toString();
+ }
+
+ /**
+ * This should be overridden by derived classes (which should be sure
+ * to call super.toString()) to append the derived class
+ * specific information to the string buffer.
+ */
+ protected void toString (StringBuffer buf)
+ {
+ buf.append("bounds=").append(StringUtil.toString(_bounds));
+ buf.append(", renderOrder=").append(_renderOrder);
+ }
+
+ /** The layer in which to render. */
+ protected int _renderOrder = 0;
+
+ /** The bounds of the media's rendering area. */
+ protected Rectangle _bounds;
+
+ /** Our manager. */
+ protected AbstractMediaManager _mgr;
+
+ /** Our observers. */
+ protected ArrayList _observers = null;
+}
diff --git a/src/java/com/threerings/media/AbstractMediaManager.java b/src/java/com/threerings/media/AbstractMediaManager.java
new file mode 100644
index 000000000..5b1255077
--- /dev/null
+++ b/src/java/com/threerings/media/AbstractMediaManager.java
@@ -0,0 +1,200 @@
+//
+// $Id: AbstractMediaManager.java,v 1.1 2002/10/08 21:03:37 ray Exp $
+
+package com.threerings.media;
+
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+
+import com.samskivert.util.SortableArrayList;
+import com.samskivert.util.StringUtil;
+
+/**
+ * Manages, ticks, and paints AbstractMedia.
+ */
+public abstract class AbstractMediaManager
+ implements MediaConstants
+{
+ /**
+ * Default constructor.
+ */
+ public AbstractMediaManager (RegionManager remgr)
+ {
+ _remgr = remgr;
+ }
+
+ /**
+ * Provides access to the region manager that the mediamanager is using.
+ */
+ public RegionManager getRegionManager ()
+ {
+ return _remgr;
+ }
+
+ /**
+ * Renders all registered media 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 renderMedia (Graphics2D gfx, int layer, Shape clip)
+ {
+ for (int ii=0, nn=_media.size(); ii < nn; ii++) {
+ AbstractMedia media = (AbstractMedia) _media.get(ii);
+ int order = media.getRenderOrder();
+ try {
+ if (((layer == ALL) ||
+ (layer == FRONT && order >= 0) ||
+ (layer == BACK && order < 0)) &&
+ clip.intersects(media.getBounds())) {
+ media.paint(gfx);
+ }
+ } catch (Exception e) {
+ Log.warning("Failed to render media " +
+ "[media=" + media + ", e=" + e + "].");
+ Log.logStackTrace(e);
+ }
+ }
+ }
+
+ /**
+ * Must be called every frame so that the media can be properly
+ * updated.
+ */
+ public void tick (long tickStamp)
+ {
+ tickAllMedia(tickStamp);
+ dispatchNotifications();
+ }
+
+ /**
+ * If the manager is paused for some length of time, it should
+ * be fast forwarded by the appropriate number of milliseconds. This
+ * allows media 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)
+ {
+ for (int ii=0, nn=_media.size(); ii < nn; ii++) {
+ ((AbstractMedia) _media.get(ii)).fastForward(timeDelta);
+ }
+ }
+
+ /**
+ * Call {@link AbstractMedia#tick} on all media to give
+ * them a chance to move about, change their look, generate dirty
+ * regions, and so forth.
+ */
+ protected void tickAllMedia (long tickStamp)
+ {
+ // we tick media in reverse order, because some may remove
+ // themselves on the tick
+ for (int ii=_media.size() - 1; ii >= 0; ii--) {
+ ((AbstractMedia) _media.get(ii)).tick(tickStamp);
+ }
+ }
+
+ /**
+ * Insert the specified media into this manager, return true on success.
+ */
+ protected boolean insertMedia (AbstractMedia media)
+ {
+ if (_media.contains(media)) {
+ Log.warning("Attempt to insert media more than once " +
+ "[media=" + media + "].");
+ return false;
+ }
+
+ _media.insertSorted(media, RENDER_ORDER);
+ media.init(this);
+ return true;
+ }
+
+ /**
+ * Remove the specified media from this manager, return true on success.
+ */
+ protected boolean removeMedia (AbstractMedia media)
+ {
+ if (_media.remove(media)) {
+ media.invalidate();
+ media.shutdown();
+ return true;
+ }
+ Log.warning("Attempt to remove media that wasn't inserted " +
+ "[media=" + media + "].");
+ return false;
+ }
+
+ /**
+ * Clears all media from the manager. This does not invalidate
+ * their vacated bounds, it is assumed that it will be ok.
+ */
+ protected void clearMedia ()
+ {
+ for (int ii=_media.size() - 1; ii >= 0; ii--) {
+ AbstractMedia media = (AbstractMedia) _media.remove(ii);
+ media.shutdown();
+ }
+ }
+
+ /**
+ * Queue the event for dispatching after we've ticked all
+ * the media.
+ */
+ public void queueNotification (ArrayList observers, Object event)
+ {
+ _notify.add(new Object[] {observers, event});
+ }
+
+ /**
+ * Dispatch all queued events.
+ */
+ protected void dispatchNotifications ()
+ {
+ for (int ii=0, nn=_notify.size(); ii < nn; ii++) {
+ Object[] junk = (Object[]) _notify.remove(0);
+ ArrayList observers = (ArrayList) junk[0];
+ Object event = junk[1];
+
+ dispatchEvent(observers, event);
+ }
+ }
+
+ /**
+ * Dispatch the specified event to the specified observers.
+ */
+ protected abstract void dispatchEvent (ArrayList observers, Object event);
+
+ /** The Region Manager. */
+ protected RegionManager _remgr;
+
+ /** List of observers to notify at the end of the tick. */
+ protected ArrayList _notify = new ArrayList();
+
+ /** Our render-order sorted list of media. */
+ protected SortableArrayList _media = new SortableArrayList();
+
+ /** Used to sort media by render order. */
+ protected static final Comparator RENDER_ORDER = new Comparator() {
+ public int compare (Object o1, Object o2) {
+ int result = (((AbstractMedia)o1)._renderOrder -
+ ((AbstractMedia)o2)._renderOrder);
+ if (result != 0) {
+ return result;
+
+ } else {
+ // find some other way to keep them stable relative to each
+ // other.
+ return o1.hashCode() - o2.hashCode();
+ }
+ }
+ };
+}
diff --git a/src/java/com/threerings/media/MediaPanel.java b/src/java/com/threerings/media/MediaPanel.java
index 3ac01b761..1a124cc9e 100644
--- a/src/java/com/threerings/media/MediaPanel.java
+++ b/src/java/com/threerings/media/MediaPanel.java
@@ -1,5 +1,5 @@
//
-// $Id: MediaPanel.java,v 1.17 2002/06/25 17:31:16 mdb Exp $
+// $Id: MediaPanel.java,v 1.18 2002/10/08 21:03:37 ray Exp $
package com.threerings.media;
@@ -371,8 +371,8 @@ public class MediaPanel extends JComponent
*/
protected void paintBits (Graphics2D gfx, int layer, Rectangle dirty)
{
- _animmgr.renderAnimations(gfx, layer, dirty);
- _spritemgr.renderSprites(gfx, layer, dirty);
+ _animmgr.renderMedia(gfx, layer, dirty);
+ _spritemgr.renderMedia(gfx, layer, dirty);
}
/** The frame manager with whom we register. */
diff --git a/src/java/com/threerings/media/animation/Animation.java b/src/java/com/threerings/media/animation/Animation.java
index 1275e57c6..313186ef7 100644
--- a/src/java/com/threerings/media/animation/Animation.java
+++ b/src/java/com/threerings/media/animation/Animation.java
@@ -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.
- *
- *
This must be set before 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 super.toString()) 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;
}
diff --git a/src/java/com/threerings/media/animation/AnimationManager.java b/src/java/com/threerings/media/animation/AnimationManager.java
index 9bc5b84d0..ab6b227af 100644
--- a/src/java/com/threerings/media/animation/AnimationManager.java
+++ b/src/java/com/threerings/media/animation/AnimationManager.java
@@ -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;
- }
- };
}
diff --git a/src/java/com/threerings/media/sprite/ImageSprite.java b/src/java/com/threerings/media/sprite/ImageSprite.java
index 779a46b47..0dfb60291 100644
--- a/src/java/com/threerings/media/sprite/ImageSprite.java
+++ b/src/java/com/threerings/media/sprite/ImageSprite.java
@@ -1,5 +1,5 @@
//
-// $Id: ImageSprite.java,v 1.14 2002/09/17 20:21:19 mdb Exp $
+// $Id: ImageSprite.java,v 1.15 2002/10/08 21:03:37 ray Exp $
package com.threerings.media.sprite;
@@ -81,9 +81,9 @@ public class ImageSprite extends Sprite
}
// documentation inherited
- protected void init (SpriteManager spritemgr)
+ protected void init ()
{
- super.init(spritemgr);
+ super.init();
// now that we have our spritemanager, we can initialize our frames
setFrameIndex(0, true);
@@ -187,8 +187,8 @@ public class ImageSprite extends Sprite
dirty.add(_bounds);
// give the dirty rectangle to the region manager
- if (_spritemgr != null) {
- _spritemgr.getRegionManager().addDirtyRegion(dirty);
+ if (_mgr != null) {
+ _mgr.getRegionManager().addDirtyRegion(dirty);
}
}
diff --git a/src/java/com/threerings/media/sprite/LabelSprite.java b/src/java/com/threerings/media/sprite/LabelSprite.java
index 722406f57..274bed5ef 100644
--- a/src/java/com/threerings/media/sprite/LabelSprite.java
+++ b/src/java/com/threerings/media/sprite/LabelSprite.java
@@ -1,5 +1,5 @@
//
-// $Id: LabelSprite.java,v 1.3 2002/07/08 21:15:35 mdb Exp $
+// $Id: LabelSprite.java,v 1.4 2002/10/08 21:03:37 ray Exp $
package com.threerings.media.sprite;
@@ -35,9 +35,9 @@ public class LabelSprite extends Sprite
}
// documentation inherited
- protected void init (SpriteManager spritemgr)
+ protected void init ()
{
- super.init(spritemgr);
+ super.init();
// size the bounds to fit our label
Dimension size = _label.getSize();
diff --git a/src/java/com/threerings/media/sprite/Sprite.java b/src/java/com/threerings/media/sprite/Sprite.java
index e811ace5c..e87ac0896 100644
--- a/src/java/com/threerings/media/sprite/Sprite.java
+++ b/src/java/com/threerings/media/sprite/Sprite.java
@@ -1,5 +1,5 @@
//
-// $Id: Sprite.java,v 1.50 2002/07/08 21:15:35 mdb Exp $
+// $Id: Sprite.java,v 1.51 2002/10/08 21:03:37 ray Exp $
package com.threerings.media.sprite;
@@ -7,10 +7,9 @@ import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
-import java.util.ArrayList;
-
import com.threerings.util.DirectionCodes;
+import com.threerings.media.AbstractMedia;
import com.threerings.media.Log;
import com.threerings.media.util.Path;
import com.threerings.media.util.Pathable;
@@ -20,7 +19,7 @@ import com.threerings.media.util.Pathable;
* view. A sprite has a position and orientation within the view, and can
* be moved along a path.
*/
-public abstract class Sprite
+public abstract class Sprite extends AbstractMedia
implements DirectionCodes, Pathable
{
/**
@@ -33,27 +32,7 @@ public abstract class Sprite
*/
public Sprite ()
{
- }
-
- /**
- * Called by the sprite manager to initialize the sprite when a sprite
- * is added to said manager for management.
- *
- * @param spritemgr the sprite manager.
- */
- protected void init (SpriteManager spritemgr)
- {
- _spritemgr = spritemgr;
- }
-
- /**
- * Called by the sprite manager after the sprite is removed from
- * service. Derived classes may override this method but should be
- * sure to call super.shutdown().
- */
- protected void shutdown ()
- {
- _spritemgr = null;
+ super(new Rectangle());
}
/**
@@ -92,14 +71,6 @@ public abstract class Sprite
return _bounds.height;
}
- /**
- * Returns the sprite's rendered bounds in pixels.
- */
- public Rectangle getBounds ()
- {
- return _bounds;
- }
-
/**
* Sprites have an orientation in one of the eight cardinal
* directions: NORTH, NORTHEAST, etc.
@@ -125,31 +96,7 @@ public abstract class Sprite
return _orient;
}
- /**
- * Returns the render order of this sprite.
- */
- public int getRenderOrder ()
- {
- return _renderOrder;
- }
-
- /**
- * Sets the render order associated with this animation. Sprites can
- * be rendered in two layers; those with negative render order and
- * those with positive render order. Someday sprites will be rendered
- * in each layer according to render order.
- */
- public void setRenderOrder (int value)
- {
- _renderOrder = value;
- }
-
- /**
- * Moves the sprite to the specified location.
- *
- * @param x the x-position in pixels.
- * @param y the y-position in pixels.
- */
+ // documentation inherited
public void setLocation (int x, int y)
{
// start with our current bounds
@@ -165,24 +112,20 @@ public abstract class Sprite
// grow the dirty rectangle to incorporate our new bounds and pass
// the dirty region to our region manager
- if (_spritemgr != null) {
+ if (_mgr != null) {
// if our new bounds intersect our old bounds, grow a single
// dirty rectangle to incorporate them both
if (_bounds.intersects(dirty)) {
dirty.add(_bounds);
} else {
// otherwise invalidate our new bounds separately
- _spritemgr.getRegionManager().invalidateRegion(_bounds);
+ _mgr.getRegionManager().invalidateRegion(_bounds);
}
- _spritemgr.getRegionManager().addDirtyRegion(dirty);
+ _mgr.getRegionManager().addDirtyRegion(dirty);
}
}
- /**
- * Paint the sprite to the specified graphics context.
- *
- * @param gfx the graphics context.
- */
+ // documentation inherited
public void paint (Graphics2D gfx)
{
gfx.draw(_bounds);
@@ -302,24 +245,7 @@ public abstract class Sprite
notifyObservers(new PathCompletedEvent(this, oldpath));
}
- /**
- * Invalidate the sprite's bounding rectangle for later repainting.
- */
- public void invalidate ()
- {
- if (_spritemgr != null) {
- _spritemgr.getRegionManager().invalidateRegion(_bounds);
- }
- }
-
- /**
- * This method is called periodically by the sprite manager to give
- * the sprite a chance to update its state. The sprite manager will
- * attempt to call this with the desired refresh rate, but will drop
- * calls to tick if it can't keep up. Thus, a sprite should rely on
- * the timestamp information to compute elapsed progress if it wishes
- * to handle heavy loads gracefully.
- */
+ // documentation inherited
public void tick (long tickStamp)
{
// if we've a path, move the sprite along toward its destination
@@ -328,12 +254,7 @@ public abstract class Sprite
}
}
- /**
- * This is called if the sprite manager is paused for some length of
- * time and then unpaused. Sprites should adjust any time stamps they
- * are maintaining internally by the delta so that time maintains the
- * illusion of flowing smoothly forward.
- */
+ // documentation inherited
public void fastForward (long timeDelta)
{
// fast forward any path we're following
@@ -360,20 +281,7 @@ public abstract class Sprite
*/
public void addSpriteObserver (SpriteObserver 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 sprite already observing " +
- "[sprite=" + this + ", obs=" + obs + "].");
- return;
- }
-
- // add the observer
- _observers.add(obs);
+ addObserver(obs);
}
/**
@@ -384,39 +292,20 @@ public abstract class Sprite
protected void notifyObservers (SpriteEvent event)
{
if (_observers != null) {
- // we pass this notification off to the sprite manager so that
- // it can dispatch all of the notifications at once after all
- // ticking has been completed
- _spritemgr.notifySpriteObservers(_observers, event);
+ _mgr.queueNotification(_observers, event);
}
}
- /**
- * Return a string representation of the sprite.
- */
- public String toString ()
- {
- StringBuffer buf = new StringBuffer("[");
- toString(buf);
- return buf.append("]").toString();
- }
-
- /**
- * This should be overridden by derived classes (which should be sure
- * to call super.toString()) to append the derived class
- * specific sprite information to the string buffer.
- */
+ // documentation inherited
protected void toString (StringBuffer buf)
{
- buf.append("ox=").append(_ox);
+ super.toString(buf);
+ buf.append(", ox=").append(_ox);
buf.append(", oy=").append(_oy);
buf.append(", oxoff=").append(_oxoff);
buf.append(", oyoff=").append(_oyoff);
}
- /** The sprite manager. */
- protected SpriteManager _spritemgr;
-
/** The location of the sprite's origin in pixel coordinates. If the
* sprite positions itself via a hotspot that is not the upper left
* coordinate of the sprite's bounds, the offset to the hotspot should
@@ -429,18 +318,9 @@ public abstract class Sprite
* its bounds. */
protected int _oxoff, _oyoff;
- /** Our rendered bounds in pixel coordinates. */
- protected Rectangle _bounds = new Rectangle();
-
/** The orientation of this sprite. */
protected int _orient = NONE;
/** When moving, the path the sprite is traversing. */
protected Path _path;
-
- /** The render order of this sprite. */
- protected int _renderOrder;
-
- /** The sprite observers observing this sprite. */
- protected ArrayList _observers;
}
diff --git a/src/java/com/threerings/media/sprite/SpriteManager.java b/src/java/com/threerings/media/sprite/SpriteManager.java
index d588c4c52..6137ad86d 100644
--- a/src/java/com/threerings/media/sprite/SpriteManager.java
+++ b/src/java/com/threerings/media/sprite/SpriteManager.java
@@ -1,42 +1,32 @@
//
-// $Id: SpriteManager.java,v 1.37 2002/09/20 02:19:53 mdb Exp $
+// $Id: SpriteManager.java,v 1.38 2002/10/08 21:03:37 ray Exp $
package com.threerings.media.sprite;
-import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Iterator;
import java.util.List;
-import com.samskivert.util.CollectionUtil;
-import com.samskivert.util.SortableArrayList;
-import com.samskivert.util.Tuple;
-
+import com.threerings.media.AbstractMediaManager;
import com.threerings.media.Log;
-import com.threerings.media.MediaConstants;
import com.threerings.media.RegionManager;
/**
* The sprite manager manages the sprites running about in the game.
*/
-public class SpriteManager
- implements MediaConstants
+public class SpriteManager extends AbstractMediaManager
{
/**
* Construct and initialize the sprite manager.
*/
public SpriteManager (RegionManager remgr)
{
- _sprites = new SortableArrayList();
- _notify = new ArrayList();
- _remgr = remgr;
+ super(remgr);
}
/**
@@ -53,9 +43,9 @@ public class SpriteManager
*/
public void getIntersectingSprites (List list, Shape shape)
{
- int size = _sprites.size();
+ int size = _media.size();
for (int ii = 0; ii < size; ii++) {
- Sprite sprite = (Sprite)_sprites.get(ii);
+ Sprite sprite = (Sprite)_media.get(ii);
if (sprite.intersects(shape)) {
list.add(sprite);
}
@@ -75,9 +65,9 @@ public class SpriteManager
*/
public void getHitSprites (List list, int x, int y)
{
- int size = _sprites.size();
+ int size = _media.size();
for (int ii = 0; ii < size; ii++) {
- Sprite sprite = (Sprite)_sprites.get(ii);
+ Sprite sprite = (Sprite)_media.get(ii);
if (sprite.hitTest(x, y)) {
list.add(sprite);
}
@@ -91,12 +81,10 @@ public class SpriteManager
*/
public void addSprite (Sprite sprite)
{
- // initialize the sprite
- sprite.init(this);
- // add the sprite to our list
- _sprites.add(sprite);
- // and invalidate the sprite's original position
- sprite.invalidate();
+ if (insertMedia(sprite)) {
+ // and invalidate the sprite's original position
+ sprite.invalidate();
+ }
}
/**
@@ -106,7 +94,7 @@ public class SpriteManager
*/
public List getSprites ()
{
- return Collections.unmodifiableList(_sprites);
+ return Collections.unmodifiableList(_media);
}
/**
@@ -117,12 +105,7 @@ public class SpriteManager
*/
public void removeSprite (Sprite sprite)
{
- // invalidate the current sprite position
- sprite.invalidate();
- // remove the sprite from our list
- _sprites.remove(sprite);
- // clear out our manager reference
- sprite.shutdown();
+ removeMedia(sprite);
}
/**
@@ -133,51 +116,7 @@ public class SpriteManager
*/
public void clearSprites ()
{
- int size = _sprites.size();
- for (int ii = 0; ii < size; ii++) {
- Sprite sprite = (Sprite)_sprites.get(ii);
- sprite.shutdown();
- }
- _sprites.clear();
- }
-
- /**
- * Provides access to the region manager that the sprite manager is
- * using to collect invalid regions every frame. This should generally
- * only be used by sprites that want to invalidate themselves.
- */
- public RegionManager getRegionManager ()
- {
- return _remgr;
- }
-
- /**
- * Render to the given graphics context the sprites intersecting the
- * given shape and residing in the specified layer.
- *
- * @param layer the layer to render; one of {@link #FRONT}, {@link
- * #BACK}, or {@link #ALL}. The front layer contains all sprites with
- * a positive render order; the back layer contains all sprites with a
- * negative render order; all, both.
- * @param bounds the bounding shape.
- */
- public void renderSprites (Graphics2D gfx, int layer, Shape bounds)
- {
- // TODO: optimize to store sprites based on quadrants they're in
- // (or somesuch), and sorted, so that we can more quickly
- // determine which sprites to draw.
-
- int size = _sprites.size();
- for (int ii = 0; ii < size; ii++) {
- Sprite sprite = (Sprite)_sprites.get(ii);
- int order = sprite.getRenderOrder();
- if (((layer == ALL) ||
- (layer == FRONT && order >= 0) ||
- (layer == BACK && order < 0)) &&
- sprite.intersects(bounds)) {
- sprite.paint(gfx);
- }
- }
+ clearMedia();
}
/**
@@ -187,187 +126,91 @@ public class SpriteManager
*/
public void renderSpritePaths (Graphics2D gfx)
{
- int size = _sprites.size();
- for (int ii = 0; ii < size; ii++) {
- Sprite sprite = (Sprite)_sprites.get(ii);
+ for (int ii=0, nn=_media.size(); ii < nn; ii++) {
+ Sprite sprite = (Sprite)_media.get(ii);
sprite.paintPath(gfx);
}
}
- /**
- * Must be called every frame so that the sprites can be properly
- * updated. Normally a sprite manager is used in conjunction with an
- * animated panel which case this is called automatically.
- */
- public void tick (long tickStamp)
+ // documentation inherited
+ protected void dispatchEvent (ArrayList observers, Object event)
{
- // tick all sprites
- tickSprites(tickStamp);
-
- // re-sort the sprite list to account for potential new positions
- _sprites.sort(SPRITE_COMP);
-
-// // notify sprite observers of any collisions
-// handleCollisions();
-
- // notify sprite observers of any sprite events. note that we
- // explicitly queue up events while ticking and checking for
- // collisions, and we only notify observers once we're
- // finished with all of those antics so that any actions the
- // observers may take, such as sprite removal, won't screw us
- // up elsewhere.
- handleSpriteEvents();
- }
-
- /**
- * If the sprite manager is paused for some length of time, it should
- * be fast forwarded by the appropriate number of milliseconds. This
- * allows sprites 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)
- {
- int size = _sprites.size();
- for (int ii = 0; ii < size; ii++) {
- Sprite sprite = (Sprite)_sprites.get(ii);
- sprite.fastForward(timeDelta);
+ SpriteEvent sevt = (SpriteEvent) event;
+ for (int ii=0, nn=observers.size(); ii < nn; ii++) {
+ ((SpriteObserver) observers.get(ii)).handleEvent(sevt);
}
}
- /**
- * Call {@link Sprite#tick} on all sprite objects to give them a
- * chance to move themselves about, change their display image,
- * generate dirty regions and so forth.
- */
- protected void tickSprites (long tickStamp)
- {
- // we tick sprites in reverse order so as not to freak out if a
- // sprite is removed as a result of our calling tick() on it
- int size = _sprites.size();
- for (int ii = size-1; ii >= 0; ii--) {
- Sprite sprite = (Sprite)_sprites.get(ii);
- sprite.tick(tickStamp);
- }
- }
-
- /**
- * Check all sprites for collisions with others and inform any
- * sprite observers.
- */
- protected void handleCollisions ()
- {
- // gather a list of all sprite collisions
- int size = _sprites.size();
- for (int ii = 0; ii < size; ii++) {
- Sprite sprite = (Sprite)_sprites.get(ii);
- checkCollisions(ii, size, sprite);
- }
- }
-
- /**
- * Check a sprite for collision with any other sprites in the
- * sprite list and notify the sprite observers associated with any
- * sprites that do indeed collide.
- *
- * @param idx the starting sprite index.
- * @param size the total number of sprites.
- * @param sprite the sprite to check against other sprites for
- * collisions.
- */
- protected void checkCollisions (int idx, int size, Sprite sprite)
- {
- // TODO: make this handle quickly moving objects that may pass
- // through each other.
-
- // if we're the last sprite we know we've already handled any
- // collisions
- if (idx == (size - 1)) {
- return;
- }
-
- // calculate the x-position of the right edge of the sprite we're
- // checking for collisions
- Rectangle bounds = sprite.getBounds();
- int edgeX = bounds.x + bounds.width;
-
- for (int ii = (idx + 1); ii < size; ii++) {
- Sprite other = (Sprite)_sprites.get(ii);
- Rectangle obounds = other.getBounds();
- if (obounds.x > edgeX) {
- // since sprites are stored in the list sorted by
- // ascending x-position, we know this sprite and any
- // other sprites farther on in the list can't possibly
- // intersect with the sprite we're checking, so we're
- // done.
- return;
-
- } else if (obounds.intersects(bounds)) {
- sprite.notifyObservers(new CollisionEvent(sprite, other));
- }
- }
- }
-
- /**
- * Notify all sprite observers of any sprite events that took place
- * during our most recent tick().
- */
- protected void handleSpriteEvents ()
- {
- int size = _notify.size();
- for (int ii = 0; ii < size; ii++) {
- Tuple tup = (Tuple)_notify.remove(0);
- ArrayList observers = (ArrayList)tup.left;
- SpriteEvent evt = (SpriteEvent)tup.right;
-
- int osize = observers.size();
- for (int jj = 0; jj < osize; jj++) {
- SpriteObserver obs = (SpriteObserver)observers.get(jj);
- obs.handleEvent(evt);
- }
- }
- }
-
- /**
- * Called by {@link Sprite#notifyObservers} to note that the
- * sprite's observers should be informed of a sprite event once
- * the current tick() is complete.
- *
- * @param observers the list of sprite observers.
- * @param event the sprite event to notify the observers of.
- */
- protected void notifySpriteObservers (ArrayList observers,
- SpriteEvent event)
- {
- // throw it on the list of events for later
- _notify.add(new Tuple(observers, event));
- }
-
- /** The sprite objects we're managing. */
- protected SortableArrayList _sprites;
-
- /** The list of pending sprite notifications. */
- protected ArrayList _notify;
-
- /** Used to accumulate dirty regions. */
- protected RegionManager _remgr;
-
- /** The comparator used to sort sprites by horizontal position. */
- protected static final Comparator SPRITE_COMP = new SpriteComparator();
-
- /** Used to sort sprites. */
- protected static class SpriteComparator implements Comparator
- {
- public int compare (Object o1, Object o2)
- {
- Sprite s1 = (Sprite)o1;
- Sprite s2 = (Sprite)o2;
- return (s2.getX() - s1.getX());
- }
-
- public boolean equals (Object obj)
- {
- return (obj == this);
- }
- }
+// NOTE- collision handling code is turned off for now. To re-implement,
+// a new array should be kept with sprites sorted in some sort of x/y order
+//
+// /**
+// * Check all sprites for collisions with others and inform any
+// * sprite observers.
+// */
+// protected void handleCollisions ()
+// {
+// // gather a list of all sprite collisions
+// int size = _sprites.size();
+// for (int ii = 0; ii < size; ii++) {
+// Sprite sprite = (Sprite)_sprites.get(ii);
+// checkCollisions(ii, size, sprite);
+// }
+// }
+//
+// /**
+// * Check a sprite for collision with any other sprites in the
+// * sprite list and notify the sprite observers associated with any
+// * sprites that do indeed collide.
+// *
+// * @param idx the starting sprite index.
+// * @param size the total number of sprites.
+// * @param sprite the sprite to check against other sprites for
+// * collisions.
+// */
+// protected void checkCollisions (int idx, int size, Sprite sprite)
+// {
+// // TODO: make this handle quickly moving objects that may pass
+// // through each other.
+//
+// // if we're the last sprite we know we've already handled any
+// // collisions
+// if (idx == (size - 1)) {
+// return;
+// }
+//
+// // calculate the x-position of the right edge of the sprite we're
+// // checking for collisions
+// Rectangle bounds = sprite.getBounds();
+// int edgeX = bounds.x + bounds.width;
+//
+// for (int ii = (idx + 1); ii < size; ii++) {
+// Sprite other = (Sprite)_sprites.get(ii);
+// Rectangle obounds = other.getBounds();
+// if (obounds.x > edgeX) {
+// // since sprites are stored in the list sorted by
+// // ascending x-position, we know this sprite and any
+// // other sprites farther on in the list can't possibly
+// // intersect with the sprite we're checking, so we're
+// // done.
+// return;
+//
+// } else if (obounds.intersects(bounds)) {
+// sprite.notifyObservers(new CollisionEvent(sprite, other));
+// }
+// }
+// }
+// /** The comparator used to sort sprites by horizontal position. */
+// protected static final Comparator SPRITE_COMP = new SpriteComparator();
+//
+// /** Used to sort sprites. */
+// protected static class SpriteComparator implements Comparator
+// {
+// public int compare (Object o1, Object o2)
+// {
+// Sprite s1 = (Sprite)o1;
+// Sprite s2 = (Sprite)o2;
+// return (s2.getX() - s1.getX());
+// }
+// }
}
diff --git a/src/java/com/threerings/miso/client/SceneViewPanel.java b/src/java/com/threerings/miso/client/SceneViewPanel.java
index 91ef63827..594f04854 100644
--- a/src/java/com/threerings/miso/client/SceneViewPanel.java
+++ b/src/java/com/threerings/miso/client/SceneViewPanel.java
@@ -1,5 +1,5 @@
//
-// $Id: SceneViewPanel.java,v 1.44 2002/09/24 07:56:25 shaper Exp $
+// $Id: SceneViewPanel.java,v 1.45 2002/10/08 21:03:37 ray Exp $
package com.threerings.miso.scene;
@@ -169,7 +169,7 @@ public class SceneViewPanel extends VirtualMediaPanel
*/
protected void paintBits (Graphics2D gfx, int layer, Rectangle dirty)
{
- _animmgr.renderAnimations(gfx, layer, dirty);
+ _animmgr.renderMedia(gfx, layer, dirty);
}
/**