In theory this should work (modulo some particularly fiddly bits that I'm going

to have to think about), but it's totally untested. That comes next!


git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@115 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
Michael Bayne
2007-01-20 02:35:56 +00:00
parent 088bc4b88b
commit 81a3dd4dd9
5 changed files with 166 additions and 159 deletions
@@ -47,18 +47,17 @@ import com.samskivert.util.RunAnywhere;
import com.samskivert.util.StringUtil; import com.samskivert.util.StringUtil;
/** /**
* Used to get Swing's repainting to jive with our active rendering * Used to get Swing's repainting to jive with our active rendering strategy.
* strategy.
* *
* @see FrameManager * @see FrameManager
*/ */
public class ActiveRepaintManager extends RepaintManager public class ActiveRepaintManager extends RepaintManager
{ {
/** /**
* Components that are rooted in this component (which must be a {@link * Components that are rooted in this component (which must be a {@link Window} or an {@link
* Window} or an {@link Applet}) will be rendered into the offscreen buffer * Applet}) will be rendered into the offscreen buffer managed by the frame manager. Other
* managed by the frame manager. Other components will be rendered into * components will be rendered into separate offscreen buffers and repainted in the normal
* separate offscreen buffers and repainted in the normal Swing manner. * Swing manner.
*/ */
public ActiveRepaintManager (Component root) public ActiveRepaintManager (Component root)
{ {
@@ -75,9 +74,8 @@ public class ActiveRepaintManager extends RepaintManager
// locate the validation root for this component // locate the validation root for this component
for (Component c = comp; c != null; c = c.getParent()) { for (Component c = comp; c != null; c = c.getParent()) {
// if the component is not part of an active widget hierarcy, // if the component is not part of an active widget hierarcy, we can stop now; if the
// we can stop now; if the component is a cell render pane, // component is a cell render pane, we're apparently supposed to ignore it as wel
// we're apparently supposed to ignore it as wel
if (!c.isDisplayable() || c instanceof CellRendererPane) { if (!c.isDisplayable() || c instanceof CellRendererPane) {
return; return;
} }
@@ -87,26 +85,23 @@ public class ActiveRepaintManager extends RepaintManager
continue; continue;
} }
// if we find our validate root, we can stop looking; NOTE: // if we find our validate root, we can stop looking; NOTE: JTextField incorrectly
// JTextField incorrectly claims to be a validate root thereby // claims to be a validate root thereby fucking up the program something serious; we
// fucking up the program something serious; we jovially // jovially ignore it's claims here and restore order to the universe; see bug #403550
// ignore it's claims here and restore order to the universe; // for more fallout from Sun's fuckup
// see bug #403550 for more fallout from Sun's fuckup if (!(c instanceof JTextField) && !(c instanceof JScrollPane) &&
if (!(c instanceof JTextField) &&
!(c instanceof JScrollPane) &&
((JComponent)c).isValidateRoot()) { ((JComponent)c).isValidateRoot()) {
vroot = c; vroot = c;
break; break;
} }
} }
// if we found no validation root we can abort as this component // if we found no validation root we can abort as this component is not part of any valid
// is not part of any valid widget hierarchy // widget hierarchy
if (vroot == null) { if (vroot == null) {
if (DEBUG) { if (DEBUG) {
Log.info("Skipping vrootless component: " + toString(comp)); Log.info("Skipping vrootless component: " + toString(comp));
} }
return; return;
} }
@@ -114,34 +109,29 @@ public class ActiveRepaintManager extends RepaintManager
// that is showing // that is showing
if (getRoot(vroot) == null) { if (getRoot(vroot) == null) {
if (DEBUG) { if (DEBUG) {
Log.info("Skipping rootless component " + Log.info("Skipping rootless component [comp=" + toString(comp) +
"[comp=" + toString(comp) +
", vroot=" + toString(vroot) + "]."); ", vroot=" + toString(vroot) + "].");
} }
return; return;
} }
// add the invalid component to our list and we'll validate it on // add the invalid component to our list and we'll validate it on the next frame
// the next frame
if (!ListUtil.containsRef(_invalid, vroot)) { if (!ListUtil.containsRef(_invalid, vroot)) {
if (DEBUG) { if (DEBUG) {
Log.info("Invalidating " + toString(vroot) + "."); Log.info("Invalidating " + toString(vroot) + ".");
} }
_invalid = ListUtil.add(_invalid, vroot); _invalid = ListUtil.add(_invalid, vroot);
// on the mac, components frequently do not repaint themselves // on the mac, components frequently do not repaint themselves after being invalidated
// after being invalidated so we have to force a repaint from // so we have to force a repaint from the validation roon on down
// the validation roon on down
if (RunAnywhere.isMacOS() && vroot instanceof JComponent) { if (RunAnywhere.isMacOS() && vroot instanceof JComponent) {
addDirtyRegion((JComponent)vroot, 0, 0, addDirtyRegion((JComponent)vroot, 0, 0, vroot.getWidth(), vroot.getHeight());
vroot.getWidth(), vroot.getHeight());
} }
} }
} }
// documentation inherited // documentation inherited
public synchronized void addDirtyRegion ( public synchronized void addDirtyRegion (JComponent comp, int x, int y, int width, int height)
JComponent comp, int x, int y, int width, int height)
{ {
// ignore invalid requests // ignore invalid requests
if ((width <= 0) || (height <= 0) || (comp == null) || if ((width <= 0) || (height <= 0) || (comp == null) ||
@@ -151,8 +141,7 @@ public class ActiveRepaintManager extends RepaintManager
return; return;
} }
// if this component is already dirty, simply expand their // if this component is already dirty, simply expand their existing dirty rectangle
// existing dirty rectangle
Rectangle drect = (Rectangle)_dirty.get(comp); Rectangle drect = (Rectangle)_dirty.get(comp);
if (drect != null) { if (drect != null) {
drect.add(x, y); drect.add(x, y);
@@ -168,28 +157,25 @@ public class ActiveRepaintManager extends RepaintManager
if (DEBUG) { if (DEBUG) {
Log.info("Dirtying component [comp=" + toString(comp) + Log.info("Dirtying component [comp=" + toString(comp) +
", drect=" + StringUtil.toString( ", drect=" + StringUtil.toString(new Rectangle(x, y, width, height)) + "].");
new Rectangle(x, y, width, height)) + "].");
} }
// if we made it this far, we can queue up a dirty region for this // if we made it this far, we can queue up a dirty region for this component to be
// component to be repainted on the next tick // repainted on the next tick
_dirty.put(comp, new Rectangle(x, y, width, height)); _dirty.put(comp, new Rectangle(x, y, width, height));
} }
/** /**
* Returns the root component for the supplied component or null if it * Returns the root component for the supplied component or null if it is not part of a rooted
* is not part of a rooted hierarchy or if any parent along the way is * hierarchy or if any parent along the way is found to be hidden or without a peer.
* found to be hidden or without a peer.
*/ */
protected Component getRoot (Component comp) protected Component getRoot (Component comp)
{ {
for (Component c = comp; c != null; c = c.getParent()) { for (Component c = comp; c != null; c = c.getParent()) {
boolean hidden = !c.isDisplayable(); boolean hidden = !c.isDisplayable();
// on the mac, the JRootPane is invalidated before it is // on the mac, the JRootPane is invalidated before it is visible and is never again
// visible and is never again invalidated or repainted, so we // invalidated or repainted, so we punt and allow all invisible components to be
// punt and allow all invisible components to be invalidated // invalidated and revalidated
// and revalidated
if (!RunAnywhere.isMacOS()) { if (!RunAnywhere.isMacOS()) {
hidden |= !c.isVisible(); hidden |= !c.isVisible();
} }
@@ -207,10 +193,9 @@ public class ActiveRepaintManager extends RepaintManager
public synchronized Rectangle getDirtyRegion (JComponent comp) public synchronized Rectangle getDirtyRegion (JComponent comp)
{ {
Rectangle drect = (Rectangle)_dirty.get(comp); Rectangle drect = (Rectangle)_dirty.get(comp);
// copy the rectangle if we found one, otherwise create an empty // copy the rectangle if we found one, otherwise create an empty rectangle because we don't
// rectangle because we don't want them leaving empty handed // want them leaving empty handed
return (drect == null) ? return (drect == null) ? new Rectangle(0, 0, 0, 0) : new Rectangle(drect);
new Rectangle(0, 0, 0, 0) : new Rectangle(drect);
} }
// documentation inherited // documentation inherited
@@ -220,8 +205,7 @@ public class ActiveRepaintManager extends RepaintManager
} }
/** /**
* Validates the invalid components that have been queued up since the * Validates the invalid components that have been queued up since the last frame tick.
* last frame tick.
*/ */
public void validateComponents () public void validateComponents ()
{ {
@@ -268,11 +252,10 @@ public class ActiveRepaintManager extends RepaintManager
_dirty = tmap; _dirty = tmap;
} }
// scan through the list, looking for components for whom a parent // scan through the list, looking for components for whom a parent component is also dirty.
// component is also dirty. in such a case, the dirty rectangle // in such a case, the dirty rectangle for the parent component is expanded to contain the
// for the parent component is expanded to contain the dirty // dirty rectangle of the child and the child is removed from the repaint list (painting
// rectangle of the child and the child is removed from the // the parent will repaint the child)
// repaint list (painting the parent will repaint the child)
Iterator iter = _spare.entrySet().iterator(); Iterator iter = _spare.entrySet().iterator();
PRUNE: PRUNE:
while (iter.hasNext()) { while (iter.hasNext()) {
@@ -281,31 +264,26 @@ public class ActiveRepaintManager extends RepaintManager
Rectangle drect = (Rectangle)entry.getValue(); Rectangle drect = (Rectangle)entry.getValue();
int x = comp.getX() + drect.x, y = comp.getY() + drect.y; int x = comp.getX() + drect.x, y = comp.getY() + drect.y;
// climb up the parent hierarchy, looking for the first opaque // climb up the parent hierarchy, looking for the first opaque parent as well as the
// parent as well as the root component // root component
for (Component c = comp.getParent(); c != null; c = c.getParent()) { for (Component c = comp.getParent(); c != null; c = c.getParent()) {
// stop looking for combinable parents for non-visible or // stop looking for combinable parents for non-visible or non-JComponents
// non-JComponents if (!c.isVisible() || !c.isDisplayable() || !(c instanceof JComponent)) {
if (!c.isVisible() || !c.isDisplayable() ||
!(c instanceof JComponent)) {
break; break;
} }
// check to see if this parent is dirty // check to see if this parent is dirty
Rectangle prect = (Rectangle)_spare.get(c); Rectangle prect = (Rectangle)_spare.get(c);
if (prect != null) { if (prect != null) {
// that we were going to merge it with its parent and // that we were going to merge it with its parent and blow it away
// blow it away
drect.x = x; drect.x = x;
drect.y = y; drect.y = y;
if (DEBUG) { if (DEBUG) {
Log.info("Found dirty parent " + Log.info("Found dirty parent [comp=" + toString(comp) +
"[comp=" + toString(comp) +
", drect=" + StringUtil.toString(drect) + ", drect=" + StringUtil.toString(drect) +
", pcomp=" + toString(c) + ", pcomp=" + toString(c) +
", prect=" + StringUtil.toString(prect) + ", prect=" + StringUtil.toString(prect) + "].");
"].");
} }
prect.add(drect); prect.add(drect);
@@ -325,26 +303,24 @@ public class ActiveRepaintManager extends RepaintManager
} }
} }
// now paint each of the dirty components, by setting the clipping // now paint each of the dirty components, by setting the clipping rectangle appropriately
// rectangle appropriately and calling paint() on the associated // and calling paint() on the associated root component
// root component
iter = _spare.entrySet().iterator(); iter = _spare.entrySet().iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
Entry entry = (Entry)iter.next(); Entry entry = (Entry)iter.next();
JComponent comp = (JComponent)entry.getKey(); JComponent comp = (JComponent)entry.getKey();
Rectangle drect = (Rectangle)entry.getValue(); Rectangle drect = (Rectangle)entry.getValue();
// get the root component, adjust the clipping (dirty) // get the root component, adjust the clipping (dirty) rectangle and obtain the bounds
// rectangle and obtain the bounds of the client in absolute // of the client in absolute coordinates
// coordinates
Component root = null, ocomp = null; Component root = null, ocomp = null;
// start with the components bounds which we'll switch to the // start with the components bounds which we'll switch to the opaque parent component's
// opaque parent component's bounds if and when we find one // bounds if and when we find one
_cbounds.setBounds(0, 0, comp.getWidth(), comp.getHeight()); _cbounds.setBounds(0, 0, comp.getWidth(), comp.getHeight());
// climb up the parent hierarchy, looking for the first opaque // climb up the parent hierarchy, looking for the first opaque parent as well as the
// parent as well as the root component // root component
for (Component c = comp; c != null; c = c.getParent()) { for (Component c = comp; c != null; c = c.getParent()) {
if (!c.isVisible() || !c.isDisplayable()) { if (!c.isVisible() || !c.isDisplayable()) {
break; break;
@@ -354,16 +330,14 @@ public class ActiveRepaintManager extends RepaintManager
// make a note of the first opaque parent we find // make a note of the first opaque parent we find
if (ocomp == null && ((JComponent)c).isOpaque()) { if (ocomp == null && ((JComponent)c).isOpaque()) {
ocomp = c; ocomp = c;
// we need to obtain the opaque parent's coordinates // we need to obtain the opaque parent's coordinates in the root coordinate
// in the root coordinate system for when we repaint // system for when we repaint
_cbounds.setBounds( _cbounds.setBounds(0, 0, ocomp.getWidth(), ocomp.getHeight());
0, 0, ocomp.getWidth(), ocomp.getHeight());
} }
} else { } else {
// oh god the hackery. apparently the fscking // oh god the hackery. apparently the fscking JEditorPane wraps a heavy weight
// JEditorPane wraps a heavy weight component around // component around every swing component it uses when doing forms
// every swing component it uses when doing forms
Component tp = c.getParent(); Component tp = c.getParent();
if (!(tp instanceof JEditorPane)) { if (!(tp instanceof JEditorPane)) {
root = c; root = c;
@@ -371,8 +345,7 @@ public class ActiveRepaintManager extends RepaintManager
} }
} }
// translate the coordinates into this component's // translate the coordinates into this component's coordinate system
// coordinate system
drect.x += c.getX(); drect.x += c.getX();
drect.y += c.getY(); drect.y += c.getY();
_cbounds.x += c.getX(); _cbounds.x += c.getX();
@@ -383,19 +356,17 @@ public class ActiveRepaintManager extends RepaintManager
c.getX(), c.getY(), c.getWidth(), c.getHeight(), drect); c.getX(), c.getY(), c.getWidth(), c.getHeight(), drect);
} }
// if we found no opaque parent, just paint the component // if we found no opaque parent, just paint the component itself (this seems to happen
// itself (this seems to happen with the top-level layered // with the top-level layered pane)
// pane)
if (ocomp == null) { if (ocomp == null) {
ocomp = comp; ocomp = comp;
} }
// if this component is rooted in our frame, repaint it into // if this component is rooted in our frame, repaint it into the supplied graphics
// the supplied graphics instance // instance
if (root == _root) { if (root == _root) {
if (DEBUG) { if (DEBUG) {
Log.info("Repainting [comp=" + toString(comp) + Log.info("Repainting [comp=" + toString(comp) + StringUtil.toString(_cbounds) +
StringUtil.toString(_cbounds) +
", ocomp=" + toString(ocomp) + ", ocomp=" + toString(ocomp) +
", drect=" + StringUtil.toString(drect) + "]."); ", drect=" + StringUtil.toString(drect) + "].");
} }
@@ -403,36 +374,30 @@ public class ActiveRepaintManager extends RepaintManager
g.setClip(drect); g.setClip(drect);
g.translate(_cbounds.x, _cbounds.y); g.translate(_cbounds.x, _cbounds.y);
try { try {
// some components are ill-behaved and may throw an // some components are ill-behaved and may throw an exception while painting
// exception while painting themselves, and so we // themselves, and so we needs must deal with these fellows gracefully
// needs must deal with these fellows gracefully
ocomp.paint(g); ocomp.paint(g);
} catch (Exception e) { } catch (Exception e) {
Log.warning("Exception while painting component " + Log.warning("Exception while painting component [comp=" + ocomp + "].");
"[comp=" + ocomp + ", e=" + e + "].");
Log.logStackTrace(e); Log.logStackTrace(e);
} }
g.translate(-_cbounds.x, -_cbounds.y); g.translate(-_cbounds.x, -_cbounds.y);
// we also need to repaint any components in this layer // we also need to repaint any components in this layer that are above our freshly
// that are above our freshly repainted component // repainted component
fmgr.renderLayers((Graphics2D)g, ocomp, _cbounds, _clipped); fmgr.renderLayers((Graphics2D)g, ocomp, _cbounds, _clipped);
} else if (root != null) { } else if (root != null) {
if (DEBUG) { if (DEBUG) {
Log.info("Repainting old-school " + Log.info("Repainting old-school [comp=" + toString(comp) +
"[comp=" + toString(comp) + ", ocomp=" + toString(ocomp) + ", root=" + toString(root) +
", ocomp=" + toString(ocomp) + ", bounds=" + StringUtil.toString(_cbounds) + "].");
", root=" + toString(root) +
", bounds=" + StringUtil.toString(_cbounds) +
"].");
dumpHierarchy(comp); dumpHierarchy(comp);
} }
// otherwise, repaint with standard swing double buffers // otherwise, repaint with standard swing double buffers
Image obuf = getOffscreenBuffer( Image obuf = getOffscreenBuffer(ocomp, _cbounds.width, _cbounds.height);
ocomp, _cbounds.width, _cbounds.height);
Graphics og = null, cg = null; Graphics og = null, cg = null;
try { try {
og = obuf.getGraphics(); og = obuf.getGraphics();
@@ -462,8 +427,7 @@ public class ActiveRepaintManager extends RepaintManager
*/ */
protected static String toString (Component comp) protected static String toString (Component comp)
{ {
return comp.getClass().getName() + return comp.getClass().getName() + StringUtil.toString(comp.getBounds());
StringUtil.toString(comp.getBounds());
} }
/** /**
@@ -486,8 +450,7 @@ public class ActiveRepaintManager extends RepaintManager
/** A mapping of invalid rectangles for each widget that is dirty. */ /** A mapping of invalid rectangles for each widget that is dirty. */
protected HashMap _dirty = new HashMap(); protected HashMap _dirty = new HashMap();
/** A spare hashmap that we swap in while repainting dirty components /** A spare hashmap that we swap in while repainting dirty components in the old hashmap. */
* in the old hashmap. */
protected HashMap _spare = new HashMap(); protected HashMap _spare = new HashMap();
/** Used to compute dirty components' bounds. */ /** Used to compute dirty components' bounds. */
@@ -496,7 +459,6 @@ public class ActiveRepaintManager extends RepaintManager
/** Used when rendering "layered" components. */ /** Used when rendering "layered" components. */
protected boolean[] _clipped = new boolean[] { true }; protected boolean[] _clipped = new boolean[] { true };
/** We debug so much that we have to make it easy to enable and /** We debug so much that we have to make it easy to enable and disable debug logging. Yay! */
* disable debug logging. Yay! */
protected static final boolean DEBUG = false; protected static final boolean DEBUG = false;
} }
@@ -221,7 +221,6 @@ public abstract class FrameManager
{ {
if (_overlay == null) { if (_overlay == null) {
_overlay = new MediaOverlay(this); _overlay = new MediaOverlay(this);
registerFrameParticipant(_overlay);
} }
return _overlay; return _overlay;
} }
@@ -232,7 +231,6 @@ public abstract class FrameManager
public void clearMediaOverlay () public void clearMediaOverlay ()
{ {
if (_overlay != null) { if (_overlay != null) {
removeFrameParticipant(_overlay);
_overlay = null; _overlay = null;
} }
} }
@@ -330,11 +328,11 @@ public abstract class FrameManager
_timer = timer; _timer = timer;
// set up our custom repaint manager // set up our custom repaint manager
_remgr = new ActiveRepaintManager(_window); _repainter = new ActiveRepaintManager(_window);
RepaintManager.setCurrentManager(_remgr); RepaintManager.setCurrentManager(_repainter);
// turn off double buffering for the whole business because we handle repaints // turn off double buffering for the whole business because we handle repaints
_remgr.setDoubleBufferingEnabled(false); _repainter.setDoubleBufferingEnabled(false);
} }
/** /**
@@ -377,7 +375,7 @@ public abstract class FrameManager
// validate any invalid components // validate any invalid components
try { try {
_remgr.validateComponents(); _repainter.validateComponents();
} catch (Throwable t) { } catch (Throwable t) {
Log.warning("Failure validating components."); Log.warning("Failure validating components.");
Log.logStackTrace(t); Log.logStackTrace(t);
@@ -412,6 +410,11 @@ public abstract class FrameManager
Log.logStackTrace(t); Log.logStackTrace(t);
} }
} }
// if we have an overlay, tick that too
if (_overlay != null) {
_overlay.tick(tickStamp);
}
} }
/** /**
@@ -494,8 +497,19 @@ public abstract class FrameManager
} }
} }
// if we have a media overlay, give that a chance to propagate dirty regions to the active
// repaint manager for areas it dirtied during this tick
if (_overlay != null) {
_overlay.propagateDirtyRegions(_repainter, _root.getRootPane());
}
// repaint any widgets that have declared they need to be repainted since the last tick // repaint any widgets that have declared they need to be repainted since the last tick
boolean pcomp = _remgr.paintComponents(gfx, this); boolean pcomp = _repainter.paintComponents(gfx, this);
// if we have a media overlay, give it a chance to paint on top of everything
if (_overlay != null) {
pcomp |= _overlay.paint(gfx);
}
// let the caller know if anybody painted anything // let the caller know if anybody painted anything
return ((painted > 0) || pcomp); return ((painted > 0) || pcomp);
@@ -676,7 +690,7 @@ public abstract class FrameManager
protected MediaTimer _timer; protected MediaTimer _timer;
/** Our custom repaint manager. */ /** Our custom repaint manager. */
protected ActiveRepaintManager _remgr; protected ActiveRepaintManager _repainter;
/** If active, an overlay that will be rendering sprites and animations on top of the frame. */ /** If active, an overlay that will be rendering sprites and animations on top of the frame. */
protected MediaOverlay _overlay; protected MediaOverlay _overlay;
+45 -15
View File
@@ -23,8 +23,9 @@ package com.threerings.media;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JRootPane;
import com.threerings.media.FrameParticipant;
import com.threerings.media.animation.AnimationManager; import com.threerings.media.animation.AnimationManager;
import com.threerings.media.sprite.SpriteManager; import com.threerings.media.sprite.SpriteManager;
@@ -35,7 +36,7 @@ import com.threerings.media.sprite.SpriteManager;
* it has left dirty. * it has left dirty.
*/ */
public class MediaOverlay public class MediaOverlay
implements MediaHost, FrameParticipant implements MediaHost
{ {
/** /**
* Returns a reference to the animation manager used by this media panel. * Returns a reference to the animation manager used by this media panel.
@@ -53,13 +54,51 @@ public class MediaOverlay
return _metamgr.getSpriteManager(); return _metamgr.getSpriteManager();
} }
/**
* Called by the {@link FrameManager} to propagate our dirty regions to the active repaint
* manager so that it can repaint the underlying components just prior to our painting our
* media. This will be followe by a call to {@link paint} after the components have been
* repainted.
*/
public void propagateDirtyRegions (ActiveRepaintManager repmgr, JRootPane root)
{
// this will clear out our region manager, so we need to keep these around for our
// subsequent call to paint
_dirty = _metamgr.getRegionManager().getDirtyRegions();
for (int ii = 0; ii < _dirty.length; ii++) {
Rectangle dirty = _dirty[ii];
repmgr.addDirtyRegion(root, dirty.x, dirty.y, dirty.width, dirty.height);
}
}
/**
* Called by the {@link FrameManager} after everything is done painting, allowing us to paint
* gloriously overtop of everything in the frame.
*
* @return true if we painted something, false otherwise.
*/
public boolean paint (Graphics2D gfx)
{
if (_metamgr.needsPaint()) {
for (int ii = 0; ii < _dirty.length; ii++) {
gfx.setClip(_dirty[ii]);
_metamgr.paintMedia(gfx, MediaConstants.BACK, _dirty[ii]);
_metamgr.paintMedia(gfx, MediaConstants.FRONT, _dirty[ii]);
}
return true;
}
return false;
}
// from interface MediaHost // from interface MediaHost
public Graphics2D createGraphics () public Graphics2D createGraphics ()
{ {
return _metamgr.getFrameManager().createGraphics(); return _metamgr.getFrameManager().createGraphics();
} }
// from interface FrameParticipant /**
* Called by the frame manager on every tick.
*/
public void tick (long tickStamp) public void tick (long tickStamp)
{ {
if (!_metamgr.isPaused()) { if (!_metamgr.isPaused()) {
@@ -68,18 +107,6 @@ public class MediaOverlay
} }
} }
// from interface FrameParticipant
public boolean needsPaint ()
{
return _metamgr.needsPaint();
}
// from interface FrameParticipant
public Component getComponent ()
{
return null; // TODO
}
/** /**
* Creates a media overlay. Only the {@link FrameManager} will construct an instance. * Creates a media overlay. Only the {@link FrameManager} will construct an instance.
*/ */
@@ -94,4 +121,7 @@ public class MediaOverlay
/** Handles the heavy lifting involving media. */ /** Handles the heavy lifting involving media. */
protected MetaMediaManager _metamgr; protected MetaMediaManager _metamgr;
/** A temporary list of dirty rectangles maintained during the painting process. */
protected Rectangle[] _dirty;
} }
@@ -127,6 +127,14 @@ public class MediaPanel extends JComponent
return _metamgr.getSpriteManager(); return _metamgr.getSpriteManager();
} }
/**
* Returns a reference to the region manager used by this media panel.
*/
public RegionManager getRegionManager ()
{
return _metamgr.getRegionManager();
}
/** /**
* Pauses the sprites and animations that are currently active on this media panel. Also stops * Pauses the sprites and animations that are currently active on this media panel. Also stops
* listening to the frame tick while paused. * listening to the frame tick while paused.
@@ -29,9 +29,8 @@ import java.util.ArrayList;
import com.samskivert.util.StringUtil; import com.samskivert.util.StringUtil;
/** /**
* Manages regions (rectangles) that are invalidated in the process of * Manages regions (rectangles) that are invalidated in the process of ticking animations and
* ticking animations and sprites and generally doing other display * sprites and generally doing other display related business.
* related business.
*/ */
public class RegionManager public class RegionManager
{ {
@@ -46,9 +45,8 @@ public class RegionManager
} }
/** /**
* Invalidates the specified region (the supplied rectangle will be * Invalidates the specified region (the supplied rectangle will be cloned as the region
* cloned as the region manager fiddles with the rectangles it uses * manager fiddles with the rectangles it uses internally).
* internally).
*/ */
public void invalidateRegion (Rectangle rect) public void invalidateRegion (Rectangle rect)
{ {
@@ -58,17 +56,15 @@ public class RegionManager
} }
/** /**
* Adds the supplied rectangle to the dirty regions. Control of the * Adds the supplied rectangle to the dirty regions. Control of the rectangle is given to the
* rectangle is given to the region manager as it may choose to bend, * region manager as it may choose to bend, fold or mutilate it later. If you don't want the
* fold or mutilate it later. If you don't want the region manager * region manager messing with your rectangle, use {@link #invalidateRegion}.
* messing with your rectangle, use {@link #invalidateRegion}.
*/ */
public void addDirtyRegion (Rectangle rect) public void addDirtyRegion (Rectangle rect)
{ {
// make sure we're on an AWT thread // make sure we're on an AWT thread
if (!EventQueue.isDispatchThread()) { if (!EventQueue.isDispatchThread()) {
Log.warning("Oi! Region dirtied on non-AWT thread " + Log.warning("Oi! Region dirtied on non-AWT thread [rect=" + rect + "].");
"[rect=" + rect + "].");
Thread.dumpStack(); Thread.dumpStack();
} }
@@ -81,8 +77,7 @@ public class RegionManager
// more sanity checking // more sanity checking
long x = rect.x, y = rect.y; long x = rect.x, y = rect.y;
if ((Math.abs(x) > Integer.MAX_VALUE/2) || if ((Math.abs(x) > Integer.MAX_VALUE/2) || (Math.abs(y) > Integer.MAX_VALUE/2)) {
(Math.abs(y) > Integer.MAX_VALUE/2)) {
Log.warning("Requested to dirty questionable region " + Log.warning("Requested to dirty questionable region " +
"[rect=" + StringUtil.toString(rect) + "]."); "[rect=" + StringUtil.toString(rect) + "].");
if (Log.getLevel() == Log.log.DEBUG) { if (Log.getLevel() == Log.log.DEBUG) {
@@ -107,8 +102,7 @@ public class RegionManager
return false; return false;
} else if (width == 0 || height == 0) { } else if (width == 0 || height == 0) {
// no need to complain about zero sized rectangles, just // no need to complain about zero sized rectangles, just ignore them
// ignore them
return false; return false;
} else { } else {
@@ -117,8 +111,8 @@ public class RegionManager
} }
/** /**
* Returns true if dirty regions have been accumulated since the last * Returns true if dirty regions have been accumulated since the last call to {@link
* call to {@link #getDirtyRegions}. * #getDirtyRegions}.
*/ */
public boolean haveDirtyRegions () public boolean haveDirtyRegions ()
{ {
@@ -126,10 +120,9 @@ public class RegionManager
} }
/** /**
* Merges all outstanding dirty regions into a single list of * Merges all outstanding dirty regions into a single list of rectangles and returns that to
* rectangles and returns that to the caller. Interally, the list of * the caller. Interally, the list of accumulated dirty regions is cleared out and prepared for
* accumulated dirty regions is cleared out and prepared for the next * the next frame.
* frame.
*/ */
public Rectangle[] getDirtyRegions () public Rectangle[] getDirtyRegions ()
{ {