Bundles! Have component bundles largely working. Wrote test code and ANT

tasks and XML parsing rule sets all the good stuff. Rewired up all the
cast code to be amenable to bundling and did some other revamping.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@640 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2001-11-27 08:09:35 +00:00
parent be313f8922
commit c25741d8e6
27 changed files with 1554 additions and 918 deletions
@@ -1,37 +1,25 @@
//
// $Id: ActionSequence.java,v 1.1 2001/11/01 01:40:42 shaper Exp $
// $Id: ActionSequence.java,v 1.2 2001/11/27 08:09:34 mdb Exp $
package com.threerings.cast;
import java.awt.Point;
import com.threerings.media.tile.TileSet;
import java.io.Serializable;
/**
* The action sequence class describes a single character animation
* sequence. An animation sequence may consist of multiple frames of
* animation, renders at a particular frame rate, and has an origin
* point that specifies where the base of the character in the
* animation sequence is to be placed.
* The action sequence class describes a particular character animation
* sequence. An animation sequence consists of one or more frames of
* animation, renders at a particular frame rate, and has an origin point
* that specifies the location of the base of the character in relation to
* the bounds of the animation images.
*/
public class ActionSequence
public class ActionSequence implements Serializable
{
/** The unique action sequence identifier. */
public int asid;
/** The action sequence name. */
public String name;
/** The file id specifier for the tile set image file name. */
public String fileid;
/** The tile set description for this sequence. Intended for
* cloning with an image path to reference an actual set of tile
* images suiting the action sequence. */
public TileSet tileset;
/** The number of frames per second to show when animating. */
public int fps;
public int framesPerSecond;
/** The position of the character's base for this sequence. */
public Point origin = new Point();
@@ -41,7 +29,7 @@ public class ActionSequence
*/
public String toString ()
{
return "[asid=" + asid + ", name=" + name +
", fps=" + fps + ", origin=" + origin + "]";
return "[name=" + name + ", framesPerSecond=" + framesPerSecond +
", origin=" + origin + "]";
}
}
@@ -1,8 +1,10 @@
//
// $Id: CharacterComponent.java,v 1.3 2001/11/01 01:40:42 shaper Exp $
// $Id: CharacterComponent.java,v 1.4 2001/11/27 08:09:34 mdb Exp $
package com.threerings.cast;
import java.io.Serializable;
import com.samskivert.util.StringUtil;
import com.threerings.media.sprite.MultiFrameImage;
@@ -10,71 +12,43 @@ import com.threerings.media.sprite.Sprite;
/**
* The character component represents a single component that can be
* composited with other character components to comprise an image
* representing a single monolithic character displayable in any of
* the eight cardinal compass directions as detailed in the {@link
* com.threerings.media.sprite.Sprite} class's direction constants.
* composited with other character components to generate an image
* representing a complete character displayable in any of the eight
* compass directions as detailed in the {@link Sprite} class direction
* constants.
*/
public class CharacterComponent
public class CharacterComponent implements Serializable
{
/** The unique component identifier. */
public int componentId;
/** The component's name. */
public String name;
/** The class of components to which this one belongs. */
public ComponentClass componentClass;
/**
* Constructs a character component.
* Constructs a character component with the specified id of the
* specified class.
*/
public CharacterComponent (
int cid, String fileid, ActionSequence seqs[], ComponentClass cclass)
public CharacterComponent (int componentId, String name,
ComponentClass compClass, FrameProvider fprov)
{
_cid = cid;
_fileid = fileid;
_seqs = seqs;
_cclass = cclass;
this.componentId = componentId;
this.name = name;
this.componentClass = compClass;
_frameProvider = fprov;
}
/**
* Returns the unique component identifier.
* Returns the image frames for the specified action animation or null
* if no animation for the specified action is available for this
* component.
*/
public int getId ()
public MultiFrameImage[] getFrames (String action)
{
return _cid;
}
/**
* Returns the action sequences for this component.
*/
public ActionSequence[] getActionSequences ()
{
return _seqs;
}
/**
* Returns the display frames used to display this component.
*/
public MultiFrameImage[][] getFrames ()
{
return _frames;
}
/**
* Returns the file id.
*/
public String getFileId ()
{
return _fileid;
}
/**
* Returns the component class associated with this component.
*/
public ComponentClass getComponentClass ()
{
return _cclass;
}
/**
* Sets the frames used to render this component.
*/
public void setFrames (MultiFrameImage frames[][])
{
_frames = frames;
return _frameProvider.getFrames(this, action);
}
/**
@@ -82,22 +56,10 @@ public class CharacterComponent
*/
public String toString ()
{
return "[cid=" + _cid + ", clid=" + _cclass.clid +
", seqs=" + StringUtil.toString(_seqs) + "]";
return "[componentId=" + componentId + ", name=" + name +
", class=" + componentClass + "]";
}
/** The unique character component identifier. */
protected int _cid;
/** The file id specifier for the tile set image file name. */
protected String _fileid;
/** The animation frames for each action sequence and orientation. */
protected MultiFrameImage _frames[][];
/** The component class. */
protected ComponentClass _cclass;
/** The character action sequences. */
protected ActionSequence _seqs[];
/** The entity from which we obtain our animation frames. */
protected FrameProvider _frameProvider;
}
@@ -1,8 +1,9 @@
//
// $Id: CharacterDescriptor.java,v 1.3 2001/11/01 01:40:42 shaper Exp $
// $Id: CharacterDescriptor.java,v 1.4 2001/11/27 08:09:34 mdb Exp $
package com.threerings.cast;
import java.util.Arrays;
import com.samskivert.util.StringUtil;
/**
@@ -14,7 +15,7 @@ public class CharacterDescriptor
/**
* Constructs the character descriptor.
*/
public CharacterDescriptor (int components[])
public CharacterDescriptor (int[] components)
{
_components = components;
}
@@ -23,19 +24,42 @@ public class CharacterDescriptor
* Returns an array of the component identifiers comprising the
* character described by this descriptor.
*/
public int[] getComponents ()
public int[] getComponentIds ()
{
return _components;
}
/**
* Compute a sensible hashcode for this object.
*/
public int hashCode ()
{
int code = 0, clength = _components.length;
for (int i = 0; i < clength; i++) {
code ^= _components[i];
}
return code;
}
/**
* Compares this character descriptor to another.
*/
public boolean equals (Object other)
{
if (other instanceof CharacterDescriptor) {
return Arrays.equals(_components,
((CharacterDescriptor)other)._components);
} else {
return false;
}
}
/**
* Returns a string representation of this character descriptor.
*/
public String toString ()
{
StringBuffer buf = new StringBuffer();
buf.append("[").append(StringUtil.toString(_components));
return buf.append("]").toString();
return "[cids=" + StringUtil.toString(_components) + "]";
}
/** The component identifiers comprising the character. */
+111 -143
View File
@@ -1,11 +1,13 @@
//
// $Id: CharacterManager.java,v 1.9 2001/11/02 15:28:20 shaper Exp $
// $Id: CharacterManager.java,v 1.10 2001/11/27 08:09:34 mdb Exp $
package com.threerings.cast;
import java.util.*;
import java.util.Arrays;
import java.util.Iterator;
import java.util.HashMap;
import com.samskivert.util.CollectionUtil;
import com.samskivert.util.Tuple;
import com.threerings.media.sprite.MultiFrameImage;
import com.threerings.media.sprite.Sprite;
@@ -14,21 +16,47 @@ 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.
* The character manager provides facilities for constructing sprites that
* are used to represent characters in a scene. It also handles the
* compositing and caching of composited character animations.
*/
public class CharacterManager
{
/**
* Constructs the character manager.
*/
public CharacterManager (ComponentRepository repo)
public CharacterManager (ComponentRepository crepo)
{
// keep this around
_repo = repo;
_crepo = crepo;
// determine component class render order
_renderRank = getRenderRank();
// populate our actions table
Iterator iter = crepo.enumerateActionSequences();
while (iter.hasNext()) {
ActionSequence action = (ActionSequence)iter.next();
_actions.put(action.name, action);
}
}
/**
* Instructs the character manager to construct instances of this
* derived class of {@link CharacterSprite} when creating new sprites.
*
* @exception IllegalArgumentException thrown if the supplied class
* does not derive from {@link CharacterSprite}.
*/
public void setCharacterClass (Class charClass)
{
// sanity check
if (!CharacterSprite.class.isAssignableFrom(charClass)) {
String errmsg = "Requested to use character sprite class that " +
"does not derive from CharacterSprite " +
"[class=" + charClass.getName() + "].";
throw new IllegalArgumentException(errmsg);
}
// make a note of it
_charClass = charClass;
}
/**
@@ -40,127 +68,12 @@ public class CharacterManager
*/
public CharacterSprite getCharacter (CharacterDescriptor desc)
{
long start = System.currentTimeMillis();
// get the array of component ids of each class
CharacterComponent components[] = getComponents(desc.getComponents());
if (components == null || components.length == 0) {
Log.warning("No character components in descriptor.");
return null;
}
// assume all components support the same set of action sequences
ActionSequence seqs[] = components[0].getActionSequences();
// create the composite character image
MultiFrameImage frames[][] =
createCompositeFrames(seqs.length, components);
if (frames == null) {
return null;
}
// instantiate the character sprite
CharacterSprite sprite = createSprite();
if (sprite == null) {
return null;
}
// populate the character sprite with its attributes
sprite.setAnimations(seqs, frames);
long end = System.currentTimeMillis();
Log.info("Generated character sprite [ms=" + (end - start) + "].");
return sprite;
}
/**
* Returns an iterator over the {@link ComponentClass} objects
* representing all available character component classes.
*/
public Iterator enumerateComponentClasses ()
{
return _repo.enumerateComponentClasses();
}
/**
* Returns an iterator over the <code>Integer</code> objects
* representing all available character component identifiers for
* the given character component class identifier.
*/
public Iterator enumerateComponentsByClass (int clid)
{
return _repo.enumerateComponentsByClass(clid);
}
/**
* Instructs the character manager to construct instances of this
* derived class of <code>CharacterSprite</code>.
*/
public void setCharacterClass (Class charClass)
{
// sanity check
if (!CharacterSprite.class.isAssignableFrom(charClass)) {
Log.warning("Requested to use character class that does not " +
"derive from CharacterSprite " +
"[class=" + charClass.getName() + "].");
return;
}
// make a note of it
_charClass = charClass;
}
/**
* Returns an array of the character component objects specified
* in the given array of component ids.
*/
protected CharacterComponent[] getComponents (int cids[])
{
int size = cids.length;
CharacterComponent components[] = new CharacterComponent[size];
try {
for (int ii = 0; ii < size; ii++) {
components[ii] = _repo.getComponent(cids[ii]);
}
CharacterSprite sprite = (CharacterSprite)
_charClass.newInstance();
sprite.init(desc, this);
return sprite;
} catch (NoSuchComponentException nsce) {
Log.warning("Exception retrieving character component " +
"[nsce=" + nsce + "].");
return null;
}
return components;
}
/**
* Returns an array of multi frame images containing the fully
* composited images for the given action sequences and
* components.
*/
protected MultiFrameImage[][] createCompositeFrames (
int seqCount, CharacterComponent components[])
{
MultiFrameImage frames[][] =
new MultiFrameImage[seqCount][Sprite.NUM_DIRECTIONS];
// render all component frames one atop another
for (int ii = 0; ii < _renderRank.length; ii++) {
int clidx = _renderRank[ii].clid;
TileUtil.compositeFrames(frames, components[clidx].getFrames());
}
return frames;
}
/**
* Returns a new instance of the {@link CharacterSprite}-derived
* class specified for use by this character manager.
*/
protected CharacterSprite createSprite ()
{
try {
return (CharacterSprite)_charClass.newInstance();
} catch (Exception e) {
Log.warning("Failed to instantiate character sprite " +
"[e=" + e + "].");
@@ -170,27 +83,82 @@ public class CharacterManager
}
/**
* Returns an array of {@link ComponentClass} objects sorted into
* the appropriate rendering order as specified by each component
* class object.
* Returns the action sequence instance with the specified name or
* null if no such sequence exists.
*/
protected ComponentClass[] getRenderRank ()
protected ActionSequence getActionSequence (String action)
{
ArrayList classes = new ArrayList();
CollectionUtil.addAll(classes, _repo.enumerateComponentClasses());
ComponentClass rank[] = new ComponentClass[classes.size()];
classes.toArray(rank);
Arrays.sort(rank, ComponentClass.RENDER_COMP);
return rank;
return (ActionSequence)_actions.get(action);
}
/** The order in which to render component classes. */
protected ComponentClass _renderRank[];
/**
* Obtains the composited animation frames for the specified action
* for a character with the specified descriptor. The resulting
* composited animation will be cached.
*
* @exception NoSuchComponentException thrown if any of the components
* in the supplied descriptor do not exist.
* @exception IllegalArgumentException thrown if any of the components
* referenced in the descriptor do not support the specified action.
*/
protected MultiFrameImage[] getActionFrames (
CharacterDescriptor descrip, String action)
throws NoSuchComponentException
{
// the cache is keyed on both values
Tuple key = new Tuple(descrip, action);
MultiFrameImage[] frames = (MultiFrameImage[])_frames.get(key);
if (frames == null) {
// do the compositing
frames = createCompositeFrames(descrip, action);
// cache the result
_frames.put(key, frames);
}
return frames;
}
/**
* Generates the composited animation frames for the specified action
* for a character with the specified descriptor.
*
* @exception NoSuchComponentException thrown if any of the components
* in the supplied descriptor do not exist.
* @exception IllegalArgumentException thrown if any of the components
* referenced in the descriptor do not support the specified action.
*/
protected MultiFrameImage[] createCompositeFrames (
CharacterDescriptor descrip, String action)
throws NoSuchComponentException
{
MultiFrameImage[] frames = new MultiFrameImage[Sprite.NUM_DIRECTIONS];
// obtain the necessary components
int[] cids = descrip.getComponentIds();
int ccount = cids.length;
CharacterComponent[] components = new CharacterComponent[ccount];
for (int i = 0; i < ccount; i++) {
components[i] = _crepo.getComponent(cids[i]);
}
// sort them into the proper rendering order
Arrays.sort(components, ComponentClass.RENDER_COMP);
// now composite the component frames, one atop the next
for (int i = 0; i < ccount; i++) {
TileUtil.compositeFrames(frames, components[i].getFrames(action));
}
return frames;
}
/** The component repository. */
protected ComponentRepository _repo;
protected ComponentRepository _crepo;
/** A table of our action sequences. */
protected HashMap _actions = new HashMap();
/** A cache of composited animation frames. */
protected HashMap _frames = new HashMap();
/** The character class to be created. */
protected Class _charClass = CharacterSprite.class;
@@ -1,65 +1,70 @@
//
// $Id: CharacterSprite.java,v 1.17 2001/11/01 01:40:42 shaper Exp $
// $Id: CharacterSprite.java,v 1.18 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast;
import java.awt.Point;
import com.threerings.media.sprite.*;
import com.threerings.cast.Log;
import com.threerings.media.sprite.MultiFrameImage;
import com.threerings.media.sprite.Path;
import com.threerings.media.sprite.Sprite;
/**
* A character sprite is a sprite that animates itself while walking
* about in a scene.
*/
public class CharacterSprite extends Sprite
public class CharacterSprite
extends Sprite implements StandardActions
{
/**
* Constructs a character sprite.
* Initializes this character sprite with the specified character
* descriptor and character manager. It will obtain animation data
* from the supplied character manager.
*/
public CharacterSprite ()
public void init (CharacterDescriptor descrip, CharacterManager charmgr)
{
// keep track of this stuff
_descrip = descrip;
_charmgr = charmgr;
// assign an arbitrary starting orientation
_orient = DIR_NORTH;
}
/**
* Sets the action sequences available for this character sprite
* and the animation frames that go along with each action.
* Resets the character's currently selected action sequence to
* the standing sequence.
* Sets the action sequence used when rendering the character, from
* the set of available sequences.
*/
public void setAnimations (ActionSequence[] seqs,
MultiFrameImage anims[][])
public void setActionSequence (String action)
{
_seqs = seqs;
_anims = anims;
setActionSequence(WALKING);
}
// get a reference to the action sequence so that we can obtain
// our animation frames and configure our frames per second
ActionSequence actseq = _charmgr.getActionSequence(action);
if (actseq == null) {
String errmsg = "No such action '" + action + "'.";
throw new IllegalArgumentException(errmsg);
}
/**
* Sets the action sequence used when rendering the character,
* from the set of available sequences.
*/
public void setActionSequence (int seqidx)
{
// save off the action sequence index
_seqidx = seqidx;
try {
// obtain our animation frames for this action sequence
_frames = _charmgr.getActionFrames(_descrip, action);
// update the sprite render attributes
ActionSequence seq = _seqs[_seqidx];
setFrames(_anims[_seqidx][_orient]);
setFrameRate(seq.fps);
setOrigin(seq.origin.x, seq.origin.y);
// update the sprite render attributes
setOrigin(actseq.origin.x, actseq.origin.y);
setFrameRate(actseq.framesPerSecond);
setFrames(_frames[_orient]);
} catch (NoSuchComponentException nsce) {
Log.warning("Character sprite referneces non-existent " +
"component [sprite=" + this + ", err=" + nsce + "].");
}
}
// documentation inherited
public void setOrientation (int orient)
{
super.setOrientation(orient);
// update the sprite frames to reflect the direction
setActionSequence((_path == null) ? STANDING : WALKING);
setFrames(_frames[orient]);
}
/**
@@ -117,26 +122,22 @@ public class CharacterSprite extends Sprite
*/
protected void halt ()
{
// disable animation
setAnimationMode(NO_ANIMATION);
// come to a halt looking settled and at peace
setActionSequence(STANDING);
// disable walking animation
setAnimationMode(NO_ANIMATION);
}
/** The action sequence constant for standing. */
protected static final int STANDING = 0;
/** A reference to the descriptor for the character that we're
* visualizing. */
protected CharacterDescriptor _descrip;
/** The action sequence constant for walking. */
protected static final int WALKING = 1;
/** A reference to the character manager that created us. */
protected CharacterManager _charmgr;
/** The currently selected action sequence. */
protected int _seqidx;
/** The available action sequences. */
protected ActionSequence _seqs[];
/** The animation frames for each action sequence and orientation. */
protected MultiFrameImage _anims[][];
/** The animation frames for the active action sequence in each
* orientation. */
protected MultiFrameImage[] _frames;
/** The origin of the sprite. */
protected int _xorigin, _yorigin;
@@ -1,42 +1,60 @@
//
// $Id: ComponentClass.java,v 1.1 2001/10/30 16:16:01 shaper Exp $
// $Id: ComponentClass.java,v 1.2 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast;
import java.io.Serializable;
import java.util.Comparator;
/**
* The component class object denotes the particular class of
* components that a {@link CharacterComponent} object belongs to.
* Examples of feasible component classes might include "Hat", "Head",
* or "Feet".
* Denotes a class of components to which {@link CharacterComponent}
* objects belong. Examples include "Hat", "Head", and "Feet". A component
* class dictates a component's rendering priority so that components can
* be rendered in an order that causes them to overlap properly.
*/
public class ComponentClass
public class ComponentClass implements Serializable
{
/** The comparator used to sort component class objects in render
* priority order. */
public static final Comparator RENDER_COMP = new RenderComparator();
/** The unique component class identifier. */
public int clid;
/** The component class name. */
public String name;
/** The render priority. */
public int render;
public int renderPriority;
/**
* Classes with the same name are the same.
*/
public boolean equals (Object other)
{
if (other instanceof ComponentClass) {
return name.equals(((ComponentClass)other).name);
} else {
return false;
}
}
/**
* Hashcode is based on component class name.
*/
public int hashCode ()
{
return name.hashCode();
}
/**
* Returns a string representation of this component class.
*/
public String toString ()
{
return "[clid=" + clid + ", name=" + name + "]";
return "[name=" + name + ", renderPriority=" + renderPriority + "]";
}
/**
* The comparator used to sort component class objects in render
* priority order so that compositing components into a single
* The comparator used to sort {@link CharacterComponent} instances in
* render priority order so that compositing components into a single
* character image can be done in the proper order.
*/
protected static class RenderComparator implements Comparator
@@ -44,21 +62,15 @@ public class ComponentClass
// documentation inherited
public int compare (Object a, Object b)
{
if (!(a instanceof ComponentClass) ||
!(b instanceof ComponentClass)) {
if (!(a instanceof CharacterComponent) ||
!(b instanceof CharacterComponent)) {
return -1;
}
ComponentClass ca = (ComponentClass)a;
ComponentClass cb = (ComponentClass)b;
if (ca.render < cb.render) {
return -1;
} else if (ca.render == cb.render) {
return 0;
} else {
return 1;
}
CharacterComponent ca = (CharacterComponent)a;
CharacterComponent cb = (CharacterComponent)b;
return (ca.componentClass.renderPriority -
cb.componentClass.renderPriority);
}
// documentation inherited
@@ -0,0 +1,45 @@
//
// $Id: ComponentIDBroker.java,v 1.1 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast;
import com.samskivert.io.PersistenceException;
/**
* Brokers component ids. The component repository interface makes
* available a collection of components based on a unique identifier. The
* expectation is that a collection of components will be used to populate
* a repository and in that population process, component ids will be
* assigned to the components. The component id broker system provides a
* means by which named components can be mapped consistently to a set of
* component ids. Humans can then be responsible for assigning unique
* names to the components and the broker will ensure that those names map
* to unique ids that won't change if the repository is rebuilt from the
* source components.
*/
public interface ComponentIDBroker
{
/**
* Returns the unique identifier for the named component. If no
* identifier has yet been assigned to the specified named component,
* one should be assigned and returned.
*
* @param cclass the name of the class to which the component belongs.
* @param cname the name of the component.
*
* @exception PersistenceException thrown if an error occurs
* communicating with the underlying persistence mechanism used to
* store the name to id mappings.
*/
public int getComponentID (String cclass, String cname)
throws PersistenceException;
/**
* When the user of a component id broker is done obtaining component
* ids, it must call this method to give the component id broker an
* opportunity to flush any newly created component ids back to its
* persistent store.
*/
public void commit ()
throws PersistenceException;
}
@@ -1,34 +1,40 @@
//
// $Id: ComponentRepository.java,v 1.3 2001/11/01 01:40:42 shaper Exp $
// $Id: ComponentRepository.java,v 1.4 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast;
import java.util.Iterator;
/**
* The component repository interface is intended to be implemented by
* classes that provide access to {@link CharacterComponent} objects
* keyed on their unique component identifier.
* Makes available a collection of character components and associated
* metadata. Character components are animated sequences that can be
* composited together to create a complete character visualization
* (imagine interchanging pairs of boots, torsos, hats, etc.).
*/
public interface ComponentRepository
{
/**
* Returns the {@link CharacterComponent} object for the given
* unique component identifier.
* component identifier.
*/
public CharacterComponent getComponent (int cid)
public CharacterComponent getComponent (int componentId)
throws NoSuchComponentException;
/**
* Returns an iterator over the {@link ComponentClass} objects
* representing all available character component classes.
* Iterates over the {@link ComponentClass} instances representing all
* available character component classes.
*/
public Iterator enumerateComponentClasses ();
/**
* Returns an iterator over the <code>Integer</code> objects
* representing all available character component identifiers for
* the given character component class identifier.
* Iterates over the {@link ActionSequence} instances representing
* every available action sequence.
*/
public Iterator enumerateComponentsByClass (int clid);
public Iterator enumerateActionSequences ();
/**
* Iterates over the component ids of all components in the specified
* class.
*/
public Iterator enumerateComponentIds (ComponentClass compClass);
}
@@ -0,0 +1,21 @@
//
// $Id: FrameProvider.java,v 1.1 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast;
import com.threerings.media.sprite.MultiFrameImage;
/**
* Provides a mechanism where by a character component can obtain access
* to its image frames for a particular action in an on demand manner.
*/
public interface FrameProvider
{
/**
* Returns the animation frames (in the eight sprite directions) for
* the specified action of the specified component. May return null if
* the specified action does not exist for the specified component.
*/
public MultiFrameImage[] getFrames (
CharacterComponent component, String action);
}
@@ -1,5 +1,5 @@
//
// $Id: NoSuchComponentException.java,v 1.1 2001/10/26 01:17:21 shaper Exp $
// $Id: NoSuchComponentException.java,v 1.2 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast;
@@ -9,16 +9,16 @@ package com.threerings.cast;
*/
public class NoSuchComponentException extends Exception
{
public NoSuchComponentException (int cid)
public NoSuchComponentException (int componentId)
{
super("No such component [cid=" + cid + "]");
_cid = cid;
super("No such component [componentId=" + componentId + "]");
_componentId = componentId;
}
public int getId ()
public int getComponentId ()
{
return _cid;
return _componentId;
}
protected int _cid;
protected int _componentId;
}
@@ -0,0 +1,19 @@
//
// $Id: StandardActions.java,v 1.1 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast;
/**
* Actions are referenced by name and this interface defines constants for
* two standard actions: standing and walking. Because character sprites
* follow paths, it is helpful for them to take care of switching between
* the standing and walking actions automatically.
*/
public interface StandardActions
{
/** The name of the standard standing action. */
public static final String STANDING = "standing";
/** The name of the standard walking action. */
public static final String WALKING = "walking";
}
@@ -1,29 +1,32 @@
//
// $Id: BuilderModel.java,v 1.3 2001/11/18 04:09:21 mdb Exp $
// $Id: BuilderModel.java,v 1.4 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.builder;
package com.threerings.cast.builder;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.samskivert.util.CollectionUtil;
import com.samskivert.util.HashIntMap;
import com.threerings.cast.CharacterManager;
import com.threerings.cast.ComponentRepository;
import com.threerings.cast.ComponentClass;
/**
* The builder model represents the current state of the character
* the user is building.
* The builder model represents the current state of the character the
* user is building.
*/
public class BuilderModel
{
/**
* Constructs a builder model.
*/
public BuilderModel (CharacterManager charmgr)
public BuilderModel (ComponentRepository crepo)
{
gatherComponentInfo(charmgr);
_selected = new int[_classes.size()];
gatherComponentInfo(crepo);
}
/**
@@ -58,28 +61,36 @@ public class BuilderModel
}
/**
* Returns a map of the components available for each component
* class, keyed on component class id.
* Returns the list of components available in the specified class.
*/
public Map getComponents ()
public List getComponents (ComponentClass cclass)
{
return Collections.unmodifiableMap(_components);
List list = (List)_components.get(cclass);
if (list == null) {
list = new ArrayList();
}
return list;
}
/**
* Returns an array of the currently selected component ids.
* Returns the selected components in an array.
*/
public int[] getSelectedComponents ()
{
return _selected;
int[] values = new int[_selected.size()];
Iterator iter = _selected.values().iterator();
for (int i = 0; iter.hasNext(); i++) {
values[i] = ((Integer)iter.next()).intValue();
}
return values;
}
/**
* Sets the selected component for the given component class id.
* Sets the selected component for the given component class.
*/
public void setSelectedComponent (int clid, int cid)
public void setSelectedComponent (ComponentClass cclass, int cid)
{
_selected[clid] = cid;
_selected.put(cclass, new Integer(cid));
notifyListeners(BuilderModelListener.COMPONENT_CHANGED);
}
@@ -87,22 +98,21 @@ public class BuilderModel
* Gathers component class and component information from the
* character manager for later reference by others.
*/
protected void gatherComponentInfo (CharacterManager charmgr)
protected void gatherComponentInfo (ComponentRepository crepo)
{
// get the list of all component classes
CollectionUtil.addAll(_classes, charmgr.enumerateComponentClasses());
CollectionUtil.addAll(_classes, crepo.enumerateComponentClasses());
for (int ii = 0; ii < _classes.size(); ii++) {
// get the list of components available for this class
int clid = ((ComponentClass)_classes.get(ii)).clid;
Iterator iter = charmgr.enumerateComponentsByClass(clid);
ComponentClass cclass = (ComponentClass)_classes.get(ii);
Iterator iter = crepo.enumerateComponentIds(cclass);
while (iter.hasNext()) {
Integer cid = (Integer)iter.next();
ArrayList clist = (ArrayList)_components.get(clid);
ArrayList clist = (ArrayList)_components.get(cclass);
if (clist == null) {
_components.put(clid, clist = new ArrayList());
_components.put(cclass, clist = new ArrayList());
}
clist.add(cid);
@@ -111,10 +121,10 @@ public class BuilderModel
}
/** The currently selected character components. */
protected int _selected[];
protected HashMap _selected = new HashMap();
/** The hashtable of available component ids for each class. */
protected HashIntMap _components = new HashIntMap();
protected HashMap _components = new HashMap();
/** The list of all available component classes. */
protected ArrayList _classes = new ArrayList();
@@ -1,7 +1,7 @@
//
// $Id: BuilderModelListener.java,v 1.2 2001/11/18 04:09:21 mdb Exp $
// $Id: BuilderModelListener.java,v 1.3 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.builder;
package com.threerings.cast.builder;
/**
* The builder model listener interface should be implemented by
@@ -1,30 +1,25 @@
//
// $Id: BuilderPanel.java,v 1.4 2001/11/18 04:09:21 mdb Exp $
// $Id: BuilderPanel.java,v 1.5 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.builder;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
package com.threerings.cast.builder;
import javax.swing.*;
import com.samskivert.swing.*;
import com.samskivert.util.StringUtil;
import com.threerings.cast.*;
import com.threerings.cast.CharacterManager;
import com.threerings.cast.ComponentRepository;
/**
* The builder panel presents the user with an overview of a
* composited character and facilities for altering the individual
* components that comprise the character's display image.
* The builder panel presents the user with an overview of a composited
* character and facilities for altering the individual components that
* comprise the character's display image.
*/
public class BuilderPanel extends JPanel
{
/**
* Constructs the builder panel.
*/
public BuilderPanel (CharacterManager charmgr)
public BuilderPanel (CharacterManager charmgr, ComponentRepository crepo)
{
setLayout(new VGroupLayout());
@@ -35,7 +30,7 @@ public class BuilderPanel extends JPanel
gl.setOffAxisPolicy(GroupLayout.STRETCH);
// create the builder model
BuilderModel model = new BuilderModel(charmgr);
BuilderModel model = new BuilderModel(crepo);
// create the component selection and sprite display panels
JPanel sub = new JPanel(gl);
@@ -1,7 +1,7 @@
//
// $Id: ClassEditor.java,v 1.2 2001/11/18 04:09:21 mdb Exp $
// $Id: ClassEditor.java,v 1.3 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.builder;
package com.threerings.cast.builder;
import java.util.List;
@@ -17,20 +17,20 @@ import com.threerings.cast.Log;
import com.threerings.cast.ComponentClass;
/**
* The class editor displays a label and a slider that allow the user
* to select the desired component for a given component class.
* The class editor displays a label and a slider that allow the user to
* select the desired component for a given component class.
*/
public class ClassEditor extends JPanel implements ChangeListener
{
/**
* Constructs a class editor.
*/
public ClassEditor (BuilderModel model, ComponentClass cclass,
List components)
public ClassEditor (
BuilderModel model, ComponentClass cclass, List components)
{
_model = model;
_components = components;
_clid = cclass.clid;
_cclass = cclass;
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
@@ -76,11 +76,11 @@ public class ClassEditor extends JPanel implements ChangeListener
protected void setSelectedComponent (int idx)
{
int cid = ((Integer)_components.get(idx)).intValue();
_model.setSelectedComponent(_clid, cid);
_model.setSelectedComponent(_cclass, cid);
}
/** The component class id associated with this editor. */
protected int _clid;
/** The component class associated with this editor. */
protected ComponentClass _cclass;
/** The components selectable via this editor. */
protected List _components;
@@ -1,7 +1,7 @@
//
// $Id: ComponentPanel.java,v 1.5 2001/11/18 04:09:21 mdb Exp $
// $Id: ComponentPanel.java,v 1.6 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.builder;
package com.threerings.cast.builder;
import java.util.List;
import java.util.Map;
@@ -40,12 +40,10 @@ public class ComponentPanel extends JPanel
protected void addClassEditors (BuilderModel model)
{
List classes = model.getComponentClasses();
Map components = model.getComponents();
int size = classes.size();
for (int ii = 0; ii < size; ii++) {
ComponentClass cclass = (ComponentClass)classes.get(ii);
List ccomps = (List)components.get(new Integer(cclass.clid));
List ccomps = model.getComponents(cclass);
add(new ClassEditor(model, cclass, ccomps));
}
}
@@ -1,7 +1,7 @@
//
// $Id: SpritePanel.java,v 1.3 2001/11/18 04:09:21 mdb Exp $
// $Id: SpritePanel.java,v 1.4 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.builder;
package com.threerings.cast.builder;
import java.awt.*;
import javax.swing.BorderFactory;
@@ -0,0 +1,55 @@
//
// $Id: BundleUtil.java,v 1.1 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.bundle;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import com.threerings.resource.ResourceBundle;
/**
* Utility functions related to creating and manipulating component
* bundles.
*/
public class BundleUtil
{
/** The path in the metadata bundle to the serialized action table. */
public static final String ACTIONS_PATH = "actions.dat";
/** The path in the metadata bundle to the serialized action tile sets
* table. */
public static final String ACTION_SETS_PATH = "action_sets.dat";
/** The path in the metadata bundle to the serialized component class
* table. */
public static final String CLASSES_PATH = "classes.dat";
/** The path in the component bundle to the serialized component id to
* class/type mapping. */
public static final String COMPONENTS_PATH = "components.dat";
/** The file extension of our action tile images. */
public static final String IMAGE_EXTENSION = ".png";
/**
* Attempts to load an object from the supplied resource bundle with
* the specified path.
*
* @return the unserialized object in question or null if no
* serialized object data was available at the specified path.
*
* @exception IOException thrown if an I/O error occurs while reading
* the object from the bundle.
*/
public static Object loadObject (ResourceBundle bundle, String path)
throws IOException, ClassNotFoundException
{
InputStream bin = bundle.getResource(path);
if (bin == null) {
return null;
}
return new ObjectInputStream(bin).readObject();
}
}
@@ -0,0 +1,303 @@
//
// $Id: BundledComponentRepository.java,v 1.1 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.bundle;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import com.samskivert.io.NestableIOException;
import com.samskivert.util.HashIntMap;
import com.samskivert.util.Tuple;
import org.apache.commons.collections.FilterIterator;
import org.apache.commons.collections.Predicate;
import com.threerings.resource.ResourceBundle;
import com.threerings.resource.ResourceManager;
import com.threerings.media.sprite.MultiFrameImage;
import com.threerings.media.sprite.Sprite;
import com.threerings.media.tile.ImageProvider;
import com.threerings.media.tile.TileSet;
import com.threerings.media.tile.NoSuchTileException;
import com.threerings.cast.CharacterComponent;
import com.threerings.cast.ComponentClass;
import com.threerings.cast.ComponentRepository;
import com.threerings.cast.FrameProvider;
import com.threerings.cast.Log;
import com.threerings.cast.NoSuchComponentException;
/**
* A component repository implementation that obtains information from
* resource bundles.
*
* @see ResourceManager
*/
public class BundledComponentRepository
implements ComponentRepository
{
/**
* Constructs a repository which will obtain its resource set from the
* supplied resource manager.
*
* @param rmgr the resource manager from which to obtain our resource
* set.
* @param name the name of the resource set from which we will be
* loading our component data.
*
* @exception IOException thrown if an I/O error occurs while reading
* our metadata from the resource bundles.
*/
public BundledComponentRepository (ResourceManager rmgr, String name)
throws IOException
{
// first we obtain the resource set from whence will come our
// bundles
ResourceBundle[] rbundles = rmgr.getResourceSet(name);
// look for our metadata info in each of the bundles
try {
for (int i = 0; i < rbundles.length; i++) {
if (_actions == null) {
_actions = (HashMap)BundleUtil.loadObject(
rbundles[i], BundleUtil.ACTIONS_PATH);
}
if (_actionSets == null) {
_actionSets = (HashMap)BundleUtil.loadObject(
rbundles[i], BundleUtil.ACTION_SETS_PATH);
}
if (_classes == null) {
_classes = (HashMap)BundleUtil.loadObject(
rbundles[i], BundleUtil.CLASSES_PATH);
}
}
// now go back and load up all of the component information
for (int i = 0; i < rbundles.length; i++) {
HashIntMap comps = (HashIntMap)BundleUtil.loadObject(
rbundles[i], BundleUtil.COMPONENTS_PATH);
if (comps == null) {
continue;
}
// create a frame provider for this bundle
FrameProvider fprov = new ResourceBundleProvider(rbundles[i]);
// now create character component instances for each component
// in the serialized table
Iterator iter = comps.keySet().iterator();
while (iter.hasNext()) {
int componentId = ((Integer)iter.next()).intValue();
Tuple info = (Tuple)comps.get(componentId);
createComponent(componentId, (String)info.left,
(String)info.right, fprov);
}
}
} catch (ClassNotFoundException cnfe) {
throw new NestableIOException(
"Internal error unserializing metadata", cnfe);
}
}
// documentation inherited
public CharacterComponent getComponent (int componentId)
throws NoSuchComponentException
{
CharacterComponent component = (CharacterComponent)
_components.get(componentId);
if (component == null) {
throw new NoSuchComponentException(componentId);
}
return component;
}
// documentation inherited
public Iterator enumerateComponentClasses ()
{
return _classes.values().iterator();
}
// documentation inherited
public Iterator enumerateActionSequences ()
{
return _actions.values().iterator();
}
// documentation inherited
public Iterator enumerateComponentIds (final ComponentClass compClass)
{
Predicate classP = new Predicate() {
public boolean evaluate (Object input) {
CharacterComponent comp = (CharacterComponent)
_components.get(input);
return comp.componentClass.equals(compClass);
}
};
return new FilterIterator(_components.keySet().iterator(), classP);
}
/**
* Creates a component and inserts it into the component table.
*/
protected void createComponent (
int componentId, String cclass, String cname, FrameProvider fprov)
{
// look up the component class information
ComponentClass clazz = (ComponentClass)_classes.get(cclass);
if (clazz == null) {
Log.warning("Non-existent component class " +
"[class=" + cclass + ", name=" + cname +
", id=" + componentId + "].");
return;
}
// create the component
CharacterComponent component = new CharacterComponent(
componentId, cname, clazz, fprov);
// cache it
_components.put(componentId, component);
}
/**
* Instances of these provide images to our component action tilesets
* and frames to our components.
*/
protected class ResourceBundleProvider
implements ImageProvider, FrameProvider
{
/**
* Constructs an instance that will obtain image data from the
* specified resource bundle.
*/
public ResourceBundleProvider (ResourceBundle bundle)
{
_bundle = bundle;
}
// documentation inherited
public BufferedImage loadImage (String path)
throws IOException
{
// obtain the image data from our resource bundle
InputStream imgin = _bundle.getResource(path);
if (imgin == null) {
String errmsg = "No such image in resource bundle " +
"[bundle=" + _bundle + ", path=" + path + "].";
throw new FileNotFoundException(errmsg);
}
return ImageIO.read(imgin);
}
// documentation inherited
public MultiFrameImage[] getFrames (
CharacterComponent component, String action)
{
// get the tileset for this action
TileSet aset = (TileSet)_actionSets.get(action);
if (aset == null) {
Log.warning("Can't provide animation frames for undefined " +
"action [action=" + action +
", component=" + component + "].");
return null;
}
// construct the appropriate image path for the component
String path = component.componentClass.name + File.separator +
component.name + File.separator + action +
BundleUtil.IMAGE_EXTENSION;
// clone the tileset with this new image path
try {
TileSet fset = aset.clone(path);
fset.setImageProvider(this);
// and create the necessary multiframe image instances
MultiFrameImage[] frames =
new MultiFrameImage[Sprite.NUM_DIRECTIONS];
for (int i = 0; i < frames.length; i++) {
frames[i] = new TileSetFrameImage(fset, i);
}
return frames;
} catch (CloneNotSupportedException cnse) {
Log.warning("Unable to clone tileset [action=" + action +
", component=" + component +
", set=" + aset + "].");
return null;
}
}
/** The resource bundle from which we obtain image data. */
protected ResourceBundle _bundle;
}
/**
* Used to provide multiframe images using data obtained from a
* tileset.
*/
protected static class TileSetFrameImage implements MultiFrameImage
{
/**
* Constructs a tileset frame image with the specified tileset and
* for the specified orientation.
*/
public TileSetFrameImage (TileSet set, int orientation)
{
_set = set;
_orient = orientation;
}
// documentation inherited
public int getFrameCount ()
{
return _set.getTileCount() / Sprite.NUM_DIRECTIONS;
}
// documentation inherited
public Image getFrame (int index)
{
int tileIndex = _orient * Sprite.NUM_DIRECTIONS + index;
try {
return _set.getTile(tileIndex).getImage();
} catch (NoSuchTileException nste) {
Log.warning("Can't extract action frame [set=" + _set +
", orient=" + _orient + ", index=" + index + "].");
return null;
}
}
/** The tileset from which we obtain our frame images. */
protected TileSet _set;
/** The particular orientation for which we are providing
* frames. */
protected int _orient;
}
/** A table of action sequences. */
protected HashMap _actions;
/** A table of action sequence tilesets. */
protected HashMap _actionSets;
/** A table of component classes. */
protected HashMap _classes;
/** The component table. */
protected HashIntMap _components = new HashIntMap();
}
@@ -0,0 +1,263 @@
//
// $Id: ComponentBundlerTask.java,v 1.1 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.bundle;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.jar.JarOutputStream;
import java.util.jar.JarEntry;
import com.samskivert.io.PersistenceException;
import com.samskivert.util.HashIntMap;
import com.samskivert.util.StringUtil;
import com.samskivert.util.Tuple;
import org.apache.commons.util.StreamUtils;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
import com.threerings.cast.ComponentIDBroker;
import com.threerings.cast.bundle.BundleUtil;
/**
* Ant task for creating component bundles. This task must be configured
* with a number of parameters:
*
* <pre>
* target=[path to bundle file, which will be created]
* mapfile=[path to the component map file which maintains a mapping from
* component id to component class/name, it will be created the
* first time and updated as new components are mapped]
* </pre>
*
* It should also contain one or more nested &lt;fileset&gt; elements that
* enumerate the action tileset images that should be included in the
* component bundle.
*/
public class ComponentBundlerTask extends Task
{
/**
* Sets the path to the bundle file that we'll be creating.
*/
public void setTarget (File target)
{
_target = target;
}
/**
* Sets the path to the component map file that we'll use to obtain
* component ids for the bundled components.
*/
public void setMapfile (File mapfile)
{
_mapfile = mapfile;
}
/**
* Adds a nested &lt;fileset&gt; element.
*/
public void addFileset (FileSet set)
{
_filesets.add(set);
}
/**
* Performs the actual work of the task.
*/
public void execute () throws BuildException
{
// make sure everythign was set up properly
ensureSet(_target, "Must specify the path to the target bundle " +
"file via the 'file' attribute.");
ensureSet(_mapfile, "Must specify the path to the component map " +
"file via the 'mapfile' attribute.");
// load up our component ID broker
ComponentIDBroker broker = loadBroker(_mapfile);
try {
// make sure we can create our bundle file
FileOutputStream fout = new FileOutputStream(_target);
JarOutputStream jout = new JarOutputStream(fout);
// we'll fill this with component id to tuple mappings as we go
HashIntMap mapping = new HashIntMap();
// deal with the filesets
for (int i = 0; i < _filesets.size(); i++) {
FileSet fs = (FileSet)_filesets.get(i);
DirectoryScanner ds = fs.getDirectoryScanner(project);
File fromDir = fs.getDir(project);
String[] srcFiles = ds.getIncludedFiles();
for (int f = 0; f < srcFiles.length; f++) {
File cfile = new File(fromDir, srcFiles[f]);
// determine the [class, name, action] triplet
String[] info = decomposePath(cfile.getPath());
// obtain the component id from our id broker
int cid = broker.getComponentID(info[0], info[1]);
// add a mapping for this component
mapping.put(cid, new Tuple(info[0], info[1]));
// construct the path that'll go in the jar file and
// stuff the component into the jarfile
jout.putNextEntry(new JarEntry(composePath(info)));
StreamUtils.pipe(new FileInputStream(cfile), jout);
}
}
// write our mapping table to the jar file as well
jout.putNextEntry(new JarEntry(BundleUtil.COMPONENTS_PATH));
ObjectOutputStream oout = new ObjectOutputStream(jout);
oout.writeObject(mapping);
oout.flush();
// seal up our jar file
jout.close();
} catch (IOException ioe) {
String errmsg = "Unable to create component bundle.";
throw new BuildException(errmsg, ioe);
} catch (PersistenceException pe) {
String errmsg = "Unable to obtain component ID mapping.";
throw new BuildException(errmsg, pe);
}
// save our updated component ID broker
saveBroker(_mapfile, broker);
}
/**
* Decomposes the full path to a component image into a [class, name,
* action] triplet.
*/
protected String[] decomposePath (String path)
throws BuildException
{
// first strip off the file extension
if (!path.endsWith(BundleUtil.IMAGE_EXTENSION)) {
throw new BuildException("Can't bundle malformed image file " +
"[path=" + path + "].");
}
path = path.substring(0, path.length() -
BundleUtil.IMAGE_EXTENSION.length());
// now decompose the path
String[] components = StringUtil.split(path, File.separator);
int clen = components.length;
if (clen < 3) {
throw new BuildException("Can't bundle malformed image file " +
"[path=" + path + "].");
}
String[] info = new String[3];
System.arraycopy(components, clen-3, info, 0, 3);
return info;
}
/**
* Composes a triplet of [class, name, action] into the path that
* should be supplied to the JarEntry that contains the associated
* image data.
*/
protected String composePath (String[] info)
{
return (info[0] + File.separator + info[1] + File.separator +
info[2] + BundleUtil.IMAGE_EXTENSION);
}
protected void ensureSet (Object value, String errmsg)
throws BuildException
{
if (value == null) {
throw new BuildException(errmsg);
}
}
/**
* Loads the hashmap ID broker from its persistent representation in
* the specified file.
*/
protected HashMapIDBroker loadBroker (File mapfile)
throws BuildException
{
HashMapIDBroker broker;
try {
FileInputStream fin = new FileInputStream(mapfile);
ObjectInputStream oin = new ObjectInputStream(fin);
broker = (HashMapIDBroker)oin.readObject();
} catch (FileNotFoundException fnfe) {
// if the file doesn't yet exist, start with a blank broker
broker = new HashMapIDBroker();
} catch (Exception e) {
throw new BuildException("Error loading component ID map.", e);
}
return broker;
}
/**
* Stores a persistent representation of the supplied hashmap ID
* broker in the specified file.
*/
protected void saveBroker (File mapfile, ComponentIDBroker broker)
throws BuildException
{
try {
FileOutputStream fout = new FileOutputStream(mapfile);
ObjectOutputStream oout = new ObjectOutputStream(fout);
oout.writeObject(broker);
oout.close();
} catch (IOException ioe) {
throw new BuildException("Unable to store component ID map.", ioe);
}
}
protected static class HashMapIDBroker
extends HashMap implements ComponentIDBroker
{
public int getComponentID (String cclass, String cname)
throws PersistenceException
{
Tuple key = new Tuple(cclass, cname);
Integer cid = (Integer)get(key);
if (cid == null) {
cid = new Integer(++_nextCID);
put(key, cid);
}
return cid.intValue();
}
public void commit ()
throws PersistenceException
{
// nothing doing
}
protected int _nextCID = 0;
}
/** The path to our component bundle file. */
protected File _target;
/** The path to our component map file. */
protected File _mapfile;
/** A list of filesets that contain tile images. */
protected ArrayList _filesets = new ArrayList();
}
@@ -0,0 +1,241 @@
//
// $Id: MetadataBundlerTask.java,v 1.1 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.bundle;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.jar.JarOutputStream;
import java.util.jar.JarEntry;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.xml.sax.SAXException;
import org.apache.commons.digester.Digester;
import com.samskivert.util.Tuple;
import com.threerings.media.tile.TileSet;
import com.threerings.media.tools.tile.xml.SwissArmyTileSetRuleSet;
import com.threerings.cast.ActionSequence;
import com.threerings.cast.ComponentClass;
import com.threerings.cast.bundle.BundleUtil;
import com.threerings.cast.tools.xml.ActionRuleSet;
import com.threerings.cast.tools.xml.ClassRuleSet;
/**
* Ant task for creating metadata bundles, which contain action sequence
* and component class definition information. This task must be
* configured with a number of parameters:
*
* <pre>
* actiondef=[path to actions.xml]
* classdef=[path to classes.xml]
* file=[path to metadata bundle, which will be created]
* </pre>
*/
public class MetadataBundlerTask extends Task
{
public void setActiondef (String actiondef)
{
_actionDef = actiondef;
}
public void setClassdef (String classdef)
{
_classDef = classdef;
}
public void setTarget (File target)
{
_target = target;
}
/**
* Performs the actual work of the task.
*/
public void execute ()
throws BuildException
{
// make sure everythign was set up properly
ensureSet(_actionDef, "Must specify the action sequence " +
"definitions via the 'actiondef' attribute.");
ensureSet(_classDef, "Must specify the component class definitions " +
"via the 'classdef' attribute.");
ensureSet(_target, "Must specify the path to the target bundle " +
"file via the 'target' attribute.");
// make sure we can write to the target bundle file
FileOutputStream fout = null;
try {
fout = new FileOutputStream(_target);
// parse our metadata
Tuple tuple = parseActions();
HashMap actions = (HashMap)tuple.left;
HashMap actionSets = (HashMap)tuple.right;
HashMap classes = parseClasses();
// and create the bundle file
JarOutputStream jout = new JarOutputStream(fout);
// throw the serialized actions table in there
JarEntry aentry = new JarEntry(BundleUtil.ACTIONS_PATH);
jout.putNextEntry(aentry);
ObjectOutputStream oout = new ObjectOutputStream(jout);
oout.writeObject(actions);
oout.flush();
// throw the serialized action tilesets table in there
JarEntry sentry = new JarEntry(BundleUtil.ACTION_SETS_PATH);
jout.putNextEntry(sentry);
oout = new ObjectOutputStream(jout);
oout.writeObject(actionSets);
oout.flush();
// throw the serialized classes table in there
JarEntry centry = new JarEntry(BundleUtil.CLASSES_PATH);
jout.putNextEntry(centry);
oout = new ObjectOutputStream(jout);
oout.writeObject(classes);
oout.flush();
// close it up and we're done
jout.close();
} catch (IOException ioe) {
String errmsg = "Unable to output to target bundle " +
"[path=" + _target.getPath() + "].";
throw new BuildException(errmsg, ioe);
} finally {
if (fout != null) {
try {
fout.close();
} catch (IOException ioe) {
// nothing to complain about here
}
}
}
}
protected Tuple parseActions ()
throws BuildException
{
// scan through the XML once to read the actions
Digester digester = new Digester();
ActionRuleSet arules = new ActionRuleSet();
arules.setPrefix("actions");
digester.addRuleSet(arules);
digester.addSetNext("actions" + ActionRuleSet.ACTION_PATH,
"add", Object.class.getName());
ArrayList actlist = parseList(digester, _actionDef);
// now go through a second time reading the tileset info
digester = new Digester();
SwissArmyTileSetRuleSet srules = new SwissArmyTileSetRuleSet();
srules.setPrefix("actions" + ActionRuleSet.ACTION_PATH);
digester.addRuleSet(srules);
digester.addSetNext("actions" + ActionRuleSet.ACTION_PATH +
SwissArmyTileSetRuleSet.TILESET_PATH, "add",
Object.class.getName());
ArrayList setlist = parseList(digester, _actionDef);
// sanity check
if (actlist.size() != setlist.size()) {
String errmsg = "An action is missing its tileset " +
"definition, or something even wackier is going on.";
throw new BuildException(errmsg);
}
// now create our mappings
HashMap actmap = new HashMap();
HashMap setmap = new HashMap();
// create the action map
for (int i = 0; i < setlist.size(); i++) {
TileSet set = (TileSet)setlist.get(i);
ActionSequence act = (ActionSequence)actlist.get(i);
actmap.put(act.name, act);
setmap.put(act.name, set);
}
return new Tuple(actmap, setmap);
}
protected HashMap parseClasses ()
throws BuildException
{
// load up our action and class info
Digester digester = new Digester();
// add our action rule set and a a rule to grab parsed actions
ClassRuleSet crules = new ClassRuleSet();
crules.setPrefix("classes");
digester.addRuleSet(crules);
digester.addSetNext("classes" + ClassRuleSet.CLASS_PATH,
"add", Object.class.getName());
ArrayList setlist = parseList(digester, _classDef);
HashMap clmap = new HashMap();
// create the action map
for (int i = 0; i < setlist.size(); i++) {
ComponentClass cl = (ComponentClass)setlist.get(i);
clmap.put(cl.name, cl);
}
return clmap;
}
protected ArrayList parseList (Digester digester, String path)
throws BuildException
{
try {
FileInputStream fin = new FileInputStream(path);
BufferedInputStream bin = new BufferedInputStream(fin);
ArrayList setlist = new ArrayList();
digester.push(setlist);
// now fire up the digester to parse the stream
try {
digester.parse(bin);
} catch (Exception e) {
throw new BuildException("Parsing error.", e);
}
return setlist;
} catch (FileNotFoundException fnfe) {
String errmsg = "Unable to load metadata definition file " +
"[path=" + path + "].";
throw new BuildException(errmsg, fnfe);
}
}
protected void ensureSet (Object value, String errmsg)
throws BuildException
{
if (value == null) {
throw new BuildException(errmsg);
}
}
protected String _actionDef;
protected String _classDef;
protected File _target;
}
@@ -0,0 +1,85 @@
//
// $Id: ActionRuleSet.java,v 1.1 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.xml;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSetBase;
import com.samskivert.util.StringUtil;
import com.samskivert.xml.CallMethodSpecialRule;
import com.samskivert.xml.SetFieldRule;
import com.samskivert.xml.SetPropertyFieldsRule;
import com.threerings.cast.ActionSequence;
/**
* The action rule set is used to parse the attributes of an action
* sequence instance.
*/
public class ActionRuleSet extends RuleSetBase
{
/** The component of the digester path that is appended by the action
* rule set to match a action. This is appended to whatever prefix is
* provided to the action rule set to obtain the complete XML path to
* a matched action. */
public static final String ACTION_PATH = "/action";
/**
* Instructs the action rule set to match actions with the supplied
* prefix. For example, passing a prefix of <code>actions</code> will
* match actions in the following XML file:
*
* <pre>
* &lt;actions&gt;
* &lt;action&gt;
* // ...
* &lt;/action&gt;
* &lt;/actions&gt;
* </pre>
*
* This must be called before adding the ruleset to a digester.
*/
public void setPrefix (String prefix)
{
_prefix = prefix;
}
/**
* Adds the necessary rules to the digester to parse our actions.
*/
public void addRuleInstances (Digester digester)
{
// this creates the appropriate instance when we encounter a
// <action> tag
digester.addObjectCreate(_prefix + ACTION_PATH,
ActionSequence.class.getName());
// grab the name attribute from the <action> tag
digester.addRule(_prefix + ACTION_PATH,
new SetPropertyFieldsRule(digester));
// grab the other attributes from their respective tags
digester.addRule(_prefix + ACTION_PATH + "/framesPerSecond",
new SetFieldRule(digester, "framesPerSecond"));
CallMethodSpecialRule origin = new CallMethodSpecialRule(digester) {
public void parseAndSet (String bodyText, Object target)
throws Exception {
int[] coords = StringUtil.parseIntArray(bodyText);
if (coords.length != 2) {
String errmsg = "Invalid <origin> specification '" +
bodyText + "'.";
throw new Exception(errmsg);
}
((ActionSequence)target).origin.setLocation(
coords[0], coords[1]);
}
};
digester.addRule(_prefix + ACTION_PATH + "/origin", origin);
}
/** The prefix at which me match our actions. */
protected String _prefix;
}
@@ -0,0 +1,60 @@
//
// $Id: ClassRuleSet.java,v 1.1 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.xml;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSetBase;
import com.samskivert.xml.SetPropertyFieldsRule;
import com.threerings.cast.ComponentClass;
/**
* The class rule set is used to parse the attributes of a component class
* instance.
*/
public class ClassRuleSet extends RuleSetBase
{
/** The component of the digester path that is appended by the class
* rule set to match a component class. This is appended to whatever
* prefix is provided to the class rule set to obtain the complete XML
* path to a matched class. */
public static final String CLASS_PATH = "/class";
/**
* Instructs the class rule set to match component classes with the
* supplied prefix. For example, passing a prefix of
* <code>classes</code> will match classes in the following XML file:
*
* <pre>
* &lt;classes&gt;
* &lt;class .../&gt;
* &lt;/classes&gt;
* </pre>
*
* This must be called before adding the ruleset to a digester.
*/
public void setPrefix (String prefix)
{
_prefix = prefix;
}
/**
* Adds the necessary rules to the digester to parse our classes.
*/
public void addRuleInstances (Digester digester)
{
// this creates the appropriate instance when we encounter a
// <class> tag
digester.addObjectCreate(_prefix + CLASS_PATH,
ComponentClass.class.getName());
// grab the attributes from the <class> tag
digester.addRule(_prefix + CLASS_PATH,
new SetPropertyFieldsRule(digester));
}
/** The prefix at which me match our component classes. */
protected String _prefix;
}
@@ -1,249 +0,0 @@
//
// $Id: XMLComponentParser.java,v 1.5 2001/11/20 04:15:43 mdb Exp $
package com.threerings.cast.tools.xml;
import java.awt.Point;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import org.xml.sax.*;
import com.samskivert.util.*;
import com.samskivert.xml.SimpleParser;
import com.threerings.media.tile.TileSet;
import com.threerings.media.tools.tile.xml.XMLTileSetParser;
import com.threerings.cast.Log;
import com.threerings.cast.ActionSequence;
import com.threerings.cast.ComponentClass;
import com.threerings.cast.CharacterComponent;
/**
* Parses an XML character component description file and populates
* hashtables with {@link ActionSequence}, {@link ComponentClass}, and the
* information necessary to construct {@link CharacterComponent} objects.
*
* <p> Does not currently perform validation on the input XML stream,
* though the parsing code assumes the XML document is well-formed.
*/
public class XMLComponentParser extends SimpleParser
{
// documentation inherited
public void startElement (
String uri, String localName, String qName, Attributes attributes)
{
if (qName.equals("charactercomponents")) {
// save off the image directory
_imagedir = attributes.getValue("imagedir");
// load the tile sets
loadTileSets(attributes.getValue("tilesets"));
} else if (qName.equals("action")) {
// construct and save off the action sequence object
ActionSequence as = getActionSequence(attributes);
_actions.put(as.asid, as);
} else if (qName.equals("class")) {
// construct and save off the component class object
ComponentClass cclass = getComponentClass(attributes);
_classes.put(cclass.clid, cclass);
} else if (qName.equals("component")) {
// construct and save off the character component
CharacterComponent component = getComponent(attributes);
_components.put(component.getId(), component);
}
}
/**
* Loads the component descriptions in the given file into the
* given component data hashtables.
*/
public void loadComponents (String file, HashIntMap actions,
HashIntMap classes, HashIntMap components)
throws IOException
{
// save off hashtables for reference while parsing
_actions = actions;
_classes = classes;
_components = components;
// clear out remnants of any previous parsing antics
_imagedir = null;
_tilesets.clear();
// parse the file
parseFile(file);
}
/**
* Returns the image directory the component tile images reside
* within.
*/
public String getImageDir ()
{
return _imagedir;
}
/**
* Loads the tile sets in the XML file at the given path into the
* tile sets available for reference by the action sequences.
*/
protected void loadTileSets (String path)
{
// make sure we have a reasonable path
if (path == null) {
Log.warning("Null component tile set description file path.");
return;
}
// parse the tile set description file
XMLTileSetParser p = new XMLTileSetParser();
try {
p.loadTileSets(path, _tilesets);
} catch (IOException e) {
Log.warning("Exception loading component tile set descriptions " +
"[path=" + path + "].");
}
}
/**
* Returns a new action sequence object as described by the given
* attributes.
*/
protected ActionSequence getActionSequence (Attributes attrs)
{
ActionSequence as = new ActionSequence();
as.asid = parseInt(attrs.getValue("asid"));
as.name = attrs.getValue("name");
as.fileid = attrs.getValue("fileid");
String tileset = attrs.getValue("tileset");
as.tileset = (TileSet)_tilesets.get(tileset);
if (as.tileset == null) {
Log.warning("Action sequence references non-existent " +
"tile set [asid=" + as.asid +
", tileset=" + tileset + "].");
}
as.fps = parseInt(attrs.getValue("fps"));
parsePoint(attrs.getValue("origin"), as.origin);
return as;
}
/**
* Returns a new component class object as described by the given
* attributes.
*/
protected ComponentClass getComponentClass (Attributes attrs)
{
ComponentClass cclass = new ComponentClass();
cclass.clid = parseInt(attrs.getValue("clid"));
cclass.name = attrs.getValue("name");
cclass.render = parseInt(attrs.getValue("render"));
return cclass;
}
/**
* Returns a new character component object as described by the
* given attributes.
*/
protected CharacterComponent getComponent (Attributes attrs)
{
// retrieve the component attributes
int cid = parseInt(attrs.getValue("cid"));
String fileid = attrs.getValue("fileid");
String val = attrs.getValue("asids");
int asids[] = StringUtil.parseIntArray(val);
int clid = parseInt(attrs.getValue("clid"));
ComponentClass cclass = (ComponentClass)_classes.get(clid);
// gather the array of relevant action sequences
ActionSequence seqs[] = getActionSequences(asids);
// construct the component sans frames for now
CharacterComponent component =
new CharacterComponent(cid, fileid, seqs, cclass);
// warn if the component has notably invalid attributes
validateComponent(cid, asids, clid);
return component;
}
/**
* Outputs a warning regarding the given component id if the given
* action sequence ids and component class id for that component
* don't exist.
*/
protected void validateComponent (int cid, int asids[], int clid)
{
// check the action sequence ids
for (int ii = 0; ii < asids.length; ii++) {
int asid = asids[ii];
if (_actions.get(asid) == null) {
Log.warning(
"Component references non-existent action sequence " +
"[cid=" + cid + ", asid=" + asid + "].");
}
}
// check the class id
if (_classes.get(clid) == null) {
Log.warning("Component references non-existent class " +
"[cid=" + cid + ", clid=" + clid + "].");
}
}
/**
* Returns an array of action sequence objects corresponding to
* the action sequence ids in the given array.
*/
protected ActionSequence[] getActionSequences (int asids[])
{
// sort the action sequence ids for better regularity
Arrays.sort(asids);
// create and populate the array
ActionSequence[] seqs = new ActionSequence[asids.length];
for (int ii = 0; ii < asids.length; ii++) {
seqs[ii] = (ActionSequence)_actions.get(asids[ii]);
}
return seqs;
}
/**
* Converts a string containing values as (x, y) into the
* corresponding integer values and populates the given point
* object.
*
* @param str the point values in string format.
* @param point the point object to populate.
*/
protected void parsePoint (String str, Point point)
{
int vals[] = StringUtil.parseIntArray(str);
point.setLocation(vals[0], vals[1]);
}
/** The image directory containing the component image files. */
protected String _imagedir;
/** The hashtable of component tile sets. */
protected HashMap _tilesets = new HashMap();
/** The hashtable of action sequences gathered while parsing. */
protected HashIntMap _actions;
/** The hashtable of component classes gathered while parsing. */
protected HashIntMap _classes;
/** The hashtable of character components gathered while parsing. */
protected HashIntMap _components;
}
@@ -1,155 +0,0 @@
//
// $Id: XMLComponentRepository.java,v 1.7 2001/11/18 04:09:21 mdb Exp $
package com.threerings.cast.tools.xml;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import com.samskivert.util.Config;
import com.samskivert.util.HashIntMap;
import com.threerings.cast.*;
import com.threerings.cast.util.TileUtil;
import com.threerings.media.ImageManager;
import com.threerings.media.tile.TileManager;
import com.threerings.miso.Log;
import com.threerings.miso.util.MisoUtil;
/**
* The xml component repository provides access to character
* components obtained from component descriptions stored in an XML
* file.
*/
public class XMLComponentRepository implements ComponentRepository
{
/**
* Constructs an xml component repository.
*/
public XMLComponentRepository (Config config)
{
// load component types and components
String file = config.getValue(COMPONENTS_KEY, DEFAULT_COMPONENTS);
try {
XMLComponentParser p = new XMLComponentParser();
p.loadComponents(file, _actions, _classes, _components);
_imagedir = p.getImageDir();
} catch (IOException ioe) {
Log.warning("Exception loading component descriptions " +
"[ioe=" + ioe + "].");
}
}
// documentation inherited
public CharacterComponent getComponent (int cid)
throws NoSuchComponentException
{
// get the component information
CharacterComponent c = (CharacterComponent)_components.get(cid);
if (c == null) {
throw new NoSuchComponentException(cid);
}
// get the character animation frames
c.setFrames(TileUtil.getComponentFrames(_imagedir, c));
return c;
}
// documentation inherited
public Iterator enumerateComponentClasses ()
{
return Collections.unmodifiableMap(_classes).values().iterator();
}
// documentation inherited
public Iterator enumerateComponentsByClass (int clid)
{
return new ComponentIterator(clid);
}
/**
* Iterates over all components of a specified component type, and
* optionally a specified component class, in the component
* hashtable.
*/
protected class ComponentIterator implements Iterator
{
/**
* Constructs an iterator that iterates over all components of
* the specified component class.
*/
public ComponentIterator (int clid)
{
_clid = clid;
_iter = _components.keys();
advance();
}
public boolean hasNext ()
{
return (_next != null);
}
public Object next ()
{
Object next = _next;
advance();
return next;
}
public void remove ()
{
throw new UnsupportedOperationException();
}
protected void advance ()
{
while (_iter.hasNext()) {
Integer cid = (Integer)_iter.next();
CharacterComponent c =
(CharacterComponent)_components.get(cid);
if (c.getComponentClass().clid == _clid) {
_next = cid;
return;
}
}
_next = null;
}
/** The component class id for inclusion in the iterator. */
protected int _clid;
/** The next character component associated with this
* iterator, or null if no more exist. */
protected Object _next;
/** The iterator over all components in the repository. */
protected Iterator _iter;
}
/** The config key for the character description file. */
protected static final String COMPONENTS_KEY =
MisoUtil.CONFIG_KEY + ".components";
/** The default character description file. */
protected static final String DEFAULT_COMPONENTS =
"rsrc/config/miso/components.xml";
/** The image directory containing the component image files. */
protected String _imagedir;
/** The hashtable of component types. */
protected HashIntMap _actions = new HashIntMap();
/** The hashtable of component classes. */
protected HashIntMap _classes = new HashIntMap();
/** The hashtable of character components. */
protected HashIntMap _components = new HashIntMap();
}
+100 -116
View File
@@ -1,16 +1,17 @@
//
// $Id: TileUtil.java,v 1.3 2001/11/18 04:09:21 mdb Exp $
// $Id: TileUtil.java,v 1.4 2001/11/27 08:09:35 mdb 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.media.sprite.MultiFrameImage;
import com.threerings.media.sprite.Sprite;
// import com.threerings.media.tile.*;
import com.threerings.cast.Log;
import com.threerings.cast.*;
// import com.threerings.cast.*;
/**
* Miscellaneous tile-related utility functions.
@@ -18,126 +19,105 @@ import com.threerings.cast.*;
public class TileUtil
{
/**
* Renders each of the given <code>src</code> component frames
* into the corresponding frames of <code>dest</code>, allocating
* blank image frames for <code>dest</code> if none yet exist.
* Renders each of the given <code>src</code> component frames into
* the corresponding frames of <code>dest</code>, allocating blank
* image frames for <code>dest</code> if none yet exist.
*
* @throws IllegalArgumentException if the frame count of the source
* and destination images don't match.
*/
public static void compositeFrames (
MultiFrameImage[][] dest, MultiFrameImage[][] src)
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]);
}
for (int orient = 0; orient < Sprite.NUM_DIRECTIONS; orient++) {
MultiFrameImage sframes = src[orient];
MultiFrameImage dframes = dest[orient];
// slap the images together
compositeFrames(dest[ii][orient], src[ii][orient]);
// create blank destination frames if needed
if (dframes == null) {
dest[orient] = new BlankFrameImage(sframes);
}
// sanity check
int dsize = dframes.getFrameCount();
int ssize = sframes.getFrameCount();
if (dsize != ssize) {
String errmsg = "Can't composite images with inequal " +
"frame counts [dest=" + dsize + ", src=" + ssize + "].";
throw new IllegalArgumentException(errmsg);
}
// slap the images together
for (int ii = 0; ii < dsize; ii++) {
Image dimg = dframes.getFrame(ii);
Image simg = sframes.getFrame(ii);
dimg.getGraphics().drawImage(simg, 0, 0, null);
}
}
}
/**
* 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 <code>src</code>.
*/
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];
/**
* 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];
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;
// 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;
// }
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.getTileCount() / Sprite.NUM_DIRECTIONS;
// get the number of frames of animation
int frameCount = tset.getTileCount() / 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.getTileImage(idx);
// }
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.getTileImage(idx);
}
// // create the multi frame image
// frames[ii][dir] = new MultiFrameImageImpl(imgs);
// }
// }
// create the multi frame image
frames[ii][dir] = new MultiFrameImageImpl(imgs);
}
}
// } catch (TileException te) {
// Log.warning("Exception retrieving character images " +
// "[te=" + te + "].");
// return null;
// }
} catch (TileException te) {
Log.warning("Exception retrieving character images " +
"[te=" + te + "].");
return null;
}
// return frames;
// }
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 <code>src</code> frames into the
* corresponding frames of <code>dest</code>.
*/
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);
}
}
// /**
// * 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;
// }
/**
* An implementation of the {@link MultiFrameImage} interface that
@@ -147,31 +127,35 @@ public class TileUtil
protected static class BlankFrameImage implements MultiFrameImage
{
/**
* Constructs a blank frame image.
* Constructs a blank frame image based on the dimensions of
* template multi-frame image.
*/
public BlankFrameImage (int width, int height, int frameCount)
public BlankFrameImage (MultiFrameImage template)
{
_imgs = new Image[frameCount];
for (int ii = 0; ii < frameCount; ii++) {
_imgs[ii] = new BufferedImage(
width, height, BufferedImage.TYPE_INT_ARGB);
int frameCount = template.getFrameCount();
_images = new Image[frameCount];
for (int i = 0; i < frameCount; i++) {
Image img = template.getFrame(i);
_images[i] = new BufferedImage(img.getWidth(null),
img.getHeight(null),
BufferedImage.TYPE_INT_ARGB);
}
}
// documentation inherited
public int getFrameCount ()
{
return _imgs.length;
return _images.length;
}
// documentation inherited
public Image getFrame (int index)
{
return _imgs[index];
return _images[index];
}
/** The frame images. */
protected Image _imgs[];
protected Image[] _images;
}
/** The image file name suffix appended to component image file names. */
@@ -1,5 +1,5 @@
//
// $Id: ResourceManager.java,v 1.5 2001/11/26 23:48:04 mdb Exp $
// $Id: ResourceManager.java,v 1.6 2001/11/27 08:09:35 mdb Exp $
package com.threerings.resource;
@@ -186,7 +186,7 @@ public class ResourceManager
while (tok.hasMoreTokens()) {
// obtain the path and fully qualify it
String path = tok.nextToken();
String path = tok.nextToken().trim();
if (!path.startsWith(File.separator)) {
path = appRoot + path;
}