From c7d26cea8ed78c73c6a1f798a53c642bf6ea8f53 Mon Sep 17 00:00:00 2001 From: Walter Korman Date: Mon, 22 Oct 2001 18:21:42 +0000 Subject: [PATCH] Fixed scene rendering issues and improved performance. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@517 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/cast/CharacterManager.java | 7 +- .../com/threerings/cast/CharacterSprite.java | 31 ++++- .../threerings/miso/client/IsoSceneView.java | 112 ++++++++++++------ .../miso/client/IsoSceneViewModel.java | 16 +-- .../com/threerings/miso/client/SceneView.java | 18 +-- .../miso/client/SceneViewPanel.java | 4 +- .../threerings/miso/client/util/IsoUtil.java | 9 +- .../miso/tools/xml/XMLSceneParser.java | 3 +- .../miso/tools/xml/XMLSceneWriter.java | 3 +- 9 files changed, 138 insertions(+), 65 deletions(-) diff --git a/src/java/com/threerings/cast/CharacterManager.java b/src/java/com/threerings/cast/CharacterManager.java index 03883fc1a..c45ed3741 100644 --- a/src/java/com/threerings/cast/CharacterManager.java +++ b/src/java/com/threerings/cast/CharacterManager.java @@ -1,8 +1,9 @@ // -// $Id: CharacterManager.java,v 1.1 2001/10/15 23:53:43 shaper Exp $ +// $Id: CharacterManager.java,v 1.2 2001/10/22 18:21:41 shaper Exp $ package com.threerings.miso.scene; +import java.awt.Point; import java.io.IOException; import com.samskivert.util.Config; @@ -59,6 +60,7 @@ public class CharacterManager AmbulatorySprite sprite = new AmbulatorySprite(0, 0, anims); sprite.setFrameRate(info.frameRate); + sprite.setOrigin(info.origin.x, info.origin.y); return sprite; } @@ -87,11 +89,12 @@ public class CharacterManager public int tsid; public int frameCount; public int frameRate; + public Point origin = new Point(); public String toString () { return "[tsid=" + tsid + ", frameCount=" + frameCount + - ", frameRate=" + frameRate + "]"; + ", frameRate=" + frameRate + ", origin=" + origin + "]"; } } } diff --git a/src/java/com/threerings/cast/CharacterSprite.java b/src/java/com/threerings/cast/CharacterSprite.java index 950948c9f..c21766967 100644 --- a/src/java/com/threerings/cast/CharacterSprite.java +++ b/src/java/com/threerings/cast/CharacterSprite.java @@ -1,5 +1,5 @@ // -// $Id: CharacterSprite.java,v 1.12 2001/10/15 23:53:43 shaper Exp $ +// $Id: CharacterSprite.java,v 1.13 2001/10/22 18:21:41 shaper Exp $ package com.threerings.miso.scene; @@ -45,6 +45,32 @@ public class AmbulatorySprite extends Sprite implements Traverser setFrames(_anims[_orient]); } + /** + * Sets the origin coordinates representing the "base" of the + * sprite, which in most cases corresponds to the center of the + * bottom of the sprite image. + */ + public void setOrigin (int x, int y) + { + _xorigin = x; + _yorigin = y; + + updateRenderOffset(); + updateRenderOrigin(); + } + + // documentation inherited + protected void updateRenderOffset () + { + super.updateRenderOffset(); + + if (_frame != null) { + // our location is based on the character origin coordinates + _rxoff = -_xorigin; + _ryoff = -_yorigin; + } + } + // documentation inherited public void cancelMove () { @@ -91,4 +117,7 @@ public class AmbulatorySprite extends Sprite implements Traverser /** The animation frames for the sprite facing each direction. */ protected MultiFrameImage[] _anims; + + /** The origin of the sprite. */ + protected int _xorigin, _yorigin; } diff --git a/src/java/com/threerings/miso/client/IsoSceneView.java b/src/java/com/threerings/miso/client/IsoSceneView.java index aff35b796..2053e8eec 100644 --- a/src/java/com/threerings/miso/client/IsoSceneView.java +++ b/src/java/com/threerings/miso/client/IsoSceneView.java @@ -1,5 +1,5 @@ // -// $Id: IsoSceneView.java,v 1.64 2001/10/19 23:26:31 shaper Exp $ +// $Id: IsoSceneView.java,v 1.65 2001/10/22 18:21:41 shaper Exp $ package com.threerings.miso.scene; @@ -78,10 +78,9 @@ public class IsoSceneView implements SceneView Graphics2D gfx = (Graphics2D)g; - // clip the drawing region to our desired bounds since we - // currently draw tiles willy-nilly in undesirable areas. + // clip everything to the overall scene view bounds Shape oldclip = gfx.getClip(); - gfx.setClip(0, 0, _model.bounds.width, _model.bounds.height); + gfx.setClip(_model.bounds); if (_numDirty == 0) { // invalidate the entire screen @@ -134,8 +133,7 @@ public class IsoSceneView implements SceneView protected void invalidate () { DirtyRectList rects = new DirtyRectList(); - rects.add(new Rectangle( - 0, 0, _model.bounds.width,_model.bounds.height)); + rects.add(_model.bounds); invalidateRects(rects); } @@ -172,12 +170,23 @@ public class IsoSceneView implements SceneView } // draw the dirty rectangles + Stroke ostroke = gfx.getStroke(); + gfx.setStroke(DIRTY_RECT_STROKE); gfx.setColor(Color.red); int size = _dirtyRects.size(); for (int ii = 0; ii < size; ii++) { Rectangle rect = (Rectangle)_dirtyRects.get(ii); gfx.draw(rect); } + gfx.setStroke(ostroke); + + // draw the dirty item rectangles + gfx.setColor(Color.yellow); + size = _dirtyItems.size(); + for (int ii = 0; ii < size; ii++) { + Rectangle rect = ((DirtyItem)_dirtyItems.get(ii)).dirtyRect; + gfx.draw(rect); + } } /** @@ -236,9 +245,36 @@ public class IsoSceneView implements SceneView // save original clipping region Shape clip = gfx.getClip(); - // render dirty sprites and objects + // merge all dirty rectangles for each item into a single + // rectangle before painting + Rectangle dirtyRect = new Rectangle(); + DirtyItem cur = null, last = null; for (int ii = 0; ii < size; ii++) { - items[ii].paint(gfx); + cur = items[ii]; + + if (last == null || + (cur.x != last.x || cur.y != last.y)) { + + if (last != null) { + // paint the item with its full dirty rectangle + // Log.info("Painting dirty item [item=" + last + "]."); + last.paint(gfx, dirtyRect); + } + + // update the current dirty item + last = cur; + dirtyRect.setBounds(cur.dirtyRect); + + } else { + // expand the item's dirty rectangle + dirtyRect.add(cur.dirtyRect); + } + } + + if (cur != null) { + // paint the final dirty item + cur.paint(gfx, dirtyRect); + // Log.info("Painting dirty item [item=" + cur + "]."); } // restore original clipping region @@ -317,10 +353,11 @@ public class IsoSceneView implements SceneView for (int yy = 0; yy < _model.scenehei; yy++) { for (int xx = 0; xx < _model.scenewid; xx++) { - if (_dirty[xx][yy]) { + // get the top-left screen coordinates of the tile + Rectangle bounds = _polys[xx][yy].getBounds(); - // get the top-left screen coordinates of the tile - Rectangle bounds = _polys[xx][yy].getBounds(); + // only draw coordinates if the tile is on-screen + if (bounds.intersects(_model.bounds)) { int sx = bounds.x, sy = bounds.y; // draw x-coordinate @@ -332,7 +369,6 @@ public class IsoSceneView implements SceneView str = "" + yy; xpos = sx + cx - (fm.stringWidth(str) / 2); gfx.drawString(str, xpos, sy + cy + fhei); - } } } @@ -405,10 +441,8 @@ public class IsoSceneView implements SceneView // documentation inherited public void invalidateRects (DirtyRectList rects) { - // 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++) { + int size = rects.size(); + for (int ii = 0; ii < size; ii++) { Rectangle r = (Rectangle)rects.get(ii); // dirty the tiles impacted by this rectangle @@ -423,14 +457,17 @@ public class IsoSceneView implements SceneView } /** - * Invalidate the specified rectangle in screen pixel coordinates - * in the view. + * Invalidates the given rectangle in screen pixel coordinates in + * the view. Returns a rectangle that bounds all tiles that were + * dirtied. * * @param rect the dirty rectangle. */ public Rectangle invalidateScreenRect (Rectangle r) { - Rectangle tileBounds = new Rectangle(); + // initialize the rectangle bounding all tiles dirtied by the + // invalidated rectangle + Rectangle tileBounds = new Rectangle(-1, -1, 0, 0); // note that corner tiles may be included unnecessarily, but // checking to determine whether they're actually needed @@ -524,22 +561,17 @@ public class IsoSceneView implements SceneView */ protected void addDirtyTile (Rectangle tileBounds, int x, int y) { - // constrain x-coordinate to a valid range - if (x < 0) { - x = 0; - } else if (x >= _model.scenewid) { - x = _model.scenewid - 1; - } - - // constrain y-coordinate to a valid range - if (y < 0) { - y = 0; - } else if (y >= _model.scenehei) { - y = _model.scenehei - 1; - } + if (!_model.isCoordinateValid(x, y)) { + return; + } // expand the tile bounds rectangle to include this tile - tileBounds.add(_polys[x][y].getBounds()); + Rectangle bounds = _polys[x][y].getBounds(); + if (tileBounds.x == -1) { + tileBounds.setBounds(bounds); + } else { + tileBounds.add(bounds); + } // do nothing if the tile's already dirty if (_dirty[x][y]) { @@ -603,10 +635,7 @@ public class IsoSceneView implements SceneView public Path getPath (AmbulatorySprite sprite, int x, int y) { // make sure the destination point is within our bounds - if (x < 0 || - x >= _model.bounds.width || - y < 0 || - y >= _model.bounds.height) { + if (!_model.bounds.contains(x, y)) { return null; } @@ -620,7 +649,11 @@ public class IsoSceneView implements SceneView int tbx = IsoUtil.fullToTile(fpos.x); int tby = IsoUtil.fullToTile(fpos.y); - // get a reasonable path from start to end + // Log.info("Seeking path [sx=" + stpos.x + ", sy=" + stpos.y + + // ", dx=" + tbx + ", dy=" + tby + " ,fdx=" + fpos.x + + // ", fdy=" + fpos.y + "]."); + + // get a reasonable path from start to end List tilepath = AStarPathUtil.getPath( _scene.getBaseLayer(), _model.scenewid, _model.scenehei, sprite, stpos.x, stpos.y, tbx, tby); @@ -680,6 +713,9 @@ public class IsoSceneView implements SceneView return path; } + /** The stroke used to draw dirty rectangles. */ + protected static final Stroke DIRTY_RECT_STROKE = new BasicStroke(2); + /** The font to draw tile coordinates. */ protected Font _font = new Font("Arial", Font.PLAIN, 7); diff --git a/src/java/com/threerings/miso/client/IsoSceneViewModel.java b/src/java/com/threerings/miso/client/IsoSceneViewModel.java index 24c9f4a57..342f6a856 100644 --- a/src/java/com/threerings/miso/client/IsoSceneViewModel.java +++ b/src/java/com/threerings/miso/client/IsoSceneViewModel.java @@ -1,9 +1,9 @@ // -// $Id: IsoSceneViewModel.java,v 1.15 2001/10/18 21:01:44 shaper Exp $ +// $Id: IsoSceneViewModel.java,v 1.16 2001/10/22 18:21:41 shaper Exp $ package com.threerings.miso.scene; -import java.awt.Dimension; +import java.awt.Rectangle; import java.awt.Point; import java.util.ArrayList; @@ -37,8 +37,8 @@ public class IsoSceneViewModel /** Scene dimensions in tile count. */ public int scenewid, scenehei; - /** The bounds dimensions for the view. */ - public Dimension bounds; + /** The bounds of the view in screen pixel coordinates. */ + public Rectangle bounds; /** The position in pixels at which tile (0, 0) is drawn. */ public Point origin; @@ -98,7 +98,7 @@ public class IsoSceneViewModel // set the desired scene view bounds int svwid = config.getValue(SCENE_VWIDTH_KEY, DEF_SCENE_VWIDTH); int svhei = config.getValue(SCENE_VHEIGHT_KEY, DEF_SCENE_VHEIGHT); - bounds = new Dimension(svwid * tilewid, svhei * tilehei); + bounds = new Rectangle(0, 0, svwid * tilewid, svhei * tilehei); // set the scene display origin int offy = config.getValue(SCENE_OFFSET_Y_KEY, DEF_OFFSET_Y); @@ -139,7 +139,7 @@ public class IsoSceneViewModel * Returns whether the given tile coordinate is a valid coordinate * within the scene. */ - public boolean isValidCoordinate (int x, int y) + public boolean isCoordinateValid (int x, int y) { return (x >= 0 && x < scenewid && y >= 0 && y < scenehei); @@ -149,11 +149,11 @@ public class IsoSceneViewModel * Returns whether the given full coordinate is a valid coordinate * within the scene. */ - public boolean isValidFullCoordinate (int x, int y) + public boolean isFullCoordinateValid (int x, int y) { int tx = IsoUtil.fullToTile(x), ty = IsoUtil.fullToTile(y); int fx = IsoUtil.fullToFine(x), fy = IsoUtil.fullToFine(y); - return (isValidCoordinate(tx, ty) && + return (isCoordinateValid(tx, ty) && fx >= 0 && fx < finegran && fy >= 0 && fy < finegran); } diff --git a/src/java/com/threerings/miso/client/SceneView.java b/src/java/com/threerings/miso/client/SceneView.java index d7dd05e47..f040e0a5d 100644 --- a/src/java/com/threerings/miso/client/SceneView.java +++ b/src/java/com/threerings/miso/client/SceneView.java @@ -1,5 +1,5 @@ // -// $Id: SceneView.java,v 1.16 2001/10/11 00:41:27 shaper Exp $ +// $Id: SceneView.java,v 1.17 2001/10/22 18:21:41 shaper Exp $ package com.threerings.miso.scene; @@ -17,37 +17,37 @@ import com.threerings.media.sprite.Path; public interface SceneView { /** - * Invalidate a list of rectangles in screen pixel coordinates in the - * scene view for later repainting. + * Invalidates a list of rectangles in screen pixel coordinates in + * the scene view for later repainting. * * @param rects the list of {@link java.awt.Rectangle} objects. */ public void invalidateRects (DirtyRectList rects); /** - * Render the scene to the given graphics context. + * Renders the scene to the given graphics context. * * @param g the graphics context. */ public void paint (Graphics g); /** - * Set the scene that we're rendering. + * Sets the scene that we're rendering. * * @param scene the scene to render in the view. */ public void setScene (MisoScene scene); /** - * Return a Path object detailing a valid path for the given - * sprite to take in the scene to get from its current position to - * the destination position. + * Returns a {@link Path} object detailing a valid path for the + * given sprite to take in the scene to get from its current + * position to the destination position. * * @param sprite the sprite to move. * @param x the destination x-position in pixel coordinates. * @param y the destination y-position in pixel coordinates. * - * @return the sprite's path or null if no valid path exists. + * @return the sprite's path, or null if no valid path exists. */ public Path getPath (AmbulatorySprite sprite, int x, int y); } diff --git a/src/java/com/threerings/miso/client/SceneViewPanel.java b/src/java/com/threerings/miso/client/SceneViewPanel.java index 5467940d9..77a8f2537 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.18 2001/10/19 23:26:31 shaper Exp $ +// $Id: SceneViewPanel.java,v 1.19 2001/10/22 18:21:41 shaper Exp $ package com.threerings.miso.scene; @@ -89,7 +89,7 @@ public class SceneViewPanel extends AnimatedPanel public Dimension getPreferredSize () { Dimension psize = (_scenemodel == null) ? - super.getPreferredSize() : _scenemodel.bounds; + super.getPreferredSize() : _scenemodel.bounds.getSize(); return psize; } diff --git a/src/java/com/threerings/miso/client/util/IsoUtil.java b/src/java/com/threerings/miso/client/util/IsoUtil.java index f1754ddbf..cb5ff64b7 100644 --- a/src/java/com/threerings/miso/client/util/IsoUtil.java +++ b/src/java/com/threerings/miso/client/util/IsoUtil.java @@ -1,5 +1,5 @@ // -// $Id: IsoUtil.java,v 1.11 2001/10/19 23:26:31 shaper Exp $ +// $Id: IsoUtil.java,v 1.12 2001/10/22 18:21:41 shaper Exp $ package com.threerings.miso.scene.util; @@ -419,6 +419,13 @@ public class IsoUtil return comp; } + // check whether right edge of b overlaps with left edge of a + comp = getRightOverlap(db, da); + if (comp != 0) { + // reverse ordering per reversed overlap check + return (comp == -1) ? 1 : -1; + } + // determine ordering based purely on coordinates if (da.x <= db.x && da.y <= db.y) { return -1; diff --git a/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java b/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java index 6c9400ab7..9a71e23f6 100644 --- a/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java +++ b/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java @@ -1,9 +1,8 @@ // -// $Id: XMLSceneParser.java,v 1.21 2001/10/17 22:21:22 shaper Exp $ +// $Id: XMLSceneParser.java,v 1.22 2001/10/22 18:21:41 shaper Exp $ package com.threerings.miso.scene.xml; -import java.awt.Point; import java.io.*; import java.util.ArrayList; diff --git a/src/java/com/threerings/miso/tools/xml/XMLSceneWriter.java b/src/java/com/threerings/miso/tools/xml/XMLSceneWriter.java index 7a17c245f..6a60ee14b 100644 --- a/src/java/com/threerings/miso/tools/xml/XMLSceneWriter.java +++ b/src/java/com/threerings/miso/tools/xml/XMLSceneWriter.java @@ -1,9 +1,8 @@ // -// $Id: XMLSceneWriter.java,v 1.16 2001/10/17 22:18:22 shaper Exp $ +// $Id: XMLSceneWriter.java,v 1.17 2001/10/22 18:21:42 shaper Exp $ package com.threerings.miso.scene.xml; -import java.awt.Point; import java.io.*; import java.util.List;