More work on character components.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@579 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Walter Korman
2001-10-30 16:16:01 +00:00
parent 933a427b68
commit 3ea91cdfdd
19 changed files with 1099 additions and 191 deletions
@@ -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;
}
@@ -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;
}
@@ -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 <code>Integer</code> 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 <code>Integer</code> 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 <code>CharacterSprite</code>.
@@ -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;
@@ -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);
}
}
}
@@ -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 <code>Integer</code> 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 <code>Integer</code> 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);
}
@@ -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;
}
+99 -3
View File
@@ -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 <code>src</code> component frames
* into the corresponding frames of <code>dest</code>.
*/
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 <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 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[];
}
}
@@ -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;
}
@@ -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;
}
@@ -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();
}
@@ -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;
}
@@ -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;
}
@@ -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();
@@ -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)
@@ -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 <code>Config</code> object that contains
* configuration parameters for miso.
*/
public static Config createConfig ()
{
return createConfig(null, null);
}
/**
* Creates a <code>Config</code> object that contains
* configuration parameters for miso. If <code>key</code> and
* <code>path</code> are non-<code>null</code>, 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 <code>CharacterManager</code> 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;
}
@@ -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;
}
@@ -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));
}
}
@@ -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);
@@ -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;