diff --git a/src/java/com/threerings/miso/client/DirtyItemList.java b/src/java/com/threerings/miso/client/DirtyItemList.java index 26dfc3529..068c8262b 100644 --- a/src/java/com/threerings/miso/client/DirtyItemList.java +++ b/src/java/com/threerings/miso/client/DirtyItemList.java @@ -1,5 +1,5 @@ // -// $Id: DirtyItemList.java,v 1.10 2002/02/06 23:14:56 mdb Exp $ +// $Id: DirtyItemList.java,v 1.11 2002/06/18 22:38:12 mdb Exp $ package com.threerings.miso.scene; @@ -8,18 +8,16 @@ import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Shape; -import java.util.Arrays; import java.util.ArrayList; import java.util.Comparator; -import com.samskivert.util.HashIntMap; +import com.samskivert.util.SortableArrayList; import com.samskivert.util.StringUtil; +import com.threerings.media.Log; 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. @@ -27,24 +25,37 @@ import com.threerings.media.Log; public class DirtyItemList { /** - * Appends the dirty sprite at the given coordinates to the dirty - * item list. + * Appends the dirty sprite at the given coordinates to the dirty item + * list. + * + * @param sprite the dirty sprite itself. + * @param tx the sprite's x tile position. + * @param ty the sprite's y tile position. */ - public void appendDirtySprite ( - MisoCharacterSprite sprite, int x, int y, Rectangle dirtyRect) + public void appendDirtySprite (MisoCharacterSprite sprite, int tx, int ty) { - _items.add(new DirtyItem(sprite, null, null, x, y, dirtyRect)); + DirtyItem item = getDirtyItem(); + item.init(sprite, null, null, tx, ty); + _items.add(item); } /** - * Appends the dirty object tile at the given coordinates to the - * dirty item list. + * Appends the dirty object tile at the given coordinates to the dirty + * item list. + * + * @param tile the object tile that is dirty. + * @param bounds the bounds of this object tile. + * @param footprint the footprint of the object tile if it should be + * rendered, null otherwise. + * @param tx the object tile's x tile position. + * @param ty the object tile's y tile position. */ public void appendDirtyObject ( - ObjectTile tile, Shape bounds, Shape footprint, - int x, int y, Rectangle dirtyRect) + ObjectTile tile, Rectangle bounds, Shape footprint, int tx, int ty) { - _items.add(new DirtyItem(tile, bounds, footprint, x, y, dirtyRect)); + DirtyItem item = getDirtyItem(); + item.init(tile, bounds, footprint, tx, ty); + _items.add(item); } /** @@ -59,7 +70,7 @@ public class DirtyItemList * Returns an array of the {@link DirtyItem} objects in the list * sorted in proper rendering order. */ - public DirtyItem[] sort () + public void sort () { int size = size(); @@ -67,41 +78,64 @@ public class DirtyItemList Log.info("Sorting dirty item list [size=" + size + "]."); } - // get items sorted by increasing origin x-coordinate - DirtyItem[] xitems = new DirtyItem[size]; - _items.toArray(xitems); - // if we've only got one item, bail out now - if (xitems.length < 2) { - return xitems; + // if we've only got one item, we need to do no sorting + if (size > 1) { + // get items sorted by increasing origin x-coordinate + _xitems.addAll(_items); + _xitems.sort(ORIGIN_X_COMP); + if (DEBUG_SORT) { + Log.info("Sorted by x-origin " + + "[items=" + toString(_xitems) + "]."); + } + + // get items sorted by increasing origin y-coordinate + _yitems.addAll(_items); + _yitems.sort(ORIGIN_Y_COMP); + if (DEBUG_SORT) { + Log.info("Sorted by y-origin " + + "[items=" + toString(_yitems) + "]."); + } + + // sort items into proper render order + _items.sort(_rcomp); + + // clear out our temporary arrays + _xitems.clear(); + _yitems.clear(); } - Arrays.sort(xitems, ORIGIN_X_COMP); if (DEBUG_SORT) { - Log.info("Sorted by x-origin " + - "[items=" + DirtyItemList.toString(xitems) + "]."); + Log.info("Sorted for render [items=" + toString(_items) + "]."); } + } - // get items sorted by increasing origin y-coordinate - DirtyItem[] yitems = new DirtyItem[size]; - _items.toArray(yitems); - Arrays.sort(yitems, ORIGIN_Y_COMP); - - if (DEBUG_SORT) { - Log.info("Sorted by y-origin " + - "[items=" + DirtyItemList.toString(yitems) + "]."); + /** + * Paints all the dirty items in this list using the supplied graphics + * context. The items are removed from the dirty list after being + * painted and the dirty list ends up empty. + */ + public void paintAndClear (Graphics2D gfx) + { + int icount = _items.size(); + for (int ii = 0; ii < icount; ii++) { + DirtyItem item = (DirtyItem)_items.get(ii); + item.paint(gfx); + item.clear(); + _freelist.add(item); } + _items.clear(); + } - // sort items into proper render order - DirtyItem[] ritems = new DirtyItem[size]; - _items.toArray(ritems); - Arrays.sort(ritems, new RenderComparator(xitems, yitems)); - - if (DEBUG_SORT) { - Log.info("Sorted for render " + - "[items=" + toString(ritems) + "]."); + /** + * Clears out any items that were in this list. + */ + public void clear () + { + for (int icount = _items.size(); icount > 0; icount--) { + DirtyItem item = (DirtyItem)_items.remove(0); + item.clear(); + _freelist.add(item); } - - return ritems; } /** @@ -113,11 +147,16 @@ public class DirtyItemList } /** - * Clears all items in the list. + * Obtains a new dirty item instance, reusing an old one if possible + * or creating a new one otherwise. */ - public void clear () + protected DirtyItem getDirtyItem () { - _items.clear(); + if (_freelist.size() > 0) { + return (DirtyItem)_freelist.remove(0); + } else { + return new DirtyItem(); + } } /** @@ -127,7 +166,12 @@ public class DirtyItemList */ protected static String toString (DirtyItem a, DirtyItem b) { - return toString(new DirtyItem[] { a, b }); + StringBuffer buf = new StringBuffer(); + buf.append("[(ox=").append(a.ox); + buf.append(", oy=").append(a.oy).append("), "); + buf.append("(ox=").append(b.ox); + buf.append(", oy=").append(b.oy).append(")"); + return buf.append("]").toString(); } /** @@ -135,14 +179,15 @@ public class DirtyItemList * items describing each by only its origin coordinates. Intended for * debugging purposes. */ - protected static String toString (DirtyItem[] items) + protected static String toString (SortableArrayList items) { StringBuffer buf = new StringBuffer(); buf.append("["); - for (int ii = 0; ii < items.length; ii++) { - buf.append("(ox=").append(items[ii].ox); - buf.append(", oy=").append(items[ii].oy).append(")"); - if (ii < (items.length - 1)) { + for (int ii = 0; ii < items.size(); ii++) { + DirtyItem item = (DirtyItem)items.get(ii); + buf.append("(ox=").append(item.ox); + buf.append(", oy=").append(item.oy).append(")"); + if (ii < (items.size() - 1)) { buf.append(", "); } } @@ -160,7 +205,7 @@ public class DirtyItemList public Object obj; /** The bounds of the dirty item if it's an object tile. */ - public Shape bounds; + public Rectangle bounds; /** The footprint of the dirty item if it's an object tile and * we're drawing footprints. */ @@ -175,25 +220,21 @@ public class DirtyItemList /** The rightmost tile coordinates. */ public int rx, ry; - /** The dirty rectangle. */ - public Rectangle dirtyRect; - /** - * Constructs a dirty item. + * Initializes a dirty item. */ - public DirtyItem (Object obj, Shape bounds, Shape footprint, - int x, int y, Rectangle dirtyRect) + public void init (Object obj, Rectangle bounds, Shape footprint, + int x, int y) { this.obj = obj; this.bounds = bounds; this.footprint = footprint; this.ox = x; this.oy = y; - this.dirtyRect = dirtyRect; - // calculate the item's leftmost and rightmost tiles. - // note that sprites occupy only a single tile, so - // leftmost and rightmost tiles are equivalent + // calculate the item's leftmost and rightmost tiles; note + // that sprites occupy only a single tile, so leftmost and + // rightmost tiles are equivalent lx = rx = ox; ly = ry = oy; if (obj instanceof ObjectTile) { @@ -208,13 +249,8 @@ public class DirtyItemList * the portion of the item that falls within the given dirty * rectangle is actually drawn. */ - public void paint (Graphics2D gfx, Rectangle clip) + public void paint (Graphics2D gfx) { - Shape oclip = gfx.getClip(); - - // clip the draw region to the dirty portion of the item - gfx.clip(clip); - // if there's a footprint, paint that if (footprint != null) { gfx.setColor(Color.black); @@ -225,11 +261,19 @@ public class DirtyItemList if (obj instanceof Sprite) { ((Sprite)obj).paint(gfx); } else { - ((ObjectTile)obj).paint(gfx, bounds); + ((ObjectTile)obj).paint(gfx, bounds.x, bounds.y); } + } - // restore original clipping region - gfx.setClip(oclip); + /** + * Releases all references held by this dirty item so that it + * doesn't inadvertently hold on to any objects while waiting to + * be reused. + */ + public void clear () + { + obj = null; + bounds = null; } // documentation inherited @@ -309,18 +353,8 @@ public class DirtyItemList * suitable for rendering in the isometric view with proper visual * results. */ - protected static class RenderComparator implements Comparator + protected class RenderComparator implements Comparator { - /** - * Constructs a render comparator with the given list of - * pre-sorted dirty item lists for each axis. - */ - public RenderComparator (DirtyItem[] xitems, DirtyItem[] yitems) - { - _xitems = xitems; - _yitems = yitems; - } - // documentation inherited public int compare (Object a, Object b) { @@ -374,7 +408,7 @@ public class DirtyItemList int axis, DirtyItem da, DirtyItem db) { // prepare for the partitioning check - DirtyItem[] sitems; + SortableArrayList sitems; Comparator comp; boolean swapped = false; switch (axis) { @@ -420,14 +454,14 @@ public class DirtyItemList // get the bounding item indices and the number of // potentially-partitioning dirty items - int aidx = Arrays.binarySearch(sitems, da, comp); - int bidx = Arrays.binarySearch(sitems, db, comp); + int aidx = sitems.binarySearch(da, comp); + int bidx = sitems.binarySearch(db, comp); int size = bidx - aidx - 1; // check each potentially partitioning item int startidx = aidx + 1, endidx = startidx + size; for (int pidx = startidx; pidx < endidx; pidx++) { - DirtyItem dp = sitems[pidx]; + DirtyItem dp = (DirtyItem)sitems.get(pidx); if (dp.obj instanceof MisoCharacterSprite) { // character sprites can't partition things continue; @@ -503,12 +537,6 @@ public class DirtyItemList } return -1; } - - /** The items in the dirty item list sorted by ascending x origin. */ - protected DirtyItem[] _xitems; - - /** The items in the dirty item list sorted by ascending y origin. */ - protected DirtyItem[] _yitems; } /** Whether to log debug info when comparing pairs of dirty items. */ @@ -532,5 +560,17 @@ public class DirtyItemList new OriginComparator(Y_AXIS); /** The list of dirty items. */ - protected ArrayList _items = new ArrayList(); + protected SortableArrayList _items = new SortableArrayList(); + + /** The list of dirty items sorted by x-position. */ + protected SortableArrayList _xitems = new SortableArrayList(); + + /** The list of dirty items sorted by y-position. */ + protected SortableArrayList _yitems = new SortableArrayList(); + + /** The render comparator we'll use for our final, magical sort. */ + protected Comparator _rcomp = new RenderComparator(); + + /** Unused dirty items. */ + protected ArrayList _freelist = new ArrayList(); } diff --git a/src/java/com/threerings/miso/client/IsoSceneView.java b/src/java/com/threerings/miso/client/IsoSceneView.java index 3442f7198..8d43cec3a 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.111 2002/06/18 21:22:34 ray Exp $ +// $Id: IsoSceneView.java,v 1.112 2002/06/18 22:38:12 mdb Exp $ package com.threerings.miso.scene; @@ -78,14 +78,8 @@ public class IsoSceneView implements SceneView _model = model; _remgr = remgr; - // create a cache which will be populated with the tile polygons - // as they are requested. We manually adjust the size/load factor - // to optimize memory usage (because we happen to know things - // hash weirdly because of the way we make the keys. - _polys = new HashIntMap(model.scenewid, (float) model.scenehei); - - // create the array used to mark dirty tiles - _dirty = new boolean[model.scenewid][model.tilehei]; + // handy rectangle + _tbounds = new Rectangle(0, 0, _model.tilewid, _model.tilehei); } /** @@ -132,80 +126,21 @@ public class IsoSceneView implements SceneView } // documentation inherited from interface - public void viewWillScroll (int dx, int dy) - { - // adjust our offsets - _xoff += dx; - _yoff += dy; - - // determine whether or not this scrolling causes us to cross - // boundaries in the x or y directions - if (_xoff >= _model.tilehwid) { - _tiledx += 1; - _tiledy -= 1; - _xoff -= _model.tilewid; - - } else if (_xoff < -_model.tilehwid) { - _tiledx -= 1; - _tiledy += 1; - _xoff += _model.tilewid; - } - - if (_yoff >= _model.tilehhei) { - _tiledx += 1; - _tiledy += 1; - _yoff -= _model.tilehei; - - } else if (_yoff < -_model.tilehhei) { - _tiledx -= 1; - _tiledy -= 1; - _yoff += _model.tilehei; - } - } - - // documentation inherited from interface - public void paint (Graphics2D gfx, Rectangle[] dirtyRects) + public void paint (Graphics2D gfx, Rectangle dirtyRect) { if (_scene == null) { Log.warning("Scene view painted with null scene."); return; } -// Log.info("Rendering: " + StringUtil.toString(dirtyRects) + -// ", clip: " + StringUtil.toString(gfx.getClip())); + // render any intersecting tiles + renderTiles(gfx, dirtyRect); -// // invalidate the invalid rectangles -// int rsize = dirtyRects.length; -// for (int ii = 0; ii < rsize; ii++) { -// invalidateRect(dirtyRects[ii]); -// } + // render anything that goes on top of the tiles + renderBaseDecorations(gfx, dirtyRect); - // translate according to our scroll parameters - gfx.translate(-_xoff, -_yoff); - - // render the scrolling part of the scene - int rcount = dirtyRects.length; - for (int ii = 0; ii < rcount; ii++) { - Rectangle rect = dirtyRects[ii]; - rect.translate(_xoff, _yoff); - Shape oclip = gfx.getClip(); - gfx.clipRect(rect.x, rect.y, rect.width, rect.height); - renderScrollingScene(gfx, rect); - gfx.setClip(oclip); - rect.translate(-_xoff, -_yoff); - } - - // untranslate according to our scroll parameters - gfx.translate(_xoff, _yoff); - - // render the fixed part of the scene - for (int ii = 0; ii < rcount; ii++) { - Rectangle rect = dirtyRects[ii]; - Shape oclip = gfx.getClip(); - gfx.clipRect(rect.x, rect.y, rect.width, rect.height); - renderFixedScene(gfx, rect); - gfx.setClip(oclip); - } + // render our dirty sprites and objects + renderDirtyItems(gfx, dirtyRect); // draw sprite paths if (_model.showPaths) { @@ -213,10 +148,10 @@ public class IsoSceneView implements SceneView } // paint our highlighted tile (if any) - paintHighlights(gfx); + paintHighlights(gfx, dirtyRect); // paint any extra goodies - paintExtras(gfx); + paintExtras(gfx, dirtyRect); } /** @@ -224,7 +159,7 @@ public class IsoSceneView implements SceneView * * @param gfx the graphics context. */ - protected void paintHighlights (Graphics2D gfx) + protected void paintHighlights (Graphics2D gfx, Rectangle clip) { // if we're not highlighting object tiles, bail now if (_hmode == HIGHLIGHT_NEVER) { @@ -241,8 +176,8 @@ public class IsoSceneView implements SceneView // this one has an action String action = _scene.getObjectAction(otile); if (_hmode != HIGHLIGHT_WITH_ACTION || !StringUtil.blank(action)) { - Polygon tpoly = getTilePoly(_hcoords.x, _hcoords.y); - hpoly = IsoUtil.getObjectFootprint(_model, tpoly, otile); + hpoly = IsoUtil.getObjectFootprint( + _model, _hcoords.x, _hcoords.y, otile); } } @@ -250,7 +185,7 @@ public class IsoSceneView implements SceneView // then paint the bounds of the highlighted base tile if (hpoly == null && _hmode == HIGHLIGHT_ALL && _hcoords.x != -1 && _hcoords.y != -1) { - hpoly = getTilePoly(_hcoords.x, _hcoords.y); + hpoly = IsoUtil.getTilePolygon(_model, _hcoords.x, _hcoords.y); } // if we've determined that there's something to highlight @@ -272,94 +207,133 @@ public class IsoSceneView implements SceneView * A function where derived classes can paint extra stuff while we've * got the clipping region set up. */ - protected void paintExtras (Graphics2D gfx) + protected void paintExtras (Graphics2D gfx, Rectangle clip) { // nothing for now } - /** - * Renders the scrolling part of the scene to the given graphics - * context. - * - * @param gfx the graphics context. - */ - protected void renderScrollingScene (Graphics2D gfx, Rectangle clip) - { - // render any intersecting tiles - renderTiles(gfx, clip); - - // render anything that goes on top of the tiles - renderBaseDecorations(gfx, clip); - } - - /** - * Renders the non-scrolling part of the scene to the given graphics - * context. - * - * @param gfx the graphics context. - */ - protected void renderFixedScene (Graphics2D gfx, Rectangle clip) - { - renderDirtyItems(gfx, clip); - } - /** * Renders the base and fringe layer tiles that intersect the * specified clipping rectangle. */ protected void renderTiles (Graphics2D gfx, Rectangle clip) { - FontMetrics fm = gfx.getFontMetrics(_font); - int fhei = fm.getAscent(); - int cx = _model.tilehwid, cy = _model.tilehhei; - + // if we're showing coordinates, we need to do some setting up + int thw = 0, thh = 0, fhei = 0; + FontMetrics fm = null; if (_model.showCoords) { + fm = gfx.getFontMetrics(_font); + fhei = fm.getAscent(); + thw = _model.tilehwid; + thh = _model.tilehhei; gfx.setFont(_font); gfx.setColor(Color.white); } - - for (int yy = 0; yy < _model.scenehei; yy++) { - for (int xx = 0; xx < _model.scenewid; xx++) { - Polygon tpoly = getTilePoly(xx, yy); - // skip non-intersecting tiles - // if (!tpoly.intersects(clip)) { - if (!tpoly.getBounds().intersects(clip)) { - continue; - } + // determine which tiles intersect this clipping region: this is + // going to be nearly incomprehensible without some sort of + // diagram; i'll do what i can to comment it, but you'll want to + // print out a scene diagram (docs/miso/scene.ps) and start making + // notes if you want to follow along - // offset the tile coordinates by our scrolled deltas - int tx = xx + _tiledx, ty = yy + _tiledy; + // obtain our upper left tile + Point tpos = IsoUtil.screenToTile(_model, clip.x, clip.y, new Point()); + // determine which quadrant of the upper left tile we occupy + Point spos = IsoUtil.tileToScreen(_model, tpos.x, tpos.y, new Point()); + boolean left = (clip.x - spos.x < _model.tilehwid); + boolean top = (clip.y - spos.y < _model.tilehhei); + + // set up our tile position counters + int dx, dy; + if (left) { + dx = 0; dy = 1; + } else { + dx = 1; dy = 0; + } + + // if we're in the top-half of the tile we need to move up a row, + // either forward or back depending on whether we're in the left + // or right half of the tile + if (top) { + if (left) { + tpos.x -= 1; + } else { + tpos.y -= 1; + } + // we'll need to start zig-zagging the other way as well + dx = 1 - dx; + dy = 1 - dy; + } + + // these will bound our loops + int rightx = clip.x + clip.width, bottomy = clip.y + clip.height; + +// Log.info("Preparing to render [tpos=" + StringUtil.toString(tpos) + +// ", left=" + left + ", top=" + top + +// ", clip=" + StringUtil.toString(clip) + +// ", spos=" + StringUtil.toString(spos) + +// "]."); + + // obtain the coordinates of the tile that starts the first row + // and loop through, rendering the intersecting tiles + IsoUtil.tileToScreen(_model, tpos.x, tpos.y, spos); + while (spos.y < bottomy) { + // set up our row counters + int tx = tpos.x, ty = tpos.y; + _tbounds.x = spos.x; + _tbounds.y = spos.y; + +// Log.info("Rendering row [tx=" + tx + ", ty=" + ty + "]."); + + // render the tiles in this row + while (_tbounds.x < rightx) { // draw the base and fringe tile images - Tile tile; - if ((tile = _scene.getBaseTile(tx, ty)) != null) { - tile.paint(gfx, tpoly); - } - if ((tile = _scene.getFringeTile(tx, ty)) != null) { - tile.paint(gfx, tpoly); + try { + Tile tile; + if ((tile = _scene.getBaseTile(tx, ty)) != null) { + tile.paint(gfx, _tbounds.x, _tbounds.y); + } + if ((tile = _scene.getFringeTile(tx, ty)) != null) { + tile.paint(gfx, _tbounds.x, _tbounds.y); + } + + } catch (ArrayIndexOutOfBoundsException e) { + Log.warning("Whoops, booched it [tx=" + tx + + ", ty=" + ty + ", tb.x=" + _tbounds.x + + ", rightx=" + rightx + "]."); } // if we're showing coordinates, do that if (_model.showCoords) { // outline the tile - gfx.draw(tpoly); +// gfx.draw(tpoly); // get the top-left screen coordinates of the tile - Rectangle bounds = tpoly.getBounds(); - int sx = bounds.x, sy = bounds.y; + int sx = _tbounds.x, sy = _tbounds.y; // draw x-coordinate - String str = String.valueOf(xx + _tiledx); - int xpos = sx + cx - (fm.stringWidth(str) / 2); - gfx.drawString(str, xpos, sy + cy); + String str = String.valueOf(tx); + int xpos = sx + thw - (fm.stringWidth(str) / 2); + gfx.drawString(str, xpos, sy + thh); // draw y-coordinate - str = String.valueOf(yy + _tiledy); - xpos = sx + cx - (fm.stringWidth(str) / 2); - gfx.drawString(str, xpos, sy + cy + fhei); + str = String.valueOf(ty); + xpos = sx + thw - (fm.stringWidth(str) / 2); + gfx.drawString(str, xpos, sy + thh + fhei); } + + // move one tile to the right + tx += 1; ty -= 1; + _tbounds.x += _model.tilewid; } + + // update our tile coordinates + tpos.x += dx; dx = 1-dx; + tpos.y += dy; dy = 1-dy; + + // obtain the screen coordinates of the next starting tile + IsoUtil.tileToScreen(_model, tpos.x, tpos.y, spos); } } @@ -379,20 +353,57 @@ public class IsoSceneView implements SceneView */ protected void renderDirtyItems (Graphics2D gfx, Rectangle clip) { - invalidateItems(clip); + // if we don't yet have a scene, do nothing + if (_scene == null) { + return; + } + + // add any sprites impacted by the dirty rectangle + _dirtySprites.clear(); + _spritemgr.getIntersectingSprites(_dirtySprites, clip); + int size = _dirtySprites.size(); + for (int ii = 0; ii < size; ii++) { + MisoCharacterSprite sprite = (MisoCharacterSprite) + _dirtySprites.get(ii); + Rectangle bounds = sprite.getBounds(); + if (!bounds.intersects(clip)) { + continue; + } + + _dirtyItems.appendDirtySprite( + sprite, sprite.getTileX(), sprite.getTileY()); + // Log.info("Dirtied item: " + sprite); + } + + // add any objects impacted by the dirty rectangle + Iterator iter = _objects.iterator(); + while (iter.hasNext()) { + ObjectMetrics metrics = (ObjectMetrics)iter.next(); + Rectangle obounds = metrics.bounds; + if (!obounds.intersects(clip)) { + continue; + } + + // compute the footprint if we're rendering those + Polygon foot = null; + if (_model.showFootprints) { + foot = IsoUtil.getObjectFootprint( + _model, metrics.x, metrics.y, metrics.tile); + } + + // add the object to the dirty items list + _dirtyItems.appendDirtyObject( + metrics.tile, obounds, foot, metrics.x, metrics.y); + // Log.info("Dirtied item: Object(" + + // metrics.x + ", " + metrics.y + ")"); + } // Log.info("renderDirtyItems [items=" + _dirtyItems.size() + "]."); - // sort the dirty sprites and objects visually back-to-front - DirtyItem items[] = _dirtyItems.sort(); - - // render each item clipping to its dirty rectangle - for (int ii = 0; ii < items.length; ii++) { - items[ii].paint(gfx, items[ii].dirtyRect); -// Log.info("Painting item [item=" + items[ii] + "]."); - } - - _dirtyItems.clear(); + // sort the dirty sprites and objects visually back-to-front; + // paint them and be done + _dirtyItems.sort(); + _dirtyItems.paintAndClear(gfx); } /** @@ -424,8 +435,7 @@ public class IsoSceneView implements SceneView metrics.tile = tile; metrics.x = x; metrics.y = y; - metrics.bounds = IsoUtil.getObjectBounds( - _model, getTilePoly(x, y), tile); + metrics.bounds = IsoUtil.getObjectBounds(_model, x, y, tile); // and add it to the list _objects.add(metrics); @@ -446,211 +456,6 @@ public class IsoSceneView implements SceneView } } - /** - * Returns the polygon bounding the tile at the specified coordinates. - */ - protected Polygon getTilePoly (int x, int y) - { - int key = IsoUtil.coordsToKey(x, y); - - Polygon poly = (Polygon) _polys.get(key); - if (poly == null) { - poly = IsoUtil.getTilePolygon(_model, x, y); - _polys.put(key, poly); - } - return poly; - } - - /** - * 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. - */ - protected Rectangle invalidateScreenRect (Rectangle r) - { -// Log.info("Invalidating [rect=" + r + -// ", xoff=" + _xoff + ", yoff=" + _yoff + "]."); - - // account for our current scrolling offset - int rx = r.x + _xoff, ry = r.y + _yoff; - - // 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 - // complicates the code with likely-insufficient benefit - - // determine the top-left tile impacted by this rect - Point tpos = new Point(); - IsoUtil.screenToTile(_model, rx, ry, tpos); - - // determine screen coordinates for top-left tile - Point topleft = new Point(); - IsoUtil.tileToScreen(_model, tpos.x, tpos.y, topleft); - - // determine number of horizontal tiles for rect - int numh = (int)Math.ceil((float)r.width / (float)_model.tilewid); - - // set up iterating variables - int tx = tpos.x, ty = tpos.y, mx = tpos.x, my = tpos.y; - - // set the starting screen y-position - int screenY = topleft.y; - - // add top row if rect may overlap - if (ry < (screenY + _model.tilehhei)) { - ty--; - for (int ii = 0; ii < numh; ii++) { - addDirtyTile(tileBounds, tx++, ty--); - } - } - - // determine the bottom-left tile impacted by this rect - Point bpos = new Point(); - IsoUtil.screenToTile(_model, rx, ry + r.height, bpos); - - // determine screen coordinates for bottom-left tile - Point botleft = new Point(); - IsoUtil.tileToScreen(_model, bpos.x, bpos.y, botleft); - - // determine the number of vertical rows for our rect (we do this - // by subtracting the "height" of the top tile from that of the - // bottom tile, the height being the sum of the x and y - // coordinate) - int numv = (bpos.x + bpos.y) - (tpos.x + tpos.y); - - // now we need to extend the rect to contain the row containing - // the bottom tile, and potentially the row below that - numv += ((ry + r.height) > (botleft.y + _model.tilehhei)) ? 2 : 1; - - // add dirty tiles from each affected row - for (int ii = 0; ii < numv; ii++) { - - // set up iterating variables for this row - tx = mx; - ty = my; - int length = numh; - - // set the starting screen x-position - int screenX = topleft.x; - if (ii%2 == 1) { - screenX -= _model.tilehwid; - } - - // skip leftmost tile if rect doesn't overlap - if (rx > screenX + _model.tilewid) { - tx++; - ty--; - screenX += _model.tilewid; - } - - // add to the right edge if rect may overlap - if (rx + r.width > (screenX + (length * _model.tilewid))) { - length++; - } - - // add all tiles in the row to the dirty set - for (int jj = 0; jj < length; jj++) { - addDirtyTile(tileBounds, tx++, ty--); - } - - // step along the x- or y-axis appropriately - if (ii%2 == 1) { - mx++; - } else { - my++; - } - } - - return tileBounds; - } - - /** - * Marks the tile at the given coordinates dirty and expands the tile - * bounds rectangle to include the rectangle for the dirtied tile. - */ - protected boolean addDirtyTile (Rectangle tileBounds, int x, int y) - { - if (!_model.isCoordinateValid(x, y)) { - return false; - } - - // expand the tile bounds rectangle to include this tile - Rectangle bounds = getTilePoly(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]) { - return false; - } - - // mark the tile dirty - _numDirty++; - _dirty[x][y] = true; - return true; - } - - /** - * 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++) { - MisoCharacterSprite sprite = - (MisoCharacterSprite)_dirtySprites.get(ii); - - // get the dirty portion of the sprite - Rectangle drect = sprite.getBounds().intersection(r); - - _dirtyItems.appendDirtySprite( - sprite, sprite.getTileX(), sprite.getTileY(), drect); - // Log.info("Dirtied item: " + sprite); - } - - // add any objects impacted by the dirty rectangle - if (_scene != null) { - Iterator iter = _objects.iterator(); - while (iter.hasNext()) { - ObjectMetrics metrics = (ObjectMetrics)iter.next(); - Rectangle obounds = metrics.bounds; - if (!obounds.intersects(r)) { - continue; - } - - // get the dirty portion of the object - Rectangle drect = obounds.intersection(r); - int tx = metrics.x, ty = metrics.y; - - // compute the footprint if we're rendering those - Polygon foot = null; - if (_model.showFootprints) { - foot = IsoUtil.getObjectFootprint( - _model, getTilePoly(tx, ty), metrics.tile); - } - - // add the intersected section of the object to the dirty - // items list - _dirtyItems.appendDirtyObject( - metrics.tile, obounds, foot, tx, ty, drect); - // Log.info("Dirtied item: Object(" + tx + ", " + ty + ")"); - } - } - } - /** * Get a path between the two points (in screen coordinates) * that will update a MisoCharacterSprite as it walks the path. @@ -677,8 +482,7 @@ public class IsoSceneView implements SceneView } // get the destination tile coordinates - Point dest = new Point(); - IsoUtil.screenToTile(_model, x + _xoff, y + _yoff, dest); + Point dest = IsoUtil.screenToTile(_model, x, y, new Point()); // get a reasonable tile path through the scene List points = AStarPathUtil.getPath( @@ -693,20 +497,13 @@ public class IsoSceneView implements SceneView // documentation inherited public Point getScreenCoords (int x, int y) { - Point coords = new Point(); - IsoUtil.fullToScreen(_model, x, y, coords); - // adjust for our scrolling offset - coords.x -= _xoff; - coords.y -= _yoff; - return coords; + return IsoUtil.fullToScreen(_model, x, y, new Point()); } // documentation inherited public Point getFullCoords (int x, int y) { - Point coords = new Point(); - IsoUtil.screenToFull(_model, x + _xoff, y + _yoff, coords); - return coords; + return IsoUtil.screenToFull(_model, x, y, new Point()); } // documentation inherited @@ -722,36 +519,36 @@ public class IsoSceneView implements SceneView } // compute the list of objects over which the mouse is hovering - _hitList.clear(); - _hitSprites.clear(); - // add the sprites that contain the point + Object hobject = null; + + // start with the sprites that contain the point _spritemgr.getHitSprites(_hitSprites, x, y); int hslen = _hitSprites.size(); for (int i = 0; i < hslen; i++) { MisoCharacterSprite sprite = (MisoCharacterSprite)_hitSprites.get(i); _hitList.appendDirtySprite( - sprite, sprite.getTileX(), sprite.getTileY(), - sprite.getBounds()); + sprite, sprite.getTileX(), sprite.getTileY()); } // add the object tiles that contain the point getHitObjects(_hitList, x, y); // sort the list of hit items by rendering order - Object hobject = null; - DirtyItem[] items = _hitList.sort(); + _hitList.sort(); + // the last element in the array is what we want (assuming there // are any items in the array) - if (items.length > 0) { - hobject = items[items.length-1].obj; - } + int icount = _hitList.size(); + if (icount > 0) { + DirtyItem item = (DirtyItem)_hitList.get(icount-1); + hobject = item.obj; - // if this is an object tile, we need to update the hcoords - if (hobject != null && hobject instanceof ObjectTile) { - DirtyItem item = items[items.length-1]; - _hcoords.x = item.ox; - _hcoords.y = item.oy; + // if this is an object tile, we need to update the hcoords + if (hobject instanceof ObjectTile) { + _hcoords.x = item.ox; + _hcoords.y = item.oy; + } } // if this hover object is different than before, we'll need to be @@ -769,6 +566,10 @@ public class IsoSceneView implements SceneView } } + // clear out the hitlists + _hitList.clear(); + _hitSprites.clear(); + return repaint; } @@ -783,22 +584,21 @@ public class IsoSceneView implements SceneView Iterator iter = _objects.iterator(); while (iter.hasNext()) { ObjectMetrics metrics = (ObjectMetrics)iter.next(); + Rectangle pbounds = metrics.bounds; // skip polys that don't contain the point - if (!metrics.bounds.contains(x, y)) { + if (!pbounds.contains(x, y)) { continue; } // now check that the pixel in the tile image is // non-transparent at that point - int tx = metrics.x, ty = metrics.y; - Rectangle pbounds = metrics.bounds.getBounds(); if (!metrics.tile.hitTest(x - pbounds.x, y - pbounds.y)) { continue; } // we've passed the test, add the object to the list list.appendDirtyObject(metrics.tile, metrics.bounds, null, - tx, ty, pbounds); + metrics.x, metrics.y); } } @@ -838,8 +638,7 @@ public class IsoSceneView implements SceneView */ protected boolean updateTileCoords (int sx, int sy, Point tpos) { - Point npos = new Point(); - IsoUtil.screenToTile(_model, sx + _xoff, sy + _yoff, npos); + Point npos = IsoUtil.screenToTile(_model, sx, sy, new Point()); // make sure the new coordinate is both valid and different if (_model.isCoordinateValid(npos.x, npos.y) && !tpos.equals(npos)) { @@ -879,31 +678,18 @@ public class IsoSceneView implements SceneView /** The scene to be displayed. */ protected DisplayMisoScene _scene; - /** Polygon outlines for all of our base tiles. */ - protected HashIntMap _polys; - /** Metric information for all of the object tiles. */ protected ArrayList _objects = new ArrayList(); - /** The rendering offsets used to support scrolling. */ - protected int _xoff = 0, _yoff = 0; - - /** The offsets from (0, 0) in tile coordinates to which we have - * scrolled. */ - protected int _tiledx, _tiledy; - - /** The dirty tiles that need to be re-painted. */ - protected boolean _dirty[][]; - - /** The number of dirty tiles. */ - protected int _numDirty; - /** 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(); + /** Used when rendering tiles. */ + protected Rectangle _tbounds; + /** Used to collect the list of sprites "hit" by a particular mouse * location. */ protected List _hitSprites = new ArrayList(); diff --git a/src/java/com/threerings/miso/client/SceneView.java b/src/java/com/threerings/miso/client/SceneView.java index 5c4d9ca98..13b91c02a 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.28 2002/05/31 03:38:03 mdb Exp $ +// $Id: SceneView.java,v 1.29 2002/06/18 22:38:12 mdb Exp $ package com.threerings.miso.scene; @@ -18,21 +18,13 @@ import com.threerings.media.util.Path; public interface SceneView { /** - * Lets the view know that it will be scrolled by the specified number - * of pixels in each direction the next time that {@link #paint} is - * called. This is called automatically by the {@link SceneViewPanel} - * which takes care of dirtying the regions exposed by the scrolling - * and copying the scrollable pixels. - */ - public void viewWillScroll (int dx, int dy); - - /** - * Renders the scene to the given graphics context. + * Renders an invalid porition of the scene to the given graphics + * context. * * @param gfx the graphics context. - * @param invalidRects the list of invalid regions to be repainted. + * @param invalidRect the invalid region to be repainted. */ - public void paint (Graphics2D gfx, Rectangle[] invalidRects); + public void paint (Graphics2D gfx, Rectangle invalidRect); /** * Sets the scene that we're rendering. diff --git a/src/java/com/threerings/miso/client/SceneViewPanel.java b/src/java/com/threerings/miso/client/SceneViewPanel.java index 59730a07c..f0337c1cf 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.40 2002/04/23 03:11:17 mdb Exp $ +// $Id: SceneViewPanel.java,v 1.41 2002/06/18 22:38:12 mdb Exp $ package com.threerings.miso.scene; @@ -13,9 +13,10 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.List; +import com.samskivert.util.StringUtil; import com.threerings.media.FrameManager; -import com.threerings.media.MediaPanel; +import com.threerings.media.VirtualMediaPanel; import com.threerings.media.sprite.Sprite; import com.threerings.media.sprite.SpriteManager; @@ -28,7 +29,7 @@ import com.threerings.miso.scene.util.IsoUtil; * SceneView}, rendering it to the screen, and handling view-related * UI events. */ -public class SceneViewPanel extends MediaPanel +public class SceneViewPanel extends VirtualMediaPanel implements IsoSceneViewModelListener { /** @@ -38,7 +39,7 @@ public class SceneViewPanel extends MediaPanel { super(framemgr); - // we're going to want to be opaque + // we're going to want to be opaque setOpaque(true); // create the data model for the scene view @@ -122,50 +123,27 @@ public class SceneViewPanel extends MediaPanel super.addSprite(sprite); } - /** - * If we're scrolling, we need to pass the word on to our scene view. - */ - protected void viewWillScroll (int dx, int dy, long now) + // documentation inherited + public void doLayout () { - _view.viewWillScroll(dx, dy); - } + super.doLayout(); - /** - * We want to pretend like we're in a view that fits our whole model - * so we return the model bounds as our view size. - */ - protected Dimension getViewSize () - { - return _viewmodel.bounds.getSize(); - } + // figure out our viewport offsets + Dimension size = getSize(); - /** - * We overload this to translate mouse events into the proper - * coordinates before they are dispatched to any of the mouse - * listeners. - */ - protected void processMouseEvent (MouseEvent event) - { - event.translatePoint(_tx, _ty); - super.processMouseEvent(event); - } + // start out centered in the display + setViewLocation((_viewmodel.bounds.width - size.width)/2, + (_viewmodel.bounds.height - size.height)/2); - /** - * We overload this to translate mouse events into the proper - * coordinates before they are dispatched to any of the mouse - * listeners. - */ - protected void processMouseMotionEvent (MouseEvent event) - { - event.translatePoint(_tx, _ty); - super.processMouseMotionEvent(event); +// Log.info("Size: " + StringUtil.toString(size) + +// ", vsize: " + StringUtil.toString(_viewmodel.bounds) + +// ", nx: " + _nx + ", ny: " + _ny + "."); } // documentation inherited - protected void paintBetween (Graphics2D gfx, Rectangle[] dirtyRects) + protected void paintBetween (Graphics2D gfx, Rectangle dirty) { - // render the isometric view - _view.paint(gfx, dirtyRects); + _view.paint(gfx, dirty); } /** @@ -173,12 +151,9 @@ public class SceneViewPanel extends MediaPanel * we intersperse them with objects in our scene and need to manage * their z-order. */ - protected void paintBits (Graphics2D gfx, int layer, Rectangle clip) + protected void paintBits (Graphics2D gfx, int layer, Rectangle dirty) { - Shape oclip = gfx.getClip(); - gfx.clipRect(clip.x, clip.y, clip.width, clip.height); - _animmgr.renderAnimations(gfx, layer, clip); - gfx.setClip(oclip); + _animmgr.renderAnimations(gfx, layer, dirty); } /** diff --git a/src/java/com/threerings/miso/client/util/IsoUtil.java b/src/java/com/threerings/miso/client/util/IsoUtil.java index ea1dfe35c..43ec235fb 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.32 2002/05/24 20:32:11 ray Exp $ +// $Id: IsoUtil.java,v 1.33 2002/06/18 22:38:12 mdb Exp $ package com.threerings.miso.scene.util; @@ -52,20 +52,20 @@ public class IsoUtil * object tile. * * @param model the scene view model. - * @param root the polygon for the root tile at which the object - * is located. + * @param tx the x tile-coordinate of the object tile. + * @param ty the y tile-coordinate of the object tile. * @param tile the object tile. * * @return the bounding polygon. */ public static Polygon getObjectFootprint ( - IsoSceneViewModel model, Polygon root, ObjectTile tile) + IsoSceneViewModel model, int tx, int ty, ObjectTile tile) { Polygon boundsPoly = new SmartPolygon(); - Rectangle bounds = root.getBounds(); + Point tpos = tileToScreen(model, tx, ty, new Point()); int bwid = tile.getBaseWidth(), bhei = tile.getBaseHeight(); - int oox = bounds.x + model.tilehwid, ooy = bounds.y + model.tilehei; + int oox = tpos.x + model.tilehwid, ooy = tpos.y + model.tilehei; int rx = oox, ry = ooy; // bottom-center point @@ -98,16 +98,16 @@ public class IsoUtil * object dimensions. This is currently not used. * * @param model the scene view model. - * @param root the polygon for the root tile at which the object is - * located. + * @param tx the x tile-coordinate of the object tile. + * @param ty the y tile-coordinate of the object tile. * @param tile the object tile. * * @return the bounding polygon. */ public static Polygon getTightObjectBounds ( - IsoSceneViewModel model, Polygon root, ObjectTile tile) + IsoSceneViewModel model, int tx, int ty, ObjectTile tile) { - Rectangle bounds = root.getBounds(); + Point tpos = tileToScreen(model, tx, ty, new Point()); // if the tile has an origin, use that, otherwise compute the // origin based on the tile footprint @@ -118,7 +118,7 @@ public class IsoUtil } float slope = (float)model.tilehei / (float)model.tilewid; - int oox = bounds.x + model.tilehwid, ooy = bounds.y + model.tilehei; + int oox = tpos.x + model.tilehwid, ooy = tpos.y + model.tilehei; int sx = oox - tox, sy = ooy - toy; Polygon boundsPoly = new SmartPolygon(); @@ -136,8 +136,7 @@ public class IsoUtil boundsPoly.addPoint(rx, ry); // bottom-middle point - boundsPoly.addPoint(bounds.x + model.tilehwid, - bounds.y + model.tilehei); + boundsPoly.addPoint(tpos.x + model.tilehwid, tpos.y + model.tilehei); // bottom-left point rx = sx; @@ -156,16 +155,16 @@ public class IsoUtil * image. * * @param model the scene view model. - * @param root the polygon for the root tile at which the object is - * located. + * @param tx the x tile-coordinate of the object tile. + * @param ty the y tile-coordinate of the object tile. * @param tile the object tile. * * @return the bounding rectangle. */ public static Rectangle getObjectBounds ( - IsoSceneViewModel model, Polygon root, ObjectTile tile) + IsoSceneViewModel model, int tx, int ty, ObjectTile tile) { - Rectangle bounds = root.getBounds(); + Point tpos = tileToScreen(model, tx, ty, new Point()); // if the tile has an origin, use that, otherwise compute the // origin based on the tile footprint @@ -175,7 +174,7 @@ public class IsoUtil toy = tile.getHeight(); } - int oox = bounds.x + model.tilehwid, ooy = bounds.y + model.tilehei; + int oox = tpos.x + model.tilehwid, ooy = tpos.y + model.tilehei; int sx = oox - tox, sy = ooy - toy; return new Rectangle(sx, sy, tile.getWidth(), tile.getHeight()); @@ -337,26 +336,42 @@ public class IsoUtil * @param sx the screen x-position pixel coordinate. * @param sy the screen y-position pixel coordinate. * @param tpos the point object to place coordinates in. + * + * @return the point instance supplied via the tpos + * parameter. */ - public static void screenToTile ( + public static Point screenToTile ( IsoSceneViewModel model, int sx, int sy, Point tpos) { - // calculate line parallel to the y-axis (from mouse pos to x-axis) - int bY = (int)(sy - (model.slopeY * sx)); + // determine the upper-left of the quadrant that contains our + // point + int zx = (int)Math.floor((float)(sx - model.origin.x) / model.tilewid); + int zy = (int)Math.floor((float)(sy - model.origin.y) / model.tilehei); - // determine intersection of x- and y-axis lines - int crossx = (int)((bY - (model.bX + model.origin.y)) / - (model.slopeX - model.slopeY)); - int crossy = (int)((model.slopeY * crossx) + bY); + // these are the screen coordinates of the tile's top + int ox = (zx * model.tilewid + model.origin.x), + oy = (zy * model.tilehei + model.origin.y); - // determine distance of mouse pos along the x axis - int xdist = (int)MathUtil.distance( - model.origin.x, model.origin.y, crossx, crossy); - tpos.x = (int)(xdist / model.tilelen); + // these are the tile coordinates + tpos.x = zy + zx; tpos.y = zy - zx; - // determine distance of mouse pos along the y-axis - int ydist = (int)MathUtil.distance(sx, sy, crossx, crossy); - tpos.y = (int)(ydist / model.tilelen); + // now determine which of the four tiles our point occupies + int dx = sx - ox, dy = sy - oy; + + if (Math.round(model.slopeY * dx + model.tilehei) < dy) { + tpos.x += 1; + } + + if (Math.round(model.slopeX * dx) > dy) { + tpos.y -= 1; + } + +// Log.info("Converted [sx=" + sx + ", sy=" + sy + +// ", zx=" + zx + ", zy=" + zy + +// ", ox=" + ox + ", oy=" + oy + +// ", dx=" + dx + ", dy=" + dy + +// ", tpos.x=" + tpos.x + ", tpos.y=" + tpos.y + "]."); + return tpos; } /** @@ -367,12 +382,16 @@ public class IsoUtil * @param x the tile x-position coordinate. * @param y the tile y-position coordinate. * @param spos the point object to place coordinates in. + * + * @return the point instance supplied via the spos + * parameter. */ - public static void tileToScreen ( + public static Point tileToScreen ( IsoSceneViewModel model, int x, int y, Point spos) { spos.x = model.origin.x + ((x - y - 1) * model.tilehwid); spos.y = model.origin.y + ((x + y) * model.tilehhei); + return spos; } /** @@ -435,8 +454,10 @@ public class IsoUtil * @param sx the screen x-position pixel coordinate. * @param sy the screen y-position pixel coordinate. * @param fpos the point object to place coordinates in. + * + * @return the point passed in to receive the coordinates. */ - public static void screenToFull ( + public static Point screenToFull ( IsoSceneViewModel model, int sx, int sy, Point fpos) { // get the tile coordinates @@ -444,8 +465,7 @@ public class IsoUtil screenToTile(model, sx, sy, tpos); // get the screen coordinates for the containing tile - Point spos = new Point(); - tileToScreen(model, tpos.x, tpos.y, spos); + Point spos = tileToScreen(model, tpos.x, tpos.y, new Point()); // get the fine coordinates within the containing tile pixelToFine(model, sx - spos.x, sy - spos.y, fpos); @@ -453,6 +473,8 @@ public class IsoUtil // toss in the tile coordinates for good measure fpos.x += (tpos.x * FULL_TILE_FACTOR); fpos.y += (tpos.y * FULL_TILE_FACTOR); + + return fpos; } /** @@ -463,14 +485,15 @@ public class IsoUtil * @param x the x-position full coordinate. * @param y the y-position full coordinate. * @param spos the point object to place coordinates in. + * + * @return the point passed in to receive the coordinates. */ - public static void fullToScreen ( + public static Point fullToScreen ( IsoSceneViewModel model, int x, int y, Point spos) { // get the tile screen position - Point tspos = new Point(); int tx = x / FULL_TILE_FACTOR, ty = y / FULL_TILE_FACTOR; - tileToScreen(model, tx, ty, tspos); + Point tspos = tileToScreen(model, tx, ty, new Point()); // get the pixel position of the fine coords within the tile Point ppos = new Point(); @@ -480,6 +503,8 @@ public class IsoUtil // final position is tile position offset by fine position spos.x = tspos.x + ppos.x; spos.y = tspos.y + ppos.y; + + return spos; } /** @@ -492,8 +517,7 @@ public class IsoUtil IsoSceneViewModel model, int x, int y) { // get the top-left screen coordinate for the tile - Point spos = new Point(); - IsoUtil.tileToScreen(model, x, y, spos); + Point spos = IsoUtil.tileToScreen(model, x, y, new Point()); // create a polygon framing the tile Polygon poly = new SmartPolygon(); @@ -516,10 +540,10 @@ public class IsoUtil Point[] p = new Point[4]; // load in all possible screen coords - IsoUtil.tileToScreen(model, sp1.x, sp1.y, p[0] = new Point()); - IsoUtil.tileToScreen(model, sp2.x, sp2.y, p[1] = new Point()); - IsoUtil.tileToScreen(model, sp1.x, sp2.y, p[2] = new Point()); - IsoUtil.tileToScreen(model, sp2.x, sp1.y, p[3] = new Point()); + p[0] = IsoUtil.tileToScreen(model, sp1.x, sp1.y, new Point()); + p[1] = IsoUtil.tileToScreen(model, sp2.x, sp2.y, new Point()); + p[2] = IsoUtil.tileToScreen(model, sp1.x, sp2.y, new Point()); + p[3] = IsoUtil.tileToScreen(model, sp2.x, sp1.y, new Point()); // locate the indexes of min/max for x and y minx = maxx = miny = maxy = 0;