diff --git a/src/java/com/threerings/media/sprite/DirtyItemList.java b/src/java/com/threerings/media/sprite/DirtyItemList.java new file mode 100644 index 000000000..ccd7ed4ee --- /dev/null +++ b/src/java/com/threerings/media/sprite/DirtyItemList.java @@ -0,0 +1,90 @@ +// +// $Id: DirtyItemList.java,v 1.1 2001/10/13 01:08:59 shaper Exp $ + +package com.threerings.media.sprite; + +import java.util.*; + +import com.threerings.media.sprite.Sprite; +import com.threerings.media.tile.ObjectTile; + +import com.threerings.media.Log; + +/** + * The dirty item list keeps track of dirty sprites and object tiles + * in a scene. Since scenes can only ever have one of either item at + * any given coordinate, dirty items are stored and checked for + * equality based solely on their coordinate, and each coordinate can + * exist in the list only once. + */ +public class DirtyItemList extends ArrayList +{ + /** + * Append the dirty item at the given coordinates to the dirty + * item list. + */ + public boolean appendDirtyItem (Object item, int x, int y) + { + // only allow appending sprites and object tiles + if (!(item instanceof Sprite) && !(item instanceof ObjectTile)) { + return false; + } + + // only add the item if there are no existing items + if (!contains(x, y)) { + add(new DirtyItem(item, x, y)); + return true; + } + + return false; + } + + /** + * Sort the items in the list using the given comparator. + */ + public void sort (Comparator comp) + { + Object[] items = new Object[size()]; + toArray(items); + Arrays.sort(items, comp); + clear(); + for (int ii = 0; ii < items.length; ii++) { + add(items[ii]); + } + } + + /** + * Returns whether the list contains a dirty item at the given + * coordinates. + */ + protected boolean contains (int x, int y) + { + int size = size(); + for (int ii = 0; ii < size; ii++) { + Object o = get(ii); + if (o instanceof DirtyItem) { + DirtyItem di = (DirtyItem)o; + return (x == di.x && y == di.y); + } + } + + return false; + } + + /** + * A wrapper class to hold the items inserted in the dirty list + * along with their coordinates in the scene. + */ + public class DirtyItem + { + public Object obj; + public int x, y; + + public DirtyItem (Object obj, int x, int y) + { + this.obj = obj; + this.x = x; + this.y = y; + } + } +} diff --git a/src/java/com/threerings/media/sprite/DirtyRectList.java b/src/java/com/threerings/media/sprite/DirtyRectList.java index 7a4ae1fd2..026aa5f75 100644 --- a/src/java/com/threerings/media/sprite/DirtyRectList.java +++ b/src/java/com/threerings/media/sprite/DirtyRectList.java @@ -1,5 +1,5 @@ // -// $Id: DirtyRectList.java,v 1.1 2001/08/22 02:14:57 mdb Exp $ +// $Id: DirtyRectList.java,v 1.2 2001/10/13 01:08:59 shaper Exp $ package com.threerings.media.sprite; @@ -16,7 +16,8 @@ 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. + * rectangle of the same position and size is not already in the + * list. * * @return true if the rectangle were appended, false if she weren't. * Har! diff --git a/src/java/com/threerings/media/sprite/Sprite.java b/src/java/com/threerings/media/sprite/Sprite.java index 1fc613f7e..7ac26c9b7 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.24 2001/10/12 00:36:03 shaper Exp $ +// $Id: Sprite.java,v 1.25 2001/10/13 01:08:59 shaper Exp $ package com.threerings.media.sprite; @@ -209,29 +209,21 @@ public class Sprite } /** - * Returns whether the sprite is inside the given polygon in + * Returns whether the sprite is inside the given shape in * pixel coordinates. - * - * @param bounds the bounding polygon. - * - * @return whether the sprite is inside the polygon. */ - public boolean inside (Polygon bounds) + public boolean inside (Shape shape) { - return bounds.contains(_x, _y); + return shape.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. + * shape in pixel coordinates. */ - public boolean intersects (Polygon bounds) + public boolean intersects (Shape shape) { - return bounds.intersects(_rbounds); + return shape.intersects(_rbounds); } /** diff --git a/src/java/com/threerings/media/sprite/SpriteManager.java b/src/java/com/threerings/media/sprite/SpriteManager.java index fd9de3813..105ee0d26 100644 --- a/src/java/com/threerings/media/sprite/SpriteManager.java +++ b/src/java/com/threerings/media/sprite/SpriteManager.java @@ -1,10 +1,11 @@ // -// $Id: SpriteManager.java,v 1.14 2001/09/13 19:36:20 mdb Exp $ +// $Id: SpriteManager.java,v 1.15 2001/10/13 01:08:59 shaper Exp $ package com.threerings.media.sprite; import java.awt.*; import java.util.*; +import java.util.List; import com.samskivert.util.Tuple; import com.threerings.media.Log; @@ -36,29 +37,23 @@ public class SpriteManager /** * 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. + * 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 sprites that intersect + * a particular region to the given list. * - * @param rects the dirty rectangle list being processed by the - * animated view. + * @param list the list to fill with any intersecting sprites. * @param bounds the bounds the intersection of which we have * interest. */ - public void invalidateIntersectingSprites ( - DirtyRectList rects, Polygon bounds) + public void getIntersectingSprites (List list, Shape shape) { 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); - } + if (sprite.intersects(shape)) { + list.add(sprite); } } } diff --git a/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java b/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java index 661a4542d..e6f51dedf 100644 --- a/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java +++ b/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java @@ -1,5 +1,5 @@ // -// $Id: DisplayMisoSceneImpl.java,v 1.39 2001/10/11 00:41:27 shaper Exp $ +// $Id: DisplayMisoSceneImpl.java,v 1.40 2001/10/13 01:08:59 shaper Exp $ package com.threerings.miso.scene; @@ -15,8 +15,8 @@ import com.threerings.whirled.data.Scene; import com.threerings.miso.Log; import com.threerings.miso.scene.util.ClusterUtil; - import com.threerings.miso.tile.MisoTile; +import com.threerings.miso.tile.ShadowTile; /** * A scene object represents the data model corresponding to a single @@ -54,6 +54,14 @@ public class MisoSceneImpl implements EditableMisoScene * initialized to contain tiles of the specified default tileset and * tile id. * + * Note: Be sure to call {@link #prepareAllObjectTiles} + * before the scene is first used so that the base layer will be + * properly populated with shadow tiles in the footprint of all + * object tiles. Similarly, any addition of tiles to or removal + * of tiles from the object layer of the scene should be followed + * by a call to {@link #prepareObjectTile} or {@link + * #unprepareObjectTile}, respectively. + * * @param model the iso scene view model. * @param deftile the default tile. */ @@ -62,11 +70,15 @@ public class MisoSceneImpl implements EditableMisoScene _model = model; _deftile = deftile; + // create the individual tile layer arrays baseTiles = new MisoTile[_model.scenewid][_model.scenehei]; fringeTiles = new Tile[_model.scenewid][_model.scenehei]; objectTiles = new ObjectTile[_model.scenewid][_model.scenehei]; + + // create the conjoined array for purely utilitarian purposes tiles = new Tile[][][] { baseTiles, fringeTiles, objectTiles }; + // initialize the always-fully-populated base layer initBaseTiles(); } @@ -76,6 +88,12 @@ public class MisoSceneImpl implements EditableMisoScene return name; } + // documentation inherited + public void setDefaultTile (MisoTile tile) + { + _deftile = tile; + } + // documentation inherited public int getId () { @@ -94,11 +112,13 @@ public class MisoSceneImpl implements EditableMisoScene return null; } + // documentation inherited public Tile[][][] getTiles () { return tiles; } + // documentation inherited public Tile[][] getTiles (int lnum) { return tiles[lnum]; @@ -267,6 +287,71 @@ public class MisoSceneImpl implements EditableMisoScene } } + /** + * Place shadow tiles in the footprint of all object tiles in the + * scene. This method should be called once the scene tiles are + * fully populated, but before the scene is used in any other + * meaningful capacity. + */ + public void prepareAllObjectTiles () + { + for (int xx = 0; xx < _model.scenewid; xx++) { + for (int yy = 0; yy < _model.scenehei; yy++) { + if (objectTiles[xx][yy] != null) { + prepareObjectTile(xx, yy); + } + } + } + } + + /** + * Place shadow tiles in the footprint of the object tile at the + * given coordinates in the scene. This method should be called + * when an object tile is added to the scene. + * + * @param x the tile x-coordinate. + * @param y the tile y-coordinate. + */ + public void prepareObjectTile (int x, int y) + { + setObjectTileFootprint(x, y, ShadowTile.TILE); + } + + /** + * Remove shadow tiles from the footprint of the object tile at + * the given coordinates in the scene. This method should be + * called when an object tile is removed from the scene. + * + * @param x the tile x-coordinate. + * @param y the tile y-coordinate. + */ + public void unprepareObjectTile (int x, int y) + { + setObjectTileFootprint(x, y, _deftile); + } + + /** + * Place the given tile in the footprint of the object tile at the + * given coordinates in the scene. + * + * @param x the tile x-coordinate. + * @param y the tile y-coordinate. + * @param stamp the tile to place in the object footprint. + */ + protected void setObjectTileFootprint (int x, int y, MisoTile stamp) + { + ObjectTile tile = objectTiles[x][y]; + + int endx = Math.max(0, (x - tile.baseWidth + 1)); + int endy = Math.max(0, (y - tile.baseHeight + 1)); + + for (int xx = x; xx >= endx; xx--) { + for (int yy = y; yy >= endy; yy--) { + baseTiles[xx][yy] = stamp; + } + } + } + /** The default scene name. */ protected static final String DEF_SCENE_NAME = "Untitled Scene"; diff --git a/src/java/com/threerings/miso/client/IsoSceneView.java b/src/java/com/threerings/miso/client/IsoSceneView.java index 635c587b2..3270d0b65 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.59 2001/10/12 00:42:08 shaper Exp $ +// $Id: IsoSceneView.java,v 1.60 2001/10/13 01:08:59 shaper Exp $ package com.threerings.miso.scene; @@ -8,7 +8,7 @@ import java.awt.geom.*; import java.awt.image.*; import java.util.List; -import java.util.ArrayList; +import java.util.*; import com.samskivert.util.HashIntMap; @@ -17,9 +17,7 @@ import com.threerings.media.tile.Tile; import com.threerings.media.tile.ObjectTile; import com.threerings.miso.Log; -import com.threerings.miso.scene.util.AStarPathUtil; -import com.threerings.miso.scene.util.IsoUtil; -import com.threerings.miso.scene.util.MisoSceneUtil; +import com.threerings.miso.scene.util.*; /** * The IsoSceneView provides an isometric view of a @@ -39,9 +37,6 @@ public class IsoSceneView implements SceneView setModel(model); - // 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 @@ -52,15 +47,9 @@ public class IsoSceneView implements SceneView } } - // create the hashtable used to store object bounds polygons - _objpolys = new HashIntMap(); - // create the array used to mark dirty tiles _dirty = new boolean[model.scenewid][model.tilehei]; - // create the list of dirty rectangles - _dirtyRects = new ArrayList(); - clearDirtyRegions(); } @@ -77,6 +66,7 @@ public class IsoSceneView implements SceneView public void paint (Graphics g) { if (_scene == null) { + Log.info("Scene view painted with null scene."); return; } @@ -88,20 +78,19 @@ public class IsoSceneView implements SceneView gfx.setClip(0, 0, _model.bounds.width, _model.bounds.height); if (_numDirty == 0) { - // render the full scene - renderScene(gfx); - - } else { - // render only dirty tiles - renderSceneInvalid(gfx); - - // draw frames of dirty tiles and rectangles - // drawDirtyRegions(gfx); - - // clear out the dirty tiles and rectangles - clearDirtyRegions(); + // invalidate the entire screen + invalidate(); } + // render the scene to the graphics context + renderScene(gfx); + + // draw frames of dirty tiles and rectangles + // drawDirtyRegions(gfx); + + // clear out the dirty tiles and rectangles + clearDirtyRegions(); + // draw sprite paths if (_model.showPaths) { _spritemgr.renderSpritePaths(gfx); @@ -127,9 +116,21 @@ public class IsoSceneView implements SceneView { } + /** + * Invalidate the entire visible scene view. + */ + protected void invalidate () + { + DirtyRectList rects = new DirtyRectList(); + rects.add(new Rectangle( + 0, 0, _model.bounds.width,_model.bounds.height)); + invalidateRects(rects); + } + protected void clearDirtyRegions () { _dirtyRects.clear(); + _dirtyItems.clear(); _numDirty = 0; for (int xx = 0; xx < _model.scenewid; xx++) { @@ -165,11 +166,22 @@ public class IsoSceneView implements SceneView * * @param gfx the graphics context. */ - protected void renderSceneInvalid (Graphics2D gfx) + protected void renderScene (Graphics2D gfx) + { + renderTiles(gfx); + renderDirtyItems(gfx); + } + + /** + * Renders the base and fringe layer tiles to the given graphics + * context. + */ + protected void renderTiles (Graphics2D gfx) { int numDrawn = 0; Tile[][][] tiles = _scene.getTiles(); + // render the base and fringe layers for (int yy = 0; yy < _model.scenehei; yy++) { for (int xx = 0; xx < _model.scenewid; xx++) { @@ -181,8 +193,9 @@ public class IsoSceneView implements SceneView // get the tile's screen position Polygon poly = _polys[xx][yy]; - // draw all layers at this tile position - for (int kk = 0; kk < MisoScene.NUM_LAYERS; kk++) { + // draw both layers at this tile position + for (int kk = MisoScene.LAYER_BASE; + kk < MisoScene.LAYER_FRINGE; kk++) { // get the tile at these coordinates and layer Tile tile = tiles[kk][xx][yy]; @@ -190,17 +203,10 @@ public class IsoSceneView implements SceneView continue; } - // offset the image y-position by the tile-specific height - int ypos = poly.ypoints[0] - _model.tilehhei - - (tile.height - _model.tilehei); - // draw the tile image renderTile(gfx, tile, xx, yy, poly); } - // draw all sprites residing in the current tile - _spritemgr.renderSprites(gfx, poly); - // paint the tile coordinate if desired if (_model.showCoords) { paintCoords(gfx, xx, yy, poly.xpoints[0], @@ -216,78 +222,33 @@ public class IsoSceneView implements SceneView } /** - * Render the scene to the given graphics context. - * - * @param gfx the graphics context. + * Renders the dirty sprites and objects in the scene to the given + * graphics context. */ - protected void renderScene (Graphics2D gfx) + protected void renderDirtyItems (Graphics2D gfx) { - Tile[][][] tiles = _scene.getTiles(); - int mx = 1; - int my = 0; + // sort the dirty sprites and objects visually back-to-front + _dirtyItems.sort(IsoUtil.DIRTY_COMP); - int screenY = _model.origin.y; + // render dirty sprites and objects + int size = _dirtyItems.size(); + for (int ii = 0; ii < size; ii++) { + DirtyItemList.DirtyItem di = + (DirtyItemList.DirtyItem)_dirtyItems.get(ii); - for (int ii = 0; ii < _model.tilerows; ii++) { - // determine starting tile coordinates - int tx = (ii < _model.scenehei) ? 0 : mx++; - int ty = my; + if (di.obj instanceof Sprite) { + ((Sprite)di.obj).paint(gfx); - // determine number of tiles in this row - int length = (ty - tx) + 1; - - // determine starting screen x-position - int screenX = _model.origin.x - ((length) * _model.tilehwid); - - for (int jj = 0; jj < length; jj++) { - - for (int kk = 0; kk < MisoScene.NUM_LAYERS; kk++) { - // grab the tile we're rendering - Tile tile = tiles[kk][tx][ty]; - if (tile == null) { - continue; - } - - Polygon poly = _polys[tx][ty]; - - // determine screen y-position, accounting for - // tile image height - int ypos = screenY - (tile.height - _model.tilehei); - - // draw the tile image at the appropriate screen position - renderTile(gfx, tile, tx, ty, poly); - - // draw all sprites residing in the current tile - // TODO: simplify other tile positioning here to use poly - _spritemgr.renderSprites(gfx, poly); - } - - // draw tile coordinates in each tile - if (_model.showCoords) { - paintCoords(gfx, tx, ty, screenX, screenY); - } - - // each tile is one tile-width to the right of the previous - screenX += _model.tilewid; - - // advance tile x and decrement tile y as we move to - // the right drawing the row - tx++; - ty--; - } - - // each row is a half-tile-height away from the previous row - screenY += _model.tilehhei; - - // advance starting y-axis coordinate unless we've hit bottom - if ((++my) > _model.scenehei - 1) { - my = _model.scenehei - 1; + } else { + Polygon poly = (Polygon) + _objpolys.get(getCoordinateKey(di.x, di.y)); + ((ObjectTile)di.obj).paint(gfx, poly); } - } + } } /** - * Render the given tile in the scene to the given graphics + * Renders the given tile in the scene to the given graphics * context. */ protected void renderTile ( @@ -301,8 +262,8 @@ public class IsoSceneView implements SceneView } /** - * Pre-processes all object tiles in the scene to create shadow - * tiles and bounding polygons. + * Pre-processes all object tiles in the scene to create bounding + * polygons. */ protected void prepareAllObjectTiles () { @@ -320,17 +281,14 @@ public class IsoSceneView implements SceneView } /** - * Pre-processes a single object tile. Creates shadow tiles in - * its footprint making the object fully impassable, and creates - * the bounding polygon for the object which is used when - * invalidating dirty rectangles or tiles, and when rendering the - * object to a graphics context. This method should be called - * when an object tile is added to a scene. + * Pre-processes a single object tile. Creates the bounding + * polygon for the object which is used when invalidating dirty + * rectangles or tiles, and when rendering the object to a + * graphics context. This method should be called when an object + * tile is added to a scene. */ protected void prepareObjectTile (ObjectTile tile, int x, int y) { - // TODO: create shadow tiles in the footprint of this object - // create the bounding polygon for this object int key = getCoordinateKey(x, y); Polygon bounds = IsoUtil.getObjectBounds(_model, _polys[x][y], tile); @@ -454,6 +412,9 @@ public class IsoSceneView implements SceneView // dirty the tiles impacted by this rectangle invalidateScreenRect(rects, r.x, r.y, r.width, r.height); + // dirty any sprites or objects impacted by this rectangle + invalidateItems(r); + // save the rectangle for potential display later _dirtyRects.add(r); } @@ -557,6 +518,11 @@ public class IsoSceneView implements SceneView } } + /** + * Marks the tile at the given coordinates dirty and adds dirty + * rectangles to the dirty rectangle list for any sprites + * currently occupying the tile. + */ protected void addDirtyTile (DirtyRectList rects, int x, int y) { // constrain x-coordinate to a valid range @@ -584,7 +550,67 @@ public class IsoSceneView implements SceneView // and add the dirty rectangles of any sprites that we've just // inadvertently touched by dirtying this tile - _spritemgr.invalidateIntersectingSprites(rects, _polys[x][y]); + invalidateIntersectingSprites(rects, _polys[x][y]); + } + + /** + * Adds any sprites or objects in the scene whose bounds overlap + * with the given dirty rectangle to the dirty item list for later + * re-rendering. + */ + protected void invalidateItems (Rectangle r) + { + // add any sprites impacted by the dirty rectangle + _dirtySprites.clear(); + _spritemgr.getIntersectingSprites(_dirtySprites, r); + + int size = _dirtySprites.size(); + for (int ii = 0; ii < size; ii++) { + Sprite sprite = (Sprite)_dirtySprites.get(ii); + Point tpos = new Point(); + IsoUtil.screenToTile(_model, sprite.getX(), sprite.getY(), tpos); + + if (_dirtyItems.appendDirtyItem(sprite, tpos.x, tpos.y)) { + // Log.info("Dirtied item: " + sprite); + } + } + + // add any objects impacted by the dirty rectangle + ObjectTile tiles[][] = _scene.getObjectLayer(); + Iterator iter = _objpolys.keys(); + while (iter.hasNext()) { + // get the object's coordinates and bounding polygon + int coord = ((Integer)iter.next()).intValue(); + Polygon poly = (Polygon)_objpolys.get(coord); + + if (poly.intersects(r)) { + int tx = coord >> 16, ty = coord & 0x0000FFFF; + if (_dirtyItems.appendDirtyItem(tiles[tx][ty], tx, ty)) { + // Log.info("Dirtied item: Object(" + tx + ", " + + // ty + ")"); + } + } + } + } + + /** + * Adds dirty rectangles to the dirty rectangle list for any + * sprites in the scene whose bounds overlap with the given + * polygon. + */ + protected void invalidateIntersectingSprites ( + DirtyRectList rects, Polygon bounds) + { + _dirtySprites.clear(); + _spritemgr.getIntersectingSprites(_dirtySprites, bounds); + + int size = _dirtySprites.size(); + for (int ii = 0; ii < size; ii++) { + Sprite sprite = (Sprite)_dirtySprites.get(ii); + if (rects.appendDirtyRect(sprite.getRenderedBounds())) { + Log.info("Expanded for: " + sprite); + } + } } public void setModel (IsoSceneViewModel model) @@ -674,13 +700,13 @@ public class IsoSceneView implements SceneView } /** The font to draw tile coordinates. */ - protected Font _font; + protected Font _font = new Font("Arial", Font.PLAIN, 7); /** Polygon instances for all of our tiles. */ protected Polygon _polys[][]; /** Bounding polygons for all of the object tiles. */ - protected HashIntMap _objpolys; + protected HashIntMap _objpolys = new HashIntMap(); /** The dirty tiles that need to be re-painted. */ protected boolean _dirty[][]; @@ -689,7 +715,13 @@ public class IsoSceneView implements SceneView protected int _numDirty; /** The dirty rectangles that need to be re-painted. */ - protected ArrayList _dirtyRects; + protected ArrayList _dirtyRects = new ArrayList(); + + /** The dirty sprites and objects that need to be re-painted. */ + protected DirtyItemList _dirtyItems = new DirtyItemList(); + + /** The working sprites list used when calculating dirty regions. */ + protected ArrayList _dirtySprites = new ArrayList(); /** The scene view model data. */ protected IsoSceneViewModel _model; diff --git a/src/java/com/threerings/miso/client/util/IsoUtil.java b/src/java/com/threerings/miso/client/util/IsoUtil.java index aae0be448..08cf213b4 100644 --- a/src/java/com/threerings/miso/client/util/IsoUtil.java +++ b/src/java/com/threerings/miso/client/util/IsoUtil.java @@ -1,11 +1,13 @@ // -// $Id: IsoUtil.java,v 1.7 2001/10/12 00:42:08 shaper Exp $ +// $Id: IsoUtil.java,v 1.8 2001/10/13 01:08:59 shaper Exp $ package com.threerings.miso.scene.util; import java.awt.*; +import java.util.Comparator; import com.threerings.media.sprite.Sprite; +import com.threerings.media.sprite.DirtyItemList; import com.threerings.media.tile.ObjectTile; import com.threerings.media.util.MathUtil; @@ -18,6 +20,20 @@ import com.threerings.miso.scene.*; */ public class IsoUtil { + /** The comparator used to sort dirty items in ascending render order. */ + public static final Comparator DIRTY_COMP = new DirtyItemComparator(); + + /** + * Returns a polygon bounding the given object tile display image, + * with the bottom of the polygon shaped to conform to the known + * object dimensions. + * + * @param model the scene view model. + * @param root the root tile at which the object is located. + * @param tile the object tile. + * + * @return the bounding polygon. + */ public static Polygon getObjectBounds ( IsoSceneViewModel model, Polygon root, ObjectTile tile) { @@ -55,7 +71,7 @@ public class IsoUtil return boundsPoly; } - /** + /** * Given two points in screen pixel coordinates, return the * compass direction that point B lies in from point A from an * isometric perspective. @@ -327,4 +343,29 @@ public class IsoUtil /** Multiplication factor to embed tile coords in full coords. */ protected static final int FULL_TILE_FACTOR = 100; + + /** + * A comparator class to facilitate sorting the dirty items in + * ascending x- and y-coordinate order suitable for rendering in + * the isometric view with proper visual results. + */ + protected static class DirtyItemComparator implements Comparator + { + public int compare (Object a, Object b) + { + DirtyItemList.DirtyItem da = (DirtyItemList.DirtyItem)a; + DirtyItemList.DirtyItem db = (DirtyItemList.DirtyItem)b; + + if (da.y <= db.y && da.x <= db.x) { + return -1; + } + + return 1; + } + + public boolean equals (Object obj) + { + return (obj == this); + } + } } diff --git a/src/java/com/threerings/miso/tile/ShadowTile.java b/src/java/com/threerings/miso/tile/ShadowTile.java new file mode 100644 index 000000000..c38959ce4 --- /dev/null +++ b/src/java/com/threerings/miso/tile/ShadowTile.java @@ -0,0 +1,41 @@ +// +// $Id: ShadowTile.java,v 1.1 2001/10/13 01:08:59 shaper Exp $ + +package com.threerings.miso.tile; + +import java.awt.Graphics2D; +import java.awt.Shape; + +/** + * The shadow tile extends miso tile to provide an always-impassable + * tile that has no display image. Shadow tiles are intended for + * placement in the footprint of {@link ObjectTile} objects. + */ +public class ShadowTile extends MisoTile +{ + /** Single instantiation of shadow tile for re-use in scenes. */ + public static ShadowTile TILE = new ShadowTile(); + + /** + * Constructs a shadow tile. + */ + public ShadowTile () + { + super(SHADOW_TSID, SHADOW_TID); + + // shadow tiles are always impassable + passable = false; + } + + // documentation inherited + public void paint (Graphics2D gfx, Shape dest) + { + // paint nothing as we're naught but a measly shadow of a tile + } + + /** The shadow tile set id. */ + protected static final int SHADOW_TSID = -1; + + /** The shadow tile id. */ + protected static final int SHADOW_TID = -1; +} diff --git a/src/java/com/threerings/miso/tools/EditableMisoScene.java b/src/java/com/threerings/miso/tools/EditableMisoScene.java index d77272b8d..e26c29ba1 100644 --- a/src/java/com/threerings/miso/tools/EditableMisoScene.java +++ b/src/java/com/threerings/miso/tools/EditableMisoScene.java @@ -1,8 +1,10 @@ // -// $Id: EditableMisoScene.java,v 1.2 2001/10/05 23:58:36 mdb Exp $ +// $Id: EditableMisoScene.java,v 1.3 2001/10/13 01:08:59 shaper Exp $ package com.threerings.miso.scene; +import com.threerings.miso.tile.MisoTile; + /** * The editable Miso scene interface provides the means for modifying a * Miso scene which is needed by things like the scene editor. This is @@ -23,6 +25,11 @@ public interface EditableMisoScene */ public void setName (String name); + /** + * Updates the scene's default tile. + */ + public void setDefaultTile (MisoTile tile); + /** * Set the default entrance portal for this scene. * diff --git a/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java b/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java index 65cc3b48a..0e524f35e 100644 --- a/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java +++ b/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java @@ -1,5 +1,5 @@ // -// $Id: XMLSceneParser.java,v 1.18 2001/10/11 00:41:27 shaper Exp $ +// $Id: XMLSceneParser.java,v 1.19 2001/10/13 01:08:59 shaper Exp $ package com.threerings.miso.scene.xml; @@ -311,6 +311,9 @@ public class XMLSceneParser extends DefaultHandler // read the XML input stream and construct the scene object XMLUtil.parse(this, bis); + // place shadow tiles for any objects in the scene + _info.scene.prepareAllObjectTiles(); + // return the final scene object return _info.scene;