// // $Id$ // // Nenya library - tools for developing networked games // Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved // http://www.threerings.net/code/nenya/ // // 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.media.tile; import java.lang.ref.SoftReference; import java.util.Iterator; import java.util.Map; import java.io.Serializable; import java.awt.Rectangle; import java.awt.image.BufferedImage; import com.google.common.collect.Maps; import com.samskivert.util.StringUtil; import com.samskivert.util.Throttle; import com.threerings.media.image.BufferedMirage; import com.threerings.media.image.Colorization; import com.threerings.media.image.ImageUtil; import com.threerings.media.image.Mirage; import com.threerings.media.tile.Tile.Key; import static com.threerings.media.Log.log; /** * A tileset stores information on a single logical set of tiles. It provides a clean interface for * the {@link TileManager} or other entities to retrieve individual tiles from the tile set and * encapsulates the potentially sophisticated process of extracting the tile image from a composite * tileset image. * *
Tiles are referenced by their tile id. The tile id is essentially the tile number, assuming * the tile at the top-left of the image is tile id zero and tiles are numbered, in ascending * order, left to right, top to bottom. * *
This class is serializable and will be serialized, so derived classes should be sure to mark
* non-persistent fields as transient.
*/
public abstract class TileSet
implements Cloneable, Serializable
{
/** Used to assign colorizations to tiles that require them. */
public static interface Colorizer
{
/**
* Returns the colorization to be used for the specified named colorization class.
*
* @param index the index of the colorization being requested in the tileset's colorization
* list.
*/
public Colorization getColorization (int index, String zation);
}
/**
* Configures this tileset with an image provider that it can use to load its tileset image.
* This will be called automatically when the tileset is fetched via the {@link TileManager}.
*/
public void setImageProvider (ImageProvider improv)
{
_improv = improv;
}
/**
* Returns the tileset name.
*/
public String getName ()
{
return (_name == null) ? _imagePath : _name;
}
/**
* Specifies the tileset name.
*/
public void setName (String name)
{
_name = name;
}
/**
* Sets the path to the image that will be used by this tileset. This must be called before the
* first call to {@link #getTile}.
*/
public void setImagePath (String imagePath)
{
_imagePath = imagePath;
}
/**
* Returns the path to the composite image used by this tileset.
*/
public String getImagePath ()
{
return _imagePath;
}
/**
* Returns the number of tiles in the tileset.
*/
public abstract int getTileCount ();
/**
* Creates a copy of this tileset which will apply the supplied colorizations to its tileset
* image when creating tiles.
*/
public TileSet clone (Colorization[] zations)
{
try {
TileSet tset = (TileSet)clone();
tset._zations = zations;
return tset;
} catch (CloneNotSupportedException cnse) {
log.warning("Unable to clone tileset prior to colorization [tset=" + this +
", zations=" + StringUtil.toString(zations) + ", error=" + cnse + "].");
return null;
}
}
/**
* Returns a new tileset that is a clone of this tileset with the image path updated to
* reference the given path. Useful for configuring a single tileset and then generating
* additional tilesets with new images with the same configuration.
*/
public TileSet clone (String imagePath)
throws CloneNotSupportedException
{
TileSet dup = (TileSet)clone();
dup.setImagePath(imagePath);
return dup;
}
/**
* Computes and fills in the bounds for the specified tile based on the mechanism used by the
* derived class to do such things. The width and height of the bounds should be the size of
* the tile image and the x and y offset should be the offset in the tileset image for the
* image data of the specified tile.
*
* @param tileIndex the index of the tile whose bounds are to be computed.
* @param bounds the rectangle object into which to fill the bounds.
*
* @return the rectangle passed into the bounds parameter.
*/
public abstract Rectangle computeTileBounds (int tileIndex, Rectangle bounds);
/**
* Equivalent to {@link #getTile(int,Colorizer)} with a null Colorizer argument.
*/
public Tile getTile (int tileIndex)
{
return getTile(tileIndex, _zations);
}
/**
* Creates a {@link Tile} object from this tileset corresponding to the specified tile id and
* returns that tile. A null tile will never be returned, but one with an error image may be
* returned if a problem occurs loading the underlying tileset image.
*
* @param tileIndex the index of the tile in the tileset. Tile indexes start with zero as the
* upper left tile and increase by one as the tiles move left to right and top to bottom over
* the source image.
* @param rizer an entity that will be used to obtain colorizations for tilesets that are
* recolorizable. Passing null if the tileset is known not to be recolorizable is valid.
*
* @return the tile object.
*/
public Tile getTile (int tileIndex, Colorizer rizer)
{
return getTile(tileIndex, getColorizations(tileIndex, rizer));
}
/**
* Creates a {@link Tile} object from this tileset corresponding to the specified tile id and
* returns that tile. A null tile will never be returned, but one with an error image may be
* returned if a problem occurs loading the underlying tileset image.
*
* @param tileIndex the index of the tile in the tileset. Tile indexes start with zero as the
* upper left tile and increase by one as the tiles move left to right and top to bottom over
* the source image.
* @param zations colorizations to be applied to the tile image prior to returning it. These
* may be null for uncolorized images.
*
* @return the tile object.
*/
public Tile getTile (int tileIndex, Colorization[] zations)
{
Tile tile = null;
// first look in the active set; if it's in use by anyone or in the cache, it will be in
// the active set
synchronized (_atiles) {
_key.tileSet = this;
_key.tileIndex = tileIndex;
_key.zations = zations;
SoftReferencesuper.initTile().
*
* @param tile the tile to initialize.
* @param tileIndex the index of the tile.
* @param zations the colorizations to be used when generating the tile image.
*/
protected void initTile (Tile tile, int tileIndex, Colorization[] zations)
{
if (_improv != null) {
tile.setImage(getTileMirage(tileIndex, zations));
}
}
@Override
public String toString ()
{
StringBuilder buf = new StringBuilder("[");
toString(buf);
return buf.append("]").toString();
}
/**
* Reports statistics detailing the image manager cache performance and the current size of the
* cached images.
*/
protected void reportCachePerformance ()
{
if (/* Log.getLevel() != Log.log.DEBUG || */
_improv == null ||
_cacheStatThrottle.throttleOp()) {
return;
}
// compute our estimated memory usage
long amem = 0;
int asize = 0;
synchronized (_atiles) {
// first total up the active tiles
Iteratorsuper.toString(buf) and then
* appending additional information to the buffer.
*/
protected void toString (StringBuilder buf)
{
buf.append("name=").append(_name);
buf.append(", path=").append(_imagePath);
buf.append(", tileCount=").append(getTileCount());
}
/** The path to the file containing the tile images. */
protected String _imagePath;
/** The tileset name. */
protected String _name;
/** Colorizations to be applied to tiles created from this tileset. */
protected transient Colorization[] _zations;
/** The entity from which we obtain our tile image. */
protected transient ImageProvider _improv;
/** Increase this value when object's serialized state is impacted by
* a class change (modification of fields, inheritance). */
private static final long serialVersionUID = 1;
/** A map containing weak references to all "active" tiles. */
protected static Map