Fixed scene rendering issues and improved performance.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@517 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Walter Korman
2001-10-22 18:21:42 +00:00
parent 7bd5d86c34
commit c7d26cea8e
9 changed files with 138 additions and 65 deletions
@@ -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 + "]";
}
}
}
@@ -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;
}
@@ -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);
@@ -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);
}
@@ -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);
}
@@ -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;
}
@@ -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;
@@ -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;
@@ -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;