acaf39b070
pixel for now. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2034 542714f4-19e9-0310-aa3c-eee0fc999fb1
238 lines
8.1 KiB
Java
238 lines
8.1 KiB
Java
//
|
|
// $Id: CompositedActionFrames.java,v 1.9 2002/12/07 02:04:31 shaper Exp $
|
|
|
|
package com.threerings.cast;
|
|
|
|
import java.awt.Graphics;
|
|
import java.awt.Image;
|
|
import java.awt.Rectangle;
|
|
|
|
import com.samskivert.util.StringUtil;
|
|
|
|
import com.threerings.media.util.Colorization;
|
|
import com.threerings.media.util.ImageUtil;
|
|
import com.threerings.media.util.MultiFrameImage;
|
|
|
|
import com.threerings.util.DirectionCodes;
|
|
|
|
/**
|
|
* An implementation of the {@link MultiFrameImage} interface that is used
|
|
* to lazily create composited character frames when they are requested.
|
|
*/
|
|
public class CompositedActionFrames
|
|
implements ActionFrames, DirectionCodes
|
|
{
|
|
/**
|
|
* Constructs a set of composited action frames with the supplied
|
|
* source frames and colorization configuration. The actual component
|
|
* frame images will not be composited until they are requested.
|
|
*/
|
|
public CompositedActionFrames (ActionFrames[] sources)
|
|
{
|
|
// sanity check
|
|
if (sources == null || sources.length == 0) {
|
|
String errmsg = "Requested to composite invalid set of source " +
|
|
"frames! [sources=" + StringUtil.toString(sources) + "].";
|
|
throw new RuntimeException(errmsg);
|
|
}
|
|
_sources = sources;
|
|
|
|
// the sources must all have the same orientation count, and each
|
|
// orientation must also have the same frame count, so we just use
|
|
// the counts from the first source and orientation
|
|
_orientCount = _sources[0].getOrientationCount();
|
|
_frameCount = _sources[0].getFrames(NORTH).getFrameCount();
|
|
_images = new Image[_orientCount][_frameCount];
|
|
_bounds = new Rectangle[_orientCount][_frameCount];
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public int getOrientationCount ()
|
|
{
|
|
return _orientCount;
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public TrimmedMultiFrameImage getFrames (final int orient)
|
|
{
|
|
return new TrimmedMultiFrameImage() {
|
|
// documentation inherited
|
|
public int getFrameCount () {
|
|
return _frameCount;
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public int getWidth (int index) {
|
|
// composite the frame if necessary
|
|
if (_bounds[orient][index] == null) {
|
|
getFrame(orient, index);
|
|
}
|
|
return _bounds[orient][index].width;
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public int getHeight (int index) {
|
|
// composite the frame if necessary
|
|
if (_bounds[orient][index] == null) {
|
|
getFrame(orient, index);
|
|
}
|
|
return _bounds[orient][index].height;
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public void paintFrame (Graphics g, int index, int x, int y) {
|
|
g.drawImage(getFrame(orient, index), x, y, null);
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public boolean hitTest (int index, int x, int y) {
|
|
return ImageUtil.hitTest(getFrame(orient, index), x, y);
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public void getTrimmedBounds (int index, Rectangle bounds) {
|
|
bounds.setBounds(0, 0, getWidth(index), getHeight(index));
|
|
}
|
|
};
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public int getXOrigin (int orient, int frameIdx)
|
|
{
|
|
return _bounds[orient][frameIdx].x;
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public int getYOrigin (int orient, int frameIdx)
|
|
{
|
|
return _bounds[orient][frameIdx].y;
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public ActionFrames cloneColorized (Colorization[] zations)
|
|
{
|
|
throw new RuntimeException("What you talkin' about Willis?");
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public long getEstimatedMemoryUsage ()
|
|
{
|
|
long size = 0;
|
|
for (int orient = 0; orient < _orientCount; orient++) {
|
|
for (int ii = 0; ii < _images[orient].length; ii++) {
|
|
Image image = _images[orient][ii];
|
|
if (image != null) {
|
|
size += ImageUtil.getEstimatedMemoryUsage(image);
|
|
}
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
// documentation inherited
|
|
protected Image getFrame (int orient, int index)
|
|
{
|
|
// create the arrays for this orientation if we haven't yet
|
|
if (_images[orient] == null) {
|
|
_images[orient] = new Image[_frameCount];
|
|
_bounds[orient] = new Rectangle[_frameCount];
|
|
}
|
|
|
|
// create the frame if we don't already have it
|
|
if (_images[orient][index] == null) {
|
|
// Log.info("Compositing [orient=" + orient +
|
|
// ", index=" + index + "].");
|
|
_images[orient][index] = compositeFrames(orient, index);
|
|
}
|
|
|
|
return _images[orient][index];
|
|
}
|
|
|
|
/**
|
|
* Renders and returns the <code>index</code>th image from each of the
|
|
* supplied source multi-frame images to a newly created buffered
|
|
* image. This is used to render a single frame of a composited
|
|
* character action, and accordingly, the source image array should be
|
|
* already sorted into the proper rendering order.
|
|
*/
|
|
protected Image compositeFrames (int orient, int index)
|
|
{
|
|
int scount = _sources.length;
|
|
// long start = System.currentTimeMillis();
|
|
|
|
// // DEBUG
|
|
// int width = 0, height = 0;
|
|
|
|
// first we need to determine the bounds of the rectangle that
|
|
// will enclose all of our various components
|
|
Rectangle tbounds = new Rectangle();
|
|
Rectangle bounds = _bounds[orient][index] = new Rectangle(0, 0, 0, 0);
|
|
for (int ii = 0; ii < scount; ii++) {
|
|
TrimmedMultiFrameImage source = _sources[ii].getFrames(orient);
|
|
source.getTrimmedBounds(index, tbounds);
|
|
// the first one defines our initial bounds
|
|
if (bounds.width == 0 && bounds.height == 0) {
|
|
bounds.setBounds(tbounds);
|
|
} else {
|
|
bounds.add(tbounds);
|
|
}
|
|
|
|
// // DEBUG
|
|
// for (int ff = 0; ff < _frameCount; ff++) {
|
|
// width = Math.max(width, source.getWidth(ff));
|
|
// height = Math.max(height, source.getHeight(ff));
|
|
// }
|
|
}
|
|
|
|
// create the image now that we know how big it should be
|
|
Image dest = ImageUtil.createImage(bounds.width, bounds.height);
|
|
Graphics g = dest.getGraphics();
|
|
|
|
// now render each of the components into a composited frame
|
|
for (int ii = 0; ii < scount; ii++) {
|
|
TrimmedMultiFrameImage source = _sources[ii].getFrames(orient);
|
|
source.getTrimmedBounds(index, tbounds);
|
|
|
|
// render this frame for this particular action for this
|
|
// component into the target image
|
|
source.paintFrame(g, index, -bounds.x, -bounds.y);
|
|
}
|
|
|
|
// clean up after ourselves
|
|
if (g != null) {
|
|
g.dispose();
|
|
}
|
|
|
|
// Log.info("Composited [orient=" + orient + ", index=" + index +
|
|
// ", tbounds=" + StringUtil.toString(bounds) +
|
|
// ", width=" + width + ", height=" + height + "].");
|
|
|
|
// keep track of our new origin
|
|
bounds.x = (_sources[0].getXOrigin(orient, index) - bounds.x);
|
|
bounds.y = (_sources[0].getYOrigin(orient, index) - bounds.y);
|
|
|
|
// Log.info("New origin [x=" + bounds.x + ", y=" + bounds.y + "].");
|
|
|
|
// long now = System.currentTimeMillis();
|
|
// Log.info("Composited " + sources.length + " frames in " +
|
|
// (now-start) + " millis.");
|
|
|
|
return dest;
|
|
}
|
|
|
|
/** The number of orientations. */
|
|
protected int _orientCount;
|
|
|
|
/** The number of frames in each orientation. */
|
|
protected int _frameCount;
|
|
|
|
/** Our source action frames. */
|
|
protected ActionFrames[] _sources;
|
|
|
|
/** The frame images. */
|
|
protected Image[][] _images;
|
|
|
|
/** Used to track our trimmed frame bounds. */
|
|
protected Rectangle[][] _bounds;
|
|
}
|