Major media subsystem revamp:

- All images are loaded through the image manager
- Architected to allow the use of prepared or unprepared images (and
  volatile images when the day comes that they support alpha)
- Tunable caches for images and tiles
- Resource manager caches unpacked resources on the filesystem
- Various and sundry other cleanups


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2116 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2003-01-13 22:49:47 +00:00
parent 8743be2131
commit 100aa3ace3
46 changed files with 1602 additions and 888 deletions
+94 -123
View File
@@ -1,22 +1,21 @@
//
// $Id: TileSet.java,v 1.35 2003/01/08 04:09:02 mdb Exp $
// $Id: TileSet.java,v 1.36 2003/01/13 22:49:46 mdb Exp $
package com.threerings.media.tile;
import java.awt.Color;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.Serializable;
import com.samskivert.util.ConfigUtil;
import com.samskivert.util.LRUHashMap;
import com.samskivert.util.StringUtil;
import com.samskivert.util.Tuple;
import com.threerings.media.Log;
import com.threerings.media.image.Colorization;
import com.threerings.media.image.ImageUtil;
import com.threerings.media.image.Mirage;
/**
* A tileset stores information on a single logical set of tiles. It
@@ -70,10 +69,6 @@ public abstract class TileSet
public void setImagePath (String imagePath)
{
_imagePath = imagePath;
// clear out any reference to a loaded image and cached tiles
_tilesetImg = null;
_tiles = null;
}
/**
@@ -90,14 +85,16 @@ public abstract class TileSet
public abstract int getTileCount ();
/**
* Creates a copy of this tileset with the supplied colorizations
* applied to its source image.
* Creates a copy of this tileset which will apply the supplied
* colorizations to its tileset image when creating tiles.
*/
public TileSet cloneColorized (Colorization[] zations)
public TileSet clone (Colorization[] zations)
{
TileSet tset = null;
try {
tset = (TileSet)clone();
TileSet tset = (TileSet)clone();
tset._zations = zations;
return tset;
} catch (CloneNotSupportedException cnse) {
Log.warning("Unable to clone tileset prior to colorization " +
"[tset=" + this +
@@ -105,37 +102,6 @@ public abstract class TileSet
", error=" + cnse + "].");
return null;
}
// make sure the tileset was able to load its image
Image timg = tset.getTileSetImage();
if (timg == null) {
Log.warning("Failed to load tileset image in preparation " +
"for colorization [tset=" + tset + "].");
// return the uncolorized tileset since it has no freaking
// source image anyway
return tset;
} else if (!(timg instanceof BufferedImage)) {
Log.warning("Can't recolor tileset with non-buffered " +
"image source [source=" + timg + "].");
return tset;
}
// create the recolored image and update the tileset
tset._tilesetImg =
ImageUtil.recolorImage((BufferedImage)timg, zations);
return tset;
}
// documentation inherited
public Object clone ()
throws CloneNotSupportedException
{
TileSet dup = (TileSet)super.clone();
// clear out the tileset cache
dup._tiles = null;
return dup;
}
/**
@@ -170,35 +136,81 @@ public abstract class TileSet
public Tile getTile (int tileIndex)
throws NoSuchTileException
{
int tcount = getTileCount();
checkTileIndex(tileIndex);
// create our tile cache if necessary
if (_tiles == null) {
int tcsize = ConfigUtil.getSystemProperty(
"narya.media.tile.cache_size", DEFAULT_TILE_CACHE_SIZE);
Log.debug("Creating tile cache [size=" + tcsize + "].");
_tiles = new LRUHashMap(tcsize);
}
// fetch and cache the tile
Tuple key = new Tuple(this, new Integer(tileIndex));
Tile tile = (Tile)_tiles.get(key);
if (tile == null) {
// create and initialize the tile object
tile = createTile(tileIndex, getTileMirage(tileIndex));
initTile(tile);
_tiles.put(key, tile);
}
return tile;
}
/**
* Returns the entire, raw, uncut, unprepared tileset source image.
*/
public BufferedImage getTileSetImage ()
{
return _improv.getTileSetImage(_imagePath, _zations);
}
/**
* Returns the raw (unprepared) image that would be used by the tile
* at the specified index.
*/
public BufferedImage getTileImage (int tileIndex)
throws NoSuchTileException
{
checkTileIndex(tileIndex);
Rectangle bounds = computeTileBounds(tileIndex);
BufferedImage timg = getTileSetImage();
return timg.getSubimage(bounds.x, bounds.y,
bounds.width, bounds.height);
}
/**
* Returns a prepared version of the image that would be used by the
* tile at the specified index. Because tilesets are often used simply
* to provide access to a collection of uniform images, this method is
* provided to bypass the creation of a {@link Tile} object when all
* that is desired is access to the underlying image.
*/
public Mirage getTileMirage (int tileIndex)
throws NoSuchTileException
{
checkTileIndex(tileIndex);
Rectangle bounds = computeTileBounds(tileIndex);
if (_improv == null) {
Log.warning("Aiya! Tile set missing image provider " +
"[path=" + _imagePath + "].");
}
return _improv.getTileImage(_imagePath, bounds, _zations);
}
/**
* Used to ensure that the specified tile index is valid.
*/
protected void checkTileIndex (int tileIndex)
throws NoSuchTileException
{
// bail if there's no such tile
int tcount = getTileCount();
if (tileIndex < 0 || tileIndex >= tcount) {
throw new NoSuchTileException(tileIndex);
}
// create our tile cache array if necessary
if (_tiles == null) {
_tiles = new Tile[tcount];
}
// fill in the cache if necessary
if (_tiles[tileIndex] == null) {
// get our tileset image
Image tsimg = getTileSetImage();
if (tsimg == null) {
// we already logged an error, so we can just freak out
throw new NoSuchTileException(tileIndex);
}
// create, initialize and cache the tile object
Tile tile = createTile(tileIndex, tsimg);
initTile(tile);
// _tiles[tileIndex] = tile;
return tile;
}
return _tiles[tileIndex];
}
/**
@@ -210,25 +222,20 @@ public abstract class TileSet
*
* @param tileIndex the index of the tile whose bounds are to be
* computed.
* @param tilesetImage the tileset image that contains the imagery for
* the tile in question.
*/
protected abstract Rectangle computeTileBounds (
int tileIndex, Image tilesetImage);
protected abstract Rectangle computeTileBounds (int tileIndex);
/**
* Creates a tile for the specified tile index.
*
* @param tileIndex the index of the tile to be created.
* @param tilesetImage the tileset image that contains the imagery for
* the tile to be created.
* @param image the tile image in the form of a {@link Mirage}.
*
* @return a configured tile.
*/
protected Tile createTile (int tileIndex, Image tilesetImage)
protected Tile createTile (int tileIndex, Mirage image)
{
return new Tile(tilesetImage,
computeTileBounds(tileIndex, tilesetImage));
return new Tile(image);
}
/**
@@ -243,42 +250,6 @@ public abstract class TileSet
// nothing for now
}
/**
* Returns the tileset image (which is loaded if it has not yet been
* loaded). Generally this is not called by external entities, rather
* {@link #getTile} is used and the image rendered by rendering the
* tile.
*
* @return the tileset image or null if an error occurred loading the
* image.
*/
public Image getTileSetImage ()
{
// return it straight away if it's already loaded
if (_tilesetImg != null) {
return _tilesetImg;
}
// load up the tileset image via the image provider
try {
_tilesetImg = _improv.loadImage(_imagePath);
// HACKOLA: if we're a vessel tileset, colorize ourselves
if (_name != null && (this instanceof ObjectTileSet) &&
_name.indexOf("Vessel") != -1) {
_tilesetImg = ImageUtil.recolorImage(
(BufferedImage)_tilesetImg, ZATIONS);
}
} catch (IOException ioe) {
Log.warning("Failed to retrieve tileset image " +
"[name=" + _name + ", path=" + _imagePath +
", error=" + ioe + "].");
}
return _tilesetImg;
}
/**
* Generates a string representation of the tileset information.
*/
@@ -307,18 +278,12 @@ public abstract class TileSet
/** The tileset name. */
protected String _name;
/** A sparse array containing the tiles that have been requested from
* this tileset. */
protected transient Tile[] _tiles;
/** 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;
/** The image containing all tile images for this set. This is private
* because it should be accessed via {@link #getTileSetImage} even by
* derived classes. */
private transient Image _tilesetImg;
/** Increase this value when object's serialized state is impacted by
* a class change (modification of fields, inheritance). */
private static final long serialVersionUID = 1;
@@ -332,4 +297,10 @@ public abstract class TileSet
new float[] { .1f, .3f, 0.6f },
new float[] { .71f, 0f, .07f }),
};
/** A weak cache of our tiles. */
protected static LRUHashMap _tiles;
/** The default tile cache size. */
protected static final int DEFAULT_TILE_CACHE_SIZE = 500;
}