diff --git a/src/java/com/threerings/cast/CharacterManager.java b/src/java/com/threerings/cast/CharacterManager.java
index 026fc5964..59fba17df 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.8 2001/11/02 01:10:28 shaper Exp $
+// $Id: CharacterManager.java,v 1.9 2001/11/02 15:28:20 shaper Exp $
package com.threerings.cast;
@@ -7,11 +7,12 @@ import java.util.*;
import com.samskivert.util.CollectionUtil;
-import com.threerings.cast.Log;
-
import com.threerings.media.sprite.MultiFrameImage;
import com.threerings.media.sprite.Sprite;
+import com.threerings.cast.Log;
+import com.threerings.cast.util.TileUtil;
+
/**
* The character manager provides facilities for constructing sprites
* that are used to represent characters in a scene.
diff --git a/src/java/com/threerings/cast/tools/xml/XMLComponentRepository.java b/src/java/com/threerings/cast/tools/xml/XMLComponentRepository.java
index fe8c67c01..72b69978b 100644
--- a/src/java/com/threerings/cast/tools/xml/XMLComponentRepository.java
+++ b/src/java/com/threerings/cast/tools/xml/XMLComponentRepository.java
@@ -1,5 +1,5 @@
//
-// $Id: XMLComponentRepository.java,v 1.4 2001/11/02 02:52:16 shaper Exp $
+// $Id: XMLComponentRepository.java,v 1.5 2001/11/02 15:28:20 shaper Exp $
package com.threerings.miso.scene.xml;
@@ -12,6 +12,7 @@ import com.samskivert.util.HashIntMap;
import com.samskivert.util.Tuple;
import com.threerings.cast.*;
+import com.threerings.cast.util.TileUtil;
import com.threerings.media.ImageManager;
import com.threerings.media.tile.TileManager;
diff --git a/src/java/com/threerings/cast/util/CastUtil.java b/src/java/com/threerings/cast/util/CastUtil.java
new file mode 100644
index 000000000..e4b498463
--- /dev/null
+++ b/src/java/com/threerings/cast/util/CastUtil.java
@@ -0,0 +1,49 @@
+//
+// $Id: CastUtil.java,v 1.1 2001/11/02 15:28:20 shaper Exp $
+
+package com.threerings.cast.util;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.samskivert.util.CollectionUtil;
+
+import com.threerings.media.util.RandomUtil;
+
+import com.threerings.cast.*;
+
+/**
+ * Miscellaneous cast utility routines.
+ */
+public class CastUtil
+{
+ /**
+ * Returns a new character descriptor populated with a random set
+ * of components.
+ */
+ public static CharacterDescriptor
+ getRandomDescriptor (CharacterManager charmgr)
+ {
+ // get all available classes
+ ArrayList classes = new ArrayList();
+ CollectionUtil.addAll(classes, charmgr.enumerateComponentClasses());
+
+ // select the components
+ int size = classes.size();
+ int components[] = new int[size];
+ for (int ii = 0; ii < size; ii++) {
+ ComponentClass cclass = (ComponentClass)classes.get(ii);
+
+ // get the components available for this class
+ ArrayList choices = new ArrayList();
+ Iterator iter = charmgr.enumerateComponentsByClass(cclass.clid);
+ CollectionUtil.addAll(choices, iter);
+
+ // choose a random component
+ int idx = RandomUtil.getInt(choices.size());
+ components[cclass.clid] = ((Integer)choices.get(idx)).intValue();
+ }
+
+ return new CharacterDescriptor(components);
+ }
+}
diff --git a/src/java/com/threerings/cast/util/TileUtil.java b/src/java/com/threerings/cast/util/TileUtil.java
new file mode 100644
index 000000000..3bd08dfb4
--- /dev/null
+++ b/src/java/com/threerings/cast/util/TileUtil.java
@@ -0,0 +1,179 @@
+//
+// $Id: TileUtil.java,v 1.1 2001/11/02 15:28:20 shaper Exp $
+
+package com.threerings.cast.util;
+
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+
+import com.threerings.media.sprite.*;
+import com.threerings.media.tile.*;
+
+import com.threerings.cast.Log;
+import com.threerings.cast.*;
+
+/**
+ * Miscellaneous tile-related utility functions.
+ */
+public class TileUtil
+{
+ /**
+ * Renders each of the given src component frames
+ * into the corresponding frames of dest, allocating
+ * blank image frames for dest if none yet exist.
+ */
+ public static void compositeFrames (
+ MultiFrameImage[][] dest, MultiFrameImage[][] src)
+ {
+ for (int ii = 0; ii < dest.length; ii++) {
+ for (int orient = 0; orient < Sprite.NUM_DIRECTIONS; orient++) {
+ // create blank destination frames if needed
+ if (dest[ii][orient] == null) {
+ dest[ii][orient] = createBlankFrames(src[ii][orient]);
+ }
+
+ // slap the images together
+ compositeFrames(dest[ii][orient], src[ii][orient]);
+ }
+ }
+ }
+
+ /**
+ * Returns a new {@link MultiFrameImage} that has empty images in
+ * all frames. The number of frames in the resulting multi frame
+ * image is the same as the frame count for src.
+ */
+ public static MultiFrameImage createBlankFrames (MultiFrameImage src)
+ {
+ // TODO: for now, just use the first frame from the source to
+ // get the width and height for all of the blank frames. fix
+ // this hack soon.
+ Image img = src.getFrame(0);
+ int wid = img.getWidth(null), hei = img.getHeight(null);
+ return new BlankFrameImage(wid, hei, src.getFrameCount());
+ }
+
+ /**
+ * Returns a two-dimensional array of multi frame images
+ * containing the frames of animation used to render the sprite
+ * while standing or walking in each of the directions it may
+ * face.
+ */
+ public static MultiFrameImage[][] getComponentFrames (
+ String imagedir, CharacterComponent c)
+ {
+ ActionSequence seqs[] = c.getActionSequences();
+ MultiFrameImage frames[][] =
+ new MultiFrameImage[seqs.length][Sprite.NUM_DIRECTIONS];
+
+ try {
+ for (int ii = 0; ii < seqs.length; ii++) {
+ ActionSequence as = seqs[ii];
+
+ // get the tile set containing the component tiles for
+ // this action sequence
+ String file = getImageFile(imagedir, as, c);
+ TileSet tset = null;
+
+ try {
+ tset = as.tileset.clone(file);
+ } catch (CloneNotSupportedException e) {
+ Log.warning("Failed to clone tile set " +
+ "[tset=" + as.tileset + "].");
+ return null;
+ }
+
+ // get the number of frames of animation
+ int frameCount = tset.getNumTiles() / Sprite.NUM_DIRECTIONS;
+
+ for (int dir = 0; dir < Sprite.NUM_DIRECTIONS; dir++) {
+ // retrieve all images for the sequence and direction
+ Image imgs[] = new Image[frameCount];
+ for (int jj = 0; jj < frameCount; jj++) {
+ int idx = (dir * frameCount) + jj;
+ imgs[jj] = tset.getTile(idx).img;
+ }
+
+ // create the multi frame image
+ frames[ii][dir] = new MultiFrameImageImpl(imgs);
+ }
+ }
+
+ } catch (TileException te) {
+ Log.warning("Exception retrieving character images " +
+ "[te=" + te + "].");
+ return null;
+ }
+
+ return frames;
+ }
+
+ /**
+ * Returns the file path for the given action sequence and component.
+ */
+ protected static String getImageFile (
+ String imagedir, ActionSequence as, CharacterComponent c)
+ {
+ return imagedir + as.fileid + "_" + c.getFileId() + IMAGE_SUFFIX;
+ }
+
+ /**
+ * Renders each of the given src frames into the
+ * corresponding frames of dest.
+ */
+ protected static void compositeFrames (
+ MultiFrameImage dest, MultiFrameImage src)
+ {
+ int dsize = dest.getFrameCount(), ssize = src.getFrameCount();
+ if (dsize != ssize) {
+ Log.warning(
+ "Can't composite images with differing frame counts " +
+ "[dest=" + dsize + ", src=" + ssize + "].");
+ return;
+ }
+
+ for (int ii = 0; ii < dsize; ii++) {
+ Image dimg = dest.getFrame(ii);
+ Image simg = src.getFrame(ii);
+ dimg.getGraphics().drawImage(simg, 0, 0, null);
+ }
+ }
+
+ /**
+ * An implementation of the {@link MultiFrameImage} interface that
+ * initializes itself to contain a specified number of blank
+ * frames of the requested dimensions.
+ */
+ protected static class BlankFrameImage implements MultiFrameImage
+ {
+ /**
+ * Constructs a blank frame image.
+ */
+ public BlankFrameImage (int width, int height, int frameCount)
+ {
+ _imgs = new Image[frameCount];
+ for (int ii = 0; ii < frameCount; ii++) {
+ _imgs[ii] = new BufferedImage(
+ width, height, BufferedImage.TYPE_INT_ARGB);
+ }
+ }
+
+ // documentation inherited
+ public int getFrameCount ()
+ {
+ return _imgs.length;
+ }
+
+ // documentation inherited
+ public Image getFrame (int index)
+ {
+ return _imgs[index];
+ }
+
+ /** The frame images. */
+ protected Image _imgs[];
+ }
+
+ /** The image file name suffix appended to component image file names. */
+ protected static final String IMAGE_SUFFIX = ".png";
+}
diff --git a/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java b/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java
index 75d81c0a5..b127a1592 100644
--- a/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java
+++ b/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java
@@ -1,19 +1,18 @@
//
-// $Id: ViewerSceneViewPanel.java,v 1.28 2001/11/02 03:09:10 shaper Exp $
+// $Id: ViewerSceneViewPanel.java,v 1.29 2001/11/02 15:28:20 shaper Exp $
package com.threerings.miso.viewer;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
import javax.swing.JPanel;
-import com.samskivert.util.CollectionUtil;
import com.samskivert.util.Config;
-import com.threerings.cast.*;
+import com.threerings.cast.CharacterDescriptor;
+import com.threerings.cast.CharacterManager;
+import com.threerings.cast.util.CastUtil;
import com.threerings.media.ImageManager;
import com.threerings.media.sprite.*;
@@ -52,8 +51,8 @@ public class ViewerSceneViewPanel extends SceneViewPanel
ctx.getConfig(), ctx.getImageManager());
// create the character descriptors
- _descUser = createCharacterDescriptor(charmgr);
- _descDecoy = createCharacterDescriptor(charmgr);
+ _descUser = CastUtil.getRandomDescriptor(charmgr);
+ _descDecoy = CastUtil.getRandomDescriptor(charmgr);
// create the manipulable sprite
_sprite = createSprite(spritemgr, charmgr, _descUser);
@@ -186,37 +185,6 @@ public class ViewerSceneViewPanel extends SceneViewPanel
} while (!createPath(s, x, y));
}
- /**
- * Returns a new {@link CharacterDescriptor} suitable for use in
- * creating character sprites via {@link
- * CharacterManager#getCharacter}.
- */
- protected CharacterDescriptor
- createCharacterDescriptor (CharacterManager charmgr)
- {
- // get all available classes
- ArrayList classes = new ArrayList();
- CollectionUtil.addAll(classes, charmgr.enumerateComponentClasses());
-
- // select the components
- int size = classes.size();
- int components[] = new int[size];
- for (int ii = 0; ii < size; ii++) {
- ComponentClass cclass = (ComponentClass)classes.get(ii);
-
- // get the components available for this class
- ArrayList choices = new ArrayList();
- Iterator iter = charmgr.enumerateComponentsByClass(cclass.clid);
- CollectionUtil.addAll(choices, iter);
-
- // choose a random component
- int idx = RandomUtil.getInt(choices.size());
- components[cclass.clid] = ((Integer)choices.get(idx)).intValue();
- }
-
- return new CharacterDescriptor(components);
- }
-
// documentation inherited
public void handleEvent (SpriteEvent event)
{