Behold, Nenya, Ring of Water and repository for our media and animation related
goodies, both Java 2D and LWJGL/JME 3D. git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@1 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// $Id: MisoSceneModel.java 3726 2005-10-11 19:17:43Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.miso.data;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.util.Random;
|
||||
|
||||
import com.threerings.io.SimpleStreamableObject;
|
||||
|
||||
import com.threerings.miso.util.ObjectSet;
|
||||
|
||||
/**
|
||||
* Contains basic information for a miso scene model that is shared among
|
||||
* the specialized model implementations.
|
||||
*/
|
||||
public abstract class MisoSceneModel extends SimpleStreamableObject
|
||||
implements Cloneable
|
||||
{
|
||||
/**
|
||||
* Creates a completely uninitialized model suitable for little more
|
||||
* than unserialization.
|
||||
*/
|
||||
public MisoSceneModel ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fully qualified tile id of the base tile at the
|
||||
* specified coordinates. <code>-1</code> will be returned if there is
|
||||
* no tile at the specified coordinate.
|
||||
*/
|
||||
public abstract int getBaseTileId (int x, int y);
|
||||
|
||||
/**
|
||||
* Updates the tile at the specified location in the base layer.
|
||||
*
|
||||
* <p> 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);
|
||||
|
||||
/**
|
||||
* Updates the default base tileset id for this scene.
|
||||
*/
|
||||
public void setDefaultBaseTileSet (int tileSetId)
|
||||
{
|
||||
// nothing doing
|
||||
}
|
||||
|
||||
/**
|
||||
* Scene models can return a default tileset to be used when no base
|
||||
* tile data exists for a particular tile.
|
||||
*/
|
||||
public int getDefaultBaseTileSet ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the supplied object set with info on all objects whose
|
||||
* origin falls in the requested region.
|
||||
*/
|
||||
public abstract void getObjects (Rectangle region, ObjectSet set);
|
||||
|
||||
/**
|
||||
* Adds an object to this scene.
|
||||
*
|
||||
* @return true if the object was added, false if the add was rejected
|
||||
* due to being a duplicate.
|
||||
*/
|
||||
public abstract boolean 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.
|
||||
*/
|
||||
public Object clone ()
|
||||
{
|
||||
try {
|
||||
return (MisoSceneModel)super.clone();
|
||||
} catch (CloneNotSupportedException cnse) {
|
||||
throw new RuntimeException("MisoSceneModel.clone: " + cnse);
|
||||
}
|
||||
}
|
||||
|
||||
/** A random number generator for filling random base tiles. */
|
||||
protected transient Random _rando = new Random();
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
//
|
||||
// $Id: ObjectInfo.java 3749 2005-11-09 04:00:16Z mdb $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.miso.data;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.io.SimpleStreamableObject;
|
||||
import com.threerings.media.tile.TileUtil;
|
||||
|
||||
/**
|
||||
* Contains information about an object in a Miso scene.
|
||||
*/
|
||||
public class ObjectInfo extends SimpleStreamableObject
|
||||
implements Cloneable
|
||||
{
|
||||
/** The fully qualified object tile id. */
|
||||
public int tileId;
|
||||
|
||||
/** The x and y tile coordinates of the object. */
|
||||
public int x, y;
|
||||
|
||||
/** Don't access this directly unless you are serializing this
|
||||
* instance. Use {@link #getPriority} instead. */
|
||||
public byte priority = 0;
|
||||
|
||||
/** The action associated with this object or null if it has no
|
||||
* action. */
|
||||
public String action;
|
||||
|
||||
/** A "spot" associated with this object (specified as an offset from
|
||||
* the fine coordinates of the object's origin tile). */
|
||||
public byte sx, sy;
|
||||
|
||||
/** The orientation of the "spot" associated with this object. */
|
||||
public byte sorient;
|
||||
|
||||
/** Up to two colorization assignments for this object. */
|
||||
public int zations;
|
||||
|
||||
/**
|
||||
* Convenience constructor.
|
||||
*/
|
||||
public ObjectInfo (int tileId, int x, int y)
|
||||
{
|
||||
this.tileId = tileId;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object info that is a copy of the supplied info.
|
||||
*/
|
||||
public ObjectInfo (ObjectInfo other)
|
||||
{
|
||||
this.tileId = other.tileId;
|
||||
this.x = other.x;
|
||||
this.y = other.y;
|
||||
this.priority = other.priority;
|
||||
this.action = other.action;
|
||||
this.sx = other.sx;
|
||||
this.sy = other.sy;
|
||||
this.sorient = other.sorient;
|
||||
this.zations = other.zations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zero argument constructor needed for unserialization.
|
||||
*/
|
||||
public ObjectInfo ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the render priority of this object tile.
|
||||
*/
|
||||
public int getPriority ()
|
||||
{
|
||||
return priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the primary colorization assignment.
|
||||
*/
|
||||
public int getPrimaryZation ()
|
||||
{
|
||||
return (zations & 0xFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the secondary colorization assignment.
|
||||
*/
|
||||
public int getSecondaryZation ()
|
||||
{
|
||||
return ((zations >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the primary and secondary colorization assignments.
|
||||
*/
|
||||
public void setZations (short primary, short secondary)
|
||||
{
|
||||
zations = ((secondary << 16) | primary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this object info contains non-default data for
|
||||
* anything other than the tile id and coordinates.
|
||||
*/
|
||||
public boolean isInteresting ()
|
||||
{
|
||||
return (!StringUtil.isBlank(action) || priority != 0 ||
|
||||
sx != 0 || sy != 0 || zations != 0);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean equals (Object other)
|
||||
{
|
||||
if (other instanceof ObjectInfo) {
|
||||
ObjectInfo ooi = (ObjectInfo)other;
|
||||
return (x == ooi.x && y == ooi.y && tileId == ooi.tileId);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int hashCode ()
|
||||
{
|
||||
return x ^ y ^ tileId;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public Object clone ()
|
||||
{
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException cnse) {
|
||||
// notgunnahappen.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Enhances our {@link SimpleStreamableObject#toString} output. */
|
||||
public String tileIdToString ()
|
||||
{
|
||||
return (TileUtil.getTileSetId(tileId) + ":" +
|
||||
TileUtil.getTileIndex(tileId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
//
|
||||
// $Id: SimpleMisoSceneModel.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
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.media.util.MathUtil;
|
||||
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
|
||||
* be stored in a single contiguous array.
|
||||
*
|
||||
* <p> 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 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;
|
||||
|
||||
/** 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)
|
||||
{
|
||||
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();
|
||||
|
||||
// start with zero-length object arrays
|
||||
objectTileIds = new int[0];
|
||||
objectXs = new short[0];
|
||||
objectYs = new short[0];
|
||||
objectInfo = new ObjectInfo[0];
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int getBaseTileId (int col, int row)
|
||||
{
|
||||
int index = getIndex(col, row);
|
||||
return (index == -1) ? 0 : baseTileIds[index];
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean setBaseTile (int fqBaseTileId, int col, int row)
|
||||
{
|
||||
int index = getIndex(col, row);
|
||||
if (index == -1) {
|
||||
return false;
|
||||
}
|
||||
baseTileIds[index] = fqBaseTileId;
|
||||
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 boolean 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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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.indexOf(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
|
||||
* 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)];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,445 @@
|
||||
//
|
||||
// $Id: SparseMisoSceneModel.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
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.ListUtil;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.io.SimpleStreamableObject;
|
||||
|
||||
import com.threerings.media.util.MathUtil;
|
||||
import com.threerings.util.StreamableHashIntMap;
|
||||
|
||||
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 (ObjectInfo info);
|
||||
}
|
||||
|
||||
/** 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 boolean addObject (ObjectInfo info) {
|
||||
// sanity check: see if there is already an object of this
|
||||
// type at these coordinates
|
||||
int dupidx;
|
||||
if ((dupidx = ListUtil.indexOf(objectInfo, info)) != -1) {
|
||||
Log.warning("Refusing to add duplicate object [ninfo=" + info +
|
||||
", oinfo=" + objectInfo[dupidx] + "].");
|
||||
return false;
|
||||
}
|
||||
if ((dupidx = indexOfUn(info)) != -1) {
|
||||
Log.warning("Refusing to add duplicate object " +
|
||||
"[info=" + info + "].");
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean removeObject (ObjectInfo info) {
|
||||
// look for it in the interesting info array
|
||||
int oidx = ListUtil.indexOf(objectInfo, info);
|
||||
if (oidx != -1) {
|
||||
objectInfo = (ObjectInfo[])
|
||||
ArrayUtil.splice(objectInfo, oidx, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// look for it in the uninteresting arrays
|
||||
oidx = indexOfUn(info);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the specified object in the uninteresting
|
||||
* arrays or -1 if it is not in this section as an uninteresting
|
||||
* object.
|
||||
*/
|
||||
protected int indexOfUn (ObjectInfo info)
|
||||
{
|
||||
for (int ii = 0; ii < objectTileIds.length; ii++) {
|
||||
if (objectTileIds[ii] == info.tileId &&
|
||||
objectXs[ii] == info.x && objectYs[ii] == info.y) {
|
||||
return ii;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this section contains no data beyond the default.
|
||||
* Used when saving a sparse scene: we omit blank sections.
|
||||
*/
|
||||
public boolean isBlank ()
|
||||
{
|
||||
if ((objectTileIds.length != 0) || (objectInfo.length != 0)) {
|
||||
return false;
|
||||
}
|
||||
for (int ii=0, nn=baseTileIds.length; ii < nn; ii++) {
|
||||
if (baseTileIds[ii] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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) ? "<no bounds>" :
|
||||
(width + "x" + (baseTileIds.length/width))) +
|
||||
"+" + x + "+" + y +
|
||||
":" + objectInfo.length + ":" + objectTileIds.length;
|
||||
}
|
||||
}
|
||||
|
||||
/** The dimensions of a section of our scene. */
|
||||
public short swidth, sheight;
|
||||
|
||||
/** The tileset to use when we have no tile data. */
|
||||
public int defTileSet = 0;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
visitObjects(visitor, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs the supplied visitor of each object in this scene.
|
||||
*
|
||||
* @param interestingOnly if true, only the interesting objects will
|
||||
* be visited.
|
||||
*/
|
||||
public void visitObjects (ObjectVisitor visitor, boolean interestingOnly)
|
||||
{
|
||||
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);
|
||||
}
|
||||
if (!interestingOnly) {
|
||||
ObjectInfo info = new ObjectInfo();
|
||||
for (int oo = 0; oo < sect.objectTileIds.length; oo++) {
|
||||
info.tileId = sect.objectTileIds[oo];
|
||||
info.x = sect.objectXs[oo];
|
||||
info.y = sect.objectYs[oo];
|
||||
visitor.visit(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 setDefaultBaseTileSet (int tileSetId)
|
||||
{
|
||||
defTileSet = tileSetId;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int getDefaultBaseTileSet ()
|
||||
{
|
||||
return defTileSet;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void getObjects (Rectangle region, ObjectSet set)
|
||||
{
|
||||
int minx = MathUtil.floorDiv(region.x, swidth)*swidth;
|
||||
int maxx = MathUtil.floorDiv(region.x+region.width-1, swidth)*swidth;
|
||||
int miny = MathUtil.floorDiv(region.y, sheight)*sheight;
|
||||
int maxy = MathUtil.floorDiv(region.y+region.height-1, sheight)*sheight;
|
||||
for (int yy = miny; yy <= maxy; yy += sheight) {
|
||||
for (int xx = minx; xx <= maxx; xx += swidth) {
|
||||
Section sec = getSection(xx, yy, false);
|
||||
if (sec != null) {
|
||||
sec.getObjects(region, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean addObject (ObjectInfo info)
|
||||
{
|
||||
return 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();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
super.toString(buf);
|
||||
buf.append(", sections=" +
|
||||
StringUtil.toString(_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 StreamableHashIntMap();
|
||||
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 StreamableHashIntMap _sections = new StreamableHashIntMap();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// $Id: VirtualMisoSceneModel.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.miso.data;
|
||||
|
||||
/**
|
||||
* 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 ()
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public boolean setBaseTile (int fqTileId, int x, int y)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public boolean 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user