From 89e625216934cd6542aafe0f816e909c20982d98 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Wed, 12 Feb 2003 05:39:15 +0000 Subject: [PATCH] Refactored Miso scene system to support larger (tiled) scenes in the future. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2268 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/miso/data/MisoScene.java | 69 ++++++ .../threerings/miso/data/MisoSceneModel.java | 205 ++-------------- .../miso/data/MisoSceneRepository.java | 35 +++ .../miso/data/SimpleMisoSceneImpl.java | 146 +++++++++++ .../miso/data/SimpleMisoSceneModel.java | 230 ++++++++++++++++++ 5 files changed, 504 insertions(+), 181 deletions(-) create mode 100644 src/java/com/threerings/miso/data/MisoScene.java create mode 100644 src/java/com/threerings/miso/data/MisoSceneRepository.java create mode 100644 src/java/com/threerings/miso/data/SimpleMisoSceneImpl.java create mode 100644 src/java/com/threerings/miso/data/SimpleMisoSceneModel.java diff --git a/src/java/com/threerings/miso/data/MisoScene.java b/src/java/com/threerings/miso/data/MisoScene.java new file mode 100644 index 000000000..5201dda85 --- /dev/null +++ b/src/java/com/threerings/miso/data/MisoScene.java @@ -0,0 +1,69 @@ +// +// $Id: MisoScene.java,v 1.1 2003/02/12 05:39:15 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. + */ + 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. + */ + public MisoSceneModel getSceneModel (); +} diff --git a/src/java/com/threerings/miso/data/MisoSceneModel.java b/src/java/com/threerings/miso/data/MisoSceneModel.java index fbe49bd0b..6b951236d 100644 --- a/src/java/com/threerings/miso/data/MisoSceneModel.java +++ b/src/java/com/threerings/miso/data/MisoSceneModel.java @@ -1,213 +1,56 @@ // -// $Id: MisoSceneModel.java,v 1.11 2003/01/31 23:10:45 mdb Exp $ +// $Id: MisoSceneModel.java,v 1.12 2003/02/12 05:39:15 mdb Exp $ package com.threerings.miso.data; -import java.util.ArrayList; - import com.threerings.io.SimpleStreamableObject; /** - * The scene model is the bare bones representation of the data for a - * scene in the Miso system. From the scene model, one would create an - * instance of {@link DisplayMisoScene}. + * Contains basic information for a miso scene model that is shared among + * every specialized model implementation. */ public class MisoSceneModel extends SimpleStreamableObject implements Cloneable { - /** The width of the scene in tile units. */ + /** The sector of our containing scene for which we contain model + * data. Simple scenes may contain only one sector, but larger more + * complicated scenes will likely contain multiple sectors to support + * fine grain updates. */ + public int sectorId; + + /** The width of our sector, in tile units. */ public int width; - /** The height of the scene in tile units. */ + /** The height of our sector, in tile units. */ public int height; - /** The viewport width in tiles. */ - public int vwidth; - - /** The viewport height in tiles. */ - public int vheight; - - /** The combined tile ids (tile set id and tile id) in compressed - * format. Don't go poking around in here, use the accessor - * 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; - /** - * Get the fully-qualified tile id of the base tile at the specified - * row and column. + * Creates a completely uninitialized model suitable for little more + * than unserialization. */ - public int getBaseTile (int col, int row) + public MisoSceneModel () { - 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. + * Creates a blank model with the specified dimensions. */ - public boolean setBaseTile (int col, int row, int fqBaseTileId) + public MisoSceneModel (int width, int height) { - int index = getIndex(col, row); - if (index == -1) { - return false; - } - baseTileIds[index] = fqBaseTileId; - return true; + this.width = width; + this.height = height; } /** - * Get the index into the baseTileIds[] for the specified - * x and y coordinates, or return -1 if the specified coordinates - * are outside of the viewable area. - * - * Assumption: The viewable area is centered and aligned as far - * to the top of the isometric scene as possible, such that - * the upper-left corner is at the point where the tiles - * (0, vwid) and (0, vwid-1) touch. The upper-right corner - * is at the point where the tiles (vwid-1, 0) and (vwid, 0) - * touch. - * - * The viewable area is made up of "fat" rows and "thin" rows. The - * fat rows display one more tile than the thin rows because their - * first and last tiles are halfway off the viewable area. The thin - * rows are fully contained within the viewable area except for the - * first and last thin rows, which display only their bottom and top - * halves, respectively. Note that #fatrows == #thinrows - 1; - */ - protected int getIndex (int x, int y) - { - // check to see if the index lies in one of the "fat" rows - if (((x + y) & 1) == (vwidth & 1)) { - - int col = (vwidth + x - y) >> 1; - int row = x - col; - if ((col < 0) || (col > vwidth) || - (row < 0) || (row >= vheight)) { - return -1; // out of view - } - - return (vwidth + 1) * row + col; - - } else { - // the index must be in a "thin" row - int col = (vwidth + x - y - 1) >> 1; - int row = x - col; - if ((col < 0) || (col >= vwidth) || - (row < 0) || (row > vheight)) { - return -1; // out of view - } - - // we store the all the fat rows first, then all the thin - // rows, the '(vwidth + 1) * vheight' is the size of all - // the fat rows. - return row * vwidth + col + (vwidth + 1) * vheight; - } - } - - /** - * Allocate the base tile array. - */ - protected void allocateBaseTileArray () - { - baseTileIds = new int[vwidth + vheight + ((vwidth * vheight) << 1)]; - } - - /** - * Creates a copy of this Miso scene model. + * Creates a copy of this scene model. */ public Object clone () - throws CloneNotSupportedException { - MisoSceneModel model = (MisoSceneModel)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; - } - - /** - * 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; + try { + return (MisoSceneModel)super.clone(); + } catch (CloneNotSupportedException cnse) { + throw new RuntimeException( + "MisoSceneModel.clone() booched " + cnse); } - - // set up the interesting array - int icount = ilist.size(); - model.objectInfo = new ObjectInfo[icount]; - ilist.toArray(model.objectInfo); - } - - /** - * Creates and returns a blank scene model (with zero width and - * height). - */ - public static MisoSceneModel blankMisoSceneModel () - { - MisoSceneModel model = new MisoSceneModel(); - populateBlankMisoSceneModel(model, 0, 0, 0, 0); - return model; - } - - /** - * Creates and returns a blank scene model with the specified width - * and height. - */ - public static MisoSceneModel blankMisoSceneModel ( - int width, int height, int vwidth, int vheight) - { - MisoSceneModel model = new MisoSceneModel(); - populateBlankMisoSceneModel(model, width, height, vwidth, vheight); - return model; - } - - /** - * Populates a blank scene model with blank values. - */ - protected static void populateBlankMisoSceneModel ( - MisoSceneModel model, int width, int height, int vwidth, int vheight) - { - model.width = width; - model.height = height; - model.vwidth = vwidth; - model.vheight = vheight; - model.allocateBaseTileArray(); - model.objectTileIds = new int[0]; - model.objectXs = new short[0]; - model.objectYs = new short[0]; - model.objectInfo = new ObjectInfo[0]; } } diff --git a/src/java/com/threerings/miso/data/MisoSceneRepository.java b/src/java/com/threerings/miso/data/MisoSceneRepository.java new file mode 100644 index 000000000..236af91f1 --- /dev/null +++ b/src/java/com/threerings/miso/data/MisoSceneRepository.java @@ -0,0 +1,35 @@ +// +// $Id: MisoSceneRepository.java,v 1.1 2003/02/12 05:39:15 mdb Exp $ + +package com.threerings.miso.data; + +import com.samskivert.io.PersistenceException; + +/** + * A generic interface for an entity that provides access to {@link + * MisoSceneModel} data. + */ +public interface MisoSceneRepository +{ + /** + * Loads the specified scene model from the repository. + * + * @return the requested scene or null if no scene exists with the + * specified scene and sector id. + * + * @exception PersistenceException thrown if an error occurs + * communicating with the underlying storage mechanism. + */ + public MisoSceneModel loadSceneModel (int sceneId, int sectorId) + throws PersistenceException; + + /** + * Stores the specified model in the repository, inserting it if it + * does not already exist, updating it otherwise. + * + * @exception PersistenceException thrown if an error occurs + * communicating with the underlying storage mechanism. + */ + public void storeSceneModel (MisoSceneModel model) + throws PersistenceException; +} diff --git a/src/java/com/threerings/miso/data/SimpleMisoSceneImpl.java b/src/java/com/threerings/miso/data/SimpleMisoSceneImpl.java new file mode 100644 index 000000000..72cc27823 --- /dev/null +++ b/src/java/com/threerings/miso/data/SimpleMisoSceneImpl.java @@ -0,0 +1,146 @@ +// +// $Id: SimpleMisoSceneImpl.java,v 1.1 2003/02/12 05:39:15 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++) { + _objects.add(createObjectInfo(_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); + _model.addObject(info); + _objects.add(info); + return info; + } + + // documentation inherited from interface + public boolean removeObject (ObjectInfo info) + { + _model.removeObject(info); + return _objects.remove(info); + } + + // documentation inherited from interface + public MisoSceneModel getSceneModel () + { + 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 new file mode 100644 index 000000000..2dfb75a06 --- /dev/null +++ b/src/java/com/threerings/miso/data/SimpleMisoSceneModel.java @@ -0,0 +1,230 @@ +// +// $Id: SimpleMisoSceneModel.java,v 1.1 2003/02/12 05:39:15 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; + +/** + * 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 + * be stored in a single contiguous array. + * + *

Additionally, it makes the assumption that the single model will be + * used to display a scene on a rectangular screen (dimensions defined by + * {@link #vwidth} and {@link #vheight}) and further optimizes the base + * tile array to obviate the need to store tile data for things that fall + * outside the bounds of the screen. + */ +public class SimpleMisoSceneModel extends MisoSceneModel +{ + /** The viewport width in tiles. */ + public int vwidth; + + /** The viewport height in tiles. */ + public int vheight; + + /** The combined tile ids (tile set id and tile id) in compressed + * format. Don't go poking around in here, use the accessor + * 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. + */ + public SimpleMisoSceneModel () + { + } + + /** + * Creates a blank scene model with the specified dimensions. + */ + public SimpleMisoSceneModel (int width, int height, int vwidth, int vheight) + { + super(width, height); + 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) + { + 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. + */ + public boolean setBaseTile (int col, int row, int fqBaseTileId) + { + int index = getIndex(col, row); + if (index == -1) { + return false; + } + baseTileIds[index] = fqBaseTileId; + return true; + } + + /** + * Adds an object to this model. + */ + 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); + } + } + + /** + * Removes an object from this model. + */ + 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); + } + + // 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); + } + } + + /** + * Get the index into the baseTileIds[] for the specified + * x and y coordinates, or return -1 if the specified coordinates + * are outside of the viewable area. + * + * Assumption: The viewable area is centered and aligned as far + * to the top of the isometric scene as possible, such that + * the upper-left corner is at the point where the tiles + * (0, vwid) and (0, vwid-1) touch. The upper-right corner + * is at the point where the tiles (vwid-1, 0) and (vwid, 0) + * touch. + * + * The viewable area is made up of "fat" rows and "thin" rows. The + * fat rows display one more tile than the thin rows because their + * first and last tiles are halfway off the viewable area. The thin + * rows are fully contained within the viewable area except for the + * first and last thin rows, which display only their bottom and top + * halves, respectively. Note that #fatrows == #thinrows - 1; + */ + protected int getIndex (int x, int y) + { + // check to see if the index lies in one of the "fat" rows + if (((x + y) & 1) == (vwidth & 1)) { + + int col = (vwidth + x - y) >> 1; + int row = x - col; + if ((col < 0) || (col > vwidth) || + (row < 0) || (row >= vheight)) { + return -1; // out of view + } + + return (vwidth + 1) * row + col; + + } else { + // the index must be in a "thin" row + int col = (vwidth + x - y - 1) >> 1; + int row = x - col; + if ((col < 0) || (col >= vwidth) || + (row < 0) || (row > vheight)) { + return -1; // out of view + } + + // we store the all the fat rows first, then all the thin + // rows, the '(vwidth + 1) * vheight' is the size of all + // the fat rows. + return row * vwidth + col + (vwidth + 1) * vheight; + } + } + + /** + * Allocate the base tile array. + */ + protected void allocateBaseTileArray () + { + baseTileIds = new int[vwidth + vheight + ((vwidth * vheight) << 1)]; + } + + // 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; + } + + /** + * 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) + { + // 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); + } +}