diff --git a/src/java/com/threerings/cast/ActionFrames.java b/src/java/com/threerings/cast/ActionFrames.java index f9ca42c38..e0fe8bac2 100644 --- a/src/java/com/threerings/cast/ActionFrames.java +++ b/src/java/com/threerings/cast/ActionFrames.java @@ -1,5 +1,5 @@ // -// $Id: ActionFrames.java,v 1.1 2002/05/04 19:38:13 mdb Exp $ +// $Id: ActionFrames.java,v 1.2 2002/05/06 18:08:31 mdb Exp $ package com.threerings.cast; @@ -7,6 +7,7 @@ import java.awt.Graphics; import java.awt.Image; import com.threerings.media.sprite.MultiFrameImage; +import com.threerings.media.util.Colorization; import com.threerings.util.DirectionCodes; /** @@ -23,10 +24,8 @@ public interface ActionFrames extends MultiFrameImage public void setOrientation (int orient); /** - * Renders the specified frame at the specified offset applying the - * supplied colorizations in the process. Note, the colorizations - * should not be applied to the source image, only the rendered copy. + * Creates a clone of these action frames which will have the supplied + * colorizations applied to the frame images. */ - public void paintColoredFrame ( - Graphics g, int index, int x, int y, Colorization[] zations); + public ActionFrames cloneColorized (Colorization[] zations); } diff --git a/src/java/com/threerings/cast/CharacterDescriptor.java b/src/java/com/threerings/cast/CharacterDescriptor.java index a141ca174..0ba51b7cd 100644 --- a/src/java/com/threerings/cast/CharacterDescriptor.java +++ b/src/java/com/threerings/cast/CharacterDescriptor.java @@ -1,10 +1,11 @@ // -// $Id: CharacterDescriptor.java,v 1.6 2002/03/10 22:31:06 mdb Exp $ +// $Id: CharacterDescriptor.java,v 1.7 2002/05/06 18:08:31 mdb Exp $ package com.threerings.cast; import java.util.Arrays; import com.samskivert.util.StringUtil; +import com.threerings.media.util.Colorization; /** * The character descriptor object details the components that are diff --git a/src/java/com/threerings/cast/CharacterManager.java b/src/java/com/threerings/cast/CharacterManager.java index 02bc8edbb..16d0e2bc5 100644 --- a/src/java/com/threerings/cast/CharacterManager.java +++ b/src/java/com/threerings/cast/CharacterManager.java @@ -1,5 +1,5 @@ // -// $Id: CharacterManager.java,v 1.19 2002/05/04 19:38:13 mdb Exp $ +// $Id: CharacterManager.java,v 1.20 2002/05/06 18:08:31 mdb Exp $ package com.threerings.cast; @@ -9,12 +9,13 @@ import java.util.HashMap; import com.samskivert.util.StringUtil; import com.samskivert.util.Tuple; + import org.apache.commons.collections.LRUMap; +import com.threerings.media.util.Colorization; import com.threerings.util.DirectionCodes; import com.threerings.cast.Log; -import com.threerings.cast.util.TileUtil; /** * The character manager provides facilities for constructing sprites that @@ -212,19 +213,20 @@ public class CharacterManager // sort them into the proper rendering order Arrays.sort(components); - // create an array with the action frames for each component + // create colorized versions of all of the source action frames ActionFrames[] sources = new ActionFrames[ccount]; - zations = new Colorization[ccount][]; for (int ii = 0; ii < ccount; ii++) { - sources[ii] = components[ii].component.getFrames(action); + ActionFrames source = components[ii].component.getFrames(action); if (zations != null) { - zations[ii] = components[ii].zations; + sources[ii] = source.cloneColorized(components[ii].zations); + } else { + sources[ii] = source; } } // use those to create an entity that will lazily composite things // together as they are needed - return new CompositedActionFrames(action, sources, zations); + return new CompositedActionFrames(sources); } /** Used when compositing component frame images. */ diff --git a/src/java/com/threerings/cast/CompositedActionFrames.java b/src/java/com/threerings/cast/CompositedActionFrames.java index 2a61f92c4..f9bd4124a 100644 --- a/src/java/com/threerings/cast/CompositedActionFrames.java +++ b/src/java/com/threerings/cast/CompositedActionFrames.java @@ -1,5 +1,5 @@ // -// $Id: CompositedActionFrames.java,v 1.2 2002/05/04 19:38:13 mdb Exp $ +// $Id: CompositedActionFrames.java,v 1.3 2002/05/06 18:08:31 mdb Exp $ package com.threerings.cast; @@ -7,8 +7,8 @@ import java.awt.Graphics; import java.awt.Image; import com.threerings.util.DirectionCodes; +import com.threerings.media.util.Colorization; import com.threerings.media.util.ImageUtil; -import com.threerings.cast.util.TileUtil; /** * An implementation of the {@link MultiFrameImage} interface that is used @@ -22,13 +22,9 @@ public class CompositedActionFrames * source frames and colorization configuration. The actual component * frame images will not be composited until they are requested. */ - public CompositedActionFrames ( - String action, ActionFrames[] sources, Colorization[][] zations) + public CompositedActionFrames (ActionFrames[] sources) { - _action = action; _sources = sources; - _zations = zations; - // the sources must all have the same frame count, so we just use // the count from the first one _frameCount = _sources[0].getFrameCount(); @@ -72,8 +68,7 @@ public class CompositedActionFrames } // documentation inherited from interface - public void paintColoredFrame ( - Graphics g, int index, int x, int y, Colorization[] zations) + public ActionFrames cloneColorized (Colorization[] zations) { throw new RuntimeException("What you talkin' about Willis?"); } @@ -86,14 +81,55 @@ public class CompositedActionFrames _images[_orient] = new Image[_frameCount]; } if (_images[_orient][index] == null) { -// Log.info("Compositing [action=" + _action + -// ", orient=" + _orient + ", index=" + index + "]."); - _images[_orient][index] = - TileUtil.compositeFrames(_orient, index, _sources, _zations); +// Log.info("Compositing [orient=" + _orient + +// ", index=" + index + "]."); + _images[_orient][index] = compositeFrames(_orient, index); } return _images[_orient][index]; } + /** + * Renders and returns the indexth image from each of the + * supplied source multi-frame images to a newly created buffered + * image. This is used to render a single frame of a composited + * character action, and accordingly, the source image array should be + * already sorted into the proper rendering order. + */ + protected Image compositeFrames (int orient, int index) + { + Image dest = null; + Graphics g = null; +// long start = System.currentTimeMillis(); + + for (int ii = 0; ii < _sources.length; ii++) { + // create the image now that we know how big it should be + if (dest == null) { + dest = ImageUtil.createImage(_sources[ii].getWidth(index), + _sources[ii].getHeight(index)); + g = dest.getGraphics(); + } + + // make sure the action frames are configured with the right + // orientation before we render + _sources[ii].setOrientation(orient); + + // render the particular action from this component into the + // target image + _sources[ii].paintFrame(g, index, 0, 0); + } + + // clean up after ourselves + if (g != null) { + g.dispose(); + } + +// long now = System.currentTimeMillis(); +// Log.info("Composited " + sources.length + " frames in " + +// (now-start) + " millis."); + + return dest; + } + /** * When fetching width and height, we can simply use the first * component's image set since they must all be the same. @@ -105,8 +141,6 @@ public class CompositedActionFrames return source; } - protected String _action; - /** The orientation we're currently using. */ protected int _orient; @@ -116,9 +150,6 @@ public class CompositedActionFrames /** Our source action frames. */ protected ActionFrames[] _sources; - /** The colorizations for our source components. */ - protected Colorization[][] _zations; - /** The frame images. */ protected Image[][] _images; } diff --git a/src/java/com/threerings/cast/bundle/BundledComponentRepository.java b/src/java/com/threerings/cast/bundle/BundledComponentRepository.java index 4957a8496..ebc52e77f 100644 --- a/src/java/com/threerings/cast/bundle/BundledComponentRepository.java +++ b/src/java/com/threerings/cast/bundle/BundledComponentRepository.java @@ -1,5 +1,5 @@ // -// $Id: BundledComponentRepository.java,v 1.10 2002/05/04 19:38:14 mdb Exp $ +// $Id: BundledComponentRepository.java,v 1.11 2002/05/06 18:08:31 mdb Exp $ package com.threerings.cast.bundle; @@ -27,17 +27,18 @@ import com.threerings.resource.ResourceBundle; import com.threerings.resource.ResourceManager; import com.threerings.media.ImageManager; +import com.threerings.media.util.Colorization; import com.threerings.media.util.ImageUtil; import com.threerings.media.tile.ImageProvider; -import com.threerings.media.tile.TileSet; import com.threerings.media.tile.NoSuchTileException; +import com.threerings.media.tile.Tile; +import com.threerings.media.tile.TileSet; import com.threerings.util.DirectionCodes; import com.threerings.cast.ActionFrames; import com.threerings.cast.CharacterComponent; -import com.threerings.cast.Colorization; import com.threerings.cast.ComponentClass; import com.threerings.cast.ComponentRepository; import com.threerings.cast.FrameProvider; @@ -311,31 +312,31 @@ public class BundledComponentRepository // documentation inherited from interface public int getWidth (int index) { - Image img = getImage(index); - return (img == null) ? 0 : img.getWidth(null); + Tile tile = getTile(index); + return (tile == null) ? 0 : tile.getWidth(); } // documentation inherited from interface public int getHeight (int index) { - Image img = getImage(index); - return (img == null) ? 0 : img.getHeight(null); + Tile tile = getTile(index); + return (tile == null) ? 0 : tile.getHeight(); } // documentation inherited from interface public void paintFrame (Graphics g, int index, int x, int y) { - Image img = getImage(index); - if (img != null) { - g.drawImage(img, x, y, null); + Tile tile = getTile(index); + if (tile != null) { + tile.paint(g, x, y); } } // documentation inherited from interface public boolean hitTest (int index, int x, int y) { - Image img = getImage(index); - return (img != null) ? ImageUtil.hitTest(img, x, y) : false; + Tile tile = getTile(index); + return (tile != null) ? tile.hitTest(x, y) : false; } // documentation inherited from interface @@ -345,38 +346,22 @@ public class BundledComponentRepository } // documentation inherited from interface - public void paintColoredFrame ( - Graphics g, int index, int x, int y, Colorization[] zations) + public ActionFrames cloneColorized (Colorization[] zations) { - BufferedImage img = (BufferedImage)getImage(index); - if (img == null) { - return; - } - - // create a recolored image with which to render - if (zations != null) { - int zcount = zations.length; - Colorization cz; - for (int zz = 0; zz < zcount; zz++) { - if ((cz = zations[zz]) == null) { - continue; - } - img = ImageUtil.recolorImage( - img, cz.rootColor, cz.range, cz.offsets); - } - } - - g.drawImage(img, x, y, null); + TileSet zset = _set.cloneColorized(zations); + TileSetFrameImage cframes = new TileSetFrameImage(zset); + cframes.setOrientation(_orient); + return cframes; } /** - * Fetches the requested tile image. + * Fetches the requested tile. */ - protected Image getImage (int index) + protected Tile getTile (int index) { int tileIndex = _orient * getFrameCount() + index; try { - return _set.getTile(tileIndex).getImage(); + return _set.getTile(tileIndex); } catch (NoSuchTileException nste) { Log.warning("Can't extract action frame [set=" + _set + ", orient=" + _orient + ", index=" + index + "]."); diff --git a/src/java/com/threerings/cast/util/TileUtil.java b/src/java/com/threerings/cast/util/TileUtil.java deleted file mode 100644 index e4816a197..000000000 --- a/src/java/com/threerings/cast/util/TileUtil.java +++ /dev/null @@ -1,65 +0,0 @@ -// -// $Id: TileUtil.java,v 1.14 2002/05/04 19:38:14 mdb Exp $ - -package com.threerings.cast.util; - -import java.awt.Graphics; -import java.awt.Image; -import java.awt.image.BufferedImage; - -import com.threerings.media.util.ImageUtil; - -import com.threerings.cast.Log; -import com.threerings.cast.ActionFrames; -import com.threerings.cast.Colorization; - -/** - * Miscellaneous tile-related utility functions. - */ -public class TileUtil -{ - /** - * Renders and returns the indexth image from each of the - * supplied source multi-frame images to a newly created buffered - * image. This is used to render a single frame of a composited - * character action, and accordingly, the source image array should be - * already sorted into the proper rendering order. - */ - public static Image compositeFrames ( - int orient, int index, ActionFrames[] sources, - Colorization[][] zations) - { - Image dest = null; - Graphics g = null; -// long start = System.currentTimeMillis(); - - for (int ii = 0; ii < sources.length; ii++) { - // create the image now that we know how big it should be - if (dest == null) { - dest = ImageUtil.createImage(sources[ii].getWidth(index), - sources[ii].getHeight(index)); - g = dest.getGraphics(); - } - - // make sure the action frames are configured with the right - // orientation before we render - sources[ii].setOrientation(orient); - - // render the particular action from this component into the - // target image - Colorization[] cz = (zations != null) ? zations[ii] : null; - sources[ii].paintColoredFrame(g, index, 0, 0, cz); - } - - // clean up after ourselves - if (g != null) { - g.dispose(); - } - -// long now = System.currentTimeMillis(); -// Log.info("Composited " + sources.length + " frames in " + -// (now-start) + " millis."); - - return dest; - } -} diff --git a/src/java/com/threerings/media/IconManager.java b/src/java/com/threerings/media/IconManager.java index dd0ac1050..b6c4e5d61 100644 --- a/src/java/com/threerings/media/IconManager.java +++ b/src/java/com/threerings/media/IconManager.java @@ -1,5 +1,5 @@ // -// $Id: IconManager.java,v 1.1 2002/02/03 22:43:54 mdb Exp $ +// $Id: IconManager.java,v 1.2 2002/05/06 18:08:32 mdb Exp $ package com.threerings.media; @@ -10,15 +10,14 @@ import java.util.Properties; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; -import java.awt.Image; import javax.swing.Icon; -import javax.swing.ImageIcon; import com.samskivert.util.ConfigUtil; import com.samskivert.util.StringUtil; import com.threerings.media.tile.NoSuchTileException; +import com.threerings.media.tile.TileIcon; import com.threerings.media.tile.TileManager; import com.threerings.media.tile.TileSet; @@ -42,7 +41,7 @@ import com.threerings.media.tile.TileSet; * A user could then request an arrows icon like so: * *
- * ImageIcon icon = iconmgr.getIcon("arrows", 2);
+ * Icon icon = iconmgr.getIcon("arrows", 2);
  * 
*/ public class IconManager @@ -113,7 +112,7 @@ public class IconManager } // fetch the appropriate image and create an image icon - return new ImageIcon(set.getTileImage(index)); + return new TileIcon(set.getTile(index)); } catch (NoSuchTileException nste) { Log.warning("Unable to load icon [iconSet=" + iconSet + diff --git a/src/java/com/threerings/media/image/Colorization.java b/src/java/com/threerings/media/image/Colorization.java index eadcb15b8..406a3efe9 100644 --- a/src/java/com/threerings/media/image/Colorization.java +++ b/src/java/com/threerings/media/image/Colorization.java @@ -1,14 +1,14 @@ // -// $Id: Colorization.java,v 1.3 2002/03/10 22:30:46 mdb Exp $ +// $Id: Colorization.java,v 1.4 2002/05/06 18:08:32 mdb Exp $ -package com.threerings.cast; +package com.threerings.media.util; import java.awt.Color; + import com.samskivert.util.StringUtil; -import com.threerings.media.util.ImageUtil; /** - * Used to support colorization of character component images. + * Used to support recoloring images. */ public class Colorization { diff --git a/src/java/com/threerings/media/image/ImageUtil.java b/src/java/com/threerings/media/image/ImageUtil.java index 62d059427..04e936e73 100644 --- a/src/java/com/threerings/media/image/ImageUtil.java +++ b/src/java/com/threerings/media/image/ImageUtil.java @@ -1,5 +1,5 @@ // -// $Id: ImageUtil.java,v 1.12 2002/05/04 21:36:32 ray Exp $ +// $Id: ImageUtil.java,v 1.13 2002/05/06 18:08:32 mdb Exp $ package com.threerings.media.util; @@ -169,6 +169,18 @@ public class ImageUtil return new BufferedImage(nicm, image.getRaster(), false, null); } + /** + * Recolors the supplied image as in {@link + * #recolorImage(BufferedImage,Color,float[],float[])} obtaining the + * recoloring parameters from the supplied {@link Colorization} + * instance. + */ + public static BufferedImage recolorImage ( + BufferedImage image, Colorization cz) + { + return recolorImage(image, cz.rootColor, cz.range, cz.offsets); + } + /** * Adjusts the supplied color by the specified offests, taking the * appropriate measures for hue (wrapping it around) and saturation @@ -245,11 +257,11 @@ public class ImageUtil } /** - * Create an image using the alpha channel from the first Image - * and the RGB values from the second. + * Create an image using the alpha channel from the first and the RGB + * values from the second. */ - public static BufferedImage composeMaskedImage (BufferedImage mask, - BufferedImage base) + public static BufferedImage composeMaskedImage ( + BufferedImage mask, BufferedImage base) { int wid = base.getWidth(null); int hei = base.getHeight(null); @@ -257,8 +269,8 @@ public class ImageUtil Raster maskdata = mask.getData(); Raster basedata = base.getData(); - WritableRaster target = basedata.createCompatibleWritableRaster( - wid, hei); + WritableRaster target = + basedata.createCompatibleWritableRaster(wid, hei); // copy the alpha from the mask image int[] adata = maskdata.getSamples(0, 0, wid, hei, 3, (int[]) null); diff --git a/src/java/com/threerings/media/tile/ObjectTile.java b/src/java/com/threerings/media/tile/ObjectTile.java index 01b326dfa..626fb2f1d 100644 --- a/src/java/com/threerings/media/tile/ObjectTile.java +++ b/src/java/com/threerings/media/tile/ObjectTile.java @@ -1,9 +1,10 @@ // -// $Id: ObjectTile.java,v 1.6 2002/01/31 02:08:52 mdb Exp $ +// $Id: ObjectTile.java,v 1.7 2002/05/06 18:08:32 mdb Exp $ package com.threerings.media.tile; import java.awt.Image; +import java.awt.Rectangle; import java.awt.image.BufferedImage; import com.threerings.media.Log; @@ -19,18 +20,19 @@ public class ObjectTile extends Tile * Constructs a new object tile with the specified image. The base * width and height should be set before using this tile. */ - public ObjectTile (Image image) + public ObjectTile (Image image, Rectangle bounds) { - super(image); + super(image, bounds); } /** * Constructs a new object tile with the specified base width and * height. */ - public ObjectTile (Image image, int baseWidth, int baseHeight) + public ObjectTile (Image image, Rectangle bounds, + int baseWidth, int baseHeight) { - super(image); + super(image, bounds); _baseWidth = baseWidth; _baseHeight = baseHeight; } diff --git a/src/java/com/threerings/media/tile/ObjectTileSet.java b/src/java/com/threerings/media/tile/ObjectTileSet.java index a756e6d17..12de8884e 100644 --- a/src/java/com/threerings/media/tile/ObjectTileSet.java +++ b/src/java/com/threerings/media/tile/ObjectTileSet.java @@ -1,9 +1,10 @@ // -// $Id: ObjectTileSet.java,v 1.6 2001/12/18 08:37:54 mdb Exp $ +// $Id: ObjectTileSet.java,v 1.7 2002/05/06 18:08:32 mdb Exp $ package com.threerings.media.tile; import java.awt.Image; +import java.awt.Rectangle; import java.util.Arrays; import com.samskivert.util.StringUtil; @@ -68,7 +69,7 @@ public class ObjectTileSet extends SwissArmyTileSet * Creates instances of {@link ObjectTile}, which can span more than a * single tile's space in a display. */ - protected Tile createTile (int tileIndex, Image image) + protected Tile createTile (int tileIndex, Image tilesetImage) { // default object dimensions to (1, 1) int wid = 1, hei = 1; @@ -79,7 +80,8 @@ public class ObjectTileSet extends SwissArmyTileSet hei = _oheights[tileIndex]; } - ObjectTile tile = new ObjectTile(image, wid, hei); + Rectangle bounds = computeTileBounds(tileIndex, tilesetImage); + ObjectTile tile = new ObjectTile(tilesetImage, bounds, wid, hei); if (_xorigins != null) { tile.setOrigin(_xorigins[tileIndex], _yorigins[tileIndex]); diff --git a/src/java/com/threerings/media/tile/SwissArmyTileSet.java b/src/java/com/threerings/media/tile/SwissArmyTileSet.java index 8478ea2f3..5e93bda73 100644 --- a/src/java/com/threerings/media/tile/SwissArmyTileSet.java +++ b/src/java/com/threerings/media/tile/SwissArmyTileSet.java @@ -1,11 +1,12 @@ // -// $Id: SwissArmyTileSet.java,v 1.7 2002/02/24 02:20:44 mdb Exp $ +// $Id: SwissArmyTileSet.java,v 1.8 2002/05/06 18:08:32 mdb Exp $ package com.threerings.media.tile; +import java.awt.Dimension; import java.awt.Image; import java.awt.Point; -import java.awt.Dimension; +import java.awt.Rectangle; import java.io.IOException; import java.io.ObjectInputStream; @@ -13,7 +14,6 @@ import java.io.ObjectInputStream; import com.samskivert.util.StringUtil; import com.threerings.media.Log; -import com.threerings.media.util.ImageUtil; /** * The swiss army tileset supports a diverse variety of tiles in the @@ -128,15 +128,8 @@ public class SwissArmyTileSet extends TileSet } // documentation inherited - protected Image extractTileImage (int tileIndex) + protected Rectangle computeTileBounds (int tileIndex, Image tilesetImage) { - Image tsimg = getTilesetImage(); - if (tsimg == null) { - // FIXME: we should really be returning a blank image of the - // appropriate width and height here rather than null - return null; - } - // find the row number containing the sought-after tile int ridx, tcount, ty, tx; ridx = tcount = 0; @@ -156,13 +149,12 @@ public class SwissArmyTileSet extends TileSet // final image x-position is based on tile width and gap distance tx += (xidx * (_widths[ridx] + _gapSize.width)); -// Log.info("Retrieving tile image [tileIndex=" + tileIndex + +// Log.info("Computed tile bounds [tileIndex=" + tileIndex + // ", ridx=" + ridx + ", xidx=" + xidx + // ", tx=" + tx + ", ty=" + ty + "]."); // crop the tile-sized image chunk from the full image - return ImageUtil.getSubimage( - tsimg, tx, ty, _widths[ridx], _heights[ridx]); + return new Rectangle(tx, ty, _widths[ridx], _heights[ridx]); } private void readObject (ObjectInputStream in) diff --git a/src/java/com/threerings/media/tile/Tile.java b/src/java/com/threerings/media/tile/Tile.java index 8135a2a15..6a854c81b 100644 --- a/src/java/com/threerings/media/tile/Tile.java +++ b/src/java/com/threerings/media/tile/Tile.java @@ -1,24 +1,35 @@ // -// $Id: Tile.java,v 1.18 2001/11/18 04:09:21 mdb Exp $ +// $Id: Tile.java,v 1.19 2002/05/06 18:08:32 mdb Exp $ package com.threerings.media.tile; +import java.awt.Graphics; import java.awt.Image; -import java.awt.Graphics2D; -import java.awt.Shape; import java.awt.Rectangle; +import java.awt.Shape; + +import java.awt.image.BufferedImage; + +import com.samskivert.util.StringUtil; +import com.threerings.media.util.ImageUtil; /** * A tile represents a single square in a single layer in a scene. */ -public class Tile +public class Tile implements Cloneable { /** - * Constructs a tile with the specified image. + * Constructs a tile with the specified tileset image. + * + * @param image the tileset image from which our tile image is + * extracted. + * @param bounds the bounds of the tile image within the greater + * tileset image. */ - public Tile (Image image) + public Tile (Image image, Rectangle bounds) { _image = image; + _bounds = bounds; } /** @@ -26,7 +37,7 @@ public class Tile */ public int getWidth () { - return _image.getWidth(null); + return _bounds.width; } /** @@ -34,25 +45,70 @@ public class Tile */ public int getHeight () { - return _image.getHeight(null); + return _bounds.height; } /** - * Returns this tile's image. + * Render the tile image at the specified position in the given + * graphics context. */ - public Image getImage () + public void paint (Graphics gfx, int x, int y) { - return _image; + Shape oclip = gfx.getClip(); + gfx.clipRect(x, y, getWidth(), getHeight()); + gfx.drawImage(_image, x - _bounds.x, y - _bounds.y, null); + gfx.setClip(oclip); } /** * Render the tile image at the top-left corner of the given shape in * the given graphics context. */ - public void paint (Graphics2D gfx, Shape dest) + public void paint (Graphics gfx, Shape dest) { Rectangle bounds = dest.getBounds(); - gfx.drawImage(_image, bounds.x, bounds.y, null); + paint(gfx, bounds.x, bounds.y); + } + + /** + * Returns true if the specified coordinates within this tile contains + * a non-transparent pixel. + */ + public boolean hitTest (int x, int y) + { + return ImageUtil.hitTest(_image, _bounds.x + x, _bounds.y + y); + } + + /** + * Returns the image used to render this tile, if access to that image + * can be obtained. The tile must have been created with a {@link + * BufferedImage} and derived classes may refuse to implement this + * function if they do special stuff that hampers their ability to + * return a single image describing the tile. + */ + public Image getImage () + { + if (_image instanceof BufferedImage) { + return ImageUtil.getSubimage(_image, _bounds.x, _bounds.y, + _bounds.width, _bounds.height); + + } else { + String errmsg = "Can't obtain tile image [tile=" + this + "]."; + throw new RuntimeException(errmsg); + } + } + + /** + * Creates a shallow copy of this tile object. + */ + public Object clone () + { + try { + return (Tile)super.clone(); + } catch (CloneNotSupportedException cnse) { + String errmsg = "All is wrong with the universe: " + cnse; + throw new RuntimeException(errmsg); + } } /** @@ -60,8 +116,7 @@ public class Tile */ public String toString () { - StringBuffer buf = new StringBuffer(); - buf.append("["); + StringBuffer buf = new StringBuffer("["); toString(buf); return buf.append("]").toString(); } @@ -71,11 +126,15 @@ public class Tile * to call super.toString()) to append the derived class * specific tile information to the string buffer. */ - public void toString (StringBuffer buf) + protected void toString (StringBuffer buf) { buf.append("image=").append(_image); + buf.append(", bounds=").append(StringUtil.toString(_bounds)); } - /** Our tile image. */ + /** Our tileset image. */ protected Image _image; + + /** The bounds of the tile image within the tileset image. */ + protected Rectangle _bounds; } diff --git a/src/java/com/threerings/media/tile/TileIcon.java b/src/java/com/threerings/media/tile/TileIcon.java new file mode 100644 index 000000000..1f018bdc6 --- /dev/null +++ b/src/java/com/threerings/media/tile/TileIcon.java @@ -0,0 +1,45 @@ +// +// $Id: TileIcon.java,v 1.1 2002/05/06 18:08:32 mdb Exp $ + +package com.threerings.media.tile; + +import java.awt.Component; +import java.awt.Graphics; + +import javax.swing.Icon; + +/** + * Implements the icon interface, using a {@link Tile} to render the icon + * image. + */ +public class TileIcon implements Icon +{ + /** + * Creates a tile icon that will use the supplied tile to render itself. + */ + public TileIcon (Tile tile) + { + _tile = tile; + } + + // documentation inherited from interface + public void paintIcon (Component c, Graphics g, int x, int y) + { + _tile.paint(g, x, y); + } + + // documentation inherited from interface + public int getIconWidth () + { + return _tile.getWidth(); + } + + // documentation inherited from interface + public int getIconHeight () + { + return _tile.getHeight(); + } + + /** The tile used to render this icon. */ + protected Tile _tile; +} diff --git a/src/java/com/threerings/media/tile/TileManager.java b/src/java/com/threerings/media/tile/TileManager.java index 01bc96e7d..8d9f6123e 100644 --- a/src/java/com/threerings/media/tile/TileManager.java +++ b/src/java/com/threerings/media/tile/TileManager.java @@ -1,5 +1,5 @@ // -// $Id: TileManager.java,v 1.23 2001/12/07 01:33:29 mdb Exp $ +// $Id: TileManager.java,v 1.24 2002/05/06 18:08:32 mdb Exp $ package com.threerings.media.tile; @@ -56,7 +56,7 @@ public class TileManager implements ImageProvider * Loads up a tileset from the specified image with the specified * metadata parameters. */ - public TileSet loadTileSet ( + public UniformTileSet loadTileSet ( String imgPath, int count, int width, int height) { UniformTileSet uts = new UniformTileSet(); diff --git a/src/java/com/threerings/media/tile/TileSet.java b/src/java/com/threerings/media/tile/TileSet.java index 144f797ae..5154f19a6 100644 --- a/src/java/com/threerings/media/tile/TileSet.java +++ b/src/java/com/threerings/media/tile/TileSet.java @@ -1,15 +1,20 @@ // -// $Id: TileSet.java,v 1.25 2002/02/24 02:20:44 mdb Exp $ +// $Id: TileSet.java,v 1.26 2002/05/06 18:08:32 mdb Exp $ package com.threerings.media.tile; 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.StringUtil; + import com.threerings.media.Log; +import com.threerings.media.util.Colorization; import com.threerings.media.util.ImageUtil; /** @@ -82,6 +87,55 @@ public abstract class TileSet */ public abstract int getTileCount (); + /** + * Creates a copy of this tileset with the supplied colorizations + * applied to its source image. + */ + public TileSet cloneColorized (Colorization[] zations) + { + TileSet tset = null; + try { + tset = (TileSet)clone(); + } catch (CloneNotSupportedException cnse) { + Log.warning("Unable to clone tileset prior to colorization " + + "[tset=" + this + + ", zations=" + StringUtil.toString(zations) + + ", 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 + BufferedImage btimg = (BufferedImage)timg; + int zcount = zations.length; + Colorization cz; + for (int zz = 0; zz < zcount; zz++) { + if ((cz = zations[zz]) == null) { + continue; + } + btimg = ImageUtil.recolorImage(btimg, cz); + } + + // stuff the recolored image back into the new tileset + tset._tilesetImg = btimg; + + return tset; + } + /** * Returns a new tileset that is a clone of this tileset with the * image path updated to reference the given path. Useful for @@ -119,93 +173,47 @@ public abstract class TileSet throw new NoSuchTileException(tileIndex); } + // 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 and initialize the tile object - Tile tile = createTile(tileIndex, checkedGet(tileIndex)); + Tile tile = createTile(tileIndex, tsimg); initTile(tile); return tile; } /** - * Returns the tile image at the specified index. In some cases, a - * tile object is not desired or required, and so this method can be - * used to fetch the image directly. A null tile image will never be - * returned, but an error image may be returned if a problem occurs - * loading the underlying tileset image. + * Computes and returns 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 image in the tileset. - * - * @return the tile image. - * - * @exception NoSuchTileException thrown if the specified tile index - * is out of range for this 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. */ - public Image getTileImage (int tileIndex) - throws NoSuchTileException - { - // bail if there's no such tile - if (tileIndex < 0 || tileIndex >= getTileCount()) { - throw new NoSuchTileException(tileIndex); - } - - // retrieve the tile image - return checkedGet(tileIndex); - } - - // used to ensure TileSet derivations adhere to the extractTileImage() - // policy of not returning null - private Image checkedGet (int tileIndex) - { - Image image = extractTileImage(tileIndex); - if (image == null) { - String errmsg = "TileSet implementation violated return " + - "policy for TileSet.extractTileImage()."; - throw new RuntimeException(errmsg); - } - return image; - } + protected abstract Rectangle computeTileBounds ( + int tileIndex, Image tilesetImage); /** - * Extracts the image corresponding to the specified tile from the - * tileset image. + * Creates a tile for the specified tile index. * - * @param tileIndex the index of the tile to be retrieved. + * @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. * - * @return the tile image. This should not return null in cases of - * failure, but should instead call {@link #createErrorImage} to - * return a valid image. + * @return a configured tile. */ - protected abstract Image extractTileImage (int tileIndex); - - /** - * Creates a blank image to be used in failure situations. If {@link - * #extractTileImage} is unable to return the actual tile image - * (because the tileset image could not be loaded or for some other - * reason), it should not return null. Instead it should return an - * error image created with this method. - * - * @param width the width of the error image in pixels. - * @param height the height of the error image in pixels. - */ - protected Image createErrorImage (int width, int height) + protected Tile createTile (int tileIndex, Image tilesetImage) { - // return a blank image for now - return ImageUtil.createImage(width, height, Transparency.OPAQUE); - } - - /** - * Construct and return a new tile object for further population with - * tile-specific information. Derived classes can override this method - * to create their own sub-class of {@link Tile}. - * - * @param tileIndex the index of the tile being created. - * @param image the tile image. - * - * @return the new tile object. - */ - protected Tile createTile (int tileIndex, Image image) - { - // construct a basic tile - return new Tile(image); + return new Tile(tilesetImage, + computeTileBounds(tileIndex, tilesetImage)); } /** @@ -269,15 +277,15 @@ public abstract class TileSet buf.append(", tileCount=").append(getTileCount()); } - /** The entity from which we obtain our tile image. */ - protected transient ImageProvider _improv; - /** The path to the file containing the tile images. */ protected String _imagePath; /** The tileset name. */ protected String _name; + /** 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. */ diff --git a/src/java/com/threerings/media/tile/TileUtil.java b/src/java/com/threerings/media/tile/TileUtil.java index 65ddd17cf..e00111f3d 100644 --- a/src/java/com/threerings/media/tile/TileUtil.java +++ b/src/java/com/threerings/media/tile/TileUtil.java @@ -1,10 +1,8 @@ // -// $Id: TileUtil.java,v 1.2 2001/11/18 04:09:21 mdb Exp $ +// $Id: TileUtil.java,v 1.3 2002/05/06 18:08:32 mdb Exp $ package com.threerings.media.tile; -import java.awt.Image; - import com.threerings.media.Log; /** @@ -23,15 +21,16 @@ public class TileUtil * tile. * @param tileIndex the index of the tile to be fetched. */ - public static Image getTileImage ( + public static Tile getTile ( TileManager tilemgr, int tileSetId, int tileIndex) { try { TileSet set = tilemgr.getTileSet(tileSetId); - return set.getTileImage(tileIndex); + return set.getTile(tileIndex); } catch (TileException te) { - Log.warning("Error retrieving tile image [error=" + te + "]."); + Log.warning("Error retrieving tile [tsid=" + tileSetId + + ", tidx=" + tileIndex + ", error=" + te + "]."); return null; } } diff --git a/src/java/com/threerings/media/tile/TrimmedTile.java b/src/java/com/threerings/media/tile/TrimmedTile.java new file mode 100644 index 000000000..b2378fd9e --- /dev/null +++ b/src/java/com/threerings/media/tile/TrimmedTile.java @@ -0,0 +1,74 @@ +// +// $Id: TrimmedTile.java,v 1.1 2002/05/06 18:08:32 mdb Exp $ + +package com.threerings.media.tile; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; + +import com.samskivert.util.StringUtil; + +import com.threerings.media.util.ImageUtil; + +/** + * Behaves just like a regular tile, but contains a "trimmed" image which + * is one where the source image has been trimmed to the smallest + * rectangle that contains all the non-transparent pixels of the original + * image. + */ +public class TrimmedTile extends Tile +{ + /** + * Creates a trimmed tile using the supplied tileset image with the + * specified bounds and coordinates. + * + * @param tilesetSource the tileset image that contains our trimmed + * tile image. + * @param bounds contains the width and height of the + * untrimmed tile, but the x and y offset of the + * trimmed tile image in the supplied tileset source image. + * @param tbounds the bounds of the trimmed image in the coordinate + * system defined by the untrimmed image. + */ + public TrimmedTile (Image image, Rectangle bounds, Rectangle tbounds) + { + super(image, bounds); + _tbounds = tbounds; + } + + // documentation inherited + public void paint (Graphics2D gfx, int x, int y) + { + int vx = x + _tbounds.x, vy = y + _tbounds.y; + Shape oclip = gfx.getClip(); + gfx.clipRect(vx, vy, _tbounds.width, _tbounds.height); + gfx.drawImage(_image, vx - _bounds.x, vy - _bounds.y, null); + gfx.setClip(oclip); + } + + // documentation inherited + public Image getImage () + { + String errmsg = "Can't convert trimmed tile to image " + + "[tile=" + this + "]."; + throw new RuntimeException(errmsg); + } + + // documentation inherited + public boolean hitTest (int x, int y) + { + return ImageUtil.hitTest(_image, _bounds.x + x, _bounds.y + y); + } + + // documentation inherited + protected void toString (StringBuffer buf) + { + buf.append(", tbounds=").append(StringUtil.toString(_tbounds)); + } + + /** The dimensions of the trimmed image in the coordinate space + * defined by the untrimmed image. */ + protected Rectangle _tbounds; +} diff --git a/src/java/com/threerings/media/tile/TrimmedTileSet.java b/src/java/com/threerings/media/tile/TrimmedTileSet.java new file mode 100644 index 000000000..c097e0c86 --- /dev/null +++ b/src/java/com/threerings/media/tile/TrimmedTileSet.java @@ -0,0 +1,54 @@ +// +// $Id: TrimmedTileSet.java,v 1.1 2002/05/06 18:08:32 mdb Exp $ + +package com.threerings.media.tile; + +import java.awt.Image; +import java.awt.Rectangle; + +/** + * Contains the necessary information to create a set of trimmed tiles + * from a base image and the associated trim metrics. + */ +public class TrimmedTileSet extends TileSet +{ + // documentation inherited + public int getTileCount () + { + return _obounds.length; + } + + /** + * Provides this tileset with access to the trimmed tile metrics. This + * generally only is called when generating a trimmed tileset from a + * regular tileset. + */ + public void setTileMetrics (Rectangle[] obounds, Rectangle[] tbounds) + { + _obounds = obounds; + _tbounds = tbounds; + } + + // documentation inherited + protected Rectangle computeTileBounds (int tileIndex, Image tilesetImage) + { + // N/A + return null; + } + + // documentation inherited + protected Tile createTile (int tileIndex, Image tilesetImage) + { + return new TrimmedTile( + tilesetImage, _obounds[tileIndex], _tbounds[tileIndex]); + } + + /** The width and height of the untrimmed tile, and the x and y offset + * of the trimmed image within our tileset image. */ + protected Rectangle[] _obounds; + + /** The width and height of the trimmed image and the x and y offset + * within the untrimmed image at which the trimmed image should be + * rendered. */ + protected Rectangle[] _tbounds; +} diff --git a/src/java/com/threerings/media/tile/UniformTileSet.java b/src/java/com/threerings/media/tile/UniformTileSet.java index 441e3f8c4..46fce0f55 100644 --- a/src/java/com/threerings/media/tile/UniformTileSet.java +++ b/src/java/com/threerings/media/tile/UniformTileSet.java @@ -1,9 +1,10 @@ // -// $Id: UniformTileSet.java,v 1.7 2002/02/24 02:20:44 mdb Exp $ +// $Id: UniformTileSet.java,v 1.8 2002/05/06 18:08:32 mdb Exp $ package com.threerings.media.tile; import java.awt.Image; +import java.awt.Rectangle; import com.threerings.media.Log; import com.threerings.media.util.ImageUtil; @@ -64,24 +65,33 @@ public class UniformTileSet extends TileSet return _height; } - // documentation inherited - protected Image extractTileImage (int tileId) + /** + * Returns the image that would be used by the tile at the specified + * index. Because the uniform tileset is 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 Image getTileImage (int tileIndex) { Image tsimg = getTilesetImage(); if (tsimg == null) { - // FIXME: we should really be returning a blank image of the - // appropriate width and height here rather than null return null; } + Rectangle tb = computeTileBounds(tileIndex, tsimg); + return ImageUtil.getSubimage(tsimg, tb.x, tb.y, tb.width, tb.height); + } + // documentation inherited + protected Rectangle computeTileBounds (int tileIndex, Image tilesetImage) + { // figure out from whence to crop the tile - int tilesPerRow = tsimg.getWidth(null) / _width; - int row = tileId / tilesPerRow; - int col = tileId % tilesPerRow; + int tilesPerRow = tilesetImage.getWidth(null) / _width; + int row = tileIndex / tilesPerRow; + int col = tileIndex % tilesPerRow; // crop the tile-sized image chunk from the full image - return ImageUtil.getSubimage( - tsimg, _width*col, _height*row, _width, _height); + return new Rectangle(_width*col, _height*row, _width, _height); } // documentation inherited diff --git a/src/java/com/threerings/miso/tile/AutoFringer.java b/src/java/com/threerings/miso/tile/AutoFringer.java index 4d443e9fc..2227991e9 100644 --- a/src/java/com/threerings/miso/tile/AutoFringer.java +++ b/src/java/com/threerings/miso/tile/AutoFringer.java @@ -1,5 +1,5 @@ // -// $Id: AutoFringer.java,v 1.10 2002/05/03 04:12:48 mdb Exp $ +// $Id: AutoFringer.java,v 1.11 2002/05/06 18:08:32 mdb Exp $ package com.threerings.miso.tile; @@ -147,8 +147,8 @@ public class AutoFringer /** * Compose a FringeTile out of the various fringe images needed. */ - protected Tile composeFringeTile (FringerRec[] fringers, HashMap masks, - Random rando) + protected Tile composeFringeTile ( + FringerRec[] fringers, HashMap masks, Random rando) { // sort the array so that higher priority fringers get drawn first QuickSort.sort(fringers); @@ -191,7 +191,6 @@ public class AutoFringer { FringeConfiguration.FringeTileSetRecord tsr = _fringeconf.getRandomFringe(baseset, rando); - int fringeset = tsr.fringe_tsid; if (!tsr.mask) { @@ -208,7 +207,6 @@ public class AutoFringer img = ImageUtil.composeMaskedImage( (BufferedImage) _tmgr.getTile(fringeset, index).getImage(), (BufferedImage) _tmgr.getTile(baseset, 0).getImage()); - masks.put(maskkey, img); } diff --git a/src/java/com/threerings/miso/tile/BaseTile.java b/src/java/com/threerings/miso/tile/BaseTile.java index e90e2e3f4..a7990e8c7 100644 --- a/src/java/com/threerings/miso/tile/BaseTile.java +++ b/src/java/com/threerings/miso/tile/BaseTile.java @@ -1,9 +1,11 @@ // -// $Id: BaseTile.java,v 1.5 2002/02/07 02:58:46 shaper Exp $ +// $Id: BaseTile.java,v 1.6 2002/05/06 18:08:32 mdb Exp $ package com.threerings.miso.tile; import java.awt.Image; +import java.awt.Rectangle; + import com.threerings.media.tile.Tile; /** @@ -17,17 +19,17 @@ public class BaseTile extends Tile * Constructs a new base tile with the specified image. Passability * will be assumed to be true. */ - public BaseTile (Image image) + public BaseTile (Image image, Rectangle bounds) { - super(image); + this(image, bounds, true); } /** * Constructs a new base tile with the specified passability. */ - public BaseTile (Image image, boolean passable) + public BaseTile (Image image, Rectangle bounds, boolean passable) { - super(image); + super(image, bounds); _passable = passable; } diff --git a/src/java/com/threerings/miso/tile/BaseTileSet.java b/src/java/com/threerings/miso/tile/BaseTileSet.java index f26acd303..60adc28da 100644 --- a/src/java/com/threerings/miso/tile/BaseTileSet.java +++ b/src/java/com/threerings/miso/tile/BaseTileSet.java @@ -1,20 +1,22 @@ // -// $Id: BaseTileSet.java,v 1.9 2001/11/29 21:58:49 mdb Exp $ +// $Id: BaseTileSet.java,v 1.10 2002/05/06 18:08:32 mdb Exp $ package com.threerings.miso.tile; import java.awt.Image; +import java.awt.Rectangle; import com.samskivert.util.StringUtil; import com.threerings.media.tile.Tile; import com.threerings.media.tile.SwissArmyTileSet; +import com.threerings.miso.scene.Traverser; + /** * The base tileset extends the swiss army tileset to add support for tile - * passability. Passability is used to determine whether {@link - * com.threerings.miso.scene.Traverser} objects can traverse a particular - * tile in a scene. + * passability. Passability is used to determine whether {@link Traverser} + * objects can traverse a particular tile in a scene. */ public class BaseTileSet extends SwissArmyTileSet { @@ -36,9 +38,11 @@ public class BaseTileSet extends SwissArmyTileSet } // documentation inherited - protected Tile createTile (int tileIndex, Image image) + protected Tile createTile (int tileIndex, Image tilesetImage) { - return new BaseTile(image, _passable[tileIndex]); + return new BaseTile(tilesetImage, + computeTileBounds(tileIndex, tilesetImage), + _passable[tileIndex]); } // documentation inherited diff --git a/src/java/com/threerings/miso/tile/FringeTile.java b/src/java/com/threerings/miso/tile/FringeTile.java index fb7c58821..716d57166 100644 --- a/src/java/com/threerings/miso/tile/FringeTile.java +++ b/src/java/com/threerings/miso/tile/FringeTile.java @@ -1,5 +1,5 @@ // -// $Id: FringeTile.java,v 1.1 2002/04/06 03:41:58 ray Exp $ +// $Id: FringeTile.java,v 1.2 2002/05/06 18:08:32 mdb Exp $ package com.threerings.miso.tile; @@ -21,7 +21,8 @@ public class FringeTile extends Tile */ public FringeTile (Image img) { - super(img); + super(img, new Rectangle( + 0, 0, img.getWidth(null), img.getHeight(null))); } /** @@ -36,13 +37,10 @@ public class FringeTile extends Tile } // documentation inherited - public void paint (Graphics2D gfx, Shape dest) + public void paint (Graphics2D gfx, int x, int y) { - Rectangle bounds = dest.getBounds(); - int x = bounds.x; - int y = bounds.y; - gfx.drawImage(_image, x, y, null); + if (_extras != null) { int size = _extras.size(); for (int ii=0; ii < size; ii++) {