Modified sprite management so that if in the course of processing its
dirty rectangles, an animated view has to expand the dirty region, it can call back to the sprite manager to determine whether this new, expanded dirty region includes sprites that weren't previously considered to be dirty. If so, those sprites' rendered bounds are added to the dirty rectangle list being processed so that they will be properly redrawn (which may trigger more sprites to be included and so on). Also modified sprite internals in a cleany uppy sort of way. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@309 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,11 +1,8 @@
|
||||
//
|
||||
// $Id: AnimatedView.java,v 1.2 2001/08/21 20:02:39 mdb Exp $
|
||||
// $Id: AnimatedView.java,v 1.3 2001/08/22 02:14:57 mdb Exp $
|
||||
|
||||
package com.threerings.media.sprite;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A view that wishes to interact with the animation manager needs to
|
||||
* implement this interface to give the animation manager a means by which
|
||||
@@ -20,7 +17,7 @@ public interface AnimatedView
|
||||
*
|
||||
* @param rects the list of {@link java.awt.Rectangle} objects.
|
||||
*/
|
||||
public void invalidateRects (List rects);
|
||||
public void invalidateRects (DirtyRectList rects);
|
||||
|
||||
/**
|
||||
* Requests that the animated view paint itself immediately (that it
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
//
|
||||
// $Id: AnimationManager.java,v 1.13 2001/08/21 20:02:39 mdb Exp $
|
||||
// $Id: AnimationManager.java,v 1.14 2001/08/22 02:14:57 mdb Exp $
|
||||
|
||||
package com.threerings.media.sprite;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.util.ArrayList;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
@@ -108,7 +107,7 @@ public class AnimationManager implements Interval, PerformanceObserver
|
||||
_spritemgr.tick();
|
||||
|
||||
// invalidate screen-rects dirtied by sprites
|
||||
ArrayList rects = _spritemgr.getDirtyRects();
|
||||
DirtyRectList rects = _spritemgr.getDirtyRects();
|
||||
if (rects.size() > 0) {
|
||||
// pass the dirty-rects on to the scene view
|
||||
_view.invalidateRects(rects);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// $Id: DirtyRectList.java,v 1.1 2001/08/22 02:14:57 mdb Exp $
|
||||
|
||||
package com.threerings.media.sprite;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The dirty rect list is used to maintain a list of dirty rectangles. It
|
||||
* differs from a plain old list only in that it provides a convenient
|
||||
* mechanism for appending a dirty rectangle to the list if and only if
|
||||
* that rectangle is not already on the list.
|
||||
*/
|
||||
public class DirtyRectList extends ArrayList
|
||||
{
|
||||
/**
|
||||
* Appends the specified dirty rectangle to the list only if a
|
||||
* rectangle of the same size is not already in the list.
|
||||
*
|
||||
* @return true if the rectangle were appended, false if she weren't.
|
||||
* Har!
|
||||
*/
|
||||
public boolean appendDirtyRect (Rectangle rect)
|
||||
{
|
||||
if (contains(rect)) {
|
||||
return false;
|
||||
} else {
|
||||
add(rect);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: Sprite.java,v 1.15 2001/08/21 21:18:42 mdb Exp $
|
||||
// $Id: Sprite.java,v 1.16 2001/08/22 02:14:57 mdb Exp $
|
||||
|
||||
package com.threerings.media.sprite;
|
||||
|
||||
@@ -70,7 +70,7 @@ public class Sprite
|
||||
_y = y;
|
||||
// we need to update our draw position which is based on the size
|
||||
// of our current frame
|
||||
updateDrawPosition();
|
||||
updateRenderOrigin();
|
||||
// invalidate our new position
|
||||
invalidate();
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public class Sprite
|
||||
_x = x;
|
||||
_y = y;
|
||||
|
||||
updateDrawPosition();
|
||||
updateRenderOrigin();
|
||||
|
||||
// set default velocity
|
||||
_vel = new Point(1, 1);
|
||||
@@ -94,7 +94,6 @@ public class Sprite
|
||||
_numTicks = 0;
|
||||
|
||||
setFrames(frames);
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@@ -114,7 +113,7 @@ public class Sprite
|
||||
*/
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
gfx.drawImage(_frame, _drawx, _drawy, null);
|
||||
gfx.drawImage(_frame, _rbounds.x, _rbounds.y, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,6 +149,19 @@ public class Sprite
|
||||
return bounds.contains(_x, _y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the sprite's drawn rectangle intersects the given
|
||||
* polygon in pixel coordinates.
|
||||
*
|
||||
* @param bounds the bounding polygon.
|
||||
*
|
||||
* @return whether the sprite intersects polygon.
|
||||
*/
|
||||
public boolean intersects (Polygon bounds)
|
||||
{
|
||||
return bounds.intersects(_rbounds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of ticks to wait before switching to the next image
|
||||
* in the array of images used to display the sprite.
|
||||
@@ -168,11 +180,30 @@ public class Sprite
|
||||
*/
|
||||
public void setFrames (MultiFrameImage frames)
|
||||
{
|
||||
if (frames == null) return;
|
||||
if (frames == null) {
|
||||
Log.warning("Someone set up us the null frames! " +
|
||||
"[sprite=" + this + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
_frames = frames;
|
||||
_frame = _frames.getFrame(_frameIdx);
|
||||
updateDrawPosition();
|
||||
|
||||
// determine our drawing offsets and rendered rectangle size
|
||||
if (_frame == null) {
|
||||
_rxoff = 0;
|
||||
_ryoff = 0;
|
||||
_rbounds.width = 0;
|
||||
_rbounds.height = 0;
|
||||
|
||||
} else {
|
||||
_rbounds.width = _frame.getWidth(null);
|
||||
_rbounds.height = _frame.getHeight(null);
|
||||
_rxoff = -(_rbounds.width / 2);
|
||||
_ryoff = -_rbounds.height;
|
||||
}
|
||||
|
||||
updateRenderOrigin();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@@ -262,6 +293,15 @@ public class Sprite
|
||||
_movey = _y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bounds that will be drawn upon when this sprite is
|
||||
* rendered.
|
||||
*/
|
||||
public Rectangle getRenderedBounds ()
|
||||
{
|
||||
return _rbounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the sprite's display rectangle for later repainting.
|
||||
*/
|
||||
@@ -270,10 +310,7 @@ public class Sprite
|
||||
if (_frame == null) return;
|
||||
|
||||
if (_spritemgr != null) {
|
||||
Rectangle dirty = new Rectangle(
|
||||
_drawx, _drawy,
|
||||
_frame.getWidth(null), _frame.getHeight(null));
|
||||
_spritemgr.addDirtyRect(dirty);
|
||||
_spritemgr.addDirtyRect(getRenderedBounds());
|
||||
|
||||
} else {
|
||||
Log.warning("Was invalidated but have no sprite manager " +
|
||||
@@ -331,7 +368,7 @@ public class Sprite
|
||||
}
|
||||
|
||||
// update the draw coordinates to reflect our new position
|
||||
updateDrawPosition();
|
||||
updateRenderOrigin();
|
||||
|
||||
// dirty our rectangle in the new position
|
||||
invalidate();
|
||||
@@ -341,16 +378,13 @@ public class Sprite
|
||||
* Update the coordinates at which the sprite image is drawn to
|
||||
* reflect the sprite's current position.
|
||||
*/
|
||||
protected void updateDrawPosition ()
|
||||
protected void updateRenderOrigin ()
|
||||
{
|
||||
if (_frame == null) {
|
||||
_drawx = _x;
|
||||
_drawy = _y;
|
||||
|
||||
} else {
|
||||
_drawx = _x - (_frame.getWidth(null) / 2);
|
||||
_drawy = _y - _frame.getHeight(null);
|
||||
}
|
||||
// our render origin differs from our location. our location is
|
||||
// the center of the bottom edge of our rendered rectangle, but
|
||||
// our render origin is the upper left
|
||||
_rbounds.x = _x + _rxoff;
|
||||
_rbounds.y = _y + _ryoff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,8 +414,11 @@ public class Sprite
|
||||
/** The location of the sprite in pixel coordinates. */
|
||||
protected int _x, _y;
|
||||
|
||||
/** The coordinates at which the frame image is drawn. */
|
||||
protected int _drawx, _drawy;
|
||||
/** The offsets from our location to our rendered origin. */
|
||||
protected int _rxoff, _ryoff;
|
||||
|
||||
/** Our rendered bounds in pixel coordinates. */
|
||||
protected Rectangle _rbounds = new Rectangle();
|
||||
|
||||
/** The PathNode objects describing the path the sprite is following. */
|
||||
protected Iterator _path;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: SpriteManager.java,v 1.9 2001/08/21 19:40:30 mdb Exp $
|
||||
// $Id: SpriteManager.java,v 1.10 2001/08/22 02:14:57 mdb Exp $
|
||||
|
||||
package com.threerings.media.sprite;
|
||||
|
||||
@@ -19,7 +19,7 @@ public class SpriteManager
|
||||
public SpriteManager ()
|
||||
{
|
||||
_sprites = new ArrayList();
|
||||
_dirty = new ArrayList();
|
||||
_dirty = new DirtyRectList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,6 +32,35 @@ public class SpriteManager
|
||||
_dirty.add(rect);
|
||||
}
|
||||
|
||||
/**
|
||||
* When an animated view processes its dirty rectangles, it may
|
||||
* require an expansion of the dirty region which may in turn require
|
||||
* the invalidation of more sprites than were originally invalid. In
|
||||
* such cases, the animated view can call back to the sprite manager,
|
||||
* asking it to append the rectangles of the sprites that intersect a
|
||||
* particular region to the dirty rectangle list that it's processing.
|
||||
* A sprite's rectangle will only be appended if it's not already in
|
||||
* the list.
|
||||
*
|
||||
* @param rects the dirty rectangle list being processed by the
|
||||
* animated view.
|
||||
* @param bounds the bounds the intersection of which we have
|
||||
* interest.
|
||||
*/
|
||||
public void invalidateIntersectingSprites (
|
||||
DirtyRectList rects, Polygon bounds)
|
||||
{
|
||||
int size = _sprites.size();
|
||||
for (int ii = 0; ii < size; ii++) {
|
||||
Sprite sprite = (Sprite)_sprites.get(ii);
|
||||
if (sprite.intersects(bounds)) {
|
||||
if (rects.appendDirtyRect(sprite.getRenderedBounds())) {
|
||||
Log.info("Expanded for: " + sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a sprite to the set of sprites managed by this manager.
|
||||
*
|
||||
@@ -70,10 +99,10 @@ public class SpriteManager
|
||||
*
|
||||
* @return the list of dirty rects.
|
||||
*/
|
||||
public ArrayList getDirtyRects ()
|
||||
public DirtyRectList getDirtyRects ()
|
||||
{
|
||||
// create a copy of the dirty rectangles
|
||||
ArrayList dirty = (ArrayList)_dirty.clone();
|
||||
DirtyRectList dirty = (DirtyRectList)_dirty.clone();
|
||||
|
||||
// clear out the list
|
||||
_dirty.clear();
|
||||
@@ -83,8 +112,8 @@ public class SpriteManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the sprites residing within the given polygon to the
|
||||
* given graphics context.
|
||||
* Render the sprites residing within the given polygon to the given
|
||||
* graphics context.
|
||||
*
|
||||
* @param gfx the graphics context.
|
||||
* @param bounds the bounding polygon.
|
||||
@@ -136,5 +165,5 @@ public class SpriteManager
|
||||
protected ArrayList _sprites;
|
||||
|
||||
/** The dirty rectangles created by sprites. */
|
||||
protected ArrayList _dirty;
|
||||
protected DirtyRectList _dirty;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: IsoSceneView.java,v 1.51 2001/08/21 21:18:42 mdb Exp $
|
||||
// $Id: IsoSceneView.java,v 1.52 2001/08/22 02:14:57 mdb Exp $
|
||||
|
||||
package com.threerings.miso.scene;
|
||||
|
||||
@@ -46,6 +46,16 @@ public class IsoSceneView implements EditableSceneView
|
||||
// get the font used to render tile coordinates
|
||||
_font = new Font("Arial", Font.PLAIN, 7);
|
||||
|
||||
// create our polygon arrays and create polygons for each of the
|
||||
// tiles. we use these repeatedly, so we go ahead and make 'em all
|
||||
// up front
|
||||
_polys = new Polygon[MisoScene.TILE_WIDTH][MisoScene.TILE_HEIGHT];
|
||||
for (int xx = 0; xx < MisoScene.TILE_WIDTH; xx++) {
|
||||
for (int yy = 0; yy < MisoScene.TILE_HEIGHT; yy++) {
|
||||
_polys[xx][yy] = IsoUtil.getTilePolygon(_model, xx, yy);
|
||||
}
|
||||
}
|
||||
|
||||
// create the array used to mark dirty tiles
|
||||
_dirty = new boolean[MisoScene.TILE_WIDTH][MisoScene.TILE_HEIGHT];
|
||||
|
||||
@@ -81,7 +91,7 @@ public class IsoSceneView implements EditableSceneView
|
||||
renderSceneInvalid(gfx);
|
||||
|
||||
// draw frames of dirty tiles and rectangles
|
||||
//drawDirtyRegions(gfx);
|
||||
// drawDirtyRegions(gfx);
|
||||
|
||||
// clear out the dirty tiles and rectangles
|
||||
clearDirtyRegions();
|
||||
@@ -123,7 +133,7 @@ public class IsoSceneView implements EditableSceneView
|
||||
for (int xx = 0; xx < MisoScene.TILE_WIDTH; xx++) {
|
||||
for (int yy = 0; yy < MisoScene.TILE_HEIGHT; yy++) {
|
||||
if (_dirty[xx][yy]) {
|
||||
gfx.draw(IsoUtil.getTilePolygon(_model, xx, yy));
|
||||
gfx.draw(_polys[xx][yy]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,7 +163,7 @@ public class IsoSceneView implements EditableSceneView
|
||||
if (!_dirty[xx][yy]) continue;
|
||||
|
||||
// get the tile's screen position
|
||||
Polygon poly = IsoUtil.getTilePolygon(_model, xx, yy);
|
||||
Polygon poly = _polys[xx][yy];
|
||||
|
||||
// draw all layers at this tile position
|
||||
for (int kk = 0; kk < MisoScene.NUM_LAYERS; kk++) {
|
||||
@@ -224,8 +234,7 @@ public class IsoSceneView implements EditableSceneView
|
||||
|
||||
// draw all sprites residing in the current tile
|
||||
// TODO: simplify other tile positioning here to use poly
|
||||
_spritemgr.renderSprites(
|
||||
gfx, IsoUtil.getTilePolygon(_model, tx, ty));
|
||||
_spritemgr.renderSprites(gfx, _polys[tx][ty]);
|
||||
}
|
||||
|
||||
// draw tile coordinates in each tile
|
||||
@@ -296,7 +305,7 @@ public class IsoSceneView implements EditableSceneView
|
||||
gfx.setColor(Color.green);
|
||||
|
||||
// draw the tile outline
|
||||
gfx.draw(IsoUtil.getTilePolygon(_model, _htile.x, _htile.y));
|
||||
gfx.draw(_polys[_htile.x][_htile.y]);
|
||||
|
||||
// restore the original stroke
|
||||
gfx.setStroke(ostroke);
|
||||
@@ -409,14 +418,16 @@ public class IsoSceneView implements EditableSceneView
|
||||
*
|
||||
* @param rects the list of Rectangle objects.
|
||||
*/
|
||||
public void invalidateRects (List rects)
|
||||
public void invalidateRects (DirtyRectList rects)
|
||||
{
|
||||
int size = rects.size();
|
||||
for (int ii = 0; ii < size; ii++) {
|
||||
// we specifically need to allow the dirty rects list to grow
|
||||
// while we're iterating over it, so we're sure to call
|
||||
// rects.size() each time through the loop
|
||||
for (int ii = 0; ii < rects.size(); ii++) {
|
||||
Rectangle r = (Rectangle)rects.get(ii);
|
||||
|
||||
// dirty the tiles impacted by this rectangle
|
||||
invalidateScreenRect(r.x, r.y, r.width, r.height);
|
||||
invalidateScreenRect(rects, r.x, r.y, r.width, r.height);
|
||||
|
||||
// save the rectangle for potential display later
|
||||
_dirtyRects.add(r);
|
||||
@@ -427,12 +438,16 @@ public class IsoSceneView implements EditableSceneView
|
||||
* Invalidate the specified rectangle in screen pixel coordinates
|
||||
* in the view.
|
||||
*
|
||||
* @param rects the dirty rectangle list that we're processing because
|
||||
* we may have to add dirty rectangles to it when invalidating this
|
||||
* particular rect.
|
||||
* @param x the rectangle x-position.
|
||||
* @param y the rectangle y-position.
|
||||
* @param width the rectangle width.
|
||||
* @param height the rectangle height.
|
||||
*/
|
||||
public void invalidateScreenRect (int x, int y, int width, int height)
|
||||
public void invalidateScreenRect (
|
||||
DirtyRectList rects, int x, int y, int width, int height)
|
||||
{
|
||||
// note that corner tiles may be included unnecessarily, but
|
||||
// checking to determine whether they're actually needed
|
||||
@@ -460,7 +475,7 @@ public class IsoSceneView implements EditableSceneView
|
||||
if (y < (screenY + _model.tilehhei)) {
|
||||
ty--;
|
||||
for (int ii = 0; ii < numh; ii++) {
|
||||
addDirtyTile(tx++, ty--);
|
||||
addDirtyTile(rects, tx++, ty--);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,7 +514,7 @@ public class IsoSceneView implements EditableSceneView
|
||||
|
||||
// add all tiles in the row to the dirty set
|
||||
for (int jj = 0; jj < length; jj++) {
|
||||
addDirtyTile(tx++, ty--);
|
||||
addDirtyTile(rects, tx++, ty--);
|
||||
}
|
||||
|
||||
// step along the x- or y-axis appropriately
|
||||
@@ -517,7 +532,7 @@ public class IsoSceneView implements EditableSceneView
|
||||
}
|
||||
}
|
||||
|
||||
protected void addDirtyTile (int x, int y)
|
||||
protected void addDirtyTile (DirtyRectList rects, int x, int y)
|
||||
{
|
||||
// constrain x-coordinate to a valid range
|
||||
if (x < 0) {
|
||||
@@ -539,6 +554,10 @@ public class IsoSceneView implements EditableSceneView
|
||||
// mark the tile dirty
|
||||
_numDirty++;
|
||||
_dirty[x][y] = true;
|
||||
|
||||
// and add the dirty rectangles of any sprites that we've just
|
||||
// inadvertently touched by dirtying this tile
|
||||
_spritemgr.invalidateIntersectingSprites(rects, _polys[x][y]);
|
||||
}
|
||||
|
||||
public void setScene (MisoScene scene)
|
||||
@@ -697,6 +716,9 @@ public class IsoSceneView implements EditableSceneView
|
||||
/** The font to draw tile coordinates. */
|
||||
protected Font _font;
|
||||
|
||||
/** Polygon instances for all of our tiles. */
|
||||
protected Polygon _polys[][];
|
||||
|
||||
/** The dirty tiles that need to be re-painted. */
|
||||
protected boolean _dirty[][];
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
//
|
||||
// $Id: SceneView.java,v 1.14 2001/08/21 20:02:39 mdb Exp $
|
||||
// $Id: SceneView.java,v 1.15 2001/08/22 02:14:57 mdb Exp $
|
||||
|
||||
package com.threerings.miso.scene;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.util.List;
|
||||
|
||||
import com.threerings.media.sprite.DirtyRectList;
|
||||
import com.threerings.media.sprite.Path;
|
||||
import com.threerings.media.tile.Tile;
|
||||
|
||||
@@ -22,7 +23,7 @@ public interface SceneView
|
||||
*
|
||||
* @param rects the list of {@link java.awt.Rectangle} objects.
|
||||
*/
|
||||
public void invalidateRects (List rects);
|
||||
public void invalidateRects (DirtyRectList rects);
|
||||
|
||||
/**
|
||||
* Render the scene to the given graphics context.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: SceneViewPanel.java,v 1.10 2001/08/21 21:18:21 mdb Exp $
|
||||
// $Id: SceneViewPanel.java,v 1.11 2001/08/22 02:14:57 mdb Exp $
|
||||
|
||||
package com.threerings.miso.scene;
|
||||
|
||||
@@ -7,8 +7,7 @@ import java.awt.*;
|
||||
import java.util.List;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.threerings.media.sprite.AnimatedView;
|
||||
import com.threerings.media.sprite.SpriteManager;
|
||||
import com.threerings.media.sprite.*;
|
||||
import com.threerings.media.tile.TileManager;
|
||||
|
||||
/**
|
||||
@@ -68,7 +67,7 @@ public class SceneViewPanel
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void invalidateRects (List rects)
|
||||
public void invalidateRects (DirtyRectList rects)
|
||||
{
|
||||
// pass the invalid rects on to our scene view
|
||||
_view.invalidateRects(rects);
|
||||
@@ -98,6 +97,9 @@ public class SceneViewPanel
|
||||
public void paintComponent (Graphics g)
|
||||
{
|
||||
render(g);
|
||||
|
||||
// Rectangle bounds = getBounds();
|
||||
// g.drawRect(bounds.x, bounds.y, bounds.width-1, bounds.height-1);
|
||||
}
|
||||
|
||||
protected void createOffscreen ()
|
||||
@@ -113,7 +115,9 @@ public class SceneViewPanel
|
||||
*/
|
||||
public Dimension getPreferredSize ()
|
||||
{
|
||||
return (_smodel == null) ? super.getPreferredSize() : _smodel.bounds;
|
||||
Dimension psize = (_smodel == null) ?
|
||||
super.getPreferredSize() : _smodel.bounds;
|
||||
return psize;
|
||||
}
|
||||
|
||||
/** Tile width in pixels. */
|
||||
|
||||
Reference in New Issue
Block a user