From 3ea91cdfddcee53dfb82054f6107473a168e93eb Mon Sep 17 00:00:00 2001 From: Walter Korman Date: Tue, 30 Oct 2001 16:16:01 +0000 Subject: [PATCH] More work on character components. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@579 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../threerings/cast/CharacterComponent.java | 37 +++- .../threerings/cast/CharacterDescriptor.java | 24 ++- .../com/threerings/cast/CharacterManager.java | 170 ++++++++++++++---- .../com/threerings/cast/ComponentClass.java | 70 ++++++++ .../threerings/cast/ComponentRepository.java | 25 ++- .../cast/NoSuchComponentTypeException.java | 24 --- src/java/com/threerings/cast/TileUtil.java | 102 ++++++++++- .../threerings/cast/builder/BuilderPanel.java | 83 +++++++++ .../cast/builder/ComponentEditor.java | 82 +++++++++ .../cast/builder/ComponentPanel.java | 126 +++++++++++++ .../threerings/cast/builder/SpritePanel.java | 89 +++++++++ .../cast/tools/xml/XMLComponentParser.java | 52 ++++-- .../tools/xml/XMLComponentRepository.java | 114 ++++++++---- .../threerings/miso/client/DirtyItemList.java | 60 ++++--- .../com/threerings/miso/util/MisoUtil.java | 39 +++- .../com/threerings/cast/builder/TestApp.java | 77 ++++++++ .../threerings/cast/builder/TestFrame.java | 25 +++ .../com/threerings/miso/viewer/ViewerApp.java | 27 +-- .../miso/viewer/ViewerSceneViewPanel.java | 64 +++++-- 19 files changed, 1099 insertions(+), 191 deletions(-) create mode 100644 src/java/com/threerings/cast/ComponentClass.java delete mode 100644 src/java/com/threerings/cast/NoSuchComponentTypeException.java create mode 100644 src/java/com/threerings/cast/builder/BuilderPanel.java create mode 100644 src/java/com/threerings/cast/builder/ComponentEditor.java create mode 100644 src/java/com/threerings/cast/builder/ComponentPanel.java create mode 100644 src/java/com/threerings/cast/builder/SpritePanel.java create mode 100644 tests/src/java/com/threerings/cast/builder/TestApp.java create mode 100644 tests/src/java/com/threerings/cast/builder/TestFrame.java diff --git a/src/java/com/threerings/cast/CharacterComponent.java b/src/java/com/threerings/cast/CharacterComponent.java index 8195d4264..7cebb5627 100644 --- a/src/java/com/threerings/cast/CharacterComponent.java +++ b/src/java/com/threerings/cast/CharacterComponent.java @@ -1,9 +1,10 @@ // -// $Id: CharacterComponent.java,v 1.1 2001/10/26 01:17:21 shaper Exp $ +// $Id: CharacterComponent.java,v 1.2 2001/10/30 16:16:01 shaper Exp $ package com.threerings.cast; import com.threerings.media.sprite.MultiFrameImage; +import com.threerings.media.sprite.Sprite; /** * The character component represents a single component that can be @@ -17,14 +18,16 @@ public class CharacterComponent /** * Constructs a character component. */ - public CharacterComponent (ComponentType type, int cid, - ComponentFrames frames) + public CharacterComponent ( + ComponentType type, ComponentClass cclass, int cid, + ComponentFrames frames) { _type = type; + _cclass = cclass; _cid = cid; _frames = frames; } - + /** * Returns the unique component identifier. */ @@ -42,20 +45,28 @@ public class CharacterComponent } /** - * Returns the {@link ComponentType} object describing the base - * component type information associated with this component. + * Returns the component type associated with this component. */ public ComponentType getType () { return _type; } + /** + * Returns the component class associated with this component. + */ + public ComponentClass getComponentClass () + { + return _cclass; + } + /** * Returns a string representation of this character component. */ public String toString () { - return "[cid=" + _cid + ", type=" + _type + "]"; + return "[cid=" + _cid + ", clid=" + _cclass.clid + + ", type=" + _type + "]"; } /** @@ -70,6 +81,15 @@ public class CharacterComponent /** The walking animations in each orientation. */ public MultiFrameImage walk[]; + + /** + * Constructs a component frames object. + */ + public ComponentFrames () + { + stand = new MultiFrameImage[Sprite.NUM_DIRECTIONS]; + walk = new MultiFrameImage[Sprite.NUM_DIRECTIONS]; + } } /** The unique character component identifier. */ @@ -78,6 +98,9 @@ public class CharacterComponent /** The animation frames. */ protected ComponentFrames _frames; + /** The component class. */ + protected ComponentClass _cclass; + /** The character component type. */ protected ComponentType _type; } diff --git a/src/java/com/threerings/cast/CharacterDescriptor.java b/src/java/com/threerings/cast/CharacterDescriptor.java index 63b932e1c..f326c06c1 100644 --- a/src/java/com/threerings/cast/CharacterDescriptor.java +++ b/src/java/com/threerings/cast/CharacterDescriptor.java @@ -1,22 +1,22 @@ // -// $Id: CharacterDescriptor.java,v 1.1 2001/10/26 01:17:21 shaper Exp $ +// $Id: CharacterDescriptor.java,v 1.2 2001/10/30 16:16:01 shaper Exp $ package com.threerings.cast; import com.samskivert.util.StringUtil; /** - * The character descriptor object contains all necessary information - * on the character components that are composited together to create - * a character image. + * The character descriptor object details the components that are + * pieced together to create a single character image. */ public class CharacterDescriptor { /** * Constructs the character descriptor. */ - public CharacterDescriptor (int components[]) + public CharacterDescriptor (ComponentType type, int components[]) { + _type = type; _components = components; } @@ -29,16 +29,28 @@ public class CharacterDescriptor return _components; } + /** + * Returns the {@link ComponentType} of the character's components. + */ + public ComponentType getType () + { + return _type; + } + /** * Returns a string representation of this character descriptor. */ public String toString () { StringBuffer buf = new StringBuffer(); - buf.append("[").append(StringUtil.toString(_components)); + buf.append("[type=").append(_type); + buf.append(StringUtil.toString(_components)); return buf.append("]").toString(); } /** The array of component identifiers. */ protected int _components[]; + + /** The component type of the character's components. */ + protected ComponentType _type; } diff --git a/src/java/com/threerings/cast/CharacterManager.java b/src/java/com/threerings/cast/CharacterManager.java index 4c189dc93..64f8de3dd 100644 --- a/src/java/com/threerings/cast/CharacterManager.java +++ b/src/java/com/threerings/cast/CharacterManager.java @@ -1,15 +1,14 @@ // -// $Id: CharacterManager.java,v 1.5 2001/10/26 01:17:21 shaper Exp $ +// $Id: CharacterManager.java,v 1.6 2001/10/30 16:16:01 shaper Exp $ package com.threerings.cast; -import java.awt.Point; -import java.io.IOException; +import java.util.*; -import com.threerings.media.tile.TileManager; +import com.samskivert.util.CollectionUtil; import com.threerings.cast.Log; -import com.threerings.cast.TileUtil; +import com.threerings.cast.CharacterComponent.ComponentFrames; /** * The character manager provides facilities for constructing sprites @@ -20,11 +19,13 @@ public class CharacterManager /** * Constructs the character manager. */ - public CharacterManager (TileManager tilemgr, ComponentRepository repo) + public CharacterManager (ComponentRepository repo) { - // save off our objects - _tilemgr = tilemgr; + // keep this around _repo = repo; + + // determine component class render order + _renderRank = getRenderRank(); } /** @@ -36,51 +37,81 @@ public class CharacterManager */ public CharacterSprite getCharacter (CharacterDescriptor desc) { - // get the list of component ids + long start = System.currentTimeMillis(); + + // get the array of component ids of each class int components[] = desc.getComponents(); - // TODO: here is where we'd iterate through all components - // building up the full composite image of the sprite in each - // orientation, standing and walking. we punt for now, but - // we'll revisit this soon enough. - if (components.length == 0 || components.length > 1) { + if (components.length == 0) { Log.warning("Invalid number of components " + - " [size=" + components.length + "]."); + "[size=" + components.length + "]."); return null; } - CharacterComponent comp; - try { - // as noted above, no compositing for now. note that when - // we do composite, we probably will want to make sure all - // components share a compatible component type. - comp = _repo.getComponent(components[0]); - } catch (Exception e) { - Log.warning("Exception retrieving character component " + - "[e=" + e + "]."); + // create the composite character image + ComponentFrames frames = createCompositeFrames(desc); + if (frames == null) { return null; } // instantiate the character sprite - CharacterSprite sprite; - try { - sprite = (CharacterSprite)_charClass.newInstance(); - } catch (Exception e) { - Log.warning("Failed to instantiate character sprite " + - "[e=" + e + "]."); - Log.logStackTrace(e); + CharacterSprite sprite = createSprite(); + if (sprite == null) { return null; } // populate the character sprite with its attributes - ComponentType ctype = comp.getType(); - sprite.setFrames(comp.getFrames()); + ComponentType ctype = desc.getType(); + sprite.setFrames(frames); sprite.setFrameRate(ctype.fps); sprite.setOrigin(ctype.origin.x, ctype.origin.y); + long end = System.currentTimeMillis(); + Log.info("Generated character sprite [ms=" + (end - start) + "]."); + return sprite; } + /** + * Returns an iterator over the {@link ComponentType} objects + * representing all available character component type + * identifiers. + */ + public Iterator enumerateComponentTypes () + { + return _repo.enumerateComponentTypes(); + } + + /** + * Returns an iterator over the Integer objects + * representing all available character component identifiers for + * the given character component type identifier. + */ + public Iterator enumerateComponentsByType (int ctid) + { + return _repo.enumerateComponentsByType(ctid); + } + + /** + * Returns an iterator over the {@link ComponentClass} objects + * representing all available character component class + * identifiers. + */ + public Iterator enumerateComponentClasses () + { + return _repo.enumerateComponentClasses(); + } + + /** + * Returns an iterator over the Integer objects + * representing all available character component identifiers for + * the given character component type and class identifiers. + */ + public Iterator enumerateComponentsByClass (int ctid, int clid) + { + return _repo.enumerateComponentsByClass(ctid, clid); + } + /** * Instructs the character manager to construct instances of this * derived class of CharacterSprite. @@ -99,8 +130,77 @@ public class CharacterManager _charClass = charClass; } - /** The tile manager. */ - protected TileManager _tilemgr; + /** + * Returns a {@link CharacterComponent.ComponentFrames} object + * containing the fully composited images detailed in the given + * character descriptor. + */ + protected ComponentFrames createCompositeFrames (CharacterDescriptor desc) + { + int components[] = desc.getComponents(); + ComponentFrames frames = null; + + for (int ii = 0; ii < _renderRank.length; ii++) { + try { + int clidx = _renderRank[ii].clid; + + // get the component to render + CharacterComponent c = _repo.getComponent(components[clidx]); + + // TODO: fix this to deal with frames of varying dimensions + if (frames == null) { + int fcount = desc.getType().frameCount; + frames = TileUtil.createBlankFrames(c.getFrames(), fcount); + } + + // render the frames onto the composite frames + TileUtil.compositeFrames(frames, c.getFrames()); + + } catch (NoSuchComponentException nsce) { + Log.warning("Exception compositing character components " + + "[nsce=" + nsce + "]."); + return null; + } + } + + return frames; + } + + /** + * Returns a new {@link CharacterSprite} of the character 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 + "]."); + Log.logStackTrace(e); + return null; + } + } + + /** + * Returns an array of {@link ComponentClass} objects sorted into + * the appropriate rendering order as specified by each component + * class object. + */ + protected ComponentClass[] getRenderRank () + { + 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; + } + + /** The order in which to render component classes. */ + protected ComponentClass _renderRank[]; /** The component repository. */ protected ComponentRepository _repo; diff --git a/src/java/com/threerings/cast/ComponentClass.java b/src/java/com/threerings/cast/ComponentClass.java new file mode 100644 index 000000000..72117b56a --- /dev/null +++ b/src/java/com/threerings/cast/ComponentClass.java @@ -0,0 +1,70 @@ +// +// $Id: ComponentClass.java,v 1.1 2001/10/30 16:16:01 shaper Exp $ + +package com.threerings.cast; + +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". + */ +public class ComponentClass +{ + /** 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; + + /** + * Returns a string representation of this component class. + */ + public String toString () + { + return "[clid=" + clid + ", name=" + name + "]"; + } + + /** + * The comparator used to sort component class objects 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 + { + // documentation inherited + public int compare (Object a, Object b) + { + if (!(a instanceof ComponentClass) || + !(b instanceof ComponentClass)) { + 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; + } + } + + // documentation inherited + public boolean equals (Object obj) + { + return (obj == this); + } + } +} diff --git a/src/java/com/threerings/cast/ComponentRepository.java b/src/java/com/threerings/cast/ComponentRepository.java index 2e9ccd0ce..f0be4736f 100644 --- a/src/java/com/threerings/cast/ComponentRepository.java +++ b/src/java/com/threerings/cast/ComponentRepository.java @@ -1,5 +1,5 @@ // -// $Id: ComponentRepository.java,v 1.1 2001/10/26 01:17:21 shaper Exp $ +// $Id: ComponentRepository.java,v 1.2 2001/10/30 16:16:01 shaper Exp $ package com.threerings.cast; @@ -17,20 +17,31 @@ public interface ComponentRepository * unique component identifier. */ public CharacterComponent getComponent (int cid) - throws NoSuchComponentException, NoSuchComponentTypeException; + throws NoSuchComponentException; + + /** + * Returns an iterator over the {@link ComponentType} objects + * representing all available character component types. + */ + public Iterator enumerateComponentTypes (); /** * Returns an iterator over the Integer objects * representing all available character component identifiers for * the given character component type identifier. */ - public Iterator enumerateComponents (int ctid) - throws NoSuchComponentTypeException; + public Iterator enumerateComponentsByType (int ctid); + + /** + * Returns an iterator over the {@link ComponentClass} objects + * representing all available character component classes. + */ + public Iterator enumerateComponentClasses (); /** * Returns an iterator over the Integer objects - * representing all available character component type - * identifiers. + * representing all available character component identifiers for + * the given character component type and class identifiers. */ - public Iterator enumerateComponentTypes (); + public Iterator enumerateComponentsByClass (int ctid, int clid); } diff --git a/src/java/com/threerings/cast/NoSuchComponentTypeException.java b/src/java/com/threerings/cast/NoSuchComponentTypeException.java deleted file mode 100644 index 1b44a6523..000000000 --- a/src/java/com/threerings/cast/NoSuchComponentTypeException.java +++ /dev/null @@ -1,24 +0,0 @@ -// -// $Id: NoSuchComponentTypeException.java,v 1.1 2001/10/26 01:17:21 shaper Exp $ - -package com.threerings.cast; - -/** - * Thrown when an attempt is made to reference a non-existent - * component type in the component repository. - */ -public class NoSuchComponentTypeException extends Exception -{ - public NoSuchComponentTypeException (int ctid) - { - super("No such component type [ctid=" + ctid + "]"); - _ctid = ctid; - } - - public int getTypeId () - { - return _ctid; - } - - protected int _ctid; -} diff --git a/src/java/com/threerings/cast/TileUtil.java b/src/java/com/threerings/cast/TileUtil.java index 0200ceeaa..c51a25b0d 100644 --- a/src/java/com/threerings/cast/TileUtil.java +++ b/src/java/com/threerings/cast/TileUtil.java @@ -1,9 +1,10 @@ // -// $Id: TileUtil.java,v 1.2 2001/10/26 01:40:22 mdb Exp $ +// $Id: TileUtil.java,v 1.3 2001/10/30 16:16:01 shaper Exp $ package com.threerings.cast; import java.awt.Image; +import java.awt.image.BufferedImage; import com.threerings.media.sprite.*; import com.threerings.media.tile.*; @@ -16,6 +17,46 @@ import com.threerings.cast.CharacterComponent.ComponentFrames; */ public class TileUtil { + /** + * Renders each of the given src component frames + * into the corresponding frames of dest. + */ + public static void compositeFrames ( + ComponentFrames dest, ComponentFrames src) + { + for (int ii = 0; ii < Sprite.NUM_DIRECTIONS; ii++) { + // composite the standing frames + compositeFrames(dest.stand[ii], src.stand[ii]); + + // composite the walking frames + compositeFrames(dest.walk[ii], src.walk[ii]); + } + } + + /** + * Constructs and returns a new {@link + * CharacterComponent.ComponentFrames} object with empty images + * for all of its frames. + */ + public static ComponentFrames createBlankFrames ( + ComponentFrames src, int frameCount) + { + ComponentFrames frames = new ComponentFrames(); + + // for now, just use the first frame from the source image to + // get the width and height for all of the blank frames + Image img = src.walk[0].getFrame(0); + int wid = img.getWidth(null), hei = img.getHeight(null); + + // allocate the blank frame images + for (int ii = 0; ii < Sprite.NUM_DIRECTIONS; ii++) { + frames.stand[ii] = new BlankFrameImage(wid, hei, 1); + frames.walk[ii] = new BlankFrameImage(wid, hei, frameCount); + } + + return frames; + } + /** * Returns a {@link CharacterComponent.ComponentFrames} object * containing the frames of animation used to render the sprite while @@ -33,8 +74,6 @@ public class TileUtil TileManager tilemgr, int tsid, int frameCount) { ComponentFrames frames = new ComponentFrames(); - frames.walk = new MultiFrameImage[Sprite.NUM_DIRECTIONS]; - frames.stand = new MultiFrameImage[Sprite.NUM_DIRECTIONS]; try { for (int ii = 0; ii < Sprite.NUM_DIRECTIONS; ii++) { @@ -63,4 +102,61 @@ public class TileUtil return frames; } + + /** + * 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 multi frame 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[]; + } } diff --git a/src/java/com/threerings/cast/builder/BuilderPanel.java b/src/java/com/threerings/cast/builder/BuilderPanel.java new file mode 100644 index 000000000..d9f48b342 --- /dev/null +++ b/src/java/com/threerings/cast/builder/BuilderPanel.java @@ -0,0 +1,83 @@ +// +// $Id: BuilderPanel.java,v 1.1 2001/10/30 16:16:01 shaper Exp $ + +package com.threerings.cast.builder; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Iterator; + +import javax.swing.*; + +import com.samskivert.swing.*; + +import com.threerings.cast.*; + +/** + * 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 implements ActionListener +{ + /** + * Constructs the builder panel. + */ + public BuilderPanel (CharacterManager charmgr) + { + _charmgr = charmgr; + + setLayout(new VGroupLayout()); + + // give ourselves a wee bit of a border + setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + GroupLayout gl = new HGroupLayout(GroupLayout.STRETCH); + gl.setOffAxisPolicy(GroupLayout.STRETCH); + + // create the component selection and sprite display panels + JPanel sub = new JPanel(gl); + ComponentType ctype = getComponentType(); + sub.add(_comppanel = new ComponentPanel(_charmgr, ctype)); + sub.add(_spritepanel = new SpritePanel()); + + add(sub); + + // create the "OK" button + JButton ok = new JButton("OK"); + ok.addActionListener(this); + ok.setActionCommand("ok"); + add(ok); + } + + public void actionPerformed (ActionEvent e) + { + String cmd = e.getActionCommand(); + if (cmd.equals("ok")) { + CharacterDescriptor desc = _comppanel.getDescriptor(); + CharacterSprite sprite = _charmgr.getCharacter(desc); + _spritepanel.setSprite(sprite); + } else { + Log.warning("Unknown action command [cmd=" + cmd + "]."); + } + } + + protected ComponentType getComponentType () + { + ComponentType ctype = null; + Iterator types = _charmgr.enumerateComponentTypes(); + // for now, fixedly choose the first component type + // TODO: fix this hack + return (ComponentType)types.next(); + } + + /** The component panel that displays components available for + * selection. */ + protected ComponentPanel _comppanel; + + /** The sprite panel that displays the composited character sprite. */ + protected SpritePanel _spritepanel; + + /** The character manager. */ + protected CharacterManager _charmgr; +} diff --git a/src/java/com/threerings/cast/builder/ComponentEditor.java b/src/java/com/threerings/cast/builder/ComponentEditor.java new file mode 100644 index 000000000..e470373e9 --- /dev/null +++ b/src/java/com/threerings/cast/builder/ComponentEditor.java @@ -0,0 +1,82 @@ +// +// $Id: ComponentEditor.java,v 1.1 2001/10/30 16:16:01 shaper Exp $ + +package com.threerings.cast.builder; + +import java.util.List; + +import javax.swing.*; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import com.samskivert.swing.*; +import com.samskivert.util.StringUtil; + +import com.threerings.cast.Log; +import com.threerings.cast.ComponentClass; + +/** + * The component editor displays a label and a slider that allow the + * user to select the desired component from a list of components of + * the same class. + */ +public class ComponentEditor extends JPanel implements ChangeListener +{ + /** + * Constructs a component editor. + */ + public ComponentEditor (ComponentClass cclass, List components) + { + _components = components; + + // Log.info("Creating editor [class=" + cclass + + // ", components=" + StringUtil.toString(components) + "]."); + + GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH); + gl.setOffAxisPolicy(GroupLayout.STRETCH); + setLayout(gl); + + gl = new HGroupLayout(); + gl.setJustification(GroupLayout.LEFT); + JPanel sub = new JPanel(gl); + + sub.add(new JLabel(cclass.name + ": ")); + sub.add(_clabel = new JLabel("0")); + + add(sub); + + int max = components.size() - 1; + _slider = new JSlider(JSlider.HORIZONTAL, 0, max, 0); + _slider.setSnapToTicks(true); + _slider.addChangeListener(this); + add(_slider); + } + + /** + * Returns the selected component id. + */ + public int getSelectedComponent () + { + int idx = _slider.getModel().getValue(); + return ((Integer)_components.get(idx)).intValue(); + } + + // documentation inherited + public void stateChanged (ChangeEvent e) + { + JSlider source = (JSlider)e.getSource(); + if (!source.getValueIsAdjusting()) { + _clabel.setText(Integer.toString(source.getValue())); + } + } + + /** The components selectable via this editor. */ + protected List _components; + + /** The slider allowing the user to select a component. */ + protected JSlider _slider; + + /** The label denoting the currently selected component index. */ + protected JLabel _clabel; +} diff --git a/src/java/com/threerings/cast/builder/ComponentPanel.java b/src/java/com/threerings/cast/builder/ComponentPanel.java new file mode 100644 index 000000000..4eabacd41 --- /dev/null +++ b/src/java/com/threerings/cast/builder/ComponentPanel.java @@ -0,0 +1,126 @@ +// +// $Id: ComponentPanel.java,v 1.1 2001/10/30 16:16:01 shaper Exp $ + +package com.threerings.cast.builder; + +import java.util.*; + +import javax.swing.*; +import javax.swing.border.Border; + +import com.samskivert.swing.*; +import com.samskivert.util.*; + +import com.threerings.cast.Log; +import com.threerings.cast.*; + +/** + * The component panel displays the available components for a + * particular component type, allows the user to choose a set of + * components for compositing, and makes available a {@link + * CharacterDescriptor} suitable for passing to {@link + * CharacterManager#getCharacter} to create a character built from the + * chosen components. + */ +public class ComponentPanel extends JPanel +{ + /** + * Constructs the component panel. + */ + public ComponentPanel (CharacterManager charmgr, ComponentType type) + { + // save off references + _type = type; + + // retrieve component classes and relevant components + gatherComponentInfo(charmgr); + + GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH); + gl.setOffAxisPolicy(GroupLayout.STRETCH); + setLayout(gl); + + // set up a border + setBorder(BorderFactory.createEtchedBorder()); + + // add the component editors to the panel + addComponentEditors(); + } + + /** + * Returns a {@link CharacterDescriptor} detailing the selected + * character components. + */ + public CharacterDescriptor getDescriptor () + { + int size = _classes.size(); + int comps[] = new int[size]; + for (int ii = 0; ii < size; ii++) { + ComponentClass cclass = (ComponentClass)_classes.get(ii); + ComponentEditor ce = (ComponentEditor)_editors.get(ii); + comps[cclass.clid] = ce.getSelectedComponent(); + } + + return new CharacterDescriptor(_type, comps); + } + + /** + * Gathers component information from the character manager for + * later use when creating the editor components and the resulting + * character descriptor. + */ + protected void gatherComponentInfo (CharacterManager charmgr) + { + // get the list of all component classes + CollectionUtil.addAll(_classes, charmgr.enumerateComponentClasses()); + + for (int ii = 0; ii < _classes.size(); ii++) { + // get the list of components available for this class + int ctid = _type.ctid; + int clid = ((ComponentClass)_classes.get(ii)).clid; + Iterator comps = charmgr.enumerateComponentsByClass(ctid, clid); + + while (comps.hasNext()) { + Integer cid = (Integer)comps.next(); + + ArrayList clist = (ArrayList)_classinfo.get(clid); + if (clist == null) { + _classinfo.put(clid, clist = new ArrayList()); + } + + clist.add(cid); + } + } + } + + /** + * Adds editor user interface elements for each component class to + * allow the user to select the desired component. + */ + protected void addComponentEditors () + { + int size = _classes.size(); + for (int ii = 0; ii < size; ii++) { + ComponentClass cclass = (ComponentClass)_classes.get(ii); + List components = (List)_classinfo.get(cclass.clid); + + // create the component editor + ComponentEditor e = new ComponentEditor(cclass, components); + _editors.add(e); + + // add it to the panel + add(e); + } + } + + /** The component type associated with the character components. */ + protected ComponentType _type; + + /** The list of all available component classes. */ + protected ArrayList _classes = new ArrayList(); + + /** The list of component editors for each component class. */ + protected ArrayList _editors = new ArrayList(); + + /** The hashtable of available component ids for each class. */ + protected HashIntMap _classinfo = new HashIntMap(); +} diff --git a/src/java/com/threerings/cast/builder/SpritePanel.java b/src/java/com/threerings/cast/builder/SpritePanel.java new file mode 100644 index 000000000..451e0bbd0 --- /dev/null +++ b/src/java/com/threerings/cast/builder/SpritePanel.java @@ -0,0 +1,89 @@ +// +// $Id: SpritePanel.java,v 1.1 2001/10/30 16:16:01 shaper Exp $ + +package com.threerings.cast.builder; + +import java.awt.*; +import javax.swing.BorderFactory; +import javax.swing.border.BevelBorder; + +import com.threerings.media.sprite.*; + +import com.threerings.cast.Log; +import com.threerings.cast.CharacterSprite; + +/** + * The sprite panel displays a character sprite centered in the panel + * suitable for user perusal. + */ +public class SpritePanel extends AnimatedPanel +{ + /** + * Constructs the sprite panel. + */ + public SpritePanel () + { + // create and save off references to our managers + _spritemgr = new SpriteManager(); + _animmgr = new AnimationManager(_spritemgr, this); + + // create a visually pleasing border + setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); + } + + /** + * Sets the sprite to be displayed. + */ + public void setSprite (CharacterSprite sprite) + { + _sprite = sprite; + _sprite.setOrientation(Sprite.DIR_SOUTHWEST); + centerSprite(); + repaint(); + } + + // documentation inherited + protected void render (Graphics g) + { + Graphics2D gfx = (Graphics2D)g; + + // clear the background + gfx.setColor(Color.lightGray); + Dimension d = getSize(); + gfx.fillRect(0, 0, d.width - 1, d.height - 1); + + if (_sprite != null) { + // render the sprite + _sprite.paint((Graphics2D)g); + } + } + + // documentation inherited + public void setBounds (Rectangle r) + { + super.setBounds(r); + centerSprite(); + } + + /** + * Sets the sprite's location to render it centered within the panel. + */ + protected void centerSprite () + { + if (_sprite != null) { + Dimension d = getSize(); + int swid = _sprite.getWidth(), shei = _sprite.getHeight(); + int x = d.width / 2, y = (d.height + shei) / 2; + _sprite.setLocation(x, y); + } + } + + /** The sprite displayed by the panel. */ + protected Sprite _sprite; + + /** The animation manager. */ + protected AnimationManager _animmgr; + + /** The sprite manager. */ + protected SpriteManager _spritemgr; +} diff --git a/src/java/com/threerings/cast/tools/xml/XMLComponentParser.java b/src/java/com/threerings/cast/tools/xml/XMLComponentParser.java index 7b0d87b56..a405bae47 100644 --- a/src/java/com/threerings/cast/tools/xml/XMLComponentParser.java +++ b/src/java/com/threerings/cast/tools/xml/XMLComponentParser.java @@ -1,5 +1,5 @@ // -// $Id: XMLComponentParser.java,v 1.1 2001/10/26 01:17:21 shaper Exp $ +// $Id: XMLComponentParser.java,v 1.2 2001/10/30 16:16:01 shaper Exp $ package com.threerings.cast; @@ -10,8 +10,16 @@ import org.xml.sax.*; import com.samskivert.util.HashIntMap; import com.samskivert.util.StringUtil; +import com.samskivert.util.Tuple; import com.samskivert.xml.SimpleParser; +/** + * Parses an XML character component description file and populates + * hashtables with component type, component class, and specific + * component information. 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 @@ -28,31 +36,52 @@ public class XMLComponentParser extends SimpleParser ct.fps = parseInt(attributes.getValue("fps")); parsePoint(attributes.getValue("origin"), ct.origin); - Log.info("Parsed component type [ct=" + ct + "]."); - // save the component type _types.put(ct.ctid, ct); + } else if (qName.equals("class")) { + // save off the component class info + ComponentClass cclass = new ComponentClass(); + cclass.clid = parseInt(attributes.getValue("clid")); + cclass.name = attributes.getValue("name"); + cclass.render = parseInt(attributes.getValue("render")); + _classes.put(cclass.clid, cclass); + } else if (qName.equals("component")) { - // save off the component info + // retrieve the component attributes int cid = parseInt(attributes.getValue("cid")); int ctid = parseInt(attributes.getValue("ctid")); - _components.put(cid, new Integer(ctid)); + int clid = parseInt(attributes.getValue("clid")); + + // output a warning if the component references valid + // attributes + if (_types.get(ctid) == null) { + Log.warning("Component references non-existent type " + + "[cid=" + cid + ", ctid=" + ctid + "]."); + } + if (_classes.get(clid) == null) { + Log.warning("Component references non-existent class " + + "[cid=" + cid + ", clid=" + clid + "]."); + } + + // save off the component information + _components.put(cid, new Tuple( + new Integer(ctid), new Integer(clid))); } } /** - * Loads the component descriptions in the given file into {@link - * ComponentType} and {@link CharacterComponent} objects in the - * given hashtables, respectively, keyed on the type and component - * unique id, also respectively. + * Loads the component descriptions in the given file into the + * given component data hashtables. */ public void loadComponents ( - String file, HashIntMap types, HashIntMap components) + String file, HashIntMap types, HashIntMap classes, + HashIntMap components) throws IOException { // save off hashtables for reference while parsing _types = types; + _classes = classes; _components = components; parseFile(file); @@ -77,4 +106,7 @@ public class XMLComponentParser extends SimpleParser /** The hashtable of character components gathered while parsing. */ protected HashIntMap _components; + + /** The hashtable of component classes gathered while parsing. */ + protected HashIntMap _classes; } diff --git a/src/java/com/threerings/cast/tools/xml/XMLComponentRepository.java b/src/java/com/threerings/cast/tools/xml/XMLComponentRepository.java index f2e181e18..b0735451b 100644 --- a/src/java/com/threerings/cast/tools/xml/XMLComponentRepository.java +++ b/src/java/com/threerings/cast/tools/xml/XMLComponentRepository.java @@ -1,13 +1,15 @@ // -// $Id: XMLComponentRepository.java,v 1.1 2001/10/26 01:17:22 shaper Exp $ +// $Id: XMLComponentRepository.java,v 1.2 2001/10/30 16:16:01 shaper Exp $ package com.threerings.miso.scene.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.samskivert.util.Tuple; import com.threerings.cast.*; import com.threerings.cast.CharacterComponent.ComponentFrames; @@ -35,8 +37,8 @@ public class XMLFileComponentRepository implements ComponentRepository // load component types and components String file = config.getValue(COMPFILE_KEY, DEFAULT_COMPFILE); try { - new XMLComponentParser().loadComponents( - file, _types, _components); + XMLComponentParser p = new XMLComponentParser(); + p.loadComponents(file, _types, _classes, _components); } catch (IOException ioe) { Log.warning("Exception loading component descriptions " + "[ioe=" + ioe + "]."); @@ -45,59 +47,77 @@ public class XMLFileComponentRepository implements ComponentRepository // documentation inherited public CharacterComponent getComponent (int cid) - throws NoSuchComponentException, NoSuchComponentTypeException + throws NoSuchComponentException { - // get the component type id - Integer ctid = (Integer)_components.get(cid); - if (ctid == null) { + // get the component information + Tuple cinfo = (Tuple)_components.get(cid); + if (cinfo == null) { throw new NoSuchComponentException(cid); } // get the component type - ComponentType type = (ComponentType)_types.get(ctid.intValue()); - if (type == null) { - throw new NoSuchComponentTypeException(ctid.intValue()); - } + int ctid = ((Integer)cinfo.left).intValue(); + ComponentType type = (ComponentType)_types.get(ctid); + + // get the component class + int clid = ((Integer)cinfo.right).intValue(); + ComponentClass cclass = (ComponentClass)_classes.get(clid); // get the character animation images ComponentFrames frames = TileUtil.getComponentFrames( _tilemgr, cid, type.frameCount); // create the component - return new CharacterComponent(type, cid, frames); - } - - // documentation inherited - public Iterator enumerateComponents (int ctid) - throws NoSuchComponentTypeException - { - return new ComponentTypeIterator(ctid); + return new CharacterComponent(type, cclass, cid, frames); } // documentation inherited public Iterator enumerateComponentTypes () { - return _types.keys(); + return Collections.unmodifiableMap(_types).values().iterator(); + } + + // documentation inherited + public Iterator enumerateComponentsByType (int ctid) + { + return new ComponentIterator(ctid); + } + + // documentation inherited + public Iterator enumerateComponentClasses () + { + return Collections.unmodifiableMap(_classes).values().iterator(); + } + + // documentation inherited + public Iterator enumerateComponentsByClass (int ctid, int clid) + { + return new ComponentIterator(ctid, clid); } /** - * Iterates over all components of a specified component type in - * the component hashtable. + * Iterates over all components of a specified component type, and + * optionally a specified component class, in the component + * hashtable. */ - protected class ComponentTypeIterator implements Iterator + protected class ComponentIterator implements Iterator { - public ComponentTypeIterator (int ctid) - throws NoSuchComponentTypeException + /** + * Constructs an iterator that iterates over all components of + * the specified component type. + */ + public ComponentIterator (int ctid) { - _ctid = ctid; - _iter = _components.keys(); - advance(); + init(ctid, -1); + } - // make sure we have at least one component of the - // specified type - if (_next == null) { - throw new NoSuchComponentTypeException(ctid); - } + /** + * Constructs an iterator that iterates over all components of + * the specified component type and class. + */ + public ComponentIterator (int ctid, int clid) + { + init(ctid, clid); } public boolean hasNext () @@ -117,12 +137,25 @@ public class XMLFileComponentRepository implements ComponentRepository throw new UnsupportedOperationException(); } + protected void init (int ctid, int clid) + { + _ctid = ctid; + _clid = clid; + _iter = _components.keys(); + advance(); + } + protected void advance () { while (_iter.hasNext()) { - CharacterComponent c = (CharacterComponent)_iter.next(); - if (c.getType().ctid == _ctid) { - _next = c; + Integer cid = (Integer)_iter.next(); + + Tuple c = (Tuple)_components.get(cid); + int ctid = ((Integer)c.left).intValue(); + int clid = ((Integer)c.right).intValue(); + if (ctid == _ctid && + (_clid == -1 || (clid == _clid))) { + _next = cid; return; } } @@ -132,11 +165,15 @@ public class XMLFileComponentRepository implements ComponentRepository /** The component type id we're enumerating over. */ protected int _ctid; + /** The component class id required for inclusion in the + * iterator, or -1 for all classes. */ + protected int _clid; + /** The next character component of the component type id * associated with this iterator, or null if no more exist. */ protected Object _next; - /** Iterator over the components in the repository. */ + /** The iterator over all components in the repository. */ protected Iterator _iter; } @@ -151,6 +188,9 @@ public class XMLFileComponentRepository implements ComponentRepository /** The hashtable of component types. */ protected HashIntMap _types = new HashIntMap(); + /** The hashtable of component classes. */ + protected HashIntMap _classes = new HashIntMap(); + /** The hashtable of character components. */ protected HashIntMap _components = new HashIntMap(); diff --git a/src/java/com/threerings/miso/client/DirtyItemList.java b/src/java/com/threerings/miso/client/DirtyItemList.java index f11768671..d6a8f72d1 100644 --- a/src/java/com/threerings/miso/client/DirtyItemList.java +++ b/src/java/com/threerings/miso/client/DirtyItemList.java @@ -1,5 +1,5 @@ // -// $Id: DirtyItemList.java,v 1.4 2001/10/26 01:17:21 shaper Exp $ +// $Id: DirtyItemList.java,v 1.5 2001/10/30 16:16:01 shaper Exp $ package com.threerings.miso.scene; @@ -142,7 +142,9 @@ public class DirtyItemList extends ArrayList public String toString () { - return "[obj=" + obj + ", ox=" + ox + ", oy=" + oy + "]"; + return "[obj=" + obj + ", ox=" + ox + ", oy=" + oy + + ", lx=" + lx + ", ly=" + ly + ", rx=" + rx + + ", ry=" + ry + "]"; } } @@ -163,28 +165,36 @@ public class DirtyItemList extends ArrayList DirtyItem db = (DirtyItem)b; if (da.ox == db.ox && - da.oy == db.oy && - (da.obj instanceof MisoCharacterSprite) && - (db.obj instanceof MisoCharacterSprite)) { - // we're comparing two sprites co-existing on the same - // tile, so study their fine coordinates to determine - // rendering order - MisoCharacterSprite as = (MisoCharacterSprite)da.obj; - MisoCharacterSprite bs = (MisoCharacterSprite)db.obj; + da.oy == db.oy) { - int ahei = as.getFineX() + as.getFineY(); - int bhei = bs.getFineX() + bs.getFineY(); + if (da.equals(db)) { + // render level is equal if we're the same sprite + // or an object at the same location + return 0; + } - if (ahei < bhei) { - // item b is in front of item a - return -1; - } else if (ahei > bhei) { - // item a is in front of item b - return 1; - } else { - // if they're at the same vertical row of - // intra-tile tiles, just use something consistent - return as.hashCode() - bs.hashCode(); + if ((da.obj instanceof MisoCharacterSprite) && + (db.obj instanceof MisoCharacterSprite)) { + // we're comparing two sprites co-existing on the same + // tile, so study their fine coordinates to determine + // rendering order + MisoCharacterSprite as = (MisoCharacterSprite)da.obj; + MisoCharacterSprite bs = (MisoCharacterSprite)db.obj; + + int ahei = as.getFineX() + as.getFineY(); + int bhei = bs.getFineX() + bs.getFineY(); + + if (ahei < bhei) { + // item b is in front of item a + return -1; + } else if (ahei > bhei) { + // item a is in front of item b + return 1; + } else { + // if they're at the same vertical row of + // intra-tile tiles, just use something consistent + return as.hashCode() - bs.hashCode(); + } } } @@ -192,10 +202,10 @@ public class DirtyItemList extends ArrayList da.ry > db.oy) { // item a is in front of item b return 1; - } else { - // item b is in front of item a - return -1; } + + // item b is in front of item a + return -1; } public boolean equals (Object obj) diff --git a/src/java/com/threerings/miso/util/MisoUtil.java b/src/java/com/threerings/miso/util/MisoUtil.java index 3a7b6ac07..20210e364 100644 --- a/src/java/com/threerings/miso/util/MisoUtil.java +++ b/src/java/com/threerings/miso/util/MisoUtil.java @@ -1,5 +1,5 @@ // -// $Id: MisoUtil.java,v 1.10 2001/10/26 01:17:22 shaper Exp $ +// $Id: MisoUtil.java,v 1.11 2001/10/30 16:16:01 shaper Exp $ package com.threerings.miso.util; @@ -43,6 +43,41 @@ public class MisoUtil config.bindProperties(CONFIG_KEY, "rsrc/config/miso/miso"); } + /** + * Creates a Config object that contains + * configuration parameters for miso. + */ + public static Config createConfig () + { + return createConfig(null, null); + } + + /** + * Creates a Config object that contains + * configuration parameters for miso. If key and + * path are non-null, the properties in + * the given file will additionally be bound to the specified + * config key namespace. + */ + public static Config createConfig (String key, String path) + { + Config config = new Config(); + try { + // load the miso config info + bindProperties(config); + + if (key != null && path != null) { + // load the application-specific config info + config.bindProperties(key, path); + } + + } catch (IOException ioe) { + Log.warning("Error loading config information [e=" + ioe + "]."); + } + + return config; + } + /** * Creates a CharacterManager object. * @@ -57,7 +92,7 @@ public class MisoUtil { XMLFileComponentRepository crepo = new XMLFileComponentRepository(config, tilemgr); - CharacterManager charmgr = new CharacterManager(tilemgr, crepo); + CharacterManager charmgr = new CharacterManager(crepo); charmgr.setCharacterClass(MisoCharacterSprite.class); return charmgr; } diff --git a/tests/src/java/com/threerings/cast/builder/TestApp.java b/tests/src/java/com/threerings/cast/builder/TestApp.java new file mode 100644 index 000000000..c3670906b --- /dev/null +++ b/tests/src/java/com/threerings/cast/builder/TestApp.java @@ -0,0 +1,77 @@ +// +// $Id: TestApp.java,v 1.1 2001/10/30 16:16:01 shaper Exp $ + +package com.threerings.cast.builder.test; + +import java.io.IOException; +import javax.swing.JFrame; + +import com.samskivert.util.Config; +import com.samskivert.swing.util.SwingUtil; + +import com.threerings.cast.Log; +import com.threerings.cast.CharacterManager; +import com.threerings.media.tile.TileManager; + +import com.threerings.miso.util.MisoContext; +import com.threerings.miso.util.MisoUtil; + +public class TestApp +{ + public TestApp (String[] args) + { + _frame = new TestFrame(); + _frame.setSize(800, 600); + SwingUtil.centerWindow(_frame); + + // create the handles on our various services + _config = MisoUtil.createConfig(); + _tilemgr = MisoUtil.createTileManager(_config, _frame); + + CharacterManager charmgr = + MisoUtil.createCharacterManager(_config, _tilemgr); + + // create the context object + _ctx = new TestContextImpl(); + + // initialize the frame + ((TestFrame)_frame).init(charmgr); + } + + public void run () + { + _frame.pack(); + _frame.show(); + } + + public static void main (String[] args) + { + TestApp app = new TestApp(args); + app.run(); + } + + protected class TestContextImpl implements MisoContext + { + public Config getConfig () + { + return _config; + } + + public TileManager getTileManager () + { + return _tilemgr; + } + } + + /** The test frame. */ + protected JFrame _frame; + + /** The test context. */ + protected MisoContext _ctx; + + /** The config object. */ + protected Config _config; + + /** The tile manager object. */ + protected TileManager _tilemgr; +} diff --git a/tests/src/java/com/threerings/cast/builder/TestFrame.java b/tests/src/java/com/threerings/cast/builder/TestFrame.java new file mode 100644 index 000000000..8b4c484d4 --- /dev/null +++ b/tests/src/java/com/threerings/cast/builder/TestFrame.java @@ -0,0 +1,25 @@ +// +// $Id: TestFrame.java,v 1.1 2001/10/30 16:16:01 shaper Exp $ + +package com.threerings.cast.builder.test; + +import javax.swing.JFrame; + +import com.threerings.cast.CharacterManager; +import com.threerings.cast.builder.BuilderPanel; + +public class TestFrame extends JFrame +{ + public TestFrame () + { + super("Character Builder"); + + setResizable(false); + setDefaultCloseOperation(EXIT_ON_CLOSE); + } + + public void init (CharacterManager charmgr) + { + getContentPane().add(new BuilderPanel(charmgr)); + } +} diff --git a/tests/src/java/com/threerings/miso/viewer/ViewerApp.java b/tests/src/java/com/threerings/miso/viewer/ViewerApp.java index 4c150346a..25da6e54b 100644 --- a/tests/src/java/com/threerings/miso/viewer/ViewerApp.java +++ b/tests/src/java/com/threerings/miso/viewer/ViewerApp.java @@ -1,5 +1,5 @@ // -// $Id: ViewerApp.java,v 1.9 2001/10/17 22:16:04 shaper Exp $ +// $Id: ViewerApp.java,v 1.10 2001/10/30 16:16:01 shaper Exp $ package com.threerings.miso.viewer; @@ -32,7 +32,8 @@ public class ViewerApp SwingUtil.centerWindow(_frame); // create the handles on our various services - _config = createConfig(); + _config = MisoUtil.createConfig( + ViewerModel.CONFIG_KEY, "rsrc/config/miso/viewer"); _model = createModel(_config, args); _tilemgr = MisoUtil.createTileManager(_config, _frame); _screpo = MisoUtil.createSceneRepository(_config, _tilemgr); @@ -44,28 +45,6 @@ public class ViewerApp ((ViewerFrame)_frame).init(_ctx); } - /** - * Create the config object that contains configuration parameters - * for the application and other utilized packages. - */ - protected Config createConfig () - { - Config config = new Config(); - try { - // load the miso config info - MisoUtil.bindProperties(config); - - // load the viewer-specific config info - config.bindProperties( - ViewerModel.CONFIG_KEY, "rsrc/config/miso/viewer"); - - } catch (IOException ioe) { - Log.warning("Error loading config information [e=" + ioe + "]."); - } - - return config; - } - protected ViewerModel createModel (Config config, String args[]) { ViewerModel model = new ViewerModel(config); diff --git a/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java b/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java index 04c148020..a53f0d977 100644 --- a/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java +++ b/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java @@ -1,13 +1,16 @@ // -// $Id: ViewerSceneViewPanel.java,v 1.24 2001/10/27 01:35:21 shaper Exp $ +// $Id: ViewerSceneViewPanel.java,v 1.25 2001/10/30 16:16:01 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.*; @@ -47,8 +50,12 @@ public class ViewerSceneViewPanel extends SceneViewPanel CharacterManager charmgr = MisoUtil.createCharacterManager( ctx.getConfig(), ctx.getTileManager()); + // create the character descriptors + _descUser = createCharacterDescriptor(charmgr); + _descDecoy = createCharacterDescriptor(charmgr); + // create the manipulable sprite - _sprite = createSprite(spritemgr, charmgr, TSID_CHAR_USER); + _sprite = createSprite(spritemgr, charmgr, _descUser); // create the decoy sprites createDecoys(spritemgr, charmgr); @@ -67,10 +74,9 @@ public class ViewerSceneViewPanel extends SceneViewPanel * Creates a new sprite. */ protected MisoCharacterSprite createSprite ( - SpriteManager spritemgr, CharacterManager charmgr, int tsid) + SpriteManager spritemgr, CharacterManager charmgr, + CharacterDescriptor desc) { - int dummy[] = { tsid }; - CharacterDescriptor desc = new CharacterDescriptor(dummy); MisoCharacterSprite s = (MisoCharacterSprite)charmgr.getCharacter(desc); if (s != null) { @@ -91,7 +97,7 @@ public class ViewerSceneViewPanel extends SceneViewPanel { _decoys = new MisoCharacterSprite[NUM_DECOYS]; for (int ii = 0; ii < NUM_DECOYS; ii++) { - _decoys[ii] = createSprite(spritemgr, charmgr, TSID_CHAR); + _decoys[ii] = createSprite(spritemgr, charmgr, _descDecoy); if (_decoys[ii] != null) { createRandomPath(_decoys[ii]); } @@ -179,6 +185,42 @@ 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 the base component type (always the first type for now). + // TODO: change this to retrieve component type by name + Iterator iter = charmgr.enumerateComponentTypes(); + ComponentType ctype = (ComponentType)iter.next(); + + // 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(); + iter = charmgr.enumerateComponentsByClass(ctype.ctid, 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(ctype, components); + } + // documentation inherited public void handleEvent (SpriteEvent event) { @@ -193,13 +235,13 @@ public class ViewerSceneViewPanel extends SceneViewPanel } /** The number of decoy characters milling about. */ - protected static final int NUM_DECOYS = 2; + protected static final int NUM_DECOYS = 10; - /** The tileset id for the decoy character tiles. */ - protected static final int TSID_CHAR = 1011; + /** The character descriptor for the user character. */ + protected CharacterDescriptor _descUser; - /** The tileset id for the user character tiles. */ - protected static final int TSID_CHAR_USER = 1012; + /** The character descriptor for the decoy characters. */ + protected CharacterDescriptor _descDecoy; /** The animation manager. */ protected AnimationManager _animmgr;