diff --git a/src/java/com/threerings/media/VirtualMediaPanel.java b/src/java/com/threerings/media/VirtualMediaPanel.java index a6fa6b8ac..0856a1833 100644 --- a/src/java/com/threerings/media/VirtualMediaPanel.java +++ b/src/java/com/threerings/media/VirtualMediaPanel.java @@ -1,5 +1,5 @@ // -// $Id: VirtualMediaPanel.java,v 1.14 2003/04/12 01:26:29 mdb Exp $ +// $Id: VirtualMediaPanel.java,v 1.15 2003/04/17 19:21:16 mdb Exp $ package com.threerings.media; @@ -224,9 +224,19 @@ public class VirtualMediaPanel extends MediaPanel // between here and the call to paint() for this tick don't // booch everything _vbounds.x = _nx; _vbounds.y = _ny; + + // let derived classes react if they so desire + viewLocationDidChange(_vbounds.x, _vbounds.y); } } + /** + * Called during our tick when we have adjusted the view location. + */ + protected void viewLocationDidChange (int nx, int ny) + { + } + /** * Implements the standard pathable tracking support. Derived classes * may wish to override this if they desire custom tracking diff --git a/src/java/com/threerings/miso/MisoConfig.java b/src/java/com/threerings/miso/MisoConfig.java index 6566d5495..004f7edfe 100644 --- a/src/java/com/threerings/miso/MisoConfig.java +++ b/src/java/com/threerings/miso/MisoConfig.java @@ -1,10 +1,12 @@ // -// $Id: MisoConfig.java,v 1.1 2002/03/28 22:32:32 mdb Exp $ +// $Id: MisoConfig.java,v 1.2 2003/04/17 19:21:16 mdb Exp $ package com.threerings.miso; import com.samskivert.util.Config; +import com.threerings.miso.util.MisoSceneMetrics; + /** * Provides access to the Miso configuration. */ @@ -12,4 +14,53 @@ public class MisoConfig { /** Provides access to configuration data for this package. */ public static Config config = new Config("rsrc/config/miso/miso"); + + /** + * Creates scene metrics with information obtained from the deployed + * config file. + */ + public static MisoSceneMetrics getSceneMetrics () + { + return new MisoSceneMetrics( + config.getValue(TILE_WIDTH_KEY, DEF_TILE_WIDTH), + config.getValue(TILE_HEIGHT_KEY, DEF_TILE_HEIGHT), + config.getValue(FINE_GRAN_KEY, DEF_FINE_GRAN), + config.getValue(SCENE_VWIDTH_KEY, DEF_SCENE_VWIDTH), + config.getValue(SCENE_VHEIGHT_KEY, DEF_SCENE_VHEIGHT), + config.getValue(SCENE_OFFSET_Y_KEY, DEF_OFFSET_Y)); + } + + /** The config key for tile width in pixels. */ + protected static final String TILE_WIDTH_KEY = "tile_width"; + + /** The config key for tile height in pixels. */ + protected static final String TILE_HEIGHT_KEY = "tile_height"; + + /** The config key for tile fine coordinate granularity. */ + protected static final String FINE_GRAN_KEY = "fine_granularity"; + + /** The config key for scene view width in tile count. */ + protected static final String SCENE_VWIDTH_KEY = "scene_view_width"; + + /** The config key for scene view height in tile count. */ + protected static final String SCENE_VHEIGHT_KEY = "scene_view_height"; + + /** The config key for scene width in tile count. */ + protected static final String SCENE_WIDTH_KEY = "scene_width"; + + /** The config key for scene height in tile count. */ + protected static final String SCENE_HEIGHT_KEY = "scene_height"; + + /** The config key for scene origin vertical offset in tile count. */ + protected static final String SCENE_OFFSET_Y_KEY = "scene_offset_y"; + + /** Default scene view parameters. */ + protected static final int DEF_TILE_WIDTH = 64; + protected static final int DEF_TILE_HEIGHT = 48; + protected static final int DEF_FINE_GRAN = 4; + protected static final int DEF_SCENE_VWIDTH = 10; + protected static final int DEF_SCENE_VHEIGHT = 12; + protected static final int DEF_SCENE_WIDTH = 22; + protected static final int DEF_SCENE_HEIGHT = 22; + protected static final int DEF_OFFSET_Y = -5; } diff --git a/src/java/com/threerings/miso/client/DirtyItemList.java b/src/java/com/threerings/miso/client/DirtyItemList.java index 8fc30477c..d053bd516 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.24 2003/04/07 23:32:47 mdb Exp $ +// $Id: DirtyItemList.java,v 1.25 2003/04/17 19:21:16 mdb Exp $ package com.threerings.miso.client; @@ -13,15 +13,14 @@ import java.awt.Shape; import java.util.ArrayList; import java.util.Comparator; -import com.samskivert.util.RuntimeAdjust; 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.miso.MisoPrefs; -import com.threerings.miso.client.util.IsoUtil; /** * The dirty item list keeps track of dirty sprites and object tiles @@ -33,9 +32,8 @@ public class DirtyItemList * Creates a dirt item list that will handle dirty items for the * specified view. */ - public DirtyItemList (IsoSceneView view) + public DirtyItemList () { - _view = view; } /** @@ -49,7 +47,7 @@ public class DirtyItemList public void appendDirtySprite (Sprite sprite, int tx, int ty) { DirtyItem item = getDirtyItem(); - item.init(sprite, null, null, tx, ty); + item.init(sprite, tx, ty); _items.add(item); } @@ -58,13 +56,11 @@ public class DirtyItemList * item list. * * @param scene the scene object that is dirty. - * @param footprint the footprint of the object tile if it should be - * rendered, null otherwise. */ - public void appendDirtyObject (DisplayObjectInfo info, Shape footprint) + public void appendDirtyObject (SceneObject scobj) { DirtyItem item = getDirtyItem(); - item.init(info, info.bounds, footprint, info.x, info.y); + item.init(scobj, scobj.info.x, scobj.info.y); _items.add(item); } @@ -257,13 +253,6 @@ public class DirtyItemList /** The dirtied object; one of either a sprite or an object tile. */ public Object obj; - /** The bounds of the dirty item if it's an object tile. */ - public Rectangle bounds; - - /** The footprint of the dirty item if it's an object tile and - * we're drawing footprints. */ - public Shape footprint; - /** The origin tile coordinates. */ public int ox, oy; @@ -276,12 +265,9 @@ public class DirtyItemList /** * Initializes a dirty item. */ - public void init (Object obj, Rectangle bounds, Shape footprint, - int x, int y) + public void init (Object obj, int x, int y) { this.obj = obj; - this.bounds = bounds; - this.footprint = footprint; this.ox = x; this.oy = y; @@ -290,8 +276,8 @@ public class DirtyItemList // rightmost tiles are equivalent lx = rx = ox; ly = ry = oy; - if (obj instanceof DisplayObjectInfo) { - ObjectTile tile = ((DisplayObjectInfo)obj).tile; + if (obj instanceof SceneObject) { + ObjectTile tile = ((SceneObject)obj).tile; lx -= (tile.getBaseWidth() - 1); ry -= (tile.getBaseHeight() - 1); } @@ -304,47 +290,10 @@ public class DirtyItemList */ public void paint (Graphics2D gfx) { - // if there's a footprint, paint that - if (footprint != null) { - gfx.setColor(Color.black); - gfx.draw(footprint); - } - - // paint the item if (obj instanceof Sprite) { ((Sprite)obj).paint(gfx); - } else if (!_hideObjects.getValue()) { - ((DisplayObjectInfo)obj).tile.paint(gfx, bounds.x, bounds.y); - } - - // and paint the object's spot if it has one - if (footprint != null && obj instanceof DisplayObjectInfo) { - DisplayObjectInfo info = (DisplayObjectInfo)obj; - if (info.tile.hasSpot()) { - // get the spot's center coordinate - Point fpos = _view.getObjectSpot(info); - Point spos = _view.getScreenCoords(fpos.x, fpos.y); - - // translate the origin to center on the portal - gfx.translate(spos.x, spos.y); - - // rotate to reflect the spot orientation - double rot = (Math.PI / 4.0f) * - info.tile.getSpotOrient(); - gfx.rotate(rot); - - // draw the spot triangle - gfx.setColor(Color.green); - gfx.fill(_spotTri); - - // outline the triangle in black - gfx.setColor(Color.black); - gfx.draw(_spotTri); - - // restore the original transform - gfx.rotate(-rot); - gfx.translate(-spos.x, -spos.y); - } + } else { + ((SceneObject)obj).paint(gfx); } } @@ -363,8 +312,8 @@ public class DirtyItemList */ public int getRenderPriority () { - if (obj instanceof DisplayObjectInfo) { - return ((DisplayObjectInfo)obj).getPriority(); + if (obj instanceof SceneObject) { + return ((SceneObject)obj).getPriority(); } else { return 0; } @@ -378,7 +327,6 @@ public class DirtyItemList public void clear () { obj = null; - bounds = null; } // documentation inherited @@ -475,11 +423,11 @@ public class DirtyItemList // if the two objects are scene objects and they overlap, we // compare them solely based on their human assigned priority - if ((da.obj instanceof DisplayObjectInfo) && - (db.obj instanceof DisplayObjectInfo)) { - DisplayObjectInfo soa = (DisplayObjectInfo)da.obj; - DisplayObjectInfo sob = (DisplayObjectInfo)db.obj; - if (IsoUtil.objectFootprintsOverlap(soa, sob)) { + if ((da.obj instanceof SceneObject) && + (db.obj instanceof SceneObject)) { + SceneObject soa = (SceneObject)da.obj; + SceneObject sob = (SceneObject)db.obj; + if (soa.objectFootprintOverlaps(sob)) { int result = soa.getPriority() - sob.getPriority(); if (DEBUG_COMPARE) { String items = DirtyItemList.toString(da, db); @@ -674,9 +622,6 @@ public class DirtyItemList } } - /** The view for which we're managing dirty items. */ - protected IsoSceneView _view; - /** The list of dirty items. */ protected SortableArrayList _items = new SortableArrayList(); @@ -695,16 +640,6 @@ public class DirtyItemList /** Unused dirty items. */ protected ArrayList _freelist = new ArrayList(); - /** The triangle used to render an object's spot. */ - protected static Polygon _spotTri; - - static { - _spotTri = new Polygon(); - _spotTri.addPoint(-3, -3); - _spotTri.addPoint(3, -3); - _spotTri.addPoint(0, 3); - }; - /** Whether to log debug info when comparing pairs of dirty items. */ protected static final boolean DEBUG_COMPARE = false; @@ -733,10 +668,4 @@ public class DirtyItemList ((DirtyItem)o2).getRearDepth()); } }; - - /** A debug hook that toggles debug rendering of object footprints. */ - protected static RuntimeAdjust.BooleanAdjust _hideObjects = - new RuntimeAdjust.BooleanAdjust( - "Turns off the rendering of objects in the scene.", - "narya.miso.hide_objects", MisoPrefs.config, false); } diff --git a/src/java/com/threerings/miso/client/DisplayMisoScene.java b/src/java/com/threerings/miso/client/DisplayMisoScene.java deleted file mode 100644 index 2acfb30b6..000000000 --- a/src/java/com/threerings/miso/client/DisplayMisoScene.java +++ /dev/null @@ -1,45 +0,0 @@ -// -// $Id: DisplayMisoScene.java,v 1.12 2003/04/12 02:14:52 mdb Exp $ - -package com.threerings.miso.client; - -import com.threerings.media.tile.Tile; - -import com.threerings.miso.client.util.AStarPathUtil; -import com.threerings.miso.data.MisoScene; -import com.threerings.miso.tile.BaseTile; - -/** - * Extends the {@link MisoScene} with functionality needed only by - * entities that plan to display a miso scene. - */ -public interface DisplayMisoScene - extends MisoScene, AStarPathUtil.TraversalPred -{ - /** - * This will be called before the scene is displayed to give it a - * chance to look up its image data and prepare itself for display. - */ - public void init (); - - /** - * Returns the base tile at the specified coordinates. - */ - public BaseTile getBaseTile (int x, int y); - - /** - * Returns the fringe tile at the specified coordinates. - */ - public Tile getFringeTile (int x, int y); - - /** - * Returns true if the supplied traverser can traverse the specified - * tile coordinate. The traverser is whatever object is passed along - * to the path finder when a path is being computed. - * - *

Scene implementations which support custom traversal based on - * the type of the traverser will want to reflect the traverser's - * class and act acordingly. - */ - public boolean canTraverse (Object traverser, int x, int y); -} diff --git a/src/java/com/threerings/miso/client/DisplayObjectInfo.java b/src/java/com/threerings/miso/client/DisplayObjectInfo.java deleted file mode 100644 index 300fe7089..000000000 --- a/src/java/com/threerings/miso/client/DisplayObjectInfo.java +++ /dev/null @@ -1,87 +0,0 @@ -// -// $Id: DisplayObjectInfo.java,v 1.8 2003/02/12 05:37:19 mdb Exp $ - -package com.threerings.miso.client; - -import java.awt.Rectangle; - -import com.threerings.media.tile.ObjectTile; -import com.threerings.miso.data.ObjectInfo; - -/** - * Used to track information about an object in the scene. - */ -public class DisplayObjectInfo extends ObjectInfo -{ - /** A reference to the object tile itself. */ - public ObjectTile tile; - - /** The object's bounding rectangle. This will be filled in - * automatically by the scene view when the object is used. */ - public Rectangle bounds; - - /** - * Convenience constructor. - */ - public DisplayObjectInfo (int tileId, int x, int y) - { - super(tileId, x, y); - } - - /** - * Convenience constructor. - */ - public DisplayObjectInfo (ObjectInfo source) - { - super(source); - } - - /** - * Provides this display object with a reference to its object tile - * when it becomes available. This must be called before the tile is - * used in any sort of display circumstances. - */ - public void setObjectTile (ObjectTile tile) - { - this.tile = tile; - } - - /** - * Returns the render priority of this object tile. - */ - public int getPriority () - { - // if we have no specified priority return our object tile's - // default priority - return (priority == 0 && tile != null) ? tile.getPriority() : priority; - } - - /** - * Overrides the render priority of this object. - */ - public void setPriority (byte priority) - { - this.priority = (byte)Math.max( - Byte.MIN_VALUE, Math.min(Byte.MAX_VALUE, priority)); - } - - /** - * Indicate to the scene object that it is being hovered over. - * - * @return true if the object should be repainted. - */ - public boolean setHovered (boolean hovered) - { - return false; - } - - /** - * Handles the toString-ification of all public members. Derived - * classes can override and include non-public members if desired. - */ - protected void toString (StringBuffer buf) - { - super.toString(buf); - buf.append(", rprio=").append(getPriority()); - } -} diff --git a/src/java/com/threerings/miso/client/IsoSceneView.java b/src/java/com/threerings/miso/client/IsoSceneView.java deleted file mode 100644 index c87f8137a..000000000 --- a/src/java/com/threerings/miso/client/IsoSceneView.java +++ /dev/null @@ -1,796 +0,0 @@ -// -// $Id: IsoSceneView.java,v 1.137 2003/04/12 02:14:52 mdb Exp $ - -package com.threerings.miso.client; - -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Composite; -import java.awt.EventQueue; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Graphics; -import java.awt.Point; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.Stroke; -import java.awt.event.MouseEvent; - -import java.util.ArrayList; -import java.util.List; - -import com.samskivert.util.HashIntMap; -import com.samskivert.util.RuntimeAdjust; -import com.samskivert.util.StringUtil; - -import com.threerings.media.RegionManager; - -import com.threerings.media.sprite.Sprite; -import com.threerings.media.sprite.SpriteManager; -import com.threerings.media.util.Path; - -import com.threerings.media.tile.ObjectTile; -import com.threerings.media.tile.Tile; - -import com.threerings.miso.Log; -import com.threerings.miso.MisoPrefs; -import com.threerings.miso.client.DirtyItemList.DirtyItem; -import com.threerings.miso.client.util.AStarPathUtil; -import com.threerings.miso.client.util.IsoUtil; -import com.threerings.miso.client.util.ObjectSet; -import com.threerings.miso.tile.BaseTile; - -/** - * The iso scene view provides an isometric view of a particular scene. It - * presently supports scrolling in a limited form. Object tiles are not - * handled properly, nor is mouse highlighting. Those should only be used - * if the view will not be scrolled. - */ -public class IsoSceneView implements SceneView -{ - /** Instructs the scene view never to draw highlights around object - * tiles. */ - public static final int HIGHLIGHT_NEVER = 0; - - /** Instructs the scene view to highlight only object tiles that have - * a non-empty action string. */ - public static final int HIGHLIGHT_WITH_ACTION = 1; - - /** Instructs the scene view to highlight every object tile, - * regardless of whether it has a valid action string. */ - public static final int HIGHLIGHT_ALWAYS = 2; - - /** Instructs the scene view to highlight whatever tile the mouse is - * over, regardless of whether or not it is an object tile. This is - * generally only useful in an editor rather than a game. */ - public static final int HIGHLIGHT_ALL = 3; - - /** - * Constructs an iso scene view. - * - * @param spritemgr the sprite manager. - * @param model the data model. - * @param remgr the region manager that is collecting invalid regions - * for this view. - */ - public IsoSceneView (SpriteManager spritemgr, IsoSceneViewModel model, - RegionManager remgr) - { - // save off references - _spritemgr = spritemgr; - _model = model; - _remgr = remgr; - - // handy rectangle - _tbounds = new Rectangle(0, 0, _model.tilewid, _model.tilehei); - } - - /** - * Configures the scene view to highlight object tiles either never - * ({@link #HIGHLIGHT_NEVER}), only when an object tile has an - * associated action string ({@link #HIGHLIGHT_WITH_ACTION}), or - * always ({@link #HIGHLIGHT_ALWAYS}). It is also possible to - * configure the view to highlight whatever tile is under the cursor, - * even if it's not an object tile which is done in the {@link - * #HIGHLIGHT_ALL} mode. - */ - public void setHighlightMode (int hmode) - { - _hmode = hmode; - } - - // documentation inherited - public void setScene (DisplayMisoScene scene) - { - _scene = scene; - _scene.init(); - - // obtain a list of the objects in the scene and generate records - // for each of them that contain precomputed metrics - refreshObjectList(); - - // invalidate the entire screen as there's a new scene in town; - // making sure we're on the AWT thread - if (EventQueue.isDispatchThread()) { - invalidate(); - } else { - EventQueue.invokeLater(new Runnable() { - public void run () { - invalidate(); - } - }); - } - } - - /** - * Big fat HACKola: checks the display scene for new objects that - * weren't there last time around and adds info for them into the - * scene. - */ - public void refreshObjectList () - { - _objects.clear(); - - // grab all available objects - Rectangle rect = new Rectangle(Short.MIN_VALUE, Short.MIN_VALUE, - 2*Short.MAX_VALUE, 2*Short.MAX_VALUE); - _scene.getObjects(rect, _objects); - addAdditionalObjects(_objects); - - // and fill in the new objects' bounds - int ocount = _objects.size(); - for (int ii = 0; ii < ocount; ii++) { - DisplayObjectInfo scobj = (DisplayObjectInfo)_objects.get(ii); - if (scobj.bounds == null) { - scobj.bounds = IsoUtil.getObjectBounds(_model, scobj); - } - } - } - - // documentation inherited - public DisplayMisoScene getScene () - { - return _scene; - } - - /** - * Invalidate the entire visible scene view. - */ - public void invalidate () - { - _remgr.invalidateRegion(_model.bounds); - } - - /** - * Returns the location associated with the specified object's "spot" - * in fine coordinates or null if the object has no spot. - */ - public Point getObjectSpot (DisplayObjectInfo info) - { - if (info.tile.hasSpot()) { - return IsoUtil.tilePlusFineToFull( - _model, info.x, info.y, info.tile.getSpotX(), - info.tile.getSpotY(), new Point()); - } else { - return null; - } - } - - // documentation inherited from interface - public void paint (Graphics2D gfx, Rectangle dirtyRect) - { - if (_scene == null) { - Log.warning("Scene view painted with null scene."); - return; - } - - // render any intersecting tiles - renderTiles(gfx, dirtyRect); - - // render anything that goes on top of the tiles - renderBaseDecorations(gfx, dirtyRect); - - // render our dirty sprites and objects - renderDirtyItems(gfx, dirtyRect); - - // draw sprite paths - if (_pathsDebug.getValue()) { - _spritemgr.renderSpritePaths(gfx); - } - - // paint our highlighted tile (if any) - paintHighlights(gfx, dirtyRect); - - // paint any extra goodies - paintExtras(gfx, dirtyRect); - } - - /** - * Paints the highlighted tile. - * - * @param gfx the graphics context. - */ - protected void paintHighlights (Graphics2D gfx, Rectangle clip) - { - // if we're not highlighting anything, bail now - if (_hmode == HIGHLIGHT_NEVER) { - return; - } - - Polygon hpoly = null; - - // if we have a hover object, do some business - if (_hobject != null && _hobject instanceof DisplayObjectInfo) { - DisplayObjectInfo scobj = (DisplayObjectInfo)_hobject; - if (scobj.action != null || _hmode == HIGHLIGHT_ALWAYS) { - hpoly = IsoUtil.getObjectFootprint(_model, scobj); - } - } - - // if we had no valid hover object, but we're in HIGHLIGHT_ALWAYS, - // go for the tile outline - if (hpoly == null && _hmode == HIGHLIGHT_ALWAYS) { - hpoly = IsoUtil.getTilePolygon(_model, _hcoords.x, _hcoords.y); - } - - if (hpoly != null) { - // set the desired stroke and color - Stroke ostroke = gfx.getStroke(); - gfx.setStroke(_hstroke); - gfx.setColor(Color.green); - - // draw the outline - gfx.draw(hpoly); - - // restore the original stroke - gfx.setStroke(ostroke); - } - } - - /** - * A function where derived classes can paint extra stuff while we've - * got the clipping region set up. - */ - protected void paintExtras (Graphics2D gfx, Rectangle clip) - { - // nothing for now - } - - /** - * Renders the base and fringe layer tiles that intersect the - * specified clipping rectangle. - */ - protected void renderTiles (Graphics2D gfx, Rectangle clip) - { - // if we're showing coordinates, we need to do some setting up - int thw = 0, thh = 0, fhei = 0; - FontMetrics fm = null; - if (_coordsDebug.getValue()) { - fm = gfx.getFontMetrics(_font); - fhei = fm.getAscent(); - thw = _model.tilehwid; - thh = _model.tilehhei; - gfx.setFont(_font); - } - - // 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 - - // 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 - try { - Tile tile; - boolean passable = true; - - if ((tile = _scene.getBaseTile(tx, ty)) != null) { - tile.paint(gfx, _tbounds.x, _tbounds.y); - passable = ((BaseTile)tile).isPassable(); - - // highlight impassable tiles - if (_traverseDebug.getValue() && !passable) { - fillTile(gfx, tx, ty, Color.yellow); - } - - } else { - // draw black where there are no tiles - Polygon poly = IsoUtil.getTilePolygon(_model, tx, ty); - gfx.setColor(Color.black); - gfx.fill(poly); - } - - if ((tile = _scene.getFringeTile(tx, ty)) != null) { - tile.paint(gfx, _tbounds.x, _tbounds.y); - } - - // highlight passable non-traversable tiles - if (_traverseDebug.getValue() && passable && - !_scene.canTraverse(null, tx, ty)) { - fillTile(gfx, tx, ty, Color.green); - } - - } 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 (_coordsDebug.getValue()) { - gfx.setColor(Color.white); - - // get the top-left screen coordinates of the tile - int sx = _tbounds.x, sy = _tbounds.y; - - // draw x-coordinate - 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(ty); - xpos = sx + thw - (fm.stringWidth(str) / 2); - gfx.drawString(str, xpos, sy + thh + fhei); - - // draw the tile polygon as well - gfx.draw(IsoUtil.getTilePolygon(_model, tx, ty)); - } - - // 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); - } - } - - /** - * Fills the specified tile with the given color at 50% alpha. - * Intended for debug-only tile highlighting purposes. - */ - protected void fillTile ( - Graphics2D gfx, int tx, int ty, Color color) - { - Composite ocomp = gfx.getComposite(); - gfx.setComposite(ALPHA_FILL_TILE); - Polygon poly = IsoUtil.getTilePolygon(_model, tx, ty); - gfx.setColor(color); - gfx.fill(poly); - gfx.setComposite(ocomp); - } - - /** - * A function where derived classes can paint things after the base - * tiles have been rendered but before anything else has been rendered - * (so that whatever is painted appears to be on the ground). - */ - protected void renderBaseDecorations (Graphics2D gfx, Rectangle clip) - { - // nothing for now - } - - /** - * Renders the dirty sprites and objects in the scene to the given - * graphics context. - */ - protected void renderDirtyItems (Graphics2D gfx, Rectangle 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++) { - Sprite sprite = (Sprite)_dirtySprites.get(ii); - Rectangle bounds = sprite.getBounds(); - if (!bounds.intersects(clip)) { - continue; - } - appendDirtySprite(_dirtyItems, sprite); - // Log.info("Dirtied item: " + sprite); - } - - // add any objects impacted by the dirty rectangle - int ocount = _objects.size(); - for (int ii = 0; ii < ocount; ii++) { - DisplayObjectInfo scobj = (DisplayObjectInfo)_objects.get(ii); - if (!scobj.bounds.intersects(clip)) { - continue; - } - - // compute the footprint if we're rendering those - Polygon foot = null; - if (_fprintDebug.getValue()) { - foot = IsoUtil.getObjectFootprint(_model, scobj); - } - - _dirtyItems.appendDirtyObject(scobj, foot); - // Log.info("Dirtied item: Object(" + - // scobj.x + ", " + scobj.y + ")"); - } - -// Log.info("renderDirtyItems [items=" + _dirtyItems.size() + "]."); - - // sort the dirty sprites and objects visually back-to-front; - // paint them and be done - _dirtyItems.sort(); - _dirtyItems.paintAndClear(gfx); - } - - /** - * Computes the tile coordinates of the supplied sprite and appends it - * to the supplied dirty item list. - */ - protected void appendDirtySprite (DirtyItemList list, Sprite sprite) - { - IsoUtil.screenToTile(_model, sprite.getX(), sprite.getY(), _tcoords); - list.appendDirtySprite(sprite, _tcoords.x, _tcoords.y); - } - - /** - * A place for subclasses to add any additional scene objects they - * may have. - */ - protected void addAdditionalObjects (ObjectSet set) - { - // nothing by default - } - - // documentation inherited - public Path getPath (Sprite sprite, int x, int y) - { - // make sure we have a scene - if (_scene == null) { - return null; - } - - // get the destination tile coordinates - Point src = IsoUtil.screenToTile( - _model, sprite.getX(), sprite.getY(), new Point()); - Point dest = IsoUtil.screenToTile(_model, x, y, new Point()); - - // TODO: compute this value from the screen size or something - int longestPath = 50; - - // get a reasonable tile path through the scene - List points = AStarPathUtil.getPath( - _scene, sprite, longestPath, src.x, src.y, dest.x, dest.y); - - // construct a path object to guide the sprite on its merry way - return (points == null) ? null : - new TilePath(_model, sprite, points, x, y); - } - - // documentation inherited - public Point getScreenCoords (int x, int y) - { - return IsoUtil.fullToScreen(_model, x, y, new Point()); - } - - // documentation inherited - public Point getFullCoords (int x, int y) - { - return IsoUtil.screenToFull(_model, x, y, new Point()); - } - - // documentation inherited - public Point getTileCoords (int x, int y) - { - return IsoUtil.screenToTile(_model, x, y, new Point()); - } - - // documentation inherited - public boolean mouseMoved (MouseEvent e) - { - int x = e.getX(), y = e.getY(); - boolean repaint = false; - - // update the mouse's tile coordinates - boolean newtile = updateTileCoords(x, y, _hcoords); - // if we're highlighting base tiles, we may need to repaint - if (_hmode == HIGHLIGHT_ALL) { - repaint = (newtile || repaint); - } - - // compute the list of objects over which the mouse is hovering - 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++) { - Sprite sprite = (Sprite)_hitSprites.get(i); - appendDirtySprite(_hitList, sprite); - } - - // add the object tiles that contain the point - getHitObjects(_hitList, x, y); - - // sort the list of hit items by rendering order - _hitList.sort(); - - // the last element in the array is what we want (assuming there - // are any items in the array) - int icount = _hitList.size(); - if (icount > 0) { - DirtyItem item = (DirtyItem)_hitList.get(icount-1); - hobject = item.obj; - } - - repaint |= changeHoverObject(hobject); - - // clear out the hitlists - _hitList.clear(); - _hitSprites.clear(); - - return repaint; - } - - /** - * Change the hover object to the new object. - * - * @return true if we need to repaint the entire scene. Bah! - */ - protected boolean changeHoverObject (Object newHover) - { - if (newHover == _hobject) { - return false; // no change, no repaint - } - - // unhover the old - if (_hobject instanceof DisplayObjectInfo) { - DisplayObjectInfo oldhov = (DisplayObjectInfo) _hobject; - if (oldhov.setHovered(false)) { - _remgr.invalidateRegion(oldhov.bounds); - } - } - - hoverObjectChanged(_hobject, newHover); - // set the new - _hobject = newHover; - - // hover the new - if (_hobject instanceof DisplayObjectInfo) { - DisplayObjectInfo newhov = (DisplayObjectInfo) _hobject; - if (newhov.setHovered(true)) { - _remgr.invalidateRegion(newhov.bounds); - } - } - - return (_hmode != HIGHLIGHT_NEVER); - } - - /** - * A place for subclasses to react to the hover object changing. - * One of the supplied arguments may be null. - */ - protected void hoverObjectChanged (Object oldHover, Object newHover) - { - // nothing by default - } - - /** - * Adds to the supplied dirty item list, all of the object tiles that - * are hit by the specified point (meaning the point is contained - * within their bounds and intersects a non-transparent pixel in the - * actual object image. - */ - protected void getHitObjects (DirtyItemList list, int x, int y) - { - int ocount = _objects.size(); - for (int ii = 0; ii < ocount; ii++) { - DisplayObjectInfo scobj = (DisplayObjectInfo)_objects.get(ii); - Rectangle pbounds = scobj.bounds; - // skip bounding rects that don't contain the point - if (!pbounds.contains(x, y)) { - continue; - } - - // now check that the pixel in the tile image is - // non-transparent at that point - if (!scobj.tile.hitTest(x - pbounds.x, y - pbounds.y)) { - continue; - } - - // we've passed the test, add the object to the list - list.appendDirtyObject(scobj, null); - } - } - - // documentation inherited - public void mouseExited (MouseEvent e) - { - // clear the highlight tracking data - _hcoords.setLocation(-1, -1); - changeHoverObject(null); - } - - // documentation inherited - public Object getHoverObject () - { - return _hobject; - } - - /** - * Returns the tile coordinates of the tile over which the mouse is - * hovering. - */ - public Point getHoverCoords () - { - return _hcoords; - } - - /** - * Converts the supplied screen coordinates into tile coordinates, - * writing the values into the supplied {@link Point} instance and - * returning true if the screen coordinates translated into a - * different set of tile coordinates than were already contained in - * the point (so that the caller can know to update a highlight, for - * example). - * - * @return true if the tile coordinates have changed. - */ - protected boolean updateTileCoords (int sx, int sy, Point tpos) - { - 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)) { - tpos.setLocation(npos.x, npos.y); - return true; - - } else { - return false; - } - } - - /** The sprite manager. */ - protected SpriteManager _spritemgr; - - /** The scene view model data. */ - protected IsoSceneViewModel _model; - - /** Our region manager. */ - protected RegionManager _remgr; - - /** The scene to be displayed. */ - protected DisplayMisoScene _scene; - - /** Information for all of the objects visible in the scene. */ - protected ObjectSet _objects = new ObjectSet(); - - /** The dirty sprites and objects that need to be re-painted. */ - protected DirtyItemList _dirtyItems = new DirtyItemList(this); - - /** The working sprites list used when calculating dirty regions. */ - protected ArrayList _dirtySprites = new ArrayList(); - - /** Used when rendering tiles. */ - protected Rectangle _tbounds; - - /** Used when dirtying sprites. */ - protected Point _tcoords = new Point(); - - /** Used to collect the list of sprites "hit" by a particular mouse - * location. */ - protected List _hitSprites = new ArrayList(); - - /** The list that we use to track and sort the items over which the - * mouse is hovering. */ - protected DirtyItemList _hitList = new DirtyItemList(this); - - /** The highlight mode. */ - protected int _hmode = HIGHLIGHT_NEVER; - - /** Info on the object that the mouse is currently hovering over. */ - protected Object _hobject; - - /** Used to track the tile coordinates over which the mouse is hovering. */ - protected Point _hcoords = new Point(); - - /** The font to draw tile coordinates. */ - protected Font _font = new Font("Arial", Font.PLAIN, 7); - - /** The stroke object used to draw highlighted tiles and coordinates. */ - protected BasicStroke _hstroke = new BasicStroke(2); - - /** A debug hook that toggles debug rendering of traversable tiles. */ - protected static RuntimeAdjust.BooleanAdjust _traverseDebug = - new RuntimeAdjust.BooleanAdjust( - "Toggles debug rendering of traversable and impassable tiles in " + - "the iso scene view.", "narya.miso.iso_traverse_debug_render", - MisoPrefs.config, false); - - /** A debug hook that toggles debug rendering of tile coordinates. */ - protected static RuntimeAdjust.BooleanAdjust _coordsDebug = - new RuntimeAdjust.BooleanAdjust( - "Toggles debug rendering of tile coordinates in the iso scene " + - "view.", "narya.miso.iso_coords_debug_render", - MisoPrefs.config, false); - - /** A debug hook that toggles debug rendering of sprite paths. */ - protected static RuntimeAdjust.BooleanAdjust _pathsDebug = - new RuntimeAdjust.BooleanAdjust( - "Toggles debug rendering of sprite paths in the iso scene view.", - "narya.miso.iso_paths_debug_render", MisoPrefs.config, false); - - /** A debug hook that toggles debug rendering of object footprints. */ - protected static RuntimeAdjust.BooleanAdjust _fprintDebug = - new RuntimeAdjust.BooleanAdjust( - "Toggles debug rendering of object footprints in the iso scene " + - "view.", "narya.miso.iso_fprint_debug_render", - MisoPrefs.config, false); - - /** The stroke used to draw dirty rectangles. */ - protected static final Stroke DIRTY_RECT_STROKE = new BasicStroke(2); - - /** The alpha used to fill tiles for debugging purposes. */ - protected static final Composite ALPHA_FILL_TILE = - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); -} diff --git a/src/java/com/threerings/miso/client/IsoSceneViewModel.java b/src/java/com/threerings/miso/client/IsoSceneViewModel.java deleted file mode 100644 index 04e33cf28..000000000 --- a/src/java/com/threerings/miso/client/IsoSceneViewModel.java +++ /dev/null @@ -1,222 +0,0 @@ -// -// $Id: IsoSceneViewModel.java,v 1.29 2003/04/12 02:14:52 mdb Exp $ - -package com.threerings.miso.client; - -import java.awt.Point; -import java.awt.Rectangle; - -import com.threerings.miso.Log; -import com.threerings.miso.MisoConfig; -import com.threerings.miso.client.util.IsoUtil; - -/** - * Provides a holding place for the myriad parameters and bits of data - * that describe the details of an isometric view of a scene. - * - *

The member data are public to facilitate speedy referencing by the - * {@link IsoSceneView} class. The model should only be modified through - * the configuration data provided via {@link MisoConfig} and the accessor - * methods. - */ -public class IsoSceneViewModel -{ - /** Tile dimensions and half-dimensions in the view. */ - public int tilewid, tilehei, tilehwid, tilehhei; - - /** Fine coordinate dimensions. */ - public int finehwid, finehhei; - - /** Number of fine coordinates on each axis within a tile. */ - public int finegran; - - /** Size of the view in tile count. */ - public int scenevwid, scenevhei; - - /** Whether or not this view can extend beyond the bounds defined by - * the view width and height. True if it cannot, false if it can. */ - public boolean bounded = false; - - /** 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; - - /** The length of a tile edge in pixels. */ - public float tilelen; - - /** The slope of the x- and y-axis lines. */ - public float slopeX, slopeY; - - /** The length between fine coordinates in pixels. */ - public float finelen; - - /** The y-intercept of the x-axis line within a tile. */ - public float fineBX; - - /** The slope of the x- and y-axis lines within a tile. */ - public float fineSlopeX, fineSlopeY; - - /** - * Construct an iso scene view model with view parameters as - * specified in the given config object. - * - * @param config the config object. - */ - public IsoSceneViewModel () - { - // and the view dimensions - scenevwid = MisoConfig.config.getValue( - SCENE_VWIDTH_KEY, DEF_SCENE_VWIDTH); - scenevhei = MisoConfig.config.getValue( - SCENE_VHEIGHT_KEY, DEF_SCENE_VHEIGHT); - - // get the tile dimensions - tilewid = MisoConfig.config.getValue(TILE_WIDTH_KEY, DEF_TILE_WIDTH); - tilehei = MisoConfig.config.getValue(TILE_HEIGHT_KEY, DEF_TILE_HEIGHT); - - // set the fine coordinate granularity - finegran = MisoConfig.config.getValue(FINE_GRAN_KEY, DEF_FINE_GRAN); - - // precalculate various things - int offy = MisoConfig.config.getValue(SCENE_OFFSET_Y_KEY, DEF_OFFSET_Y); - precalculate(offy); - } - - /** - * Constructs an iso scene view model by directly specifying the - * desired scene configuration parameters. - * - * @param scenewid the total scene width in tiles. - * @param scenehei the total scene height in tiles. - * @param tilewid the width in pixels of the tiles. - * @param tilehei the height in pixels of the tiles. - * @param finegran the number of sub-tile divisions to use for fine - * coordinates. - * @param svwid the width in tiles of the viewport. - * @param svhei the height in tiles of the viewport. - * @param offy the offset of the origin (in tiles) from the top of the - * viewport. - */ - public IsoSceneViewModel (int scenewid, int scenehei, - int tilewid, int tilehei, int finegran, - int svwid, int svhei, int offy) - { - // keep track of this stuff - this.tilewid = tilewid; - this.tilehei = tilehei; - this.finegran = finegran; - this.scenevwid = svwid; - this.scenevhei = svhei; - - // let our flags default to false - - // precalculate various things - precalculate(offy); - } - - /** - * Returns whether the given tile coordinate is a valid coordinate in - * our coordinate system (which allows tile coordinates from 0 to - * 2^15-1). - */ - public boolean isCoordinateValid (int x, int y) - { - return (x >= 0 && x < Short.MAX_VALUE && - y >= 0 && y < Short.MAX_VALUE); - } - - /** - * Returns whether the given full coordinate is a valid coordinate - * within the scene. - */ - 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 (isCoordinateValid(tx, ty) && - fx >= 0 && fx < finegran && - fy >= 0 && fy < finegran); - } - - /** - * Pre-calculate various member data that are commonly used in working - * with an isometric view. - */ - protected void precalculate (int offy) - { - // set the desired scene view bounds - bounds = new Rectangle(0, 0, scenevwid * tilewid, scenevhei * tilehei); - - // set the scene display origin - origin = new Point((bounds.width / 2), (offy * tilehei)); - - // pre-calculate tile-related data - precalculateTiles(); - - // calculate the edge length separating each fine coordinate - finelen = tilelen / (float)finegran; - - // calculate the fine-coordinate x-axis line - fineSlopeX = (float)tilehei / (float)tilewid; - fineBX = -(fineSlopeX * (float)tilehwid); - fineSlopeY = -fineSlopeX; - - // calculate the fine coordinate dimensions - finehwid = (int)((float)tilehwid / (float)finegran); - finehhei = (int)((float)tilehhei / (float)finegran); - } - - /** - * Pre-calculate various tile-related member data. - */ - protected void precalculateTiles () - { - // halve the dimensions - tilehwid = (tilewid / 2); - tilehhei = (tilehei / 2); - - // calculate the length of a tile edge in pixels - tilelen = (float) Math.sqrt( - (tilehwid * tilehwid) + (tilehhei * tilehhei)); - - // calculate the slope of the x- and y-axis lines - slopeX = (float)tilehei / (float)tilewid; - slopeY = -slopeX; - } - - /** The config key for tile width in pixels. */ - protected static final String TILE_WIDTH_KEY = "tile_width"; - - /** The config key for tile height in pixels. */ - protected static final String TILE_HEIGHT_KEY = "tile_height"; - - /** The config key for tile fine coordinate granularity. */ - protected static final String FINE_GRAN_KEY = "fine_granularity"; - - /** The config key for scene view width in tile count. */ - protected static final String SCENE_VWIDTH_KEY = "scene_view_width"; - - /** The config key for scene view height in tile count. */ - protected static final String SCENE_VHEIGHT_KEY = "scene_view_height"; - - /** The config key for scene width in tile count. */ - protected static final String SCENE_WIDTH_KEY = "scene_width"; - - /** The config key for scene height in tile count. */ - protected static final String SCENE_HEIGHT_KEY = "scene_height"; - - /** The config key for scene origin vertical offset in tile count. */ - protected static final String SCENE_OFFSET_Y_KEY = "scene_offset_y"; - - /** Default scene view parameters. */ - protected static final int DEF_TILE_WIDTH = 64; - protected static final int DEF_TILE_HEIGHT = 48; - protected static final int DEF_FINE_GRAN = 4; - protected static final int DEF_SCENE_VWIDTH = 10; - protected static final int DEF_SCENE_VHEIGHT = 12; - protected static final int DEF_SCENE_WIDTH = 22; - protected static final int DEF_SCENE_HEIGHT = 22; - protected static final int DEF_OFFSET_Y = -5; -} diff --git a/src/java/com/threerings/miso/client/MisoScenePanel.java b/src/java/com/threerings/miso/client/MisoScenePanel.java new file mode 100644 index 000000000..923992ad2 --- /dev/null +++ b/src/java/com/threerings/miso/client/MisoScenePanel.java @@ -0,0 +1,1420 @@ +// +// $Id: MisoScenePanel.java,v 1.1 2003/04/17 19:21:16 mdb Exp $ + +package com.threerings.miso.client; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Composite; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.Stroke; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; + +import javax.swing.Icon; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Random; + +import com.samskivert.swing.Controller; +import com.samskivert.swing.RadialMenu; +import com.samskivert.util.HashIntMap; +import com.samskivert.util.RuntimeAdjust; +import com.samskivert.util.StringUtil; + +import com.threerings.media.VirtualMediaPanel; +import com.threerings.media.sprite.Sprite; +import com.threerings.media.tile.Tile; +import com.threerings.media.tile.TileManager; +import com.threerings.media.tile.TileSet; +import com.threerings.media.util.Path; + +import com.threerings.miso.Log; +import com.threerings.miso.MisoPrefs; +import com.threerings.miso.client.DirtyItemList.DirtyItem; +import com.threerings.miso.data.MisoSceneModel; +import com.threerings.miso.data.ObjectInfo; +import com.threerings.miso.tile.BaseTile; +import com.threerings.miso.util.AStarPathUtil; +import com.threerings.miso.util.MisoContext; +import com.threerings.miso.util.MisoSceneMetrics; +import com.threerings.miso.util.MisoUtil; +import com.threerings.miso.util.ObjectSet; + +/** + * Renders a Miso scene for all to see. + */ +public class MisoScenePanel extends VirtualMediaPanel + implements MouseListener, MouseMotionListener, AStarPathUtil.TraversalPred, + RadialMenu.Host +{ + /** Instructs the scene view never to draw highlights around object + * tiles. */ + public static final int HIGHLIGHT_NEVER = 0; + + /** Instructs the scene view to highlight only object tiles that have + * a non-empty action string. */ + public static final int HIGHLIGHT_WITH_ACTION = 1; + + /** Instructs the scene view to highlight every object tile, + * regardless of whether it has a valid action string. */ + public static final int HIGHLIGHT_ALWAYS = 2; + + /** Instructs the scene view to highlight whatever tile the mouse is + * over, regardless of whether or not it is an object tile. This is + * generally only useful in an editor rather than a game. */ + public static final int HIGHLIGHT_ALL = 3; + + /** Show flag that indicates we should show all tips. */ + public static final int SHOW_TIPS = (1 << 0); + + /** Show flag that indicates we should show everything. */ + public static final int SHOW_ALL = 0xFFFFFF; + + /** + * Creates a blank miso scene display. Configure it with a scene model + * via {@link #setSceneModel} to cause it to display something. + */ + public MisoScenePanel (MisoContext ctx, MisoSceneMetrics metrics) + { + super(ctx.getFrameManager()); + _ctx = ctx; + _metrics = metrics; + + // set ourselves up + setOpaque(true); + addMouseListener(this); + addMouseMotionListener(this); + + // handy rectangle + _tbounds = new Rectangle(0, 0, _metrics.tilewid, _metrics.tilehei); + } + + /** + * Configures the scene view to highlight object tiles either never + * ({@link #HIGHLIGHT_NEVER}), only when an object tile has an + * associated action string ({@link #HIGHLIGHT_WITH_ACTION}), or + * always ({@link #HIGHLIGHT_ALWAYS}). It is also possible to + * configure the view to highlight whatever tile is under the cursor, + * even if it's not an object tile which is done in the {@link + * #HIGHLIGHT_ALL} mode. + */ + public void setHighlightMode (int hmode) + { + _hmode = hmode; + } + + /** + * Configures this display with a scene model which will immediately + * be resolved and displayed. + */ + public void setSceneModel (MisoSceneModel model) + { + _model = model; + + // clear out old blocks and objects + _blocks.clear(); + _vizobjs.clear(); + _masks.clear(); + + // this will cause us to relayout which will center us in the + // middle of the scene which will cause us to rethink and load up + // all the necessary scene blocks to display ourselves; magic! + revalidate(); + } + + /** + * Returns the scene model being displayed by this panel. Do + * not modify! + */ + public MisoSceneModel getSceneModel () + { + return _model; + } + + /** + * Returns the scene metrics in use by this panel. Do not + * modify! + */ + public MisoSceneMetrics getSceneMetrics () + { + return _metrics; + } + + /** + * Set whether or not to highlight object tooltips (and potentially + * other scene entities). + */ + public void setShowFlags (int flags, boolean on) + { + int oldshow = _showFlags; + + if (on) { + _showFlags |= flags; + } else { + _showFlags &= ~flags; + } + + if (oldshow != _showFlags) { + showFlagsDidChange(oldshow); + } + } + + /** + * Check to see if the specified show flag is on. + */ + public boolean checkShowFlag (int flag) + { + return (0 != (flag & _showFlags)); + } + + /** + * Called when our show flags have changed. + */ + protected void showFlagsDidChange (int oldflags) + { + if ((oldflags & SHOW_TIPS) != (_showFlags & SHOW_TIPS)) { + for (Iterator iter = _tips.values().iterator(); iter.hasNext(); ) { + dirtyTip((SceneObjectTip)iter.next()); + } + } + } + + /** + * Returns the top-most object over which the mouse is hovering; this + * may be a sprite or a {@link SceneObject}. + */ + public Object getHoverObject () + { + return _hobject; + } + + /** + * Returns the tile coordinates of the tile over which the mouse is + * hovering. + */ + public Point getHoverCoords () + { + return _hcoords; + } + + /** + * Computes a path for the specified sprite to the specified tile + * coordinates. + */ + public Path getPath (Sprite sprite, int x, int y) + { + // get the destination tile coordinates + Point src = MisoUtil.screenToTile( + _metrics, sprite.getX(), sprite.getY(), new Point()); + Point dest = MisoUtil.screenToTile(_metrics, x, y, new Point()); + + // TODO: compute this value from the screen size or something + int longestPath = 50; + + // get a reasonable tile path through the scene + List points = AStarPathUtil.getPath( + this, sprite, longestPath, src.x, src.y, dest.x, dest.y); + + // construct a path object to guide the sprite on its merry way + return (points == null) ? null : + new TilePath(_metrics, sprite, points, x, y); + } + + /** + * Converts the supplied full coordinates to screen coordinates. + */ + public Point getScreenCoords (int x, int y) + { + return MisoUtil.fullToScreen(_metrics, x, y, new Point()); + } + + /** + * Coverts the supplied screen coordinates to full coordinates. + */ + public Point getFullCoords (int x, int y) + { + return MisoUtil.screenToFull(_metrics, x, y, new Point()); + } + + /** + * Coverts the supplied screen coordinates to tile coordinates. + */ + public Point getTileCoords (int x, int y) + { + return MisoUtil.screenToTile(_metrics, x, y, new Point()); + } + + /** + * Clears any radial menu being displayed. + */ + public void clearRadialMenu () + { + if (_activeMenu != null) { + _activeMenu.deactivate(); + } + } + +// // documentation inherited from interface +// public void setBaseTile (int fqTileId, int x, int y) +// { +// _model.setBaseTile(x, y, fqTileId); +// populateBaseTile(fqTileId, x, y); + +// // setting a base tile has the side-effect of clearing out the +// // surrounding fringe tiles. +// for (int xx=Math.max(x - 1, 0), +// xn=Math.min(x + 1, _model.width - 1); xx <= xn; xx++) { +// for (int yy=Math.max(y - 1, 0), +// yn=Math.min(y + 1, _model.height - 1); yy <= yn; yy++) { +// _fringe[yy * _model.width + xx] = null; +// } +// } +// } + + // documentation inherited from interface + public void mouseClicked (MouseEvent e) + { + // nothing doing + } + + // documentation inherited from interface + public void mousePressed (MouseEvent e) + { + // if this was not the first button, treat it as a cancellation of + // whatever might be going on + if (e.getButton() != MouseEvent.BUTTON1) { + return; + } + + // ignore mouse presses if we're not responsive + if (!isResponsive()) { + return; + } + + if (_hobject instanceof Sprite) { + handleSpritePressed((Sprite)_hobject, e.getX(), e.getY()); + } else if (_hobject instanceof SceneObject) { + handleObjectPressed((SceneObject)_hobject, e.getX(), e.getY()); + } else { + handleMousePressed(_hobject, e.getX(), e.getY()); + } + } + + /** + * Called when the user presses the mouse button over a sprite. + */ + protected void handleSpritePressed (Sprite sprite, int mx, int my) + { + } + + /** + * Called when the user presses the mouse button over an object. + */ + protected void handleObjectPressed (final SceneObject scobj, int mx, int my) + { + String action = scobj.info.action; + final ObjectActionHandler handler = ObjectActionHandler.lookup(action); + + // if there's no handler, just fire the action immediately + if (handler == null) { + fireObjectAction(null, scobj, new ActionEvent(this, 0, action, 0)); + return; + } + + // if the action's not allowed, pretend like we handled it + if (!handler.actionAllowed(action)) { + return; + } + + // if there's no menu for this object, fire the action immediately + RadialMenu menu = handler.handlePressed(scobj); + if (menu == null) { + fireObjectAction(handler, scobj, + new ActionEvent(this, 0, action, 0)); + return; + } + + // make the menu surround the clicked object, but don't go crazy + // if the object is huge + Rectangle mbounds = new Rectangle(scobj.bounds); + if (mbounds.width > 100) { + mbounds.x += (mbounds.width-100)/2; + mbounds.width = 100; + } + if (mbounds.height > 100) { + mbounds.y += (mbounds.height-100)/2; + mbounds.height = 100; + } + + _activeMenu = menu; + _activeMenu.addActionListener(new ActionListener() { + public void actionPerformed (ActionEvent e) { + fireObjectAction(handler, scobj, e); + } + }); + _activeMenu.activate(this, mbounds, scobj); + } + + /** + * Called when an object or object menu item has been clicked. + */ + protected void fireObjectAction ( + ObjectActionHandler handler, SceneObject scobj, ActionEvent event) + { + if (handler == null) { + Controller.postAction(event); + } else { + handler.handleAction(scobj, event); + } + } + + /** + * Called when the mouse is pressed over an unknown or non-existent + * hover object. + * + * @param hobject the hover object at the time of the mouse press or + * null if no hover object is active. + * + * @return true if the mouse press was handled, false if not. + */ + protected boolean handleMousePressed (Object hobject, int mx, int my) + { + return false; + } + + // documentation inherited from interface + public void mouseReleased (MouseEvent e) + { + // nothing doing; everything is handled on pressed + } + + // documentation inherited from interface + public void mouseEntered (MouseEvent e) + { + // nothing doing + } + + // documentation inherited from interface + public void mouseExited (MouseEvent e) + { + // clear the highlight tracking data + _hcoords.setLocation(-1, -1); + changeHoverObject(null); + repaint(); + } + + // documentation inherited from interface + public void mouseDragged (MouseEvent e) + { + // nothing doing + } + + // documentation inherited from interface + public void mouseMoved (MouseEvent e) + { + int x = e.getX(), y = e.getY(); + boolean repaint = false; + + // update the mouse's tile coordinates + boolean newtile = updateTileCoords(x, y, _hcoords); + // if we're highlighting base tiles, we may need to repaint + if (_hmode == HIGHLIGHT_ALL) { + repaint = (newtile || repaint); + } + + // stop now if we're not responsive + if (!isResponsive()) { + return; + } + + // give derived classes a chance to start with a hover object + Object hobject = computeOverHover(x, y); + + // if they came up with nothing, compute the list of objects over + // which the mouse is hovering + if (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++) { + Sprite sprite = (Sprite)_hitSprites.get(i); + appendDirtySprite(_hitList, sprite); + } + + // add the object tiles that contain the point + getHitObjects(_hitList, x, y); + + // sort the list of hit items by rendering order + _hitList.sort(); + + // the last element in the array is what we want (assuming + // there are any items in the array) + int icount = _hitList.size(); + if (icount > 0) { + DirtyItem item = (DirtyItem)_hitList.get(icount-1); + hobject = item.obj; + } + } + + // if the user isn't hovering over a sprite or object with an + // action, allow derived classes to provide some other hover + if (hobject == null) { + hobject = computeUnderHover(x, y); + } + + repaint |= changeHoverObject(hobject); + + // clear out the hitlists + _hitList.clear(); + _hitSprites.clear(); + + if (repaint) { + repaint(); + } + } + + /** + * Gives derived classes a chance to compute a hover object that takes + * precedence over sprites and actionable objects. If this method + * returns non-null, no sprite or object hover calculations will be + * performed and the object returned will become the new hover object. + */ + protected Object computeOverHover (int mx, int my) + { + return null; + } + + /** + * Gives derived classes a chance to compute a hover object that is + * used if the mouse is not hovering over a sprite or actionable + * object. If this method is called, it means that there are no + * sprites or objects under the mouse. Thus if it returns non-null, + * the object returned will become the new hover object. + */ + protected Object computeUnderHover (int mx, int my) + { + return null; + } + + // documentation inherited + public boolean canTraverse (Object traverser, int tx, int ty) + { + SceneBlock block = getBlock(tx, ty); + return (block == null) ? false : block.canTraverse(traverser, tx, ty); + } + + // documentation inherited from interface + public Component getComponent () + { + return this; + } + + // documentation inherited from interface + public void repaintRect (int x, int y, int width, int height) + { + // translate back into view coordinates + x -= _vbounds.x; + y -= _vbounds.y; + repaint(x, y, width, height); + } + + // documentation inherited from interface + public void menuDeactivated (RadialMenu menu) + { + _activeMenu = null; + } + + // documentation inherited + public void doLayout () + { + super.doLayout(); + + // start out centered in the display + setViewLocation((_metrics.bounds.width - _vbounds.width)/2, + (_metrics.bounds.height - _vbounds.height)/2); + + // repaint the whole kit and kaboodle + if (EventQueue.isDispatchThread()) { + repaint(); + } + + Log.info("View: " + StringUtil.toString(_vbounds) + + ", vsize: " + StringUtil.toString(_metrics.bounds) + + ", nx: " + _nx + ", ny: " + _ny + "."); + } + + /** + * Returns the desired size for the panel based on the requested and + * calculated bounds of the scene view. + */ + public Dimension getPreferredSize () + { + return (_metrics == null || isPreferredSizeSet()) ? + super.getPreferredSize() : _metrics.bounds.getSize(); + } + + // documentation inherited + public void setBounds (int x, int y, int width, int height) + { + super.setBounds(x, y, width, height); + + // if we change size, force a rethink + if (width != _rsize.width || height != _rsize.height) { + _rsize.setSize(width, height); + Log.info("Size change rethink"); + rethink(); + } + } + + // documentation inherited + public void setViewLocation (int x, int y) + { + // if we're bounded, make sure no one tries to set our view + // location outside the bounds defined by the view model + if (_metrics.bounded) { + int minx = _metrics.bounds.x, + maxx = _metrics.bounds.width-getWidth(); + int miny = _metrics.bounds.y, + maxy = _metrics.bounds.height-getHeight(); + if (x < minx) { x = minx; } else if (x > maxx) { x = maxx; } + if (y < miny) { y = miny; } else if (y > maxy) { y = maxy; } + } + + super.setViewLocation(x, y); + } + + // documentation inherited + protected void viewLocationDidChange (int nx, int ny) + { + // compute the tile coordinates of our upper left screen + // coordinate and request a rethink if they've changed + MisoUtil.screenToTile(_metrics, nx, ny, _tcoords); + if (!_tcoords.equals(_ulpos)) { + Log.info("Rethinking +" + nx + "+" + ny + " -> " + + StringUtil.toString(_vbounds) + "/" + + StringUtil.toString(_tcoords) + "/" + + StringUtil.toString(_ulpos)); + _ulpos.setLocation(_tcoords); + rethink(); + } + } + + /** + * Derived classes can override this method and provide a colorizer + * that will be used to colorize the supplied scene object when + * rendering. + */ + protected TileSet.Colorizer getColorizer (ObjectInfo oinfo) + { + return null; + } + + /** + * Computes the tile coordinates of the supplied sprite and appends it + * to the supplied dirty item list. + */ + protected void appendDirtySprite (DirtyItemList list, Sprite sprite) + { + MisoUtil.screenToTile(_metrics, sprite.getX(), sprite.getY(), _tcoords); + list.appendDirtySprite(sprite, _tcoords.x, _tcoords.y); + } + + /** + * Returns the tile manager from which we load our tiles. + */ + protected TileManager getTileManager () + { + return _ctx.getTileManager(); + } + + /** + * This is called when our view position has changed by more than one + * tile in any direction. Herein we do a whole crapload of stuff: + * + *

+ */ + protected void rethink () + { + // recompute our "area of influence" + int infborx = _vbounds.width/4; + int infbory = _vbounds.height/4; + _ibounds.setBounds(_vbounds.x-infborx, _vbounds.y-infbory, + _vbounds.width+2*infborx, _vbounds.height+2*infbory); + + // prune any blocks that are no longer influential + for (Iterator iter = _blocks.values().iterator(); iter.hasNext(); ) { + SceneBlock block = (SceneBlock)iter.next(); + if (!block.getFootprint().intersects(_ibounds)) { + Log.info("Flushing block " + block + "."); + iter.remove(); + } + } + + // flush our visible object set which we'll recreate later + _vizobjs.clear(); + + // not to worry if we presently have no scene model + if (_model == null) { + return; + } + + Log.info("View: " + StringUtil.toString(_vbounds) + + ", vsize: " + StringUtil.toString(_metrics.bounds) + + ", ibounds: " + StringUtil.toString(_ibounds) + "."); + + // compute the set of blocks that are influential and queue up any + // that aren't already resolved to become so + Rectangle itb = new Rectangle(); + int minx, miny, maxx, maxy; + Point tpos = MisoUtil.screenToTile( + _metrics, _ibounds.x, _ibounds.y, new Point()); + itb.x = tpos.x; + minx = Math.max(0, tpos.x / _metrics.blockwid); + MisoUtil.screenToTile( + _metrics, _ibounds.x + _ibounds.width, _ibounds.y, tpos); + itb.y = tpos.y; + miny = Math.max(0, tpos.y / _metrics.blockhei); + MisoUtil.screenToTile(_metrics, _ibounds.x + _ibounds.width, + _ibounds.y + _ibounds.height, tpos); + itb.width = (tpos.x-itb.x); + maxx = Math.max(0, tpos.x / _metrics.blockwid); + MisoUtil.screenToTile( + _metrics, _ibounds.x, _ibounds.y + _ibounds.height, tpos); + itb.height = (tpos.y-itb.y); + maxy = Math.max(0, tpos.y / _metrics.blockhei); + + Log.info("Resolving blocks from " + minx + "," + miny + " to " + + maxx + "," + maxy + " (" + StringUtil.toString(itb) + ")."); + for (int yy = miny; yy <= maxy; yy++) { + for (int xx = minx; xx <= maxx; xx++) { + int bkey = (xx << 16) | yy; + if (!_blocks.containsKey(bkey)) { + SceneBlock block = new SceneBlock( + this, xx*_metrics.blockwid, yy*_metrics.blockhei, + _metrics.blockwid, _metrics.blockhei); + _blocks.put(bkey, block); + Log.info("Created new block " + block + "."); + } + } + } + + Rectangle vbounds = new Rectangle( + _vbounds.x-_metrics.tilewid, _vbounds.y-_metrics.tilehei, + _vbounds.width+2*_metrics.tilewid, + _vbounds.height+2*_metrics.tilehei); + + for (Iterator iter = _blocks.values().iterator(); iter.hasNext(); ) { + // links this block to its neighbors; computes coverage + SceneBlock block = (SceneBlock)iter.next(); + block.update(_blocks); + + // see which of this block's objects are visible + SceneObject[] objs = block.getObjects(); + for (int ii = 0; ii < objs.length; ii++) { + if (objs[ii].bounds != null && + vbounds.intersects(objs[ii].bounds)) { + _vizobjs.add(objs[ii]); + } + } + } + + // recompute our object tips + computeTips(); + + Log.info("Computed " + _vizobjs.size() + " visible objects."); + repaint(); + } + + /** + * Returns the resolved block that contains the specified tile + * coordinate or null if no block is resolved for that coordinate. + */ + protected SceneBlock getBlock (int tx, int ty) + { + if (tx < 0 || ty < 0) { + return null; + } + int bkey = (tx/_metrics.blockwid << 16) | (ty/_metrics.blockhei); + return (SceneBlock)_blocks.get(bkey); + } + + /** + * Compute the tips for any objects in the scene. + */ + protected void computeTips () + { + // clear any old tips + _tips.clear(); + + for (int ii = 0, nn = _vizobjs.size(); ii < nn; ii++) { + SceneObject scobj = (SceneObject)_vizobjs.get(ii); + String action = scobj.info.action; + + // if the object has no action, skip it + if (StringUtil.blank(action)) { + continue; + } + + // if we have an object action handler, possibly let them veto + // the display of this tooltip and action + ObjectActionHandler oah = ObjectActionHandler.lookup(action); + if (oah != null && !oah.actionAllowed(action)) { + continue; + } + + String tiptext = getTipText(scobj, action); + if (tiptext != null) { + Icon icon = (oah == null) ? null : oah.getTipIcon(action); + SceneObjectTip tip = new SceneObjectTip(tiptext, icon); + _tips.put(scobj, tip); + } + } + + _tipsLaidOut = false; + } + + /** + * Derived classes can provide human readable object tips via this + * method. + */ + protected String getTipText (SceneObject scobj, String action) + { + return action; + } + + /** + * Dirties the specified tip. + */ + protected void dirtyTip (SceneObjectTip tip) + { + if (tip != null) { + Rectangle r = tip.bounds; + if (r != null) { + _remgr.invalidateRegion(r); + } + } + } + + /** + * Change the hover object to the new object. + * + * @return true if we need to repaint the entire scene. Bah! + */ + protected boolean changeHoverObject (Object newHover) + { + if (newHover == _hobject) { + return false; // no change, no repaint + } + + // unhover the old + if (_hobject instanceof SceneObject) { + SceneObject oldhov = (SceneObject)_hobject; + if (oldhov.setHovered(false)) { + _remgr.invalidateRegion(oldhov.bounds); + } + } + + hoverObjectChanged(_hobject, newHover); + // set the new + _hobject = newHover; + + // hover the new + if (_hobject instanceof SceneObject) { + SceneObject newhov = (SceneObject)_hobject; + if (newhov.setHovered(true)) { + _remgr.invalidateRegion(newhov.bounds); + } + } + + return (_hmode != HIGHLIGHT_NEVER); + } + + /** + * A place for subclasses to react to the hover object changing. + * One of the supplied arguments may be null. + */ + protected void hoverObjectChanged (Object oldHover, Object newHover) + { + // dirty the tips associated with the hover objects + dirtyTip((SceneObjectTip)_tips.get(oldHover)); + dirtyTip((SceneObjectTip)_tips.get(newHover)); + } + + /** + * Adds to the supplied dirty item list, all of the object tiles that + * are hit by the specified point (meaning the point is contained + * within their bounds and intersects a non-transparent pixel in the + * actual object image. + */ + protected void getHitObjects (DirtyItemList list, int x, int y) + { + for (int ii = 0, ll = _vizobjs.size(); ii < ll; ii++) { + SceneObject scobj = (SceneObject)_vizobjs.get(ii); + Rectangle pbounds = scobj.bounds; + // skip actionless objects and those whose bounding rects + // don't contain the point + if (StringUtil.blank(scobj.info.action) || + !pbounds.contains(x, y)) { + continue; + } + + // now check that the pixel in the tile image is + // non-transparent at that point + if (!scobj.tile.hitTest(x - pbounds.x, y - pbounds.y)) { + continue; + } + + // we've passed the test, add the object to the list + list.appendDirtyObject(scobj); + } + } + + /** + * Converts the supplied screen coordinates into tile coordinates, + * writing the values into the supplied {@link Point} instance and + * returning true if the screen coordinates translated into a + * different set of tile coordinates than were already contained in + * the point (so that the caller can know to update a highlight, for + * example). + * + * @return true if the tile coordinates have changed. + */ + protected boolean updateTileCoords (int sx, int sy, Point tpos) + { + Point npos = MisoUtil.screenToTile(_metrics, sx, sy, new Point()); + + // make sure the new coordinate is both valid and different + if (_metrics.isCoordinateValid(npos.x, npos.y) && !tpos.equals(npos)) { + tpos.setLocation(npos.x, npos.y); + return true; + + } else { + return false; + } + } + + // documentation inherited + protected void paintInFront (Graphics2D gfx, Rectangle dirty) + { + super.paintInFront(gfx, dirty); + + // paint any active menu (this should in theory check to see if + // the active menu intersects one or more of the dirty rects and + // render clipped through those) + if (_activeMenu != null) { + _activeMenu.render(gfx); + } + } + + // documentation inherited + protected void paintBetween (Graphics2D gfx, Rectangle dirty) + { + // render any intersecting tiles + paintTiles(gfx, dirty); + + // render anything that goes on top of the tiles + paintBaseDecorations(gfx, dirty); + + // render our dirty sprites and objects + paintDirtyItems(gfx, dirty); + + // draw sprite paths + if (_pathsDebug.getValue()) { + _spritemgr.renderSpritePaths(gfx); + } + + // paint our highlighted tile (if any) + paintHighlights(gfx, dirty); + + // paint any extra goodies + paintExtras(gfx, dirty); + } + + /** + * Paints the highlighted tile. + * + * @param gfx the graphics context. + */ + protected void paintHighlights (Graphics2D gfx, Rectangle clip) + { + // if we're not highlighting anything, bail now + if (_hmode == HIGHLIGHT_NEVER) { + return; + } + + Polygon hpoly = null; + + // if we have a hover object, do some business + if (_hobject != null && _hobject instanceof SceneObject) { + SceneObject scobj = (SceneObject)_hobject; + if (scobj.info.action != null || _hmode == HIGHLIGHT_ALWAYS) { + hpoly = scobj.getObjectFootprint(); + } + } + + // if we had no valid hover object, but we're in HIGHLIGHT_ALWAYS, + // go for the tile outline + if (hpoly == null && _hmode == HIGHLIGHT_ALWAYS) { + hpoly = MisoUtil.getTilePolygon(_metrics, _hcoords.x, _hcoords.y); + } + + if (hpoly != null) { + // set the desired stroke and color + Stroke ostroke = gfx.getStroke(); + gfx.setStroke(HIGHLIGHT_STROKE); + gfx.setColor(Color.green); + + // draw the outline + gfx.draw(hpoly); + + // restore the original stroke + gfx.setStroke(ostroke); + } + } + + /** + * A function where derived classes can paint extra stuff while we've + * got the clipping region set up. + */ + protected void paintExtras (Graphics2D gfx, Rectangle clip) + { + if (isResponsive()) { + paintTips(gfx, clip); + } + } + + /** + * Paint all the appropriate tips for our scene objects. + */ + protected void paintTips (Graphics2D gfx, Rectangle clip) + { + // make sure the tips are ready + maybeLayoutTips(gfx); + + if (checkShowFlag(SHOW_TIPS)) { + // show all the tips + for (Iterator iter = _tips.values().iterator(); iter.hasNext(); ) { + paintTip(gfx, clip, (SceneObjectTip)iter.next()); + } + + } else { + // show maybe one tip + SceneObjectTip tip = (SceneObjectTip)_tips.get(_hobject); + if (tip != null) { + paintTip(gfx, clip, tip); + } + } + } + + /** + * Called to layout the tips if they haven't already been. + */ + protected void maybeLayoutTips (Graphics2D gfx) + { + if (!_tipsLaidOut) { + ArrayList boxlist = new ArrayList(); + for (Iterator iter = _tips.keySet().iterator(); iter.hasNext(); ) { + SceneObject scobj = (SceneObject)iter.next(); + SceneObjectTip tip = (SceneObjectTip)_tips.get(scobj); + tip.layout(gfx, scobj.bounds, _vbounds, boxlist); + boxlist.add(tip.bounds); + } + _tipsLaidOut = true; + } + } + + /** + * Paint the specified tip if it intersects the clipping rectangle. + */ + protected void paintTip (Graphics2D gfx, Rectangle clip, SceneObjectTip tip) + { + if (clip.intersects(tip.bounds)) { + tip.paint(gfx); + } + } + + /** + * Renders the base and fringe layer tiles that intersect the + * specified clipping rectangle. + */ + protected void paintTiles (Graphics2D gfx, Rectangle clip) + { + // if we're showing coordinates, we need to do some setting up + int thw = 0, thh = 0, fhei = 0; + FontMetrics fm = null; + if (_coordsDebug.getValue()) { + fm = gfx.getFontMetrics(_font); + fhei = fm.getAscent(); + thw = _metrics.tilehwid; + thh = _metrics.tilehhei; + gfx.setFont(_font); + } + + // 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 + + // obtain our upper left tile + Point tpos = MisoUtil.screenToTile( + _metrics, clip.x, clip.y, new Point()); + + // determine which quadrant of the upper left tile we occupy + Point spos = MisoUtil.tileToScreen( + _metrics, tpos.x, tpos.y, new Point()); + boolean left = (clip.x - spos.x < _metrics.tilehwid); + boolean top = (clip.y - spos.y < _metrics.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 + MisoUtil.tileToScreen(_metrics, 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 + try { + Tile tile; + boolean passable = true; + + if ((tile = getBaseTile(tx, ty)) != null) { + tile.paint(gfx, _tbounds.x, _tbounds.y); + passable = ((BaseTile)tile).isPassable(); + + // highlight impassable tiles + if (_traverseDebug.getValue() && !passable) { + fillTile(gfx, tx, ty, Color.yellow); + } + + } else { + // draw black where there are no tiles + Polygon poly = + MisoUtil.getTilePolygon(_metrics, tx, ty); + gfx.setColor(Color.black); + gfx.fill(poly); + } + + if ((tile = getFringeTile(tx, ty)) != null) { + tile.paint(gfx, _tbounds.x, _tbounds.y); + } + + // highlight passable non-traversable tiles + if (_traverseDebug.getValue() && passable && + !canTraverse(null, tx, ty)) { + fillTile(gfx, tx, ty, Color.green); + } + + } catch (ArrayIndexOutOfBoundsException e) { + Log.warning("Whoops, booched it [tx=" + tx + + ", ty=" + ty + ", tb.x=" + _tbounds.x + + ", rightx=" + rightx + "]."); + e.printStackTrace(System.err); + System.exit(-1); + } + + // if we're showing coordinates, do that + if (_coordsDebug.getValue()) { + gfx.setColor(Color.white); + + // get the top-left screen coordinates of the tile + int sx = _tbounds.x, sy = _tbounds.y; + + // draw x-coordinate + 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(ty); + xpos = sx + thw - (fm.stringWidth(str) / 2); + gfx.drawString(str, xpos, sy + thh + fhei); + + // draw the tile polygon as well + gfx.draw(MisoUtil.getTilePolygon(_metrics, tx, ty)); + } + + // move one tile to the right + tx += 1; ty -= 1; + _tbounds.x += _metrics.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 + MisoUtil.tileToScreen(_metrics, tpos.x, tpos.y, spos); + } + } + + /** + * Fills the specified tile with the given color at 50% alpha. + * Intended for debug-only tile highlighting purposes. + */ + protected void fillTile ( + Graphics2D gfx, int tx, int ty, Color color) + { + Composite ocomp = gfx.getComposite(); + gfx.setComposite(ALPHA_FILL_TILE); + Polygon poly = MisoUtil.getTilePolygon(_metrics, tx, ty); + gfx.setColor(color); + gfx.fill(poly); + gfx.setComposite(ocomp); + } + + /** + * A function where derived classes can paint things after the base + * tiles have been rendered but before anything else has been rendered + * (so that whatever is painted appears to be on the ground). + */ + protected void paintBaseDecorations (Graphics2D gfx, Rectangle clip) + { + // nothing for now + } + + /** + * Renders the dirty sprites and objects in the scene to the given + * graphics context. + */ + protected void paintDirtyItems (Graphics2D gfx, Rectangle clip) + { + // 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++) { + Sprite sprite = (Sprite)_dirtySprites.get(ii); + Rectangle bounds = sprite.getBounds(); + if (!bounds.intersects(clip)) { + continue; + } + appendDirtySprite(_dirtyItems, sprite); +// Log.info("Dirtied item: " + sprite); + } + + // add any objects impacted by the dirty rectangle + for (int ii = 0, ll = _vizobjs.size(); ii < ll; ii++) { + SceneObject scobj = (SceneObject)_vizobjs.get(ii); + if (!scobj.bounds.intersects(clip)) { + continue; + } + _dirtyItems.appendDirtyObject(scobj); +// Log.info("Dirtied item: " + scobj); + } + +// Log.info("paintDirtyItems [items=" + _dirtyItems.size() + "]."); + + // sort the dirty items so that we can paint them back-to-front + _dirtyItems.sort(); + _dirtyItems.paintAndClear(gfx); + } + + /** + * We don't want sprites rendered using the standard mechanism because + * we intersperse them with objects in our scene and need to manage + * their z-order. + */ + protected void paintBits (Graphics2D gfx, int layer, Rectangle dirty) + { + _animmgr.renderMedia(gfx, layer, dirty); + } + + /** Returns the base tile for the specified tile coordinate. */ + protected BaseTile getBaseTile (int tx, int ty) + { + SceneBlock block = getBlock(tx, ty); + return (block == null) ? null : block.getBaseTile(tx, ty); + } + + /** Returns the fringe tile for the specified tile coordinate. */ + protected Tile getFringeTile (int tx, int ty) + { + SceneBlock block = getBlock(tx, ty); + return (block == null) ? null : block.getFringeTile(tx, ty); + } + + /** Computes the fringe tile for the specified coordinate. */ + protected Tile computeFringeTile (int tx, int ty) + { + return _ctx.getTileManager().getAutoFringer().getFringeTile( + _model, tx, ty, _masks, _rando); + } + + /** + * Returns true if we're responding to user input. This is used to + * control the display of tooltips and other potential user + * interactions. By default we are always responsive. + */ + protected boolean isResponsive () + { + return true; + } + + /** Provides access to a few things. */ + protected MisoContext _ctx; + + /** Contains basic scene metrics like tile width and height. */ + protected MisoSceneMetrics _metrics; + + /** The scene model to be displayed. */ + protected MisoSceneModel _model; + + /** Used to colorize object tiles in this scene. */ + protected TileSet.Colorizer _rizer; + + /** Tracks the size at which we were last "rethunk". */ + protected Dimension _rsize = new Dimension(); + + /** Contains the tile coords of our upper-left view coord. */ + protected Point _ulpos = new Point(); + + /** Contains the bounds of our "area of influence" in screen coords. */ + protected Rectangle _ibounds = new Rectangle(); + + /** Contains our scene blocks. See {@link #getBlock} for details. */ + protected HashIntMap _blocks = new HashIntMap(); + + /** A list of the potentially visible objects in the scene. */ + protected ArrayList _vizobjs = new ArrayList(); + + /** For computing fringe tiles. */ + protected HashMap _masks = new HashMap(); + + /** For computing fringe tiles. */ + protected Random _rando = new Random(); + + /** 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 when dirtying sprites. */ + protected Point _tcoords = new Point(); + + /** Used to collect the list of sprites "hit" by a particular mouse + * location. */ + protected List _hitSprites = new ArrayList(); + + /** The list that we use to track and sort the items over which the + * mouse is hovering. */ + protected DirtyItemList _hitList = new DirtyItemList(); + + /** The highlight mode. */ + protected int _hmode = HIGHLIGHT_NEVER; + + /** Info on the object that the mouse is currently hovering over. */ + protected Object _hobject; + + /** The item that the user has clicked on with the mouse. */ + protected Object _armedItem = null; + + /** The active radial menu (or null). */ + protected RadialMenu _activeMenu; + + /** Used to track the tile coordinates over which the mouse is hovering. */ + protected Point _hcoords = new Point(); + + /** Our object tips, indexed by the object that they tip for. */ + protected HashMap _tips = new HashMap(); + + /** Have the tips been laid out? */ + protected boolean _tipsLaidOut = false; + + /** Flags indicating which features we should show in the scene. */ + protected int _showFlags = 0; + + /** The font to draw tile coordinates. */ + protected Font _font = new Font("Arial", Font.PLAIN, 7); + + /** A debug hook that toggles debug rendering of traversable tiles. */ + protected static RuntimeAdjust.BooleanAdjust _traverseDebug = + new RuntimeAdjust.BooleanAdjust( + "Toggles debug rendering of traversable and impassable tiles in " + + "the iso scene view.", "narya.miso.iso_traverse_debug_render", + MisoPrefs.config, false); + + /** A debug hook that toggles debug rendering of tile coordinates. */ + protected static RuntimeAdjust.BooleanAdjust _coordsDebug = + new RuntimeAdjust.BooleanAdjust( + "Toggles debug rendering of tile coordinates in the iso scene " + + "view.", "narya.miso.iso_coords_debug_render", + MisoPrefs.config, false); + + /** A debug hook that toggles debug rendering of sprite paths. */ + protected static RuntimeAdjust.BooleanAdjust _pathsDebug = + new RuntimeAdjust.BooleanAdjust( + "Toggles debug rendering of sprite paths in the iso scene view.", + "narya.miso.iso_paths_debug_render", MisoPrefs.config, false); + + /** The stroke object used to draw highlighted tiles and coordinates. */ + protected static final Stroke HIGHLIGHT_STROKE = new BasicStroke(2); + + /** The stroke used to draw dirty rectangles. */ + protected static final Stroke DIRTY_RECT_STROKE = new BasicStroke(2); + + /** The alpha used to fill tiles for debugging purposes. */ + protected static final Composite ALPHA_FILL_TILE = + AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); +} diff --git a/src/java/com/threerings/miso/client/ObjectActionHandler.java b/src/java/com/threerings/miso/client/ObjectActionHandler.java new file mode 100644 index 000000000..a337dd972 --- /dev/null +++ b/src/java/com/threerings/miso/client/ObjectActionHandler.java @@ -0,0 +1,115 @@ +// +// $Id: ObjectActionHandler.java,v 1.1 2003/04/17 19:21:16 mdb Exp $ + +package com.threerings.miso.client; + +import java.awt.event.ActionEvent; +import java.util.HashMap; +import javax.swing.Icon; + +import com.samskivert.swing.RadialMenu; +import com.samskivert.util.StringUtil; + +import com.threerings.miso.Log; +import com.threerings.miso.client.SceneObject; + +/** + * Objects in scenes can be configured to generate action events. Those + * events are grouped into types and an object action handler can be + * registered to handle all actions of a particular type. + */ +public class ObjectActionHandler +{ + /** + * Returns true if we should allow this object action, false if we + * should not. This is used to completely hide actions that should not + * be visible without the proper privileges. + */ + public boolean actionAllowed (String action) + { + return true; + } + + /** + * Returns the tooltip icon for the specified action or null if the + * action has no tooltip icon. + */ + public Icon getTipIcon (String action) + { + return null; + } + + /** + * Return a {@link RadialMenu} or null if no menu needed. + */ + public RadialMenu handlePressed (SceneObject sourceObject) + { + return null; + } + + /** + * Called when an action is generated for an object. + */ + public void handleAction (SceneObject scobj, ActionEvent event) + { + Log.warning("Unknown object action [scobj=" + scobj + + ", action=" + event + "]."); + } + + /** + * Returns the type associated with this action command (which is + * mapped to a registered object action handler) or the empty string + * if it has no type. + */ + public static String getType (String command) + { + int cidx = StringUtil.blank(command) ? -1 : command.indexOf(':'); + return (cidx == -1) ? "" : command.substring(0, cidx); + } + + /** + * Returns the unqualified object action (minus the type, see {@link + * #getType}). + */ + public static String getAction (String command) + { + int cidx = StringUtil.blank(command) ? -1 : command.indexOf(':'); + return (cidx == -1) ? command : command.substring(cidx+1); + } + + /** + * Looks up the object action handler associated with the specified + * command. + */ + public static ObjectActionHandler lookup (String command) + { + return (ObjectActionHandler)_oahandlers.get(getType(command)); + } + + /** + * Registers an object action handler which will be called when a user + * clicks on an object in a scene that has an associated action. + */ + public static void register (String prefix, ObjectActionHandler handler) + { + // make sure we know about potential funny business + if (_oahandlers.containsKey(prefix)) { + Log.warning("Warning! Overwriting previous object action " + + "handler registration, all hell could shortly " + + "break loose [prefix=" + prefix + + ", handler=" + handler + "]."); + } + _oahandlers.put(prefix, handler); + } + + /** + * Removes an object action handler registration. + */ + public static void unregister (String prefix) + { + _oahandlers.remove(prefix); + } + + /** Our registered object action handlers. */ + protected static HashMap _oahandlers = new HashMap(); +} diff --git a/src/java/com/threerings/miso/client/SceneBlock.java b/src/java/com/threerings/miso/client/SceneBlock.java new file mode 100644 index 000000000..5746402d8 --- /dev/null +++ b/src/java/com/threerings/miso/client/SceneBlock.java @@ -0,0 +1,262 @@ +// +// $Id: SceneBlock.java,v 1.1 2003/04/17 19:21:16 mdb Exp $ + +package com.threerings.miso.client; + +import java.awt.Polygon; +import java.awt.Rectangle; + +import com.samskivert.util.HashIntMap; +import com.samskivert.util.StringUtil; + +import com.threerings.media.tile.NoSuchTileException; +import com.threerings.media.tile.NoSuchTileSetException; +import com.threerings.media.tile.Tile; +import com.threerings.media.tile.TileManager; +import com.threerings.media.tile.TileSet; + +import com.threerings.miso.Log; +import com.threerings.miso.data.MisoSceneModel; +import com.threerings.miso.tile.BaseTile; +import com.threerings.miso.util.MisoUtil; +import com.threerings.miso.util.ObjectSet; + +/** + * Contains the base and object tile information on a particular + * rectangular region of a scene. + */ +public class SceneBlock +{ + /** + * Creates a scene block and resolves the base and object tiles that + * reside therein. + */ + public SceneBlock ( + MisoScenePanel panel, int tx, int ty, int width, int height) + { + _bounds = new Rectangle(tx, ty, width, height); + _base = new BaseTile[width*height]; + _fringe = new Tile[width*height]; + _covered = new boolean[width*height]; + + // compute our screen-coordinate footprint polygon + _footprint = MisoUtil.getFootprintPolygon( + panel.getSceneMetrics(), tx, ty, width, height); + + // resolve our base tiles + MisoSceneModel model = panel.getSceneModel(); + TileManager tmgr = panel.getTileManager(); + for (int yy = 0; yy < height; yy++) { + for (int xx = 0; xx < width; xx++) { + int x = tx + xx, y = ty + yy; + int fqTileId = model.getBaseTileId(x, y); + if (fqTileId <= 0) { + continue; + } + + // this is a bit magical, but the tile manager will fetch + // tiles from the tileset repository and the tile set id + // from which we request this tile must map to a base tile + // as provided by the repository, so we just cast it to a + // base tile and know that all is well + String errmsg = null; + int tidx = yy*width+xx; + try { + _base[tidx] = (BaseTile)tmgr.getTile(fqTileId); + } catch (ClassCastException cce) { + errmsg = "Scene contains non-base tile in base layer"; + } catch (NoSuchTileSetException nste) { + errmsg = "Scene contains non-existent tileset"; + } catch (NoSuchTileException nste) { + errmsg = "Scene contains non-existent tile"; + } + + if (errmsg != null) { + Log.warning(errmsg + " [fqtid=" + fqTileId + + ", x=" + x + ", y=" + y + "]."); + } + + if (_base[tidx] == null) { + continue; + } + + // compute the fringe for this tile + _fringe[tidx] = panel.computeFringeTile(x, y); + } + } + + // resolve our objects + ObjectSet set = new ObjectSet(); + model.getObjects(_bounds, set); + _objects = new SceneObject[set.size()]; + for (int ii = 0; ii < _objects.length; ii++) { + _objects[ii] = new SceneObject(panel, set.get(ii)); + } + } + + /** + * Returns the screen-coordinate polygon bounding the footprint of + * this block. + */ + public Polygon getFootprint () + { + return _footprint; + } + + /** + * Returns an array of all resolved scene objects in this block. + */ + public SceneObject[] getObjects () + { + return _objects; + } + + /** + * Returns the base tile at the specified coordinates or null if + * there's no tile at said coordinates. + */ + public BaseTile getBaseTile (int tx, int ty) + { + return _base[index(tx, ty)]; + } + + /** + * Returns the fringe tile at the specified coordinates or null if + * there's no tile at said coordinates. + */ + public Tile getFringeTile (int tx, int ty) + { + return _fringe[index(tx, ty)]; + } + + /** + * Returns true if the specified traverser can traverse the specified + * tile (which is assumed to be in the bounds of this scene block). + */ + public boolean canTraverse (Object traverser, int tx, int ty) + { + BaseTile base = getBaseTile(tx, ty); + return !_covered[index(tx, ty)] && (base != null && base.isPassable()); + } + + /** + * Returns the index into our arrays of the specified tile. + */ + protected final int index (int tx, int ty) + { + return (ty-_bounds.y)*_bounds.width + (tx-_bounds.x); + } + + /** + * Returns a string representation of this instance. + */ + public String toString () + { + return StringUtil.toString(_bounds) + ":" + _objects.length; + } + + /** + * Links this block to its neighbors; informs neighboring blocks of + * object coverage. + */ + protected void update (HashIntMap blocks) + { + boolean recover = false; + + // link up to our neighbors + for (int ii = 0; ii < DX.length; ii++) { + SceneBlock neigh = (SceneBlock) + blocks.get(neighborKey(DX[ii], DY[ii])); + if (neigh != _neighbors[ii]) { + _neighbors[ii] = neigh; + // if we're linking up to a neighbor for the first time; + // we need to recalculate our coverage + recover = recover || (neigh != null); +// Log.info(this + " was introduced to " + neigh + "."); + } + } + + // if we need to regenerate the set of tiles covered by our + // objects, do so + if (recover) { + for (int ii = 0; ii < _objects.length; ii++) { + setCovered(blocks, _objects[ii]); + } + } + } + + /** Computes the key of our neighbor. */ + protected final int neighborKey (int dx, int dy) + { + return ((short)(_bounds.x/_bounds.width+dx) << 16 | + (short)(_bounds.y/_bounds.height+dy)); + } + + /** Computes the key for the block that holds the specified tile. */ + protected final int blockKey (int tx, int ty) + { + return ((short)(tx/_bounds.width) << 16 | + (short)(ty/_bounds.height)); + } + + /** + * Sets the footprint of this object tile + */ + protected void setCovered (HashIntMap blocks, SceneObject scobj) + { + int endx = Math.max(0, (scobj.info.x - scobj.tile.getBaseWidth() + 1)); + int endy = Math.max(0, (scobj.info.y - scobj.tile.getBaseHeight() + 1)); + + for (int xx = scobj.info.x; xx >= endx; xx--) { + if ((xx < 0) || (xx >= Short.MAX_VALUE)) { + continue; + } + + for (int yy = scobj.info.y; yy >= endy; yy--) { + if ((yy < 0) || (yy >= Short.MAX_VALUE)) { + continue; + } + + SceneBlock block = (SceneBlock)blocks.get(blockKey(xx, yy)); + if (block != null) { + block.setCovered(xx, yy); + } + } + } + +// Log.info("Updated coverage " + scobj.info + "."); + } + + /** + * Indicates that this tile is covered by an object footprint. + */ + protected void setCovered (int tx, int ty) + { + _covered[index(tx, ty)] = true; + } + + /** The bounds of (in tile coordinates) of this block. */ + protected Rectangle _bounds; + + /** A polygon bounding the footprint of this block. */ + protected Polygon _footprint; + + /** Our base tiles. */ + protected BaseTile[] _base; + + /** Our fringe tiles. */ + protected Tile[] _fringe; + + /** Indicates whether our tiles are covered by an object. */ + protected boolean[] _covered; + + /** Info on our objects. */ + protected SceneObject[] _objects; + + /** Our neighbors in the eight cardinal directions. */ + protected SceneBlock[] _neighbors = new SceneBlock[DX.length]; + + // used to link up to our neighbors + protected static final int[] DX = { -1, -1, 0, 1, 1, 1, 0, -1 }; + protected static final int[] DY = { 0, -1, -1, -1, 0, 1, 1, 1 }; +} diff --git a/src/java/com/threerings/miso/client/SceneObject.java b/src/java/com/threerings/miso/client/SceneObject.java new file mode 100644 index 000000000..c18781bd5 --- /dev/null +++ b/src/java/com/threerings/miso/client/SceneObject.java @@ -0,0 +1,260 @@ +// +// $Id: SceneObject.java,v 1.1 2003/04/17 19:21:16 mdb Exp $ + +package com.threerings.miso.client; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; + +import com.samskivert.util.RuntimeAdjust; +import com.samskivert.util.StringUtil; + +import com.threerings.media.tile.NoSuchTileException; +import com.threerings.media.tile.NoSuchTileSetException; +import com.threerings.media.tile.ObjectTile; +import com.threerings.media.tile.TileUtil; + +import com.threerings.miso.Log; +import com.threerings.miso.MisoPrefs; +import com.threerings.miso.data.ObjectInfo; +import com.threerings.miso.util.MisoSceneMetrics; +import com.threerings.miso.util.MisoUtil; + +/** + * Contains resolved information on an object in a scene. + */ +public class SceneObject +{ + /** The object's info record. */ + public ObjectInfo info; + + /** The object tile used to display this object. */ + public ObjectTile tile; + + /** The screen coordinate bounds of our object tile given its position + * in the scene. */ + public Rectangle bounds; + + /** + * Creates a scene object for display by the specified panel. The + * appropriate object tile is resolved and the object's in-situ bounds + * are computed. + */ + public SceneObject (MisoScenePanel panel, ObjectInfo info) + { + this.info = info; + + // resolve our object tile + int tsid = TileUtil.getTileSetId(info.tileId); + int tidx = TileUtil.getTileIndex(info.tileId); + try { + tile = (ObjectTile)panel.getTileManager().getTile( + tsid, tidx, panel.getColorizer(info)); + init(panel); + + } catch (NoSuchTileException nste) { + Log.warning("Scene contains non-existent object tile " + + "[info=" + info + "]."); + } catch (NoSuchTileSetException te) { + Log.warning("Scene contains non-existent object tileset " + + "[info=" + info + "]."); + } + } + + /** + * Creates a scene object for display by the specified panel. + */ + public SceneObject (MisoScenePanel panel, ObjectInfo info, ObjectTile tile) + { + this.info = info; + this.tile = tile; + init(panel); + } + + /** + * Finishes the initialization of this scene object. + */ + protected void init (MisoScenePanel panel) + { + // compute our object's screen bounds + MisoSceneMetrics metrics = panel.getSceneMetrics(); + + // start with the screen coordinates of our origin tile + Point tpos = MisoUtil.tileToScreen( + metrics, info.x, info.y, new Point()); + + // if the tile has an origin coordinate, use that, otherwise + // compute it from the tile footprint + int tox = tile.getOriginX(), toy = tile.getOriginY(); + if (tox == Integer.MIN_VALUE) { + tox = tile.getBaseWidth() * metrics.tilehwid; + } + if (toy == Integer.MIN_VALUE) { + toy = tile.getHeight(); + } + + bounds = new Rectangle(tpos.x + metrics.tilehwid - tox, + tpos.y + metrics.tilehei - toy, + tile.getWidth(), tile.getHeight()); + + // compute our object footprint as well + _footprint = MisoUtil.getFootprintPolygon( + metrics, info.x-tile.getWidth()+1, info.y-tile.getHeight()+1, + tile.getWidth(), tile.getHeight()); + + // compute our object spot if we've got one + if (tile.hasSpot()) { + _fspot = MisoUtil.tilePlusFineToFull( + metrics, info.x, info.y, tile.getSpotX(), tile.getSpotY(), + new Point()); + _sspot = MisoUtil.fullToScreen( + metrics, _fspot.x, _fspot.y, new Point()); + } + } + + /** + * Requests that this scene object render itself. + */ + public void paint (Graphics2D gfx) + { + if (_hideObjects.getValue()) { + return; + } + + // if we're rendering footprints, paint that + boolean footpaint = _fprintDebug.getValue(); + if (footpaint) { + gfx.setColor(Color.black); + gfx.draw(_footprint); + } + + // paint our tile + tile.paint(gfx, bounds.x, bounds.y); + + // and possibly paint the object's spot + if (footpaint && _sspot != null) { + // translate the origin to center on the portal + gfx.translate(_sspot.x, _sspot.y); + + // rotate to reflect the spot orientation + double rot = (Math.PI / 4.0f) * tile.getSpotOrient(); + gfx.rotate(rot); + + // draw the spot triangle + gfx.setColor(Color.green); + gfx.fill(_spotTri); + + // outline the triangle in black + gfx.setColor(Color.black); + gfx.draw(_spotTri); + + // restore the original transform + gfx.rotate(-rot); + gfx.translate(-_sspot.x, -_sspot.y); + } + } + + /** + * Returns the location associated with this object's "spot" in fine + * coordinates or null if it has no spot. + */ + public Point getObjectSpot () + { + return _fspot; + } + + /** + * Returns true if this object's footprint overlaps that of the + * specified other object. + */ + public boolean objectFootprintOverlaps (SceneObject so) + { + return (so.info.x > info.x - tile.getBaseWidth() && + info.x > so.info.x - so.tile.getBaseWidth() && + so.info.y > info.y - tile.getBaseHeight() && + info.y > so.info.y - so.tile.getBaseHeight()); + } + + /** + * Returns a polygon bounding all footprint tiles of this scene + * object. + * + * @return the bounding polygon. + */ + public Polygon getObjectFootprint () + { + return _footprint; + } + + /** + * Returns the render priority of this scene object. + */ + public int getPriority () + { + // if we have no overridden priority, return our object tile's + // default priority + return (info.priority == 0 && tile != null) ? + tile.getPriority() : info.priority; + } + + /** + * Overrides the render priority of this object. + */ + public void setPriority (byte priority) + { + info.priority = (byte)Math.max( + Byte.MIN_VALUE, Math.min(Byte.MAX_VALUE, priority)); + } + + /** + * Informs this scene object that the mouse is now hovering over it. + * Custom objects may wish to adjust some internal state and return + * true from this method indicating that they should be repainted. + */ + public boolean setHovered (boolean hovered) + { + return false; + } + + /** + * Returns a string representation of this instance. + */ + public String toString () + { + return info + "[" + StringUtil.toString(bounds) + "]"; + } + + /** Our object footprint as a polygon. */ + protected Polygon _footprint; + + /** The full-coordinates of our object spot; or null if we have none. */ + protected Point _fspot; + + /** The screen-coordinates of our object spot; or null if we have none. */ + protected Point _sspot; + + /** A debug hook that toggles rendering of objects. */ + protected static RuntimeAdjust.BooleanAdjust _hideObjects = + new RuntimeAdjust.BooleanAdjust( + "Toggles rendering of objects in the scene view.", + "narya.miso.hide_objects", MisoPrefs.config, false); + + /** A debug hook that toggles rendering of object footprints. */ + protected static RuntimeAdjust.BooleanAdjust _fprintDebug = + new RuntimeAdjust.BooleanAdjust( + "Toggles rendering of object footprints in the scene view.", + "narya.miso.iso_fprint_debug_render", MisoPrefs.config, false); + + /** The triangle used to render an object's spot. */ + protected static Polygon _spotTri; + + static { + _spotTri = new Polygon(); + _spotTri.addPoint(-3, -3); + _spotTri.addPoint(3, -3); + _spotTri.addPoint(0, 3); + }; +} diff --git a/src/java/com/threerings/miso/client/SceneObjectTip.java b/src/java/com/threerings/miso/client/SceneObjectTip.java new file mode 100644 index 000000000..06fb19f78 --- /dev/null +++ b/src/java/com/threerings/miso/client/SceneObjectTip.java @@ -0,0 +1,126 @@ +// +// $Id: SceneObjectTip.java,v 1.1 2003/04/17 19:21:16 mdb Exp $ + +package com.threerings.miso.client; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Rectangle; + +import java.util.Collection; + +import javax.swing.Icon; +import javax.swing.UIManager; + +import com.samskivert.swing.Label; +import com.samskivert.swing.LabelSausage; +import com.samskivert.swing.LabelStyleConstants; +import com.samskivert.swing.util.SwingUtil; +import com.samskivert.util.StringUtil; + +/** + * A lightweight tooltip used by the {@link MisoScenePanel}. The tip + * foreground and background are controlled by the following {@link + * UIManager} properties: + * + *
+ * SceneObjectTip.background
+ * SceneObjectTip.foreground
+ * SceneObjectTip.font (falls back to Label.font)
+ * 
+ */ +public class SceneObjectTip extends LabelSausage +{ + /** The bounding box of this tip, or null prior to layout(). */ + public Rectangle bounds; + + /** + * Construct a SceneObjectTip. + */ + public SceneObjectTip (String text, Icon icon) + { + super(new Label(text, _foreground, _font), icon); + } + + /** + * Called to initialize the tip so that it can be painted. + * + * @param tipFor the bounding rectangle for the object we tip for. + * @param boundary the boundary of all displayable space. + * @param othertips other tip boundaries that we should avoid. + */ + public void layout (Graphics2D gfx, Rectangle tipFor, Rectangle boundary, + Collection othertips) + { + layout(gfx, PAD); + bounds = new Rectangle(_size); + + // center in the on-screen portion of the bounding box of the + // object we're tipping for, but don't go above MAX_HEIGHT from + // the bottom... + Rectangle anchor = boundary.intersection(tipFor); + bounds.setLocation( + anchor.x + (anchor.width - bounds.width) / 2, + anchor.y + Math.max( + (anchor.height - bounds.height) / 2, + anchor.height - MAX_HEIGHT)); + + // and jiggle it to not overlap any other tips + SwingUtil.positionRect(bounds, boundary, othertips); + } + + /** + * Paint this tip at it's location. + */ + public void paint (Graphics2D gfx) + { + paint(gfx, bounds.x, bounds.y, _background, null); + } + + /** + * Generates a string representation of this instance. + */ + public String toString () + { + return _label.getText() + "[" + StringUtil.toString(bounds) + "]"; + } + + // documentation inherited + protected void drawBase (Graphics2D gfx, int x, int y) + { + Composite ocomp = gfx.getComposite(); + gfx.setComposite(ALPHA); + super.drawBase(gfx, x, y); + gfx.setComposite(ocomp); + } + + /** The alpha we use for our base. */ + protected static final Composite ALPHA = AlphaComposite.getInstance( + AlphaComposite.SRC_OVER, .75f); + + /** Colors to use when rendering the tip. */ + protected static Color _background, _foreground; + + /** The font to use when rendering the tip. */ + protected static Font _font; + + // initialize resources shared by all tips + static { + _background = UIManager.getColor("SceneObjectTip.background"); + _foreground = UIManager.getColor("SceneObjectTip.foreground"); + _font = UIManager.getFont("SceneObjectTip.font"); + if (_font == null) { + _font = UIManager.getFont("Label.font"); + } + } + + /** The number of pixels to reserve between elements of the tip. */ + protected static final int PAD = 3; + + /** The maximum height above the bottom of the object bounds that we are + * to center ourselves. */ + protected static final int MAX_HEIGHT = 80; +} diff --git a/src/java/com/threerings/miso/client/SceneView.java b/src/java/com/threerings/miso/client/SceneView.java deleted file mode 100644 index 7fd1d08ef..000000000 --- a/src/java/com/threerings/miso/client/SceneView.java +++ /dev/null @@ -1,87 +0,0 @@ -// -// $Id: SceneView.java,v 1.33 2003/01/31 23:10:45 mdb Exp $ - -package com.threerings.miso.client; - -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.event.MouseEvent; - -import com.threerings.media.sprite.Sprite; -import com.threerings.media.util.Path; - -/** - * The scene view interface provides an interface to be implemented by - * classes that provide a view of a given scene by drawing the scene - * contents onto a particular GUI component. - */ -public interface SceneView -{ - /** - * Renders an invalid porition of the scene to the given graphics - * context. - * - * @param gfx the graphics context. - * @param invalidRect the invalid region to be repainted. - */ - public void paint (Graphics2D gfx, Rectangle invalidRect); - - /** - * Sets the scene that we're rendering. - * - * @param scene the scene to render in the view. - */ - public void setScene (DisplayMisoScene scene); - - /** - * Returns the scene being rendered. - */ - public DisplayMisoScene getScene (); - - /** - * 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. - */ - public Path getPath (Sprite sprite, int x, int y); - - /** - * Returns screen coordinates given the specified full coordinates. - */ - public Point getScreenCoords (int x, int y); - - /** - * Returns full coordinates given the specified screen coordinates. - */ - public Point getFullCoords (int x, int y); - - /** - * Must be called by the containing panel when the mouse moves over - * the view. - * - * @return true if a repaint is required, false if not. - */ - public boolean mouseMoved (MouseEvent e); - - /** - * Must be called by the containing panel when the mouse exits the - * view. - */ - public void mouseExited (MouseEvent e); - - /** - * Returns information about the object over which the mouse is - * currently hovering (either a {@link DisplayObjectInfo} or a {@link - * Sprite}), or null if the mouse is not hovering over anything of - * interest. - */ - public Object getHoverObject (); -} diff --git a/src/java/com/threerings/miso/client/SceneViewPanel.java b/src/java/com/threerings/miso/client/SceneViewPanel.java deleted file mode 100644 index 305990505..000000000 --- a/src/java/com/threerings/miso/client/SceneViewPanel.java +++ /dev/null @@ -1,174 +0,0 @@ -// -// $Id: SceneViewPanel.java,v 1.49 2003/01/31 23:10:45 mdb Exp $ - -package com.threerings.miso.client; - -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.Shape; - -import java.awt.event.MouseAdapter; -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.VirtualMediaPanel; - -import com.threerings.media.sprite.Sprite; -import com.threerings.media.sprite.SpriteManager; - -import com.threerings.miso.Log; -import com.threerings.miso.client.util.IsoUtil; - -/** - * The scene view panel is responsible for managing a {@link - * SceneView}, rendering it to the screen, and handling view-related - * UI events. - */ -public class SceneViewPanel extends VirtualMediaPanel -{ - /** - * Constructs the scene view panel with the supplied view model. - */ - public SceneViewPanel (FrameManager framemgr, IsoSceneViewModel model) - { - super(framemgr); - - // we're going to want to be opaque - setOpaque(true); - - // create the data model for the scene view - _viewmodel = model; - - // create the scene view - _view = newSceneView(_spritemgr, _viewmodel); - - // listen to mouse... - addMouseListener(new MouseAdapter() { - public void mouseExited (MouseEvent e) { - _view.mouseExited(e); - repaint(); - } - }); - - // ...and mouse motion events - addMouseMotionListener(new MouseMotionAdapter() { - public void mouseMoved (MouseEvent e) { - if (_view.mouseMoved(e)) { - repaint(); - } - } - public void mouseDragged (MouseEvent e) { - if (_view.mouseMoved(e)) { - repaint(); - } - } - }); - } - - /** - * Gets the iso scene view model associated with this panel. - */ - public IsoSceneViewModel getModel () - { - return _viewmodel; - } - - /** - * Constructs the underlying scene view implementation. - */ - protected SceneView newSceneView ( - SpriteManager smgr, IsoSceneViewModel model) - { - return new IsoSceneView(smgr, model, _remgr); - } - - /** - * Sets the scene managed by the panel. - */ - public void setScene (DisplayMisoScene scene) - { - if (scene == null) { - Log.warning("Ignoring request to set null scene."); - } else { - _view.setScene(scene); - } - } - - /** - * Gets the scene managed by the panel. - */ - public SceneView getSceneView () - { - return _view; - } - - // documentation inherited - public void doLayout () - { - super.doLayout(); - - // figure out our viewport offsets - Dimension size = getSize(); - - // start out centered in the display - setViewLocation((_viewmodel.bounds.width - size.width)/2, - (_viewmodel.bounds.height - size.height)/2); - -// Log.info("Size: " + StringUtil.toString(size) + -// ", vsize: " + StringUtil.toString(_viewmodel.bounds) + -// ", nx: " + _nx + ", ny: " + _ny + "."); - } - - // documentation inherited - public void setViewLocation (int x, int y) - { - // if we're bounded, make sure no one tries to set our view - // location outside the bounds defined by the view model - if (_viewmodel.bounded) { - int minx = _viewmodel.bounds.x, - maxx = _viewmodel.bounds.width-getWidth(); - int miny = _viewmodel.bounds.y, - maxy = _viewmodel.bounds.height-getHeight(); - if (x < minx) { x = minx; } else if (x > maxx) { x = maxx; } - if (y < miny) { y = miny; } else if (y > maxy) { y = maxy; } - } - super.setViewLocation(x, y); - } - - // documentation inherited - protected void paintBetween (Graphics2D gfx, Rectangle dirty) - { - _view.paint(gfx, dirty); - } - - /** - * We don't want sprites rendered using the standard mechanism because - * we intersperse them with objects in our scene and need to manage - * their z-order. - */ - protected void paintBits (Graphics2D gfx, int layer, Rectangle dirty) - { - _animmgr.renderMedia(gfx, layer, dirty); - } - - /** - * Returns the desired size for the panel based on the requested - * and calculated bounds of the scene view. - */ - public Dimension getPreferredSize () - { - return (_viewmodel == null || isPreferredSizeSet()) ? - super.getPreferredSize() : _viewmodel.bounds.getSize(); - } - - /** The scene view data model. */ - protected IsoSceneViewModel _viewmodel; - - /** The scene view we're managing. */ - protected SceneView _view; -} diff --git a/src/java/com/threerings/miso/client/SimpleDisplayMisoSceneImpl.java b/src/java/com/threerings/miso/client/SimpleDisplayMisoSceneImpl.java deleted file mode 100644 index 8e3a21c30..000000000 --- a/src/java/com/threerings/miso/client/SimpleDisplayMisoSceneImpl.java +++ /dev/null @@ -1,320 +0,0 @@ -// -// $Id: SimpleDisplayMisoSceneImpl.java,v 1.4 2003/04/07 22:04:39 mdb Exp $ - -package com.threerings.miso.client; - -import java.util.HashMap; - -import com.threerings.media.tile.NoSuchTileException; -import com.threerings.media.tile.NoSuchTileSetException; -import com.threerings.media.tile.ObjectTile; -import com.threerings.media.tile.Tile; -import com.threerings.media.tile.TileSet; - -import com.threerings.miso.Log; -import com.threerings.miso.client.util.ObjectSet; -import com.threerings.miso.data.ObjectInfo; -import com.threerings.miso.data.SimpleMisoSceneImpl; -import com.threerings.miso.data.SimpleMisoSceneModel; -import com.threerings.miso.tile.AutoFringer; -import com.threerings.miso.tile.BaseTile; -import com.threerings.miso.tile.MisoTileManager; - -/** - * An implementation of the {@link DisplayMisoScene} interface that uses a - * simple miso scene model. - */ -public class SimpleDisplayMisoSceneImpl extends SimpleMisoSceneImpl - implements DisplayMisoScene -{ - /** - * Constructs an instance that will be used to display the supplied - * miso scene data. The tiles identified by the scene model will be - * loaded via the supplied tile manager. - * - * @param model the scene data that we'll be displaying. - * @param tmgr the tile manager from which to load our tiles. - */ - public SimpleDisplayMisoSceneImpl (SimpleMisoSceneModel model, - MisoTileManager tmgr) - { - super(model); - - _tmgr = tmgr; - _fringer = tmgr.getAutoFringer(); - - int swid = _model.width; - int shei = _model.height; - - // create the individual tile layer objects - _base = new BaseTile[swid*shei]; - _fringe = new Tile[swid*shei]; - _covered = new boolean[swid*shei]; - } - - // documentation inherited from interface - public void init () - { - int swid = _model.width; - int shei = _model.height; - - // load up the tiles for our base layer - for (int column = 0; column < shei; column++) { - for (int row = 0; row < swid; row++) { - int fqTileId = getBaseTileId(column, row); - if (fqTileId > 0) { - populateBaseTile(fqTileId, column, row); - } - } - } - - // populate our display objects with object tiles - for (int ii = 0; ii < _objects.size(); ii++) { - if (!populateObject((DisplayObjectInfo)_objects.get(ii))) { - // initialization failed, remove the object - _objects.remove(ii--); - } - } - } - - // documentation inherited from interface - public void setBaseTile (int fqTileId, int x, int y) - { - super.setBaseTile(fqTileId, x, y); - populateBaseTile(fqTileId, x, y); - - // setting a base tile has the side-effect of clearing out the - // surrounding fringe tiles. - for (int xx=Math.max(x - 1, 0), - xn=Math.min(x + 1, _model.width - 1); xx <= xn; xx++) { - for (int yy=Math.max(y - 1, 0), - yn=Math.min(y + 1, _model.height - 1); yy <= yn; yy++) { - _fringe[yy * _model.width + xx] = null; - } - } - } - - // documentation inherited from interface - public ObjectInfo addObject (int fqTileId, int x, int y) - { - DisplayObjectInfo info = (DisplayObjectInfo) - super.addObject(fqTileId, x, y); - populateObject(info); - return info; - } - - // documentation inherited from interface - public boolean removeObject (ObjectInfo info) - { - if (super.removeObject(info)) { - // clear out this object's "shadow" - DisplayObjectInfo dinfo = (DisplayObjectInfo)info; - setObjectTileFootprint(dinfo.tile, dinfo.x, dinfo.y, false); - return true; - } else { - return false; - } - } - - // documentation inherited from interface - public BaseTile getBaseTile (int x, int y) - { - if (x < 0 || y < 0 || x >= _model.width || y >= _model.height) { - return null; - } - return _base[y*_model.width+x]; - } - - // documentation inherited from interface - public Tile getFringeTile (int x, int y) - { - if (x < 0 || y < 0 || x >= _model.width || y >= _model.height) { - return null; - } - - // if we have not yet composed this fringe tile, do so - int idx = y * _model.width + x; - if (_fringe[idx] == null) { - _fringe[idx] = _fringer.getFringeTile(this, x, y, _masks, _rando); - // make a note of non-fringed tiles that have been resolved - // but have no fringe tile - if (_fringe[idx] == null) { - _fringe[idx] = _nullFringe; - } - } - - return (_fringe[idx] == _nullFringe) ? null : _fringe[idx]; - } - - // documentation inherited from interface - public boolean canTraverse (Object trav, int x, int y) - { - BaseTile tile = getBaseTile(x, y); - return (((tile != null) && tile.isPassable()) && - !_covered[y*_model.width+x]); - } - - /** - * Called to populate a coordinate with its base tile. - */ - protected void populateBaseTile (int fqTileId, int x, int y) - { - if (x < 0 || y < 0 || x >= _model.width || y >= _model.height) { - // nothing doing - return; - } - - // this is a bit magical, but the tile manager will fetch tiles - // from the tileset repository and the tile set id from which we - // request this tile must map to a base tile as provided by the - // repository, so we just cast it to a base tile and know that all - // is well - String errmsg = null; - try { - _base[y*_model.width+x] = (BaseTile)_tmgr.getTile(fqTileId); - } catch (ClassCastException cce) { - errmsg = "Scene contains non-base tile in base layer"; - } catch (NoSuchTileSetException nste) { - errmsg = "Scene contains non-existent tileset"; - } catch (NoSuchTileException nste) { - errmsg = "Scene contains non-existent tile"; - } - - if (errmsg != null) { - Log.warning(errmsg + " [fqtid=" + fqTileId + - ", x=" + x + ", y=" + y + "]."); - } - } - - /** - * Called to populate an object with its object tile. - */ - protected boolean populateObject (DisplayObjectInfo info) - { - int tsid = (info.tileId >> 16) & 0xFFFF, tid = (info.tileId & 0xFFFF); - try { - initObject(info, (ObjectTile)_tmgr.getTile( - tsid, tid, getColorizer(info))); - return true; - } catch (NoSuchTileException nste) { - Log.warning("Scene contains non-existent object tile " + - "[info=" + info + "]."); - } catch (NoSuchTileSetException te) { - Log.warning("Scene contains non-existent object tileset " + - "[info=" + info + "]."); - } - return false; - } - - /** - * Initializes the supplied object with its object tile and configures - * any necessary peripheral scene business that couldn't be configured - * prior to the object having its tile. - */ - protected void initObject (DisplayObjectInfo info, ObjectTile tile) - { - // configure the object info with its object tile - info.setObjectTile(tile); - - // generate a "shadow" for this object tile by toggling the - // "covered" flag on in all base tiles below it (to prevent - // sprites from walking on those tiles) - setObjectTileFootprint(info.tile, info.x, info.y, true); - } - - /** - * Locates the display object info record for the object tile at the - * specified location. Two of the same kind of object tile cannot - * exist at the same location. - */ - protected DisplayObjectInfo getObjectInfo (ObjectTile tile, int x, int y) - { - int ocount = _objects.size(); - for (int ii = 0; ii < ocount; ii++) { - DisplayObjectInfo oinfo = (DisplayObjectInfo)_objects.get(ii); - if (oinfo.tile == tile && oinfo.x == x && oinfo.y == y) { - return oinfo; - } - } - return null; - } - - /** - * Sets the "covered" flag on all base tiles that are in the footprint - * of the specified object tile. - * - * @param otile the object tile whose footprint should be set. - * @param x the tile x-coordinate. - * @param y the tile y-coordinate. - * @param covered whether or not the footprint is being covered or - * uncovered. - */ - protected void setObjectTileFootprint ( - ObjectTile otile, int x, int y, boolean covered) - { - int endx = Math.max(0, (x - otile.getBaseWidth() + 1)); - int endy = Math.max(0, (y - otile.getBaseHeight() + 1)); - - for (int xx = x; xx >= endx; xx--) { - if ((xx < 0) || (xx >= _model.width)) { - continue; - } - - for (int yy = y; yy >= endy; yy--) { - if ((yy < 0) || (yy >= _model.height)) { - continue; - } - - _covered[yy*_model.width+xx] = true; - } - } - - // Log.info("Set object tile footprint [tile=" + otile + ", sx=" + x + - // ", sy=" + y + ", ex=" + endx + ", ey=" + endy + "]."); - } - - // documentation inherited - protected ObjectInfo createObjectInfo (int tileId, int x, int y) - { - return new DisplayObjectInfo(tileId, x, y); - } - - // documentation inherited - protected ObjectInfo createObjectInfo (ObjectInfo source) - { - return new DisplayObjectInfo(source); - } - - /** - * Returns the colorizer for the specified display object. The - * colorizer must provide colorization assignments that will be used - * to recolor the tile image when it is obtained from the tile - * manager. For an object with no colorizations, it is valid to return - * null here. - */ - protected TileSet.Colorizer getColorizer (DisplayObjectInfo oinfo) - { - return null; - } - - /** The tile manager from which we load tiles. */ - protected MisoTileManager _tmgr; - - /** The base layer of tiles. */ - protected BaseTile[] _base; - - /** The fringe layer of tiles. */ - protected Tile[] _fringe; - - /** Contains cached fringe mask tiles. TODO: LRU this or something. */ - protected HashMap _masks = new HashMap(); - - /** Used to identify non-existent fringe tiles. */ - protected Tile _nullFringe; - - /** Information on which tiles are covered by object tiles. */ - protected boolean[] _covered; - - /** The autofringer. */ - protected AutoFringer _fringer; -} diff --git a/src/java/com/threerings/miso/client/TilePath.java b/src/java/com/threerings/miso/client/TilePath.java index cfdecb14b..bc859c959 100644 --- a/src/java/com/threerings/miso/client/TilePath.java +++ b/src/java/com/threerings/miso/client/TilePath.java @@ -1,5 +1,5 @@ // -// $Id: TilePath.java,v 1.13 2003/01/31 23:10:45 mdb Exp $ +// $Id: TilePath.java,v 1.14 2003/04/17 19:21:16 mdb Exp $ package com.threerings.miso.client; @@ -14,7 +14,8 @@ import com.threerings.media.util.PathNode; import com.threerings.media.util.Pathable; import com.threerings.miso.Log; -import com.threerings.miso.client.util.IsoUtil; +import com.threerings.miso.util.MisoSceneMetrics; +import com.threerings.miso.util.MisoUtil; /** * The tile path represents a path of tiles through a scene. The path is @@ -28,7 +29,8 @@ public class TilePath extends LineSegmentPath /** * Constructs a tile path. * - * @param model the iso scene view model the path is associated with. + * @param metrics the metrics for the scene the with which the path is + * associated. * @param sprite the sprite to follow the path. * @param tiles the tiles to be traversed during the path. * @param destx the destination x-position in screen pixel @@ -36,10 +38,10 @@ public class TilePath extends LineSegmentPath * @param desty the destination y-position in screen pixel * coordinates. */ - public TilePath (IsoSceneViewModel model, Sprite sprite, + public TilePath (MisoSceneMetrics metrics, Sprite sprite, List tiles, int destx, int desty) { - _model = model; + _metrics = metrics; // set up the path nodes createPath(sprite, tiles, destx, desty); @@ -58,7 +60,7 @@ public class TilePath extends LineSegmentPath // check whether we've arrived at the destination tile if (!_arrived) { // get the sprite's latest tile coordinates - IsoUtil.screenToTile(_model, sx, sy, pos); + MisoUtil.screenToTile(_metrics, sx, sy, pos); // if the sprite has reached the destination tile, // update the sprite's tile location and remember @@ -98,12 +100,12 @@ public class TilePath extends LineSegmentPath { // constrain destination pixels to fine coordinates Point fpos = new Point(); - IsoUtil.screenToFull(_model, destx, desty, fpos); + MisoUtil.screenToFull(_metrics, destx, desty, fpos); // add the starting path node Point ipos = new Point(); int sx = sprite.getX(), sy = sprite.getY(); - IsoUtil.screenToTile(_model, sx, sy, ipos); + MisoUtil.screenToTile(_metrics, sx, sy, ipos); addNode(ipos.x, ipos.y, sx, sy, NORTH); // TODO: make more visually appealing path segments from start @@ -117,15 +119,15 @@ public class TilePath extends LineSegmentPath Point next = (Point)tiles.get(ii); // determine the direction from previous to next node - int dir = IsoUtil.getIsoDirection(prev.x, prev.y, next.x, next.y); + int dir = MisoUtil.getIsoDirection(prev.x, prev.y, next.x, next.y); // determine the node's position in screen pixel coordinates - IsoUtil.tileToScreen(_model, next.x, next.y, spos); + MisoUtil.tileToScreen(_metrics, next.x, next.y, spos); // add the node to the path, wandering through the middle // of each tile in the path for now - int dsx = spos.x + _model.tilehwid; - int dsy = spos.y + _model.tilehhei; + int dsx = spos.x + _metrics.tilehwid; + int dsy = spos.y + _metrics.tilehhei; addNode(next.x, next.y, dsx, dsy, dir); prev = next; @@ -133,22 +135,22 @@ public class TilePath extends LineSegmentPath // get the final destination point's screen coordinates // constrained to the closest full coordinate - IsoUtil.fullToScreen(_model, fpos.x, fpos.y, spos); + MisoUtil.fullToScreen(_metrics, fpos.x, fpos.y, spos); // get the tile coordinates for the final destination tile - int tdestx = IsoUtil.fullToTile(fpos.x); - int tdesty = IsoUtil.fullToTile(fpos.y); + int tdestx = MisoUtil.fullToTile(fpos.x); + int tdesty = MisoUtil.fullToTile(fpos.y); // get the facing direction for the final node int dir; if (prev.x == ipos.x && prev.y == ipos.y) { // if destination is within starting tile, direction is // determined by studying the fine coordinates - dir = IsoUtil.getDirection(_model, sx, sy, spos.x, spos.y); + dir = MisoUtil.getDirection(_metrics, sx, sy, spos.x, spos.y); } else { // else it's based on the last tile we traversed - dir = IsoUtil.getIsoDirection(prev.x, prev.y, tdestx, tdesty); + dir = MisoUtil.getIsoDirection(prev.x, prev.y, tdestx, tdesty); } // add the final destination path node @@ -176,6 +178,6 @@ public class TilePath extends LineSegmentPath /** The destination tile path node. */ protected TilePathNode _dest; - /** The iso scene view model. */ - protected IsoSceneViewModel _model; + /** The scene metrics. */ + protected MisoSceneMetrics _metrics; } diff --git a/src/java/com/threerings/miso/client/VirtualDisplayMisoSceneImpl.java b/src/java/com/threerings/miso/client/VirtualDisplayMisoSceneImpl.java deleted file mode 100644 index 529597b60..000000000 --- a/src/java/com/threerings/miso/client/VirtualDisplayMisoSceneImpl.java +++ /dev/null @@ -1,87 +0,0 @@ -// -// $Id: VirtualDisplayMisoSceneImpl.java,v 1.2 2003/04/01 02:17:58 mdb Exp $ - -package com.threerings.miso.client; - -import java.awt.Rectangle; - -import com.threerings.media.tile.Tile; - -import com.threerings.miso.client.util.ObjectSet; -import com.threerings.miso.data.MisoSceneModel; -import com.threerings.miso.data.ObjectInfo; -import com.threerings.miso.tile.BaseTile; - -/** - * Provides a useful base class for "virtual" {@link DisplayMisoScene} - * implementations. These return tiles based on some algorithm rather than - * a repository of predefined tile data. - */ -public class VirtualDisplayMisoSceneImpl - implements DisplayMisoScene -{ - // documentation inherited from interface - public void init () - { - } - - // documentation inherited from interface - public int getBaseTileId (int x, int y) - { - return -1; - } - - // documentation inherited from interface - public void getObjects (Rectangle region, ObjectSet set) - { - // nothing doing - } - - // documentation inherited from interface - public void setBaseTile (int fqTileId, int x, int y) - { - // nothing doing - } - - // documentation inherited from interface - public void setBaseTiles (Rectangle r, int setId, int setSize) - { - // nothing doing - } - - // documentation inherited from interface - public ObjectInfo addObject (int fqTileId, int x, int y) - { - return null; - } - - // documentation inherited from interface - public boolean removeObject (ObjectInfo info) - { - return false; - } - - // documentation inherited from interface - public MisoSceneModel getSceneModel () - { - return null; - } - - // documentation inherited from interface - public BaseTile getBaseTile (int x, int y) - { - return null; - } - - // documentation inherited from interface - public Tile getFringeTile (int x, int y) - { - return null; - } - - // documentation inherited from interface - public boolean canTraverse (Object traverser, int x, int y) - { - return true; - } -} diff --git a/src/java/com/threerings/miso/data/MisoScene.java b/src/java/com/threerings/miso/data/MisoScene.java deleted file mode 100644 index 8e1205449..000000000 --- a/src/java/com/threerings/miso/data/MisoScene.java +++ /dev/null @@ -1,77 +0,0 @@ -// -// $Id: MisoScene.java,v 1.3 2003/02/24 18:40:41 mdb Exp $ - -package com.threerings.miso.data; - -import java.awt.Rectangle; - -import com.threerings.miso.client.util.ObjectSet; - -/** - * Provides information on the composition of tiles in a Miso scene. - */ -public interface MisoScene -{ - /** - * Returns the fully qualified tile id of the base tile at the - * specified coordinates. -1 will be returned if there is - * no tile at the specified coordinate. - */ - public int getBaseTileId (int x, int y); - - /** - * Populates the supplied object set with info on all objects whose - * origin falls in the requested region. - */ - public void getObjects (Rectangle region, ObjectSet set); - - /** - * Updates the tile at the specified location in the base layer. - * - * @param fqTileId the fully-qualified tile id (@see - * TileUtil#getFQTileId}) of the tile to set. - * @param x the x-coordinate of the tile to set. - * @param y the y-coordinate of the tile to set. - * - * Note that if there are fringe tiles associated with this scene, - * calling this method may result in the surrounding fringe tiles being - * cleared and subsequently recalculated. This should not be called - * on a displaying scene unless you know what you are doing. - */ - public void setBaseTile (int fqTileId, int x, int y); - - /** - * Fill a rectangular area with random tiles from the specified base - * tileset. - * - * @param r the region to be filled. - * @param setId the id of the tileset to use when filling. - * @param setSize the number of tiles in the tileset. - */ - public void setBaseTiles (Rectangle r, int setId, int setSize); - - /** - * Adds an object to this scene. - * - * @param fqTileId the fully-qualified tile id (@see - * TileUtil#getFQTileId}) of the object tile. - * @param x the object's origin x-coordinate. - * @param y the object's origin y-coordinate. - * - * @return the new object info record. - */ - public ObjectInfo addObject (int fqTileId, int x, int y); - - /** - * Removes the specified object from the scene. - */ - public boolean removeObject (ObjectInfo info); - - /** - * Returns the scene model used by this scene. This is an expensive - * operation as it must recreate the scene model from the (possibly - * changed) runtime data. Thus it should not be called in a normal - * client display and is provided mainly for scene editors and such. - */ - public MisoSceneModel getSceneModel (); -} diff --git a/src/java/com/threerings/miso/data/MisoSceneModel.java b/src/java/com/threerings/miso/data/MisoSceneModel.java index 32e8f185b..80be14d29 100644 --- a/src/java/com/threerings/miso/data/MisoSceneModel.java +++ b/src/java/com/threerings/miso/data/MisoSceneModel.java @@ -1,48 +1,31 @@ // -// $Id: MisoSceneModel.java,v 1.13 2003/04/12 02:14:10 mdb Exp $ +// $Id: MisoSceneModel.java,v 1.14 2003/04/17 19:21:16 mdb Exp $ package com.threerings.miso.data; -import java.util.ArrayList; - -import com.samskivert.util.ArrayUtil; -import com.samskivert.util.IntListUtil; -import com.samskivert.util.ListUtil; +import java.awt.Rectangle; +import java.util.Random; import com.threerings.io.SimpleStreamableObject; + +import com.threerings.media.tile.TileUtil; import com.threerings.media.util.MathUtil; +import com.threerings.miso.util.ObjectSet; + /** * Contains basic information for a miso scene model that is shared among - * every specialized model implementation. + * the specialized model implementations. */ -public class MisoSceneModel extends SimpleStreamableObject +public abstract class MisoSceneModel extends SimpleStreamableObject implements Cloneable { - /** The width of this scene or section of the scene (depending on the - * model implementation), in tile units. */ + /** The width of this scene in tiles. */ public short width; - /** The height of this scene or section of the scene (depending on the - * model implementation), in tile units. */ + /** The height of this scene in tiles. */ public short height; - /** The combined tile ids (tile set id and tile id) of the - * "uninteresting" tiles in the object layer. */ - public int[] objectTileIds; - - /** The x coordinate of the "uninteresting" tiles in the object - * layer. */ - public short[] objectXs; - - /** The y coordinate of the "uninteresting" tiles in the object - * layer. */ - public short[] objectYs; - - /** Information records for the "interesting" objects in the object - * layer. */ - public ObjectInfo[] objectInfo; - /** * Creates a completely uninitialized model suitable for little more * than unserialization. @@ -60,47 +43,74 @@ public class MisoSceneModel extends SimpleStreamableObject Short.MIN_VALUE, width, Short.MAX_VALUE); this.height = (short)MathUtil.bound( Short.MIN_VALUE, height, Short.MAX_VALUE); - - // start with zero-length object arrays - objectTileIds = new int[0]; - objectXs = new short[0]; - objectYs = new short[0]; - objectInfo = new ObjectInfo[0]; } /** - * Adds an object to this model. + * Returns the fully qualified tile id of the base tile at the + * specified coordinates. -1 will be returned if there is + * no tile at the specified coordinate. */ - public void addObject (ObjectInfo info) + public abstract int getBaseTileId (int x, int y); + + /** + * Updates the tile at the specified location in the base layer. + * + *

Note that if there are fringe tiles associated with this scene, + * calling this method may result in the surrounding fringe tiles + * being cleared and subsequently recalculated. This should not be + * called on a displaying scene unless you know what you are doing. + * + * @param fqTileId the fully-qualified tile id (@see + * TileUtil#getFQTileId}) of the tile to set. + * @param x the x-coordinate of the tile to set. + * @param y the y-coordinate of the tile to set. + * + * @return false if the specified tile coordinates are outside of the + * scene and the tile was not saved, true otherwise. + */ + public abstract boolean setBaseTile (int fqTileId, int x, int y); + + /** + * Fill a rectangular area with random tiles from the specified base + * tileset. + * + * @param r the region to be filled. + * @param setId the id of the tileset to use when filling. + * @param setSize the number of tiles in the tileset. + */ + public void setBaseTiles (Rectangle r, int setId, int setSize) { - if (info.isInteresting()) { - objectInfo = (ObjectInfo[])ArrayUtil.append(objectInfo, info); - } else { - objectTileIds = ArrayUtil.append(objectTileIds, info.tileId); - objectXs = ArrayUtil.append(objectXs, (short)info.x); - objectYs = ArrayUtil.append(objectYs, (short)info.y); + for (int x = r.x; x < r.x + r.width; x++) { + for (int y = r.y; y < r.y + r.height; y++) { + int index = _rando.nextInt(setSize); + setBaseTile(TileUtil.getFQTileId(setId, index), x, y); + } } } /** - * Removes an object from this model. + * Populates the supplied object set with info on all objects whose + * origin falls in the requested region. */ - public void removeObject (ObjectInfo info) - { - // look for it in the interesting info array - int oidx = ListUtil.indexOfEqual(objectInfo, info); - if (oidx != -1) { - objectInfo = (ObjectInfo[])ArrayUtil.splice(objectInfo, oidx, 1); - } + public abstract void getObjects (Rectangle region, ObjectSet set); - // look for it in the uninteresting arrays - oidx = IntListUtil.indexOf(objectTileIds, info.tileId); - if (oidx != -1) { - objectTileIds = ArrayUtil.splice(objectTileIds, oidx, 1); - objectXs = ArrayUtil.splice(objectXs, oidx, 1); - objectYs = ArrayUtil.splice(objectYs, oidx, 1); - } - } + /** + * Adds an object to this scene. + */ + public abstract void addObject (ObjectInfo info); + + /** + * Updates an object in this scene. + */ + public abstract void updateObject (ObjectInfo info); + + /** + * Removes the specified object from the scene. + * + * @return true if it was removed, false if the object was not in the + * scene. + */ + public abstract boolean removeObject (ObjectInfo info); /** * Creates a copy of this scene model. @@ -108,39 +118,12 @@ public class MisoSceneModel extends SimpleStreamableObject public Object clone () { try { - MisoSceneModel model = (MisoSceneModel)super.clone(); - model.objectTileIds = (int[])objectTileIds.clone(); - model.objectXs = (short[])objectXs.clone(); - model.objectYs = (short[])objectYs.clone(); - model.objectInfo = (ObjectInfo[])objectInfo.clone(); - return model; + return (MisoSceneModel)super.clone(); } catch (CloneNotSupportedException cnse) { throw new RuntimeException("MisoSceneModel.clone: " + cnse); } } - /** - * Populates the interesting and uninteresting parts of a miso scene - * model given lists of {@link ObjectInfo} records for each. - */ - public static void populateObjects (MisoSceneModel model, - ArrayList ilist, ArrayList ulist) - { - // set up the uninteresting arrays - int ucount = ulist.size(); - model.objectTileIds = new int[ucount]; - model.objectXs = new short[ucount]; - model.objectYs = new short[ucount]; - for (int ii = 0; ii < ucount; ii++) { - ObjectInfo info = (ObjectInfo)ulist.get(ii); - model.objectTileIds[ii] = info.tileId; - model.objectXs[ii] = (short)info.x; - model.objectYs[ii] = (short)info.y; - } - - // set up the interesting array - int icount = ilist.size(); - model.objectInfo = new ObjectInfo[icount]; - ilist.toArray(model.objectInfo); - } + /** A random number generator for filling random base tiles. */ + protected transient Random _rando = new Random(); } diff --git a/src/java/com/threerings/miso/data/SimpleMisoSceneImpl.java b/src/java/com/threerings/miso/data/SimpleMisoSceneImpl.java deleted file mode 100644 index 6fe74b83a..000000000 --- a/src/java/com/threerings/miso/data/SimpleMisoSceneImpl.java +++ /dev/null @@ -1,175 +0,0 @@ -// -// $Id: SimpleMisoSceneImpl.java,v 1.2 2003/02/24 18:40:41 mdb Exp $ - -package com.threerings.miso.data; - -import java.awt.Rectangle; -import java.util.ArrayList; -import java.util.Random; - -import com.threerings.media.tile.TileUtil; - -import com.threerings.miso.Log; -import com.threerings.miso.client.util.ObjectSet; - -/** - * A simple implementation of the {@link MisoScene} interface that assumes - * a scene will be relatively small and all tile and object data can be - * held in memory all at once. - */ -public class SimpleMisoSceneImpl - implements MisoScene -{ - /** - * Creates an initializes an instance using the supplied source model. - */ - public SimpleMisoSceneImpl (SimpleMisoSceneModel model) - { - _model = model; - - // create display object infos for our uninteresting objects - int ocount = (_model.objectTileIds == null) ? 0 : - _model.objectTileIds.length; - for (int ii = 0; ii < ocount; ii++) { - _objects.add(createObjectInfo(_model.objectTileIds[ii], - _model.objectXs[ii], - _model.objectYs[ii])); - } - - // create display object infos for our interesting objects - for (int ii = 0, ll = _model.objectInfo.length; ii < ll; ii++) { - // replace the object info in our model with the possibly - // expanded derived class - _model.objectInfo[ii] = createObjectInfo(_model.objectInfo[ii]); - _objects.add(_model.objectInfo[ii]); - } - } - - // documentation inherited from interface - public int getBaseTileId (int x, int y) - { - return _model.getBaseTile(x, y); - } - - // documentation inherited from interface - public void getObjects (Rectangle region, ObjectSet set) - { - for (int ii = 0, ll = _objects.size(); ii < ll; ii++) { - ObjectInfo info = (ObjectInfo)_objects.get(ii); - if (region.contains(info.x, info.y)) { - set.insert(info); - } - } - } - - // documentation inherited from interface - public void setBaseTile (int fqTileId, int x, int y) - { - _model.setBaseTile(x, y, fqTileId); - } - - // documentation inherited from interface - public void setBaseTiles (Rectangle r, int setId, int setSize) - { - for (int x = r.x; x < r.x + r.width; x++) { - for (int y = r.y; y < r.y + r.height; y++) { - int index = _rando.nextInt(setSize); - setBaseTile(TileUtil.getFQTileId(setId, index), x, y); - } - } - } - - // documentation inherited from interface - public ObjectInfo addObject (int fqTileId, int x, int y) - { - ObjectInfo info = createObjectInfo(fqTileId, x, y); - _objects.add(info); - return info; - } - - // documentation inherited from interface - public boolean removeObject (ObjectInfo info) - { - return _objects.remove(info); - } - - // documentation inherited from interface - public MisoSceneModel getSceneModel () - { - // flush our objects list back to the arrays so that we pick up - // any changes made since we created the list from the model - int plain = 0, ocount = _objects.size(); - for (int ii = 0; ii < ocount; ii++) { - ObjectInfo info = (ObjectInfo)_objects.get(ii); - if (!info.isInteresting()) { - plain++; - } - } - - // create new arrays of the appropriate size - _model.objectInfo = new ObjectInfo[ocount-plain]; - _model.objectTileIds = new int[plain]; - _model.objectXs = new short[plain]; - _model.objectYs = new short[plain]; - - // populate those arrays appropriately - for (int cc = 0, pp = 0, ii = 0; cc < ocount; cc++) { - ObjectInfo info = (ObjectInfo)_objects.get(cc); - if (info.isInteresting()) { - _model.objectInfo[ii++] = info; - } else { - _model.objectTileIds[pp] = info.tileId; - _model.objectXs[pp] = (short)info.x; - _model.objectYs[pp++] = (short)info.y; - } - } - - return _model; - } - - /** - * Return a string representation of this Miso scene object. - */ - public String toString () - { - StringBuffer buf = new StringBuffer("["); - toString(buf); - return buf.append("]").toString(); - } - - /** - * An extensible {@link #toString()} helper. - */ - protected void toString (StringBuffer buf) - { - buf.append("width=").append(_model.width); - buf.append(", height=").append(_model.height); - } - - /** - * Creates an {@link ObjectInfo} record from the supplied tile - * information. - */ - protected ObjectInfo createObjectInfo (int tileId, int x, int y) - { - return new ObjectInfo(tileId, x, y); - } - - /** - * Creates an {@link ObjectInfo} record from the supplied source - * record. - */ - protected ObjectInfo createObjectInfo (ObjectInfo source) - { - return source; - } - - /** The miso scene model from which we obtain our data. */ - protected SimpleMisoSceneModel _model; - - /** The scene object records. */ - protected ArrayList _objects = new ArrayList(); - - /** A random number generator for filling random base tiles. */ - protected Random _rando = new Random(); -} diff --git a/src/java/com/threerings/miso/data/SimpleMisoSceneModel.java b/src/java/com/threerings/miso/data/SimpleMisoSceneModel.java index 818a3ca11..cfbc7fc7a 100644 --- a/src/java/com/threerings/miso/data/SimpleMisoSceneModel.java +++ b/src/java/com/threerings/miso/data/SimpleMisoSceneModel.java @@ -1,14 +1,17 @@ // -// $Id: SimpleMisoSceneModel.java,v 1.2 2003/04/12 02:14:10 mdb Exp $ +// $Id: SimpleMisoSceneModel.java,v 1.3 2003/04/17 19:21:16 mdb Exp $ package com.threerings.miso.data; +import java.awt.Rectangle; import java.util.ArrayList; import com.samskivert.util.ArrayUtil; import com.samskivert.util.IntListUtil; import com.samskivert.util.ListUtil; +import com.threerings.miso.util.ObjectSet; + /** * Contains miso scene data for a scene that is assumed to be reasonably * simple and small, such that all base tile data for the entire scene can @@ -33,6 +36,22 @@ public class SimpleMisoSceneModel extends MisoSceneModel * methods. */ public int[] baseTileIds; + /** The combined tile ids (tile set id and tile id) of the + * "uninteresting" tiles in the object layer. */ + public int[] objectTileIds; + + /** The x coordinate of the "uninteresting" tiles in the object + * layer. */ + public short[] objectXs; + + /** The y coordinate of the "uninteresting" tiles in the object + * layer. */ + public short[] objectYs; + + /** Information records for the "interesting" objects in the object + * layer. */ + public ObjectInfo[] objectInfo; + /** * Creates a completely uninitialized model suitable for little more * than unserialization. @@ -50,24 +69,22 @@ public class SimpleMisoSceneModel extends MisoSceneModel this.vwidth = vwidth; this.vheight = vheight; allocateBaseTileArray(); + + // start with zero-length object arrays + objectTileIds = new int[0]; + objectXs = new short[0]; + objectYs = new short[0]; + objectInfo = new ObjectInfo[0]; } - /** - * Get the fully-qualified tile id of the base tile at the specified - * row and column. - */ - public int getBaseTile (int col, int row) + // documentation inherited + public int getBaseTileId (int col, int row) { int index = getIndex(col, row); return (index == -1) ? 0 : baseTileIds[index]; } - /** - * Set the fully-qualified tile id of a base tile. - * - * @return false if the specified tile coordinates are outside - * of the viewport and the tile was not saved. - */ + // documentation inherited public boolean setBaseTile (int col, int row, int fqBaseTileId) { int index = getIndex(col, row); @@ -78,6 +95,80 @@ public class SimpleMisoSceneModel extends MisoSceneModel return true; } + // documentation inherited + public void getObjects (Rectangle region, ObjectSet set) + { + // first look for intersecting interesting objects + for (int ii = 0; ii < objectInfo.length; ii++) { + ObjectInfo info = objectInfo[ii]; + if (region.contains(info.x, info.y)) { + set.insert(info); + } + } + + // now look for intersecting non-interesting objects + for (int ii = 0; ii < objectTileIds.length; ii++) { + int x = objectXs[ii], y = objectYs[ii]; + if (region.contains(x, y)) { + set.insert(new ObjectInfo(objectTileIds[ii], x, y)); + } + } + } + + // documentation inherited + public void addObject (ObjectInfo info) + { + if (info.isInteresting()) { + objectInfo = (ObjectInfo[])ArrayUtil.append(objectInfo, info); + } else { + objectTileIds = ArrayUtil.append(objectTileIds, info.tileId); + objectXs = ArrayUtil.append(objectXs, (short)info.x); + objectYs = ArrayUtil.append(objectYs, (short)info.y); + } + } + + // documentation inherited + public void updateObject (ObjectInfo info) + { + // not efficient, but this is only done in editing situations + removeObject(info); + addObject(info); + } + + // documentation inherited + public boolean removeObject (ObjectInfo info) + { + // look for it in the interesting info array + int oidx = ListUtil.indexOfEqual(objectInfo, info); + if (oidx != -1) { + objectInfo = (ObjectInfo[])ArrayUtil.splice(objectInfo, oidx, 1); + return true; + } + + // look for it in the uninteresting arrays + oidx = IntListUtil.indexOf(objectTileIds, info.tileId); + if (oidx != -1) { + objectTileIds = ArrayUtil.splice(objectTileIds, oidx, 1); + objectXs = ArrayUtil.splice(objectXs, oidx, 1); + objectYs = ArrayUtil.splice(objectYs, oidx, 1); + return true; + } + + return false; + } + + // documentation inherited + public Object clone () + { + SimpleMisoSceneModel model = (SimpleMisoSceneModel)super.clone(); + model.baseTileIds = (int[])baseTileIds.clone(); + model.objectTileIds = (int[])objectTileIds.clone(); + model.objectXs = (short[])objectXs.clone(); + model.objectYs = (short[])objectYs.clone(); + model.objectInfo = (ObjectInfo[])objectInfo.clone(); + return model; + } + /** * Get the index into the baseTileIds[] for the specified * x and y coordinates, or return -1 if the specified coordinates @@ -135,11 +226,28 @@ public class SimpleMisoSceneModel extends MisoSceneModel baseTileIds = new int[vwidth + vheight + ((vwidth * vheight) << 1)]; } - // documentation inherited - public Object clone () + /** + * Populates the interesting and uninteresting parts of a miso scene + * model given lists of {@link ObjectInfo} records for each. + */ + public static void populateObjects (SimpleMisoSceneModel model, + ArrayList ilist, ArrayList ulist) { - SimpleMisoSceneModel model = (SimpleMisoSceneModel)super.clone(); - model.baseTileIds = (int[])baseTileIds.clone(); - return model; + // set up the uninteresting arrays + int ucount = ulist.size(); + model.objectTileIds = new int[ucount]; + model.objectXs = new short[ucount]; + model.objectYs = new short[ucount]; + for (int ii = 0; ii < ucount; ii++) { + ObjectInfo info = (ObjectInfo)ulist.get(ii); + model.objectTileIds[ii] = info.tileId; + model.objectXs[ii] = (short)info.x; + model.objectYs[ii] = (short)info.y; + } + + // set up the interesting array + int icount = ilist.size(); + model.objectInfo = new ObjectInfo[icount]; + ilist.toArray(model.objectInfo); } } diff --git a/src/java/com/threerings/miso/data/VirtualMisoSceneModel.java b/src/java/com/threerings/miso/data/VirtualMisoSceneModel.java new file mode 100644 index 000000000..ee64c93b7 --- /dev/null +++ b/src/java/com/threerings/miso/data/VirtualMisoSceneModel.java @@ -0,0 +1,53 @@ +// +// $Id: VirtualMisoSceneModel.java,v 1.1 2003/04/17 19:21:16 mdb Exp $ + +package com.threerings.miso.data; + +import java.awt.Rectangle; + +/** + * A convenient base class for "virtual" scenes which do not allow editing + * and compute the base and object tiles rather than obtain them from some + * data structure. + */ +public abstract class VirtualMisoSceneModel extends MisoSceneModel +{ + public VirtualMisoSceneModel () + { + } + + public VirtualMisoSceneModel (int width, int height) + { + super(width, height); + } + + // documentation inherited from interface + public boolean setBaseTile (int fqTileId, int x, int y) + { + throw new UnsupportedOperationException(); + } + + // documentation inherited from interface + public void setBaseTiles (Rectangle r, int setId, int setSize) + { + throw new UnsupportedOperationException(); + } + + // documentation inherited from interface + public void addObject (ObjectInfo info) + { + throw new UnsupportedOperationException(); + } + + // documentation inherited from interface + public void updateObject (ObjectInfo info) + { + throw new UnsupportedOperationException(); + } + + // documentation inherited from interface + public boolean removeObject (ObjectInfo info) + { + throw new UnsupportedOperationException(); + } +} diff --git a/src/java/com/threerings/miso/tile/AutoFringer.java b/src/java/com/threerings/miso/tile/AutoFringer.java index 327e96801..18b74f660 100644 --- a/src/java/com/threerings/miso/tile/AutoFringer.java +++ b/src/java/com/threerings/miso/tile/AutoFringer.java @@ -1,5 +1,5 @@ // -// $Id: AutoFringer.java,v 1.19 2003/02/12 05:38:12 mdb Exp $ +// $Id: AutoFringer.java,v 1.20 2003/04/17 19:21:16 mdb Exp $ package com.threerings.miso.tile; @@ -32,7 +32,7 @@ import com.threerings.media.image.BackedVolatileMirage; import com.threerings.media.image.ImageManager; import com.threerings.media.image.Mirage; -import com.threerings.miso.data.MisoScene; +import com.threerings.miso.data.MisoSceneModel; /** * Automatically fringes a scene according to the rules in the supplied @@ -56,7 +56,7 @@ public class AutoFringer * Compute and return the fringe tile to be inserted at the specified * location. */ - public Tile getFringeTile (MisoScene scene, int col, int row, + public Tile getFringeTile (MisoSceneModel scene, int col, int row, HashMap masks, Random rando) { // get the tileset id of the base tile we are considering diff --git a/src/java/com/threerings/miso/tools/xml/SimpleMisoSceneParser.java b/src/java/com/threerings/miso/tools/xml/SimpleMisoSceneParser.java new file mode 100644 index 000000000..e43a923c5 --- /dev/null +++ b/src/java/com/threerings/miso/tools/xml/SimpleMisoSceneParser.java @@ -0,0 +1,73 @@ +// +// $Id: SimpleMisoSceneParser.java,v 1.1 2003/04/17 19:21:16 mdb Exp $ + +package com.threerings.miso.tools.xml; + +import java.io.IOException; +import java.io.FileInputStream; + +import org.xml.sax.SAXException; +import org.apache.commons.digester.Digester; + +import com.samskivert.util.StringUtil; +import com.threerings.tools.xml.NestableRuleSet; + +import com.threerings.miso.data.SimpleMisoSceneModel; + +/** + * A simple class for parsing simple miso scene models. + */ +public class SimpleMisoSceneParser +{ + /** + * Constructs a scene parser that parses scenes with the specified XML + * path prefix. + */ + public SimpleMisoSceneParser (String prefix) + { + // create and configure our digester + _digester = new Digester(); + + // create our scene rule set + SimpleMisoSceneRuleSet set = new SimpleMisoSceneRuleSet(); + + // configure our top-level path prefix + if (StringUtil.blank(prefix)) { + _prefix = set.getOuterElement(); + } else { + _prefix = prefix + "/" + set.getOuterElement(); + } + + // add the scene rules + set.addRuleInstances(_prefix, _digester); + + // add a rule to grab the finished scene model + _digester.addSetNext( + _prefix, "setScene", SimpleMisoSceneModel.class.getName()); + } + + /** + * Parses the XML file at the specified path into a scene model + * instance. + */ + public SimpleMisoSceneModel parseScene (String path) + throws IOException, SAXException + { + _model = null; + _digester.push(this); + _digester.parse(new FileInputStream(path)); + return _model; + } + + /** + * Called by the parser once the scene is parsed. + */ + public void setScene (SimpleMisoSceneModel model) + { + _model = model; + } + + protected String _prefix; + protected Digester _digester; + protected SimpleMisoSceneModel _model; +} diff --git a/src/java/com/threerings/miso/client/util/AStarPathUtil.java b/src/java/com/threerings/miso/util/AStarPathUtil.java similarity index 99% rename from src/java/com/threerings/miso/client/util/AStarPathUtil.java rename to src/java/com/threerings/miso/util/AStarPathUtil.java index 839c64124..a289660d2 100644 --- a/src/java/com/threerings/miso/client/util/AStarPathUtil.java +++ b/src/java/com/threerings/miso/util/AStarPathUtil.java @@ -1,7 +1,7 @@ // -// $Id: AStarPathUtil.java,v 1.27 2003/04/12 02:14:52 mdb Exp $ +// $Id: AStarPathUtil.java,v 1.1 2003/04/17 19:21:16 mdb Exp $ -package com.threerings.miso.client.util; +package com.threerings.miso.util; import java.awt.Point; import java.util.*; diff --git a/src/java/com/threerings/miso/util/MisoContext.java b/src/java/com/threerings/miso/util/MisoContext.java index 923c68d61..5df8c3466 100644 --- a/src/java/com/threerings/miso/util/MisoContext.java +++ b/src/java/com/threerings/miso/util/MisoContext.java @@ -1,8 +1,9 @@ // -// $Id: MisoContext.java,v 1.9 2002/04/06 02:04:23 mdb Exp $ +// $Id: MisoContext.java,v 1.10 2003/04/17 19:21:16 mdb Exp $ package com.threerings.miso.util; +import com.threerings.media.FrameManager; import com.threerings.miso.tile.MisoTileManager; /** @@ -11,6 +12,11 @@ import com.threerings.miso.tile.MisoTileManager; */ public interface MisoContext { + /** + * Returns the frame manager that our scene panel will interact with. + */ + public FrameManager getFrameManager (); + /** * Returns a reference to the tile manager. This reference is valid * for the lifetime of the application. diff --git a/src/java/com/threerings/miso/util/MisoSceneMetrics.java b/src/java/com/threerings/miso/util/MisoSceneMetrics.java new file mode 100644 index 000000000..03d19cddf --- /dev/null +++ b/src/java/com/threerings/miso/util/MisoSceneMetrics.java @@ -0,0 +1,134 @@ +// +// $Id: MisoSceneMetrics.java,v 1.1 2003/04/17 19:21:16 mdb Exp $ + +package com.threerings.miso.util; + +import java.awt.Point; +import java.awt.Rectangle; + +/** + * Contains information on the configuration of a particular isometric + * view. The member data are public to facilitate convenient referencing + * by the {@link MisoScenePanel} class, the values should not be modified + * once the metrics are constructed. + */ +public class MisoSceneMetrics +{ + /** Tile dimensions and half-dimensions in the view. */ + public int tilewid, tilehei, tilehwid, tilehhei; + + /** Fine coordinate dimensions. */ + public int finehwid, finehhei; + + /** Number of fine coordinates on each axis within a tile. */ + public int finegran; + + /** Size of the view in tile count. */ + public int scenevwid, scenevhei; + + /** Dimensions of our scene blocks in tile count. */ + public int blockwid = 10, blockhei = 10; + + /** Whether or not this view can extend beyond the bounds defined by + * the view width and height. True if it cannot, false if it can. */ + public boolean bounded = true; + + /** 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; + + /** The length of a tile edge in pixels. */ + public float tilelen; + + /** The slope of the x- and y-axis lines. */ + public float slopeX, slopeY; + + /** The length between fine coordinates in pixels. */ + public float finelen; + + /** The y-intercept of the x-axis line within a tile. */ + public float fineBX; + + /** The slope of the x- and y-axis lines within a tile. */ + public float fineSlopeX, fineSlopeY; + + /** + * Constructs scene metrics by directly specifying the desired config + * parameters. + * + * @param tilewid the width in pixels of the tiles. + * @param tilehei the height in pixels of the tiles. + * @param finegran the number of sub-tile divisions to use for fine + * coordinates. + * @param svwid the width in tiles of the viewport. + * @param svhei the height in tiles of the viewport. + * @param offy the offset of the origin (in tiles) from the top of the + * viewport. + */ + public MisoSceneMetrics (int tilewid, int tilehei, int finegran, + int svwid, int svhei, int offy) + { + // keep track of this stuff + this.tilewid = tilewid; + this.tilehei = tilehei; + this.finegran = finegran; + this.scenevwid = svwid; + this.scenevhei = svhei; + + // set the desired scene view bounds + bounds = new Rectangle(0, 0, scenevwid * tilewid, scenevhei * tilehei); + + // set the scene display origin + origin = new Point((bounds.width / 2), (offy * tilehei)); + + // halve the dimensions + tilehwid = (tilewid / 2); + tilehhei = (tilehei / 2); + + // calculate the length of a tile edge in pixels + tilelen = (float) Math.sqrt( + (tilehwid * tilehwid) + (tilehhei * tilehhei)); + + // calculate the slope of the x- and y-axis lines + slopeX = (float)tilehei / (float)tilewid; + slopeY = -slopeX; + + // calculate the edge length separating each fine coordinate + finelen = tilelen / (float)finegran; + + // calculate the fine-coordinate x-axis line + fineSlopeX = (float)tilehei / (float)tilewid; + fineBX = -(fineSlopeX * (float)tilehwid); + fineSlopeY = -fineSlopeX; + + // calculate the fine coordinate dimensions + finehwid = (int)((float)tilehwid / (float)finegran); + finehhei = (int)((float)tilehhei / (float)finegran); + } + + /** + * Returns whether the given tile coordinate is a valid coordinate in + * our coordinate system (which allows tile coordinates from 0 to + * 2^15-1). + */ + public boolean isCoordinateValid (int x, int y) + { + return (x >= 0 && x < Short.MAX_VALUE && + y >= 0 && y < Short.MAX_VALUE); + } + + /** + * Returns whether the given full coordinate is a valid coordinate + * within the scene. + */ + public boolean isFullCoordinateValid (int x, int y) + { + int tx = MisoUtil.fullToTile(x), ty = MisoUtil.fullToTile(y); + int fx = MisoUtil.fullToFine(x), fy = MisoUtil.fullToFine(y); + return (isCoordinateValid(tx, ty) && + fx >= 0 && fx < finegran && + fy >= 0 && fy < finegran); + } +} diff --git a/src/java/com/threerings/miso/client/util/IsoUtil.java b/src/java/com/threerings/miso/util/MisoUtil.java similarity index 62% rename from src/java/com/threerings/miso/client/util/IsoUtil.java rename to src/java/com/threerings/miso/util/MisoUtil.java index daf04ac9a..4a4856b6a 100644 --- a/src/java/com/threerings/miso/client/util/IsoUtil.java +++ b/src/java/com/threerings/miso/util/MisoUtil.java @@ -1,7 +1,7 @@ // -// $Id: IsoUtil.java,v 1.45 2003/02/12 05:36:18 mdb Exp $ +// $Id: MisoUtil.java,v 1.18 2003/04/17 19:21:16 mdb Exp $ -package com.threerings.miso.client.util; +package com.threerings.miso.util; import java.awt.Point; import java.awt.Polygon; @@ -16,108 +16,13 @@ import com.threerings.util.DirectionCodes; import com.threerings.util.DirectionUtil; import com.threerings.miso.Log; -import com.threerings.miso.client.IsoSceneViewModel; -import com.threerings.miso.client.DisplayObjectInfo; /** - * The IsoUtil class is a holding place for miscellaneous - * isometric-display-related utility routines. + * Miscellaneous isometric-display-related utility routines. */ -public class IsoUtil +public class MisoUtil implements DirectionCodes { - /** - * Returns a polygon bounding all footprint tiles of the given - * object tile. - * - * @param model the scene view model. - * @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, DisplayObjectInfo scobj) - { - Polygon boundsPoly = new SmartPolygon(); - Point tpos = tileToScreen(model, scobj.x, scobj.y, new Point()); - - int bwid = scobj.tile.getBaseWidth(), bhei = scobj.tile.getBaseHeight(); - int oox = tpos.x + model.tilehwid, ooy = tpos.y + model.tilehei; - int rx = oox, ry = ooy; - - // bottom-center point - boundsPoly.addPoint(rx, ry); - - // left point - rx -= bwid * model.tilehwid; - ry -= bwid * model.tilehhei; - boundsPoly.addPoint(rx, ry); - - // top-center point - rx += bhei * model.tilehwid; - ry -= bhei * model.tilehhei; - boundsPoly.addPoint(rx, ry); - - // right point - rx += bwid * model.tilehwid; - ry += bwid * model.tilehhei; - boundsPoly.addPoint(rx, ry); - - // bottom-center point - boundsPoly.addPoint(rx, ry); - - return boundsPoly; - } - - /** - * Returns a rectangle that encloses the entire object image, with the - * upper left set to the appropriate values for rendering the object - * image. - * - * @param model the scene view model. - * @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, DisplayObjectInfo scobj) - { - Point tpos = tileToScreen(model, scobj.x, scobj.y, new Point()); - - // if the tile has an origin, use that, otherwise compute the - // origin based on the tile footprint - int tox = scobj.tile.getOriginX(), toy = scobj.tile.getOriginY(); - if (tox == Integer.MIN_VALUE) { - tox = scobj.tile.getBaseWidth() * model.tilehwid; - } - if (toy == Integer.MIN_VALUE) { - toy = scobj.tile.getHeight(); - } - - int oox = tpos.x + model.tilehwid, ooy = tpos.y + model.tilehei; - int sx = oox - tox, sy = ooy - toy; - - return new Rectangle( - sx, sy, scobj.tile.getWidth(), scobj.tile.getHeight()); - } - - /** - * Returns true if the footprints of the two object tiles overlap when - * the objects occupy the specified coordinates, false if not. - */ - public static boolean objectFootprintsOverlap ( - DisplayObjectInfo so1, DisplayObjectInfo so2) - { - return (so2.x > so1.x - so1.tile.getBaseWidth() && - so1.x > so2.x - so2.tile.getBaseWidth() && - so2.y > so1.y - so1.tile.getBaseHeight() && - so1.y > so2.y - so2.tile.getBaseHeight()); - } - /** * Given two points in screen pixel coordinates, return the * compass direction that point B lies in from point A from an @@ -132,14 +37,14 @@ public class IsoUtil * class's direction constants. */ public static int getDirection ( - IsoSceneViewModel model, int ax, int ay, int bx, int by) + MisoSceneMetrics metrics, int ax, int ay, int bx, int by) { Point afpos = new Point(), bfpos = new Point(); // convert screen coordinates to full coordinates to get both // tile coordinates and fine coordinates - screenToFull(model, ax, ay, afpos); - screenToFull(model, bx, by, bfpos); + screenToFull(metrics, ax, ay, afpos); + screenToFull(metrics, bx, by, bfpos); // pull out the tile coordinates for each point int tax = afpos.x / FULL_TILE_FACTOR; @@ -278,16 +183,18 @@ public class IsoUtil * parameter. */ public static Point screenToTile ( - IsoSceneViewModel model, int sx, int sy, Point tpos) + MisoSceneMetrics metrics, int sx, int sy, Point tpos) { // 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); + int zx = (int)Math.floor((float)(sx - metrics.origin.x) / + metrics.tilewid); + int zy = (int)Math.floor((float)(sy - metrics.origin.y) / + metrics.tilehei); // 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); + int ox = (zx * metrics.tilewid + metrics.origin.x), + oy = (zy * metrics.tilehei + metrics.origin.y); // these are the tile coordinates tpos.x = zy + zx; tpos.y = zy - zx; @@ -295,11 +202,11 @@ public class IsoUtil // 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) { + if (Math.round(metrics.slopeY * dx + metrics.tilehei) <= dy) { tpos.x += 1; } - if (Math.round(model.slopeX * dx) > dy) { + if (Math.round(metrics.slopeX * dx) > dy) { tpos.y -= 1; } @@ -313,8 +220,10 @@ public class IsoUtil /** * Convert the given tile-based coordinates to their corresponding - * screen-based pixel coordinates. Converted coordinates are - * placed in the given point object. + * screen-based pixel coordinates. The screen coordinate for a tile is + * the upper-left coordinate of the rectangle that bounds the tile + * polygon. Converted coordinates are placed in the given point + * object. * * @param x the tile x-position coordinate. * @param y the tile y-position coordinate. @@ -324,10 +233,10 @@ public class IsoUtil * parameter. */ public static Point tileToScreen ( - IsoSceneViewModel model, int x, int y, Point spos) + MisoSceneMetrics metrics, 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); + spos.x = metrics.origin.x + ((x - y - 1) * metrics.tilehwid); + spos.y = metrics.origin.y + ((x + y) * metrics.tilehhei); return spos; } @@ -341,10 +250,10 @@ public class IsoUtil * @param ppos the point object to place coordinates in. */ public static void fineToPixel ( - IsoSceneViewModel model, int x, int y, Point ppos) + MisoSceneMetrics metrics, int x, int y, Point ppos) { - ppos.x = model.tilehwid + ((x - y) * model.finehwid); - ppos.y = (x + y) * model.finehhei; + ppos.x = metrics.tilehwid + ((x - y) * metrics.finehwid); + ppos.y = (x + y) * metrics.finehhei; } /** @@ -358,28 +267,28 @@ public class IsoUtil * @param fpos the point object to place coordinates in. */ public static void pixelToFine ( - IsoSceneViewModel model, int x, int y, Point fpos) + MisoSceneMetrics metrics, int x, int y, Point fpos) { // calculate line parallel to the y-axis (from the given // x/y-pos to the x-axis) - float bY = y - (model.fineSlopeY * x); + float bY = y - (metrics.fineSlopeY * x); // determine intersection of x- and y-axis lines - int crossx = (int)((bY - model.fineBX) / - (model.fineSlopeX - model.fineSlopeY)); - int crossy = (int)((model.fineSlopeY * crossx) + bY); + int crossx = (int)((bY - metrics.fineBX) / + (metrics.fineSlopeX - metrics.fineSlopeY)); + int crossy = (int)((metrics.fineSlopeY * crossx) + bY); // TODO: final position should check distance between our // position and the surrounding fine coords and return the // actual closest fine coord, rather than just dividing. // determine distance along the x-axis - float xdist = MathUtil.distance(model.tilehwid, 0, crossx, crossy); - fpos.x = (int)(xdist / model.finelen); + float xdist = MathUtil.distance(metrics.tilehwid, 0, crossx, crossy); + fpos.x = (int)(xdist / metrics.finelen); // determine distance along the y-axis float ydist = MathUtil.distance(x, y, crossx, crossy); - fpos.y = (int)(ydist / model.finelen); + fpos.y = (int)(ydist / metrics.finelen); } /** @@ -395,17 +304,17 @@ public class IsoUtil * @return the point passed in to receive the coordinates. */ public static Point screenToFull ( - IsoSceneViewModel model, int sx, int sy, Point fpos) + MisoSceneMetrics metrics, int sx, int sy, Point fpos) { // get the tile coordinates Point tpos = new Point(); - screenToTile(model, sx, sy, tpos); + screenToTile(metrics, sx, sy, tpos); // get the screen coordinates for the containing tile - Point spos = tileToScreen(model, tpos.x, tpos.y, new Point()); + Point spos = tileToScreen(metrics, tpos.x, tpos.y, new Point()); // get the fine coordinates within the containing tile - pixelToFine(model, sx - spos.x, sy - spos.y, fpos); + pixelToFine(metrics, sx - spos.x, sy - spos.y, fpos); // toss in the tile coordinates for good measure fpos.x += (tpos.x * FULL_TILE_FACTOR); @@ -426,16 +335,16 @@ public class IsoUtil * @return the point passed in to receive the coordinates. */ public static Point fullToScreen ( - IsoSceneViewModel model, int x, int y, Point spos) + MisoSceneMetrics metrics, int x, int y, Point spos) { // get the tile screen position int tx = x / FULL_TILE_FACTOR, ty = y / FULL_TILE_FACTOR; - Point tspos = tileToScreen(model, tx, ty, new Point()); + Point tspos = tileToScreen(metrics, tx, ty, new Point()); // get the pixel position of the fine coords within the tile Point ppos = new Point(); int fx = x - (tx * FULL_TILE_FACTOR), fy = y - (ty * FULL_TILE_FACTOR); - fineToPixel(model, fx, fy, ppos); + fineToPixel(metrics, fx, fy, ppos); // final position is tile position offset by fine position spos.x = tspos.x + ppos.x; @@ -449,9 +358,9 @@ public class IsoUtil * coordinate plus a fine coordinate remainder). The fine coordinate * is assumed to be relative to tile (0, 0). */ - public static int fineToFull (IsoSceneViewModel model, int fine) + public static int fineToFull (MisoSceneMetrics metrics, int fine) { - return toFull(fine / model.finegran, fine % model.finegran); + return toFull(fine / metrics.finegran, fine % metrics.finegran); } /** @@ -470,61 +379,58 @@ public class IsoUtil * @param y the tile y-position coordinate. */ public static Polygon getTilePolygon ( - IsoSceneViewModel model, int x, int y) + MisoSceneMetrics metrics, int x, int y) { - // get the top-left screen coordinate for the tile - Point spos = IsoUtil.tileToScreen(model, x, y, new Point()); - - // create a polygon framing the tile - Polygon poly = new SmartPolygon(); - poly.addPoint(spos.x, spos.y + model.tilehhei); - poly.addPoint(spos.x + model.tilehwid, spos.y); - poly.addPoint(spos.x + model.tilewid, spos.y + model.tilehhei); - poly.addPoint(spos.x + model.tilehwid, spos.y + model.tilehei); - - return poly; + return getFootprintPolygon(metrics, x, y, 1, 1); } /** * Return a screen-coordinates polygon framing the two specified * tile-coordinate points. */ - public static Polygon getMultiTilePolygon (IsoSceneViewModel model, + public static Polygon getMultiTilePolygon (MisoSceneMetrics metrics, Point sp1, Point sp2) { - int minx, maxx, miny, maxy; - Point[] p = new Point[4]; + int x = Math.min(sp1.x, sp2.x), y = Math.min(sp1.y, sp2.y); + int width = Math.abs(sp1.x-sp2.x), height = Math.abs(sp1.y-sp2.y); + return getFootprintPolygon(metrics, x, y, width, height); + } - // load in all possible screen coords - 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()); + /** + * Returns a polygon framing the specified scene footprint. + * + * @param x the x tile coordinate of the "upper-left" of the footprint. + * @param y the y tile coordinate of the "upper-left" of the footprint. + * @param width the width in tiles of the footprint. + * @param height the height in tiles of the footprint. + */ + public static Polygon getFootprintPolygon ( + MisoSceneMetrics metrics, int x, int y, int width, int height) + { + SmartPolygon footprint = new SmartPolygon(); + Point tpos = MisoUtil.tileToScreen(metrics, x, y, new Point()); - // locate the indexes of min/max for x and y - minx = maxx = miny = maxy = 0; - for (int ii=1; ii < 4; ii++) { - if (p[ii].x < p[minx].x) { - minx = ii; - } else if (p[ii].x > p[maxx].x) { - maxx = ii; - } + // start with top-center point + int rx = tpos.x + metrics.tilehwid, ry = tpos.y; + footprint.addPoint(rx, ry); + // right point + rx += width * metrics.tilehwid; + ry += width * metrics.tilehhei; + footprint.addPoint(rx, ry); + // bottom-center point + rx -= height * metrics.tilehwid; + ry += height * metrics.tilehhei; + footprint.addPoint(rx, ry); + // left point + rx -= width * metrics.tilehwid; + ry -= width * metrics.tilehhei; + footprint.addPoint(rx, ry); + // end with top-center point + rx -= height * metrics.tilehwid; + ry += height * metrics.tilehhei; + footprint.addPoint(rx, ry); - if (p[ii].y < p[miny].y) { - miny = ii; - } else if (p[ii].y > p[maxy].y) { - maxy = ii; - } - } - - // now make the polygon! Whoo! - Polygon poly = new SmartPolygon(); - poly.addPoint(p[minx].x, p[minx].y + model.tilehhei); - poly.addPoint(p[miny].x + model.tilehwid, p[miny].y); - poly.addPoint(p[maxx].x + model.tilewid, p[maxx].y + model.tilehhei); - poly.addPoint(p[maxy].x + model.tilehwid, p[maxy].y + model.tilehei); - - return poly; + return footprint; } /** @@ -533,22 +439,22 @@ public class IsoUtil * * @retun the point object supplied as full. */ - public static Point tilePlusFineToFull (IsoSceneViewModel model, + public static Point tilePlusFineToFull (MisoSceneMetrics metrics, int tileX, int tileY, int fineX, int fineY, Point full) { - int dtx = fineX / model.finegran; - int dty = fineY / model.finegran; - int fx = fineX - dtx * model.finegran; + int dtx = fineX / metrics.finegran; + int dty = fineY / metrics.finegran; + int fx = fineX - dtx * metrics.finegran; if (fx < 0) { dtx--; - fx += model.finegran; + fx += metrics.finegran; } - int fy = fineY - dty * model.finegran; + int fy = fineY - dty * metrics.finegran; if (fy < 0) { dty--; - fy += model.finegran; + fy += metrics.finegran; } full.x = toFull(tileX + dtx, fx); diff --git a/src/java/com/threerings/miso/client/util/ObjectSet.java b/src/java/com/threerings/miso/util/ObjectSet.java similarity index 97% rename from src/java/com/threerings/miso/client/util/ObjectSet.java rename to src/java/com/threerings/miso/util/ObjectSet.java index ddf7b8ec6..a8032afc6 100644 --- a/src/java/com/threerings/miso/client/util/ObjectSet.java +++ b/src/java/com/threerings/miso/util/ObjectSet.java @@ -1,7 +1,7 @@ // -// $Id: ObjectSet.java,v 1.4 2003/02/12 05:36:44 mdb Exp $ +// $Id: ObjectSet.java,v 1.1 2003/04/17 19:21:17 mdb Exp $ -package com.threerings.miso.client.util; +package com.threerings.miso.util; import java.util.Arrays; import java.util.Comparator; diff --git a/tests/rsrc/scenes/idyll.xml b/tests/rsrc/scenes/idyll.xml index 88d405a13..2c5abae18 100644 --- a/tests/rsrc/scenes/idyll.xml +++ b/tests/rsrc/scenes/idyll.xml @@ -6,7 +6,14 @@ 10 12 131072, 131072, 131072, 131072, 131073, 131073, 131073, 131073, 131074, 65537, 65537, 131072, 131074, 131074, 131074, 131074, 131072, 131073, 131074, 131074, 131072, 131074, 131074, 131072, 131072, 131072, 131073, 131073, 131073, 131074, 131072, 65536, 65538, 131072, 131072, 131074, 131072, 131072, 131073, 131074, 131072, 131072, 131072, 131072, 131072, 131074, 131072, 131074, 131072, 131073, 131074, 131073, 131074, 65537, 65536, 131072, 131073, 131072, 131073, 131072, 131074, 131073, 131073, 131073, 131072, 131074, 131073, 131072, 131073, 131074, 131074, 131072, 131074, 131072, 131073, 65536, 65538, 131074, 131074, 131074, 131073, 131073, 131072, 131072, 131073, 131072, 131072, 131072, 131074, 131072, 131074, 131072, 131074, 131074, 131073, 131074, 131074, 65536, 65536, 131073, 131072, 131072, 131074, 131074, 131074, 131073, 131072, 131072, 131074, 131073, 131074, 131073, 131074, 131072, 131073, 131072, 131073, 131073, 131074, 65537, 65538, 131072, 131072, 131072, 131072, 131073, 131072, 131072, 131073, 131074, 131074, 131074, 131073, 131074, 131072, 131073, 131074, 131073, 131072, 131072, 131072, 65536, 65537, 131074, 131073, 131074, 131072, 131074, 131073, 131074, 131073, 131072, 131073, 131072, 131073, 131074, 131074, 131074, 131072, 131074, 131074, 131074, 131072, 65538, 65538, 131074, 131074, 131073, 131073, 131074, 131073, 131073, 131074, 131074, 131072, 131072, 131072, 131073, 131073, 131072, 131072, 131073, 131073, 131074, 131073, 65536, 65537, 65538, 65536, 65537, 65536, 65537, 65537, 65538, 65538, 65536, 131074, 131073, 131073, 131072, 131073, 131074, 131074, 131074, 131073, 131074, 131072, 65536, 65537, 65538, 65536, 65537, 65536, 65538, 65536, 65538, 65537, 65536, 131073, 131073, 131074, 131072, 131074, 131073, 131072, 131074, 131072, 131073, 131072, 65536, 65538, 65536, 65538, 65537, 65538, 65537, 65538, 65536, 65536, 65538, 65538, 131074, 131072, 131074, 131073, 131074, 131074, 131074, 131073, 131074, 131072, 65538, 131073, 131074, 131074, 131072, 131074, 131072, 131074, 131074, 131074, 131072, 131074, 131073, 131073, 131072, 131073, 131072, 131072, 131073, 131073, 131074, 131072, 65537, 131074, 131073, 131073, 131072, 131073, 131072, 131074, 131074, 131073, 131072, 131073, 131072, 131072, 131073, 131074, 131073, 131073, 131074, 65536, 65538, 65538, 65538, 131074, 131073, 131073, 131074, 131073, 131073, 131072, 131073, 131074, 131074, 131072, 131074, 131074, 131073, 131072, 131072, 131074, 131072, 65536, 65538, 65538, 65538, 131073, 131074, 131073, 131074, 131073, 131072, 131073, 131074, 131074, 131073, 131073, 131074, 131072, 131074, 131072, 131073, 131073, 131074, 65536, 65536, 65537, 65537, 131073, 131074, 131073, 131074, 131073, 131072, 131074, 131074, 131073, 131073, 131074, 131074, 131072, 131073, 131073, 131074, 131073, 131074, 65536, 65536, 65537, 65538, 131072, 131073, 131074, 131073, 131073, 131074, 131072, 131074, 131073, 131072, 131074, 131072, 131073, 131073, 131072, 131073, 131073, 131072, 131072, 131072, 65537, 65538, 131074, 131072, 131072, 131072, 131073, 131072, 131072, 131074, 131073, 131074, 131073, 131072, 131073, 131072, 131072, 131072, 131072, 131072, 131073, 131072, 65537, 65536, 131073, 131073, 131074, 131073, 131074, 131074, 131073, 131073, 131072, 131074, 131073, 131074, 131072, 131073, 131073, 131073, 131073, 131072, 131072, 131072, 65537, 65537, 131074, 131074, 131074, 131072, 131073, 131074, 131072, 131074, 131072, 131072, 131074, 131072, 131074, 131074, 131073, 131073, 131073, 131072, 131072, 131074, 131074, 131073, 131073, 131073, 131072, 131072, 131072, 131074, 131074, 131072, 131072, 131074, 131074, 131072, 131074, 131072, 131073, 131074, 131073, 131073, 131072, 131074, 131072, 131073, 131072, 131073, 131073, 131073, 131074, 131074, 131073, 131074, 131073, 131074, 131072, 131074 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - 17, 11, 851968, 16, 14, 589825, 14, 7, 917505, 13, 7, 917505, 8, 15, 1179649, 8, 13, 917505, 7, 10, 655361 - , , , , , , + + + + + + + + + + diff --git a/tests/src/java/com/threerings/media/sound/SoundTestApp.java b/tests/src/java/com/threerings/media/sound/SoundTestApp.java index a596f7f39..df522d1f8 100644 --- a/tests/src/java/com/threerings/media/sound/SoundTestApp.java +++ b/tests/src/java/com/threerings/media/sound/SoundTestApp.java @@ -1,5 +1,5 @@ // -// $Id: SoundTestApp.java,v 1.4 2003/01/13 22:57:45 mdb Exp $ +// $Id: SoundTestApp.java,v 1.5 2003/04/17 19:21:17 mdb Exp $ package com.threerings.media.sound; @@ -18,7 +18,7 @@ public class SoundTestApp } ResourceManager rmgr = new ResourceManager("rsrc"); - _soundmgr = new SoundManager(rmgr); + _soundmgr = new SoundManager(rmgr, null, null); _keys = args; } diff --git a/tests/src/java/com/threerings/miso/client/ScrollingScene.java b/tests/src/java/com/threerings/miso/client/ScrollingScene.java index 6594cd819..8c2bbf25a 100644 --- a/tests/src/java/com/threerings/miso/client/ScrollingScene.java +++ b/tests/src/java/com/threerings/miso/client/ScrollingScene.java @@ -1,5 +1,5 @@ // -// $Id: ScrollingScene.java,v 1.12 2003/02/12 07:24:07 mdb Exp $ +// $Id: ScrollingScene.java,v 1.13 2003/04/17 19:21:17 mdb Exp $ package com.threerings.miso.client; @@ -18,15 +18,17 @@ import com.threerings.media.tile.Tile; import com.threerings.media.tile.TileSet; import com.threerings.media.tile.TileSetRepository; -import com.threerings.miso.client.util.ObjectSet; +import com.threerings.miso.data.MisoSceneModel; import com.threerings.miso.tile.BaseTile; import com.threerings.miso.tile.BaseTileSet; import com.threerings.miso.util.MisoContext; +import com.threerings.miso.util.ObjectSet; +import com.threerings.miso.data.ObjectInfo; /** * Provides an infinite array of tiles in which to scroll. */ -public class ScrollingScene extends VirtualDisplayMisoSceneImpl +public class ScrollingScene extends MisoSceneModel { public ScrollingScene (MisoContext ctx) throws NoSuchTileSetException, NoSuchTileException, PersistenceException @@ -60,6 +62,33 @@ public class ScrollingScene extends VirtualDisplayMisoSceneImpl } } + public int getBaseTileId (int x, int y) + { + return -1; + } + + public boolean setBaseTile (int fqTileId, int x, int y) + { + return false; + } + + public void addObject (ObjectInfo info) + { + } + + public void getObjects (Rectangle region, ObjectSet set) + { + } + + public void updateObject (ObjectInfo info) + { + } + + public boolean removeObject (ObjectInfo info) + { + return false; + } + // documentation inherited from interface public BaseTile getBaseTile (int x, int y) { diff --git a/tests/src/java/com/threerings/miso/client/ScrollingTestApp.java b/tests/src/java/com/threerings/miso/client/ScrollingTestApp.java index 0a6d1a901..0d6320975 100644 --- a/tests/src/java/com/threerings/miso/client/ScrollingTestApp.java +++ b/tests/src/java/com/threerings/miso/client/ScrollingTestApp.java @@ -1,5 +1,5 @@ // -// $Id: ScrollingTestApp.java,v 1.20 2003/02/12 07:24:07 mdb Exp $ +// $Id: ScrollingTestApp.java,v 1.21 2003/04/17 19:21:17 mdb Exp $ package com.threerings.miso.client; @@ -98,7 +98,7 @@ public class ScrollingTestApp CharacterManager charmgr = new CharacterManager(imgr, crepo); // create our scene view panel - _panel = new SceneViewPanel(_framemgr, new IsoSceneViewModel()); + _panel = new MisoScenePanel(ctx, MisoConfig.getSceneMetrics()); _frame.setPanel(_panel); // create our "ship" sprite @@ -114,8 +114,8 @@ public class ScrollingTestApp _ship.setFollowingPathAction("sailing"); _ship.setRestingAction("sailing"); _ship.setActionSequence("sailing"); - _ship.setLocation(_panel.getModel().bounds.width/2, - _panel.getModel().bounds.height/2); + _ship.setLocation(_panel.getSceneMetrics().bounds.width/2, + _panel.getSceneMetrics().bounds.height/2); _panel.addSprite(_ship); } @@ -161,7 +161,7 @@ public class ScrollingTestApp } try { - _panel.setScene(new ScrollingScene(ctx)); + _panel.setSceneModel(new ScrollingScene(ctx)); } catch (Exception e) { Log.warning("Error creating scene: " + e); Log.logStackTrace(e); @@ -174,10 +174,13 @@ public class ScrollingTestApp */ protected class ContextImpl implements MisoContext { - public MisoTileManager getTileManager () - { + public MisoTileManager getTileManager () { return _tilemgr; } + + public FrameManager getFrameManager () { + return _framemgr; + } } /** @@ -214,7 +217,7 @@ public class ScrollingTestApp protected ScrollingFrame _frame; /** The main panel. */ - protected SceneViewPanel _panel; + protected MisoScenePanel _panel; /** The ship in the center of our screen. */ protected CharacterSprite _ship; diff --git a/tests/src/java/com/threerings/miso/viewer/ViewerApp.java b/tests/src/java/com/threerings/miso/viewer/ViewerApp.java index 8440df07f..d7b31d7ea 100644 --- a/tests/src/java/com/threerings/miso/viewer/ViewerApp.java +++ b/tests/src/java/com/threerings/miso/viewer/ViewerApp.java @@ -1,5 +1,5 @@ // -// $Id: ViewerApp.java,v 1.37 2003/02/12 07:24:08 mdb Exp $ +// $Id: ViewerApp.java,v 1.38 2003/04/17 19:21:17 mdb Exp $ package com.threerings.miso.viewer; @@ -21,7 +21,6 @@ import com.threerings.cast.CharacterManager; import com.threerings.cast.bundle.BundledComponentRepository; import com.threerings.miso.Log; -import com.threerings.miso.client.SimpleDisplayMisoSceneImpl; import com.threerings.miso.data.SimpleMisoSceneModel; import com.threerings.miso.tile.MisoTileManager; import com.threerings.miso.tools.xml.SimpleMisoSceneParser; @@ -83,19 +82,19 @@ public class ViewerApp CharacterManager charmgr = new CharacterManager(imgr, crepo); // create our scene view panel - _panel = new ViewerSceneViewPanel(ctx, _framemgr, charmgr, crepo); + _panel = new ViewerSceneViewPanel(ctx, charmgr, crepo); _frame.setPanel(_panel); // load up the scene specified by the user try { - SimpleMisoSceneParser parser = new SimpleMisoSceneParser("miso"); + SimpleMisoSceneParser parser = new SimpleMisoSceneParser(""); SimpleMisoSceneModel model = parser.parseScene(args[0]); if (model == null) { Log.warning("No miso scene found in scene file " + "[path=" + args[0] + "]."); System.exit(-1); } - _panel.setScene(new SimpleDisplayMisoSceneImpl(model, _tilemgr)); + _panel.setSceneModel(model); } catch (Exception e) { Log.warning("Unable to parse scene [path=" + args[0] + "]."); @@ -128,6 +127,11 @@ public class ViewerApp { return _tilemgr; } + + public FrameManager getFrameManager () + { + return _framemgr; + } } /** diff --git a/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java b/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java index 03009f23f..d24ee9307 100644 --- a/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java +++ b/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java @@ -1,5 +1,5 @@ // -// $Id: ViewerSceneViewPanel.java,v 1.56 2003/02/12 07:24:08 mdb Exp $ +// $Id: ViewerSceneViewPanel.java,v 1.57 2003/04/17 19:21:17 mdb Exp $ package com.threerings.miso.viewer; @@ -28,25 +28,22 @@ import com.threerings.media.util.PerformanceMonitor; import com.threerings.media.util.PerformanceObserver; import com.threerings.miso.Log; -import com.threerings.miso.client.DisplayMisoScene; -import com.threerings.miso.client.IsoSceneView; -import com.threerings.miso.client.IsoSceneViewModel; -import com.threerings.miso.client.SceneViewPanel; -import com.threerings.miso.client.util.IsoUtil; +import com.threerings.miso.MisoConfig; +import com.threerings.miso.client.MisoScenePanel; +import com.threerings.miso.data.MisoSceneModel; import com.threerings.miso.util.MisoContext; -public class ViewerSceneViewPanel extends SceneViewPanel +public class ViewerSceneViewPanel extends MisoScenePanel implements PerformanceObserver, SpriteObserver { /** * Construct the panel and initialize it with a context. */ public ViewerSceneViewPanel (MisoContext ctx, - FrameManager framemgr, CharacterManager charmgr, ComponentRepository crepo) { - super(framemgr, new IsoSceneViewModel()); + super(ctx, MisoConfig.getSceneMetrics()); // create the character descriptors _descUser = CastUtil.getRandomDescriptor("female", crepo); @@ -56,26 +53,17 @@ public class ViewerSceneViewPanel extends SceneViewPanel _sprite = createSprite(_spritemgr, charmgr, _descUser); setFollowsPathable(_sprite); -// // turn on object highlighting -// ((IsoSceneView)_view).setHighlightMode(IsoSceneView.HIGHLIGHT_ALWAYS); - // create the decoy sprites createDecoys(_spritemgr, charmgr); - // listen to the desired events - addMouseListener(new MouseAdapter() { - public void mousePressed (MouseEvent e) { - ViewerSceneViewPanel.this.mousePressed(e); - } - }); - PerformanceMonitor.register(this, "paint", 1000); } // documentation inherited - public void setScene (DisplayMisoScene scene) + public void setSceneModel (MisoSceneModel model) { - super.setScene(scene); + super.setSceneModel(model); + Log.info("Using " + model + "."); // now that we have a scene, we can create valid paths for our // decoy sprites @@ -138,10 +126,13 @@ public class ViewerSceneViewPanel extends SceneViewPanel Log.info(name + " [ticks=" + ticks + "]."); } - /** MouseListener interface methods */ + // documentation inherited public void mousePressed (MouseEvent e) { + super.mousePressed(e); + int x = e.getX(), y = e.getY(); + Log.info("Mouse pressed +" + x + "+" + y); switch (e.getModifiers()) { case MouseEvent.BUTTON1_MASK: @@ -164,7 +155,7 @@ public class ViewerSceneViewPanel extends SceneViewPanel protected boolean createPath (CharacterSprite s, int x, int y) { // get the path from here to there - LineSegmentPath path = (LineSegmentPath)_view.getPath(s, x, y); + LineSegmentPath path = (LineSegmentPath)getPath(s, x, y); if (path == null) { s.cancelMove(); return false; @@ -181,7 +172,7 @@ public class ViewerSceneViewPanel extends SceneViewPanel */ protected void createRandomPath (CharacterSprite s) { - Dimension d = _viewmodel.bounds.getSize(); + Dimension d = _metrics.bounds.getSize(); int x, y; do { @@ -204,7 +195,7 @@ public class ViewerSceneViewPanel extends SceneViewPanel } /** The number of decoy characters milling about. */ - protected static final int NUM_DECOYS = 100; + protected static final int NUM_DECOYS = 5; /** The character descriptor for the user character. */ protected CharacterDescriptor _descUser; diff --git a/tests/src/java/com/threerings/whirled/DummyClientSceneRepository.java b/tests/src/java/com/threerings/whirled/DummyClientSceneRepository.java index b1bcd7cdd..f6e693812 100644 --- a/tests/src/java/com/threerings/whirled/DummyClientSceneRepository.java +++ b/tests/src/java/com/threerings/whirled/DummyClientSceneRepository.java @@ -1,5 +1,5 @@ // -// $Id: DummyClientSceneRepository.java,v 1.5 2001/11/18 04:09:21 mdb Exp $ +// $Id: DummyClientSceneRepository.java,v 1.6 2003/04/17 19:21:17 mdb Exp $ package com.threerings.whirled; @@ -26,7 +26,14 @@ public class DummyClientSceneRepository implements SceneRepository } // documentation inherited - public void updateSceneModel (SceneModel scene) + public void storeSceneModel (SceneModel model) + throws IOException + { + // nothing doing + } + + // documentation inherited + public void deleteSceneModel (int sceneId) throws IOException { // nothing doing diff --git a/tests/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneParserTest.java b/tests/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneParserTest.java index 437597493..9496420c4 100644 --- a/tests/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneParserTest.java +++ b/tests/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneParserTest.java @@ -1,5 +1,5 @@ // -// $Id: SpotSceneParserTest.java,v 1.4 2003/02/12 07:24:08 mdb Exp $ +// $Id: SpotSceneParserTest.java,v 1.5 2003/04/17 19:21:17 mdb Exp $ package com.threerings.whirled.spot.tools.xml; @@ -8,7 +8,8 @@ import com.samskivert.test.TestUtil; import junit.framework.Test; import junit.framework.TestCase; -import com.threerings.whirled.spot.data.SpotScene; +import com.threerings.whirled.data.SceneModel; +import com.threerings.whirled.tools.xml.SceneParser; public class SpotSceneParserTest extends TestCase { @@ -20,9 +21,10 @@ public class SpotSceneParserTest extends TestCase public void runTest () { try { - SpotSceneParser parser = new SpotSceneParser("scene"); + SceneParser parser = new SceneParser("scene"); + parser.registerAuxRuleSet(new SpotSceneRuleSet()); String tspath = TestUtil.getResourcePath(TEST_SCENE_PATH); - SpotScene scene = parser.parseScene(tspath); + SceneModel scene = parser.parseScene(tspath); System.out.println("Parsed " + scene + "."); } catch (Exception e) { diff --git a/tests/src/java/com/threerings/whirled/tools/xml/SceneParserTest.java b/tests/src/java/com/threerings/whirled/tools/xml/SceneParserTest.java index 0518cb984..91a35688d 100644 --- a/tests/src/java/com/threerings/whirled/tools/xml/SceneParserTest.java +++ b/tests/src/java/com/threerings/whirled/tools/xml/SceneParserTest.java @@ -1,5 +1,5 @@ // -// $Id: SceneParserTest.java,v 1.4 2003/02/12 07:24:08 mdb Exp $ +// $Id: SceneParserTest.java,v 1.5 2003/04/17 19:21:17 mdb Exp $ package com.threerings.whirled.tools.xml; @@ -8,7 +8,7 @@ import com.samskivert.test.TestUtil; import junit.framework.Test; import junit.framework.TestCase; -import com.threerings.whirled.data.Scene; +import com.threerings.whirled.data.SceneModel; public class SceneParserTest extends TestCase { @@ -22,7 +22,7 @@ public class SceneParserTest extends TestCase try { SceneParser parser = new SceneParser("scene"); String tspath = TestUtil.getResourcePath(TEST_SCENE_PATH); - Scene scene = parser.parseScene(tspath); + SceneModel scene = parser.parseScene(tspath); System.out.println("Parsed " + scene + "."); } catch (Exception e) {