From 3c94cd67f6dce7626a21bfe7332a86d8f987f333 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Sat, 19 Apr 2003 22:40:34 +0000 Subject: [PATCH] Various fixes to support negative tile coordinates; created sparse miso scene model and associated business to store scene data in an arbitrary set of blocks rather than fixed arrays; finally stuck a fork in scene width and height as well as view width and height along with origin offset and a few other now obsolete bits. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2434 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../miso/client/MisoScenePanel.java | 72 ++-- .../threerings/miso/client/SceneObject.java | 7 +- .../threerings/miso/data/MisoSceneModel.java | 20 +- .../miso/data/SimpleMisoSceneModel.java | 14 +- .../miso/data/SparseMisoSceneModel.java | 339 ++++++++++++++++++ .../miso/data/VirtualMisoSceneModel.java | 7 +- .../miso/tools/xml/SparseMisoSceneParser.java | 73 ++++ .../tools/xml/SparseMisoSceneRuleSet.java | 68 ++++ .../miso/tools/xml/SparseMisoSceneWriter.java | 109 ++++++ .../miso/util/MisoSceneMetrics.java | 54 +-- .../com/threerings/miso/util/MisoUtil.java | 41 ++- 11 files changed, 678 insertions(+), 126 deletions(-) create mode 100644 src/java/com/threerings/miso/data/SparseMisoSceneModel.java create mode 100644 src/java/com/threerings/miso/tools/xml/SparseMisoSceneParser.java create mode 100644 src/java/com/threerings/miso/tools/xml/SparseMisoSceneRuleSet.java create mode 100644 src/java/com/threerings/miso/tools/xml/SparseMisoSceneWriter.java diff --git a/src/java/com/threerings/miso/client/MisoScenePanel.java b/src/java/com/threerings/miso/client/MisoScenePanel.java index 300c152cc..689816465 100644 --- a/src/java/com/threerings/miso/client/MisoScenePanel.java +++ b/src/java/com/threerings/miso/client/MisoScenePanel.java @@ -1,5 +1,5 @@ // -// $Id: MisoScenePanel.java,v 1.8 2003/04/19 17:06:08 mdb Exp $ +// $Id: MisoScenePanel.java,v 1.9 2003/04/19 22:40:34 mdb Exp $ package com.threerings.miso.client; @@ -43,6 +43,7 @@ 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.MathUtil; import com.threerings.media.util.Path; import com.threerings.miso.Log; @@ -103,7 +104,7 @@ public class MisoScenePanel extends VirtualMediaPanel _masks.clear(); // recenter and rethink - centerOnTile(_model.width/2, _model.height/2); + centerOnTile(0, 0); rethink(); repaint(); } @@ -493,16 +494,6 @@ public class MisoScenePanel extends VirtualMediaPanel _activeMenu = null; } - /** - * 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) { @@ -589,22 +580,30 @@ public class MisoScenePanel extends VirtualMediaPanel // compute the tile bounds of this influential area Rectangle itb = new Rectangle(); int minx, miny, maxx, maxy; - Point tpos = MisoUtil.screenToTile( - _metrics, _ibounds.x, _ibounds.y, new Point()); + Point tpos = new Point(); + + // calculate minimum x + MisoUtil.screenToTile(_metrics, _ibounds.x, _ibounds.y, tpos); itb.x = tpos.x; - minx = Math.max(0, tpos.x / _metrics.blockwid); + minx = MathUtil.floorDiv(tpos.x, _metrics.blockwid); + + // calculate minimum y MisoUtil.screenToTile( _metrics, _ibounds.x + _ibounds.width, _ibounds.y, tpos); itb.y = tpos.y; - miny = Math.max(0, tpos.y / _metrics.blockhei); + miny = MathUtil.floorDiv(tpos.y, _metrics.blockhei); + + // calculate maximum x 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); + itb.width = (tpos.x-itb.x+1); + maxx = MathUtil.floorDiv(tpos.x, _metrics.blockwid); + + // calculate maximum y MisoUtil.screenToTile( _metrics, _ibounds.x, _ibounds.y + _ibounds.height, tpos); - itb.height = (tpos.y-itb.y); - maxy = Math.max(0, tpos.y / _metrics.blockhei); + itb.height = (tpos.y-itb.y+1); + maxy = MathUtil.floorDiv(tpos.y, _metrics.blockhei); // Log.info("Resolving blocks from " + minx + "," + miny + " to " + // maxx + "," + maxy + " (" + StringUtil.toString(itb) + ")."); @@ -630,7 +629,7 @@ public class MisoScenePanel extends VirtualMediaPanel // become so for (int yy = miny; yy <= maxy; yy++) { for (int xx = minx; xx <= maxx; xx++) { - int bkey = (xx << 16) | yy; + int bkey = compose(xx, yy); if (!_blocks.containsKey(bkey)) { SceneBlock block = new SceneBlock( this, xx*_metrics.blockwid, yy*_metrics.blockhei, @@ -642,11 +641,17 @@ public class MisoScenePanel extends VirtualMediaPanel } } - // if nothing changed, we need do nothing more - if (!changed) { - return; + // if anything changed, we recompute our visible object set + if (changed) { + recomputeVisible(); } + } + /** + * Recomputes our set of visible objects and their tips. + */ + protected void recomputeVisible () + { // flush our visible object set which we'll recreate later _vizobjs.clear(); @@ -682,11 +687,18 @@ public class MisoScenePanel extends VirtualMediaPanel */ 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); + int bx = MathUtil.floorDiv(tx, _metrics.blockwid); + int by = MathUtil.floorDiv(ty, _metrics.blockhei); + return (SceneBlock)_blocks.get(compose(bx, by)); + } + + /** + * Masks off the lower 16 bits of the supplied integers and composes + * them into a single int. + */ + protected static int compose (int x, int y) + { + return (x << 16) | (y & 0xFFFF); } /** @@ -840,7 +852,7 @@ public class MisoScenePanel extends VirtualMediaPanel protected boolean updateTileCoords (int sx, int sy, Point tpos) { Point npos = MisoUtil.screenToTile(_metrics, sx, sy, new Point()); - if (!tpos.equals(npos) && _metrics.isCoordinateValid(npos.x, npos.y)) { + if (!tpos.equals(npos)) { tpos.setLocation(npos.x, npos.y); return true; } else { diff --git a/src/java/com/threerings/miso/client/SceneObject.java b/src/java/com/threerings/miso/client/SceneObject.java index eb06ea524..29ec67939 100644 --- a/src/java/com/threerings/miso/client/SceneObject.java +++ b/src/java/com/threerings/miso/client/SceneObject.java @@ -1,5 +1,5 @@ // -// $Id: SceneObject.java,v 1.3 2003/04/18 23:17:33 mdb Exp $ +// $Id: SceneObject.java,v 1.4 2003/04/19 22:40:34 mdb Exp $ package com.threerings.miso.client; @@ -218,6 +218,11 @@ public class SceneObject _sspot = MisoUtil.fullToScreen( metrics, _fspot.x, _fspot.y, new Point()); } + +// Log.info("Computed object metrics " + +// "[tpos=" + StringUtil.coordsToString(tx, ty) + +// ", info=" + info + +// ", sbounds=" + StringUtil.toString(bounds) + "]."); } /** diff --git a/src/java/com/threerings/miso/data/MisoSceneModel.java b/src/java/com/threerings/miso/data/MisoSceneModel.java index 853fb6d08..5779258d5 100644 --- a/src/java/com/threerings/miso/data/MisoSceneModel.java +++ b/src/java/com/threerings/miso/data/MisoSceneModel.java @@ -1,5 +1,5 @@ // -// $Id: MisoSceneModel.java,v 1.15 2003/04/18 18:31:20 mdb Exp $ +// $Id: MisoSceneModel.java,v 1.16 2003/04/19 22:40:34 mdb Exp $ package com.threerings.miso.data; @@ -9,7 +9,6 @@ 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; @@ -20,12 +19,6 @@ import com.threerings.miso.util.ObjectSet; public abstract class MisoSceneModel extends SimpleStreamableObject implements Cloneable { - /** The width of this scene in tiles. */ - public short width; - - /** The height of this scene in tiles. */ - public short height; - /** * Creates a completely uninitialized model suitable for little more * than unserialization. @@ -34,17 +27,6 @@ public abstract class MisoSceneModel extends SimpleStreamableObject { } - /** - * Creates a blank model with the specified dimensions. - */ - public MisoSceneModel (int width, int height) - { - this.width = (short)MathUtil.bound( - Short.MIN_VALUE, width, Short.MAX_VALUE); - this.height = (short)MathUtil.bound( - Short.MIN_VALUE, height, Short.MAX_VALUE); - } - /** * Returns the fully qualified tile id of the base tile at the * specified coordinates. -1 will be returned if there is diff --git a/src/java/com/threerings/miso/data/SimpleMisoSceneModel.java b/src/java/com/threerings/miso/data/SimpleMisoSceneModel.java index 35e8e2f5b..bc0fc46a7 100644 --- a/src/java/com/threerings/miso/data/SimpleMisoSceneModel.java +++ b/src/java/com/threerings/miso/data/SimpleMisoSceneModel.java @@ -1,5 +1,5 @@ // -// $Id: SimpleMisoSceneModel.java,v 1.4 2003/04/18 22:59:18 mdb Exp $ +// $Id: SimpleMisoSceneModel.java,v 1.5 2003/04/19 22:40:34 mdb Exp $ package com.threerings.miso.data; @@ -10,6 +10,7 @@ import com.samskivert.util.ArrayUtil; import com.samskivert.util.IntListUtil; import com.samskivert.util.ListUtil; +import com.threerings.media.util.MathUtil; import com.threerings.miso.util.ObjectSet; /** @@ -25,6 +26,12 @@ import com.threerings.miso.util.ObjectSet; */ public class SimpleMisoSceneModel extends MisoSceneModel { + /** The width of this scene in tiles. */ + public short width; + + /** The height of this scene in tiles. */ + public short height; + /** The viewport width in tiles. */ public int vwidth; @@ -65,7 +72,10 @@ public class SimpleMisoSceneModel extends MisoSceneModel */ public SimpleMisoSceneModel (int width, int height, int vwidth, int vheight) { - super(width, height); + this.width = (short)MathUtil.bound( + Short.MIN_VALUE, width, Short.MAX_VALUE); + this.height = (short)MathUtil.bound( + Short.MIN_VALUE, height, Short.MAX_VALUE); this.vwidth = vwidth; this.vheight = vheight; allocateBaseTileArray(); diff --git a/src/java/com/threerings/miso/data/SparseMisoSceneModel.java b/src/java/com/threerings/miso/data/SparseMisoSceneModel.java new file mode 100644 index 000000000..850db3370 --- /dev/null +++ b/src/java/com/threerings/miso/data/SparseMisoSceneModel.java @@ -0,0 +1,339 @@ +// +// $Id: SparseMisoSceneModel.java,v 1.1 2003/04/19 22:40:34 mdb Exp $ + +package com.threerings.miso.data; + +import java.awt.Rectangle; +import java.util.ArrayList; +import java.util.Iterator; + +import com.samskivert.util.ArrayUtil; +import com.samskivert.util.HashIntMap; +import com.samskivert.util.IntListUtil; +import com.samskivert.util.ListUtil; + +import com.threerings.io.SimpleStreamableObject; + +import com.threerings.media.util.MathUtil; + +import com.threerings.miso.Log; +import com.threerings.miso.util.ObjectSet; + +/** + * Contains miso scene data that is broken up into NxN tile sections. + */ +public class SparseMisoSceneModel extends MisoSceneModel +{ + /** An interface that allows external entities to "visit" and inspect + * every object in this scene. */ + public static interface ObjectVisitor + { + /** Called for each object in the scene, interesting and not. */ + public void visit (int tileId, int x, int y); + } + + /** Contains information on a section of this scene. This is only + * public so that the scene model parser can do its job, so don't go + * poking around in here. */ + public static class Section extends SimpleStreamableObject + implements Cloneable + { + /** The tile coordinate of our upper leftmost tile. */ + public short x, y; + + /** The width of this section in tiles. */ + public int width; + + /** The combined tile ids (tile set id and tile id) for our + * section (in row major order). */ + public int[] baseTileIds; + + /** The combined tile ids (tile set id and tile id) of the + * "uninteresting" tiles in the object layer. */ + public int[] objectTileIds = new int[0]; + + /** The x coordinate of the "uninteresting" tiles in the object + * layer. */ + public short[] objectXs = new short[0]; + + /** The y coordinate of the "uninteresting" tiles in the object + * layer. */ + public short[] objectYs = new short[0]; + + /** Information records for the "interesting" objects in the + * object layer. */ + public ObjectInfo[] objectInfo = new ObjectInfo[0]; + + /** + * Creates a blank section instance, suitable for unserialization + * or configuration by the XML scene parser. + */ + public Section () + { + } + + /** + * Creates a new scene section with the specified dimensions. + */ + public Section (short x, short y, short width, short height) + { + this.x = x; + this.y = y; + this.width = width; + baseTileIds = new int[width*height]; + } + + public int getBaseTileId (int col, int row) { +// if (col < x || col >= (x+width) || row < y || row >= (y+width)) { +// Log.warning("Requested bogus tile +" + col + "+" + row + +// " from " + this + "."); +// return -1; +// } else { + return baseTileIds[(row-y)*width+(col-x)]; +// } + } + + public void setBaseTile (int col, int row, int fqBaseTileId) { + baseTileIds[(row-y)*width+(col-x)] = fqBaseTileId; + } + + 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); + } + } + + 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; + } + + 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)); + } + } + } + + public Object clone () { + try { + Section section = (Section)super.clone(); + section.baseTileIds = (int[])baseTileIds.clone(); + section.objectTileIds = (int[])objectTileIds.clone(); + section.objectXs = (short[])objectXs.clone(); + section.objectYs = (short[])objectYs.clone(); + section.objectInfo = (ObjectInfo[])objectInfo.clone(); + return section; + } catch (CloneNotSupportedException cnse) { + throw new RuntimeException( + "SparseMisoSceneModel.Section.clone: " + cnse); + } + } + + public String toString () { + return ((width == 0) ? "" : + (width + "x" + (baseTileIds.length/width))) + + "+" + x + "+" + y + + ":" + objectInfo.length + ":" + objectTileIds.length; + } + } + + /** The dimensions of a section of our scene. */ + public short swidth, sheight; + + /** + * Creates a scene model with the specified bounds. + * + * @param swidth the width of a single section (in tiles). + * @param sheight the height of a single section (in tiles). + */ + public SparseMisoSceneModel (int swidth, int sheight) + { + this.swidth = (short)swidth; + this.sheight = (short)sheight; + } + + /** + * Creates a blank model suitable for unserialization. + */ + public SparseMisoSceneModel () + { + } + + /** + * Adds all interesting {@link ObjectInfo} records in this scene to + * the supplied list. + */ + public void getInterestingObjects (ArrayList list) + { + for (Iterator iter = getSections(); iter.hasNext(); ) { + Section sect = (Section)iter.next(); + for (int oo = 0; oo < sect.objectInfo.length; oo++) { + list.add(sect.objectInfo[oo]); + } + } + } + + /** + * Informs the supplied visitor of each object in this scene. + */ + public void visitObjects (ObjectVisitor visitor) + { + for (Iterator iter = getSections(); iter.hasNext(); ) { + Section sect = (Section)iter.next(); + for (int oo = 0; oo < sect.objectInfo.length; oo++) { + ObjectInfo oinfo = sect.objectInfo[oo]; + visitor.visit(oinfo.tileId, oinfo.x, oinfo.y); + } + for (int oo = 0; oo < sect.objectTileIds.length; oo++) { + visitor.visit(sect.objectTileIds[oo], + sect.objectXs[oo], sect.objectYs[oo]); + } + } + } + + // documentation inherited + public int getBaseTileId (int col, int row) + { + Section sec = getSection(col, row, false); + return (sec == null) ? -1 : sec.getBaseTileId(col, row); + } + + // documentation inherited + public boolean setBaseTile (int fqBaseTileId, int col, int row) + { + getSection(col, row, true).setBaseTile(col, row, fqBaseTileId); + return true; + } + + // documentation inherited + public void getObjects (Rectangle region, ObjectSet set) + { + int minx = MathUtil.floorDiv(region.x, swidth); + int maxx = MathUtil.floorDiv(region.x+region.width-1, swidth); + int miny = MathUtil.floorDiv(region.y, sheight); + int maxy = MathUtil.floorDiv(region.y+region.height-1, sheight); + for (int yy = miny; yy <= maxy; yy++) { + for (int xx = minx; xx <= maxx; xx++) { + Section sec = getSection(xx, yy, false); + if (sec != null) { + sec.getObjects(region, set); + } + } + } + } + + // documentation inherited + public void addObject (ObjectInfo info) + { + getSection(info.x, info.y, true).addObject(info); + } + + // 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) + { + Section sec = getSection(info.x, info.y, false); + if (sec != null) { + return sec.removeObject(info); + } else { + return false; + } + } + + /** + * Don't call this method! This is only public so that the scene + * parser can construct a scene from raw data. If only Java supported + * class friendship. + */ + public void setSection (Section section) + { + _sections.put(key(section.x, section.y), section); + } + + /** + * Don't call this method! This is only public so that the scene + * writer can generate XML from the raw scene data. + */ + public Iterator getSections () + { + return _sections.values().iterator(); + } + + /** + * Returns the key for the specified section. + */ + protected final int key (int x, int y) + { + int sx = MathUtil.floorDiv(x, swidth); + int sy = MathUtil.floorDiv(y, sheight); + return (sx << 16) | (sy & 0xFFFF); + } + + /** Returns the section for the specified tile coordinate. */ + protected final Section getSection (int x, int y, boolean create) + { + int key = key(x, y); + Section sect = (Section)_sections.get(key); + if (sect == null && create) { + short sx = (short)(MathUtil.floorDiv(x, swidth)*swidth); + short sy = (short)(MathUtil.floorDiv(y, sheight)*sheight); + _sections.put(key, sect = new Section(sx, sy, swidth, sheight)); +// Log.info("Created new section " + sect + "."); + } + return sect; + } + + // documentation inherited + public Object clone () + { + SparseMisoSceneModel model = (SparseMisoSceneModel)super.clone(); + model._sections = new HashIntMap(); + for (Iterator iter = getSections(); iter.hasNext(); ) { + Section sect = (Section)iter.next(); + model.setSection((Section)sect.clone()); + } + return model; + } + + /** Contains our sections in row major order. */ + protected HashIntMap _sections = new HashIntMap(); +} diff --git a/src/java/com/threerings/miso/data/VirtualMisoSceneModel.java b/src/java/com/threerings/miso/data/VirtualMisoSceneModel.java index 540f7b676..79adcca03 100644 --- a/src/java/com/threerings/miso/data/VirtualMisoSceneModel.java +++ b/src/java/com/threerings/miso/data/VirtualMisoSceneModel.java @@ -1,5 +1,5 @@ // -// $Id: VirtualMisoSceneModel.java,v 1.2 2003/04/18 18:31:21 mdb Exp $ +// $Id: VirtualMisoSceneModel.java,v 1.3 2003/04/19 22:40:34 mdb Exp $ package com.threerings.miso.data; @@ -16,11 +16,6 @@ public abstract class VirtualMisoSceneModel extends MisoSceneModel { } - public VirtualMisoSceneModel (int width, int height) - { - super(width, height); - } - // documentation inherited from interface public boolean setBaseTile (int fqTileId, int x, int y) { diff --git a/src/java/com/threerings/miso/tools/xml/SparseMisoSceneParser.java b/src/java/com/threerings/miso/tools/xml/SparseMisoSceneParser.java new file mode 100644 index 000000000..89e0bc4c9 --- /dev/null +++ b/src/java/com/threerings/miso/tools/xml/SparseMisoSceneParser.java @@ -0,0 +1,73 @@ +// +// $Id: SparseMisoSceneParser.java,v 1.1 2003/04/19 22:40:34 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.SparseMisoSceneModel; + +/** + * A simple class for parsing simple miso scene models. + */ +public class SparseMisoSceneParser +{ + /** + * Constructs a scene parser that parses scenes with the specified XML + * path prefix. + */ + public SparseMisoSceneParser (String prefix) + { + // create and configure our digester + _digester = new Digester(); + + // create our scene rule set + SparseMisoSceneRuleSet set = new SparseMisoSceneRuleSet(); + + // 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", SparseMisoSceneModel.class.getName()); + } + + /** + * Parses the XML file at the specified path into a scene model + * instance. + */ + public SparseMisoSceneModel 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 (SparseMisoSceneModel model) + { + _model = model; + } + + protected String _prefix; + protected Digester _digester; + protected SparseMisoSceneModel _model; +} diff --git a/src/java/com/threerings/miso/tools/xml/SparseMisoSceneRuleSet.java b/src/java/com/threerings/miso/tools/xml/SparseMisoSceneRuleSet.java new file mode 100644 index 000000000..27b512ba6 --- /dev/null +++ b/src/java/com/threerings/miso/tools/xml/SparseMisoSceneRuleSet.java @@ -0,0 +1,68 @@ +// +// $Id: SparseMisoSceneRuleSet.java,v 1.1 2003/04/19 22:40:34 mdb Exp $ + +package com.threerings.miso.tools.xml; + +import java.util.ArrayList; +import org.xml.sax.Attributes; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.Rule; + +import com.samskivert.xml.CallMethodSpecialRule; +import com.samskivert.xml.SetFieldRule; +import com.samskivert.xml.SetPropertyFieldsRule; + +import com.threerings.tools.xml.NestableRuleSet; + +import com.threerings.miso.data.ObjectInfo; +import com.threerings.miso.data.SparseMisoSceneModel.Section; +import com.threerings.miso.data.SparseMisoSceneModel; + +/** + * Used to parse a {@link SparseMisoSceneModel} from XML. + */ +public class SparseMisoSceneRuleSet implements NestableRuleSet +{ + // documentation inherited from interface + public String getOuterElement () + { + return SparseMisoSceneWriter.OUTER_ELEMENT; + } + + // documentation inherited from interface + public void addRuleInstances (String prefix, Digester dig) + { + // this creates the appropriate instance when we encounter our + // prefix tag + dig.addRule(prefix, new Rule(dig) { + public void begin (Attributes attributes) throws Exception { + digester.push(createMisoSceneModel()); + } + public void end () throws Exception { + digester.pop(); + } + }); + + // set up rules to parse and set our fields + dig.addRule(prefix + "/swidth", new SetFieldRule(dig, "swidth")); + dig.addRule(prefix + "/sheight", new SetFieldRule(dig, "sheight")); + + String sprefix = prefix + "/sections/section"; + dig.addObjectCreate(sprefix, Section.class.getName()); + dig.addRule(sprefix, new SetPropertyFieldsRule(dig)); + dig.addRule(sprefix + "/base", new SetFieldRule(dig, "baseTileIds")); + dig.addObjectCreate(sprefix + "/objects/object", + ObjectInfo.class.getName()); + dig.addRule(sprefix + "/objects/object", + new SetPropertyFieldsRule(dig)); + dig.addSetNext(sprefix + "/objects/object", "addObject", + ObjectInfo.class.getName()); + dig.addSetNext(sprefix, "setSection", Section.class.getName()); + } + + protected SparseMisoSceneModel createMisoSceneModel () + { + return new SparseMisoSceneModel(); + } +} diff --git a/src/java/com/threerings/miso/tools/xml/SparseMisoSceneWriter.java b/src/java/com/threerings/miso/tools/xml/SparseMisoSceneWriter.java new file mode 100644 index 000000000..c7aa0b1cf --- /dev/null +++ b/src/java/com/threerings/miso/tools/xml/SparseMisoSceneWriter.java @@ -0,0 +1,109 @@ +// +// $Id: SparseMisoSceneWriter.java,v 1.1 2003/04/19 22:40:34 mdb Exp $ + +package com.threerings.miso.tools.xml; + +import java.util.Iterator; + +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +import com.megginson.sax.DataWriter; +import com.samskivert.util.StringUtil; +import com.threerings.tools.xml.NestableWriter; + +import com.threerings.miso.data.ObjectInfo; +import com.threerings.miso.data.SparseMisoSceneModel.Section; +import com.threerings.miso.data.SparseMisoSceneModel; + +/** + * Generates an XML representation of a {@link SparseMisoSceneModel}. + */ +public class SparseMisoSceneWriter implements NestableWriter +{ + /** The element used to enclose scene models written with this + * writer. */ + public static final String OUTER_ELEMENT = "miso"; + + // documentation inherited from interface + public void write (Object object, DataWriter writer) + throws SAXException + { + SparseMisoSceneModel model = (SparseMisoSceneModel)object; + writer.startElement(OUTER_ELEMENT); + writeSceneData(model, writer); + writer.endElement(OUTER_ELEMENT); + } + + /** + * Writes just the scene data which is handy for derived classes which + * may wish to add their own scene data to the scene output. + */ + protected void writeSceneData (SparseMisoSceneModel model, + DataWriter writer) + throws SAXException + { + writer.dataElement("swidth", Integer.toString(model.swidth)); + writer.dataElement("sheight", Integer.toString(model.sheight)); + + writer.startElement("sections"); + for (Iterator iter = model.getSections(); iter.hasNext(); ) { + Section sect = (Section)iter.next(); + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "x", "", "", String.valueOf(sect.x)); + attrs.addAttribute("", "y", "", "", String.valueOf(sect.y)); + attrs.addAttribute("", "width", "", "", String.valueOf(sect.width)); + writer.startElement("", "section", "", attrs); + + writer.dataElement( + "base", StringUtil.toString(sect.baseTileIds, "", "")); + + // write our uninteresting object tile information + writer.startElement("objects"); + for (int ii = 0; ii < sect.objectTileIds.length; ii++) { + attrs = new AttributesImpl(); + attrs.addAttribute("", "tileId", "", "", + String.valueOf(sect.objectTileIds[ii])); + attrs.addAttribute("", "x", "", "", + String.valueOf(sect.objectXs[ii])); + attrs.addAttribute("", "y", "", "", + String.valueOf(sect.objectYs[ii])); + writer.emptyElement("", "object", "", attrs); + } + + // write our interesting object tile information + for (int ii = 0; ii < sect.objectInfo.length; ii++) { + ObjectInfo info = sect.objectInfo[ii]; + attrs = new AttributesImpl(); + attrs.addAttribute("", "tileId", "", "", + String.valueOf(info.tileId)); + attrs.addAttribute("", "x", "", "", String.valueOf(info.x)); + attrs.addAttribute("", "y", "", "", String.valueOf(info.y)); + + if (!StringUtil.blank(info.action)) { + attrs.addAttribute("", "action", "", "", info.action); + } + if (info.priority != 0) { + attrs.addAttribute("", "priority", "", "", + String.valueOf(info.priority)); + } + if (info.sx != 0 || info.sy != 0) { + attrs.addAttribute("", "sx", "", "", + String.valueOf(info.sx)); + attrs.addAttribute("", "sy", "", "", + String.valueOf(info.sy)); + attrs.addAttribute("", "sorient", "", "", + String.valueOf(info.sorient)); + } + if (info.zations != 0) { + attrs.addAttribute("", "zations", "", "", + String.valueOf(info.zations)); + } + writer.emptyElement("", "object", "", attrs); + } + writer.endElement("objects"); + writer.endElement("section"); + } + writer.endElement("sections"); + } +} diff --git a/src/java/com/threerings/miso/util/MisoSceneMetrics.java b/src/java/com/threerings/miso/util/MisoSceneMetrics.java index 03d19cddf..857759582 100644 --- a/src/java/com/threerings/miso/util/MisoSceneMetrics.java +++ b/src/java/com/threerings/miso/util/MisoSceneMetrics.java @@ -1,5 +1,5 @@ // -// $Id: MisoSceneMetrics.java,v 1.1 2003/04/17 19:21:16 mdb Exp $ +// $Id: MisoSceneMetrics.java,v 1.2 2003/04/19 22:40:34 mdb Exp $ package com.threerings.miso.util; @@ -23,22 +23,9 @@ public class MisoSceneMetrics /** 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; @@ -62,26 +49,13 @@ public class MisoSceneMetrics * @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) + public MisoSceneMetrics (int tilewid, int tilehei, int finegran) { // 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); @@ -107,28 +81,4 @@ public class MisoSceneMetrics 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/util/MisoUtil.java b/src/java/com/threerings/miso/util/MisoUtil.java index 671b48f20..867cc500c 100644 --- a/src/java/com/threerings/miso/util/MisoUtil.java +++ b/src/java/com/threerings/miso/util/MisoUtil.java @@ -1,5 +1,5 @@ // -// $Id: MisoUtil.java,v 1.20 2003/04/18 22:59:04 mdb Exp $ +// $Id: MisoUtil.java,v 1.21 2003/04/19 22:40:34 mdb Exp $ package com.threerings.miso.util; @@ -8,6 +8,7 @@ import java.awt.Polygon; import java.awt.Rectangle; import com.samskivert.swing.SmartPolygon; +import com.samskivert.util.StringUtil; import com.threerings.media.sprite.Sprite; import com.threerings.media.util.MathUtil; @@ -16,6 +17,7 @@ import com.threerings.util.DirectionCodes; import com.threerings.util.DirectionUtil; import com.threerings.miso.Log; +import com.threerings.miso.MisoConfig; /** * Miscellaneous isometric-display-related utility routines. @@ -47,11 +49,11 @@ public class MisoUtil screenToFull(metrics, bx, by, bfpos); // pull out the tile coordinates for each point - int tax = afpos.x / FULL_TILE_FACTOR; - int tay = afpos.y / FULL_TILE_FACTOR; + int tax = fullToTile(afpos.x); + int tay = fullToTile(afpos.y); - int tbx = bfpos.x / FULL_TILE_FACTOR; - int tby = bfpos.y / FULL_TILE_FACTOR; + int tbx = fullToTile(bfpos.x); + int tby = fullToTile(bfpos.y); // compare tile coordinates to determine direction int dir = getIsoDirection(tax, tay, tbx, tby); @@ -159,7 +161,7 @@ public class MisoUtil */ public static int fullToTile (int val) { - return (val / FULL_TILE_FACTOR); + return MathUtil.floorDiv(val, FULL_TILE_FACTOR); } /** @@ -167,7 +169,7 @@ public class MisoUtil */ public static int fullToFine (int val) { - return (val - ((val / FULL_TILE_FACTOR) * FULL_TILE_FACTOR)); + return (val - (fullToTile(val) * FULL_TILE_FACTOR)); } /** @@ -187,14 +189,11 @@ public class MisoUtil { // determine the upper-left of the quadrant that contains our // point - int zx = (int)Math.floor((float)(sx - metrics.origin.x) / - metrics.tilewid); - int zy = (int)Math.floor((float)(sy - metrics.origin.y) / - metrics.tilehei); + int zx = (int)Math.floor((float)sx / metrics.tilewid); + int zy = (int)Math.floor((float)sy / metrics.tilehei); // these are the screen coordinates of the tile's top - int ox = (zx * metrics.tilewid + metrics.origin.x), - oy = (zy * metrics.tilehei + metrics.origin.y); + int ox = (zx * metrics.tilewid), oy = (zy * metrics.tilehei); // these are the tile coordinates tpos.x = zy + zx; tpos.y = zy - zx; @@ -235,8 +234,8 @@ public class MisoUtil public static Point tileToScreen ( MisoSceneMetrics metrics, int x, int y, Point spos) { - spos.x = metrics.origin.x + ((x - y - 1) * metrics.tilehwid); - spos.y = metrics.origin.y + ((x + y) * metrics.tilehhei); + spos.x = (x - y - 1) * metrics.tilehwid; + spos.y = (x + y) * metrics.tilehhei; return spos; } @@ -289,6 +288,9 @@ public class MisoUtil // determine distance along the y-axis float ydist = MathUtil.distance(x, y, crossx, crossy); fpos.y = (int)(ydist / metrics.finelen); + +// Log.info("Pixel to fine " + StringUtil.coordsToString(x, y) + +// " -> " + StringUtil.toString(fpos) + "."); } /** @@ -313,6 +315,13 @@ public class MisoUtil // get the screen coordinates for the containing tile Point spos = tileToScreen(metrics, tpos.x, tpos.y, new Point()); +// Log.info("Screen to full " + +// "[screen=" + StringUtil.coordsToString(sx, sy) + +// ", tpos=" + StringUtil.toString(tpos) + +// ", spos=" + StringUtil.toString(spos) + +// ", fpix=" + StringUtil.coordsToString( +// sx-spos.x, sy-spos.y) + "]."); + // get the fine coordinates within the containing tile pixelToFine(metrics, sx - spos.x, sy - spos.y, fpos); @@ -338,7 +347,7 @@ public class MisoUtil MisoSceneMetrics metrics, int x, int y, Point spos) { // get the tile screen position - int tx = x / FULL_TILE_FACTOR, ty = y / FULL_TILE_FACTOR; + int tx = fullToTile(x), ty = fullToTile(y); Point tspos = tileToScreen(metrics, tx, ty, new Point()); // get the pixel position of the fine coords within the tile