8a10f090da
git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@434 ed5b42cb-e716-0410-a449-f6a68f950b19
322 lines
9.8 KiB
Java
322 lines
9.8 KiB
Java
//
|
|
// $Id$
|
|
//
|
|
// Nenya library - tools for developing networked games
|
|
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
|
|
// http://www.threerings.net/code/nenya/
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License as published
|
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
package com.threerings.cast;
|
|
|
|
import java.awt.Graphics2D;
|
|
import java.awt.Point;
|
|
import java.awt.Rectangle;
|
|
import java.awt.Transparency;
|
|
import java.awt.image.BufferedImage;
|
|
import java.util.Arrays;
|
|
import java.util.Comparator;
|
|
|
|
import com.threerings.cast.CompositedActionFrames.ComponentFrames;
|
|
import com.threerings.cast.bundle.BundledComponentRepository.TileSetFrameImage;
|
|
import com.threerings.media.image.ImageManager;
|
|
import com.threerings.media.image.Mirage;
|
|
import com.threerings.media.image.VolatileMirage;
|
|
|
|
/**
|
|
* Used to composite the action frames for a particular orientation of a
|
|
* {@link CompositedActionFrames}.
|
|
*/
|
|
public class CompositedMultiFrameImage
|
|
implements TrimmedMultiFrameImage
|
|
{
|
|
public CompositedMultiFrameImage (
|
|
ImageManager imgr, ComponentFrames[] sources,
|
|
String action, int orient)
|
|
{
|
|
_imgr = imgr;
|
|
_sources = sources;
|
|
_action = action;
|
|
_orient = orient;
|
|
|
|
// create our frame images (which will do the compositing)
|
|
int fcount = sources[0].frames.getFrames(orient).getFrameCount();
|
|
_images = new CompositedMirage[fcount];
|
|
for (int ii = 0; ii < fcount; ii++) {
|
|
_images[ii] = createCompositedMirage(ii);
|
|
}
|
|
}
|
|
|
|
// documentation inherited
|
|
public int getFrameCount () {
|
|
return _images.length;
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public int getWidth (int index) {
|
|
return _images[index].getWidth();
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public int getHeight (int index) {
|
|
return _images[index].getHeight();
|
|
}
|
|
|
|
public int getXOrigin (int index)
|
|
{
|
|
return _images[index].getXOrigin();
|
|
}
|
|
|
|
public int getYOrigin (int index)
|
|
{
|
|
return _images[index].getYOrigin();
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public void paintFrame (Graphics2D g, int index, int x, int y) {
|
|
_images[index].paint(g, x, y);
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public boolean hitTest (int index, int x, int y) {
|
|
return _images[index].hitTest(x, y);
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public void getTrimmedBounds (int index, Rectangle bounds) {
|
|
bounds.setBounds(0, 0, getWidth(index), getHeight(index));
|
|
}
|
|
|
|
/**
|
|
* Returns the estimated memory usage of our composited frame images.
|
|
*/
|
|
public long getEstimatedMemoryUsage ()
|
|
{
|
|
long size = 0;
|
|
for (int ii = 0; ii < _images.length; ii++) {
|
|
size += _images[ii].getEstimatedMemoryUsage();
|
|
}
|
|
return size;
|
|
}
|
|
|
|
/**
|
|
* Creates a composited image for the specified frame.
|
|
*/
|
|
protected CompositedMirage createCompositedMirage (int index)
|
|
{
|
|
if (_sources.length == 1 && _sources[0].frames instanceof TileSetFrameImage) {
|
|
TileSetFrameImage frames = (TileSetFrameImage)_sources[0].frames;
|
|
Rectangle tbounds = new Rectangle();
|
|
frames.getTrimmedBounds(_orient, index, tbounds);
|
|
int x = frames.getXOrigin(_orient, index) - tbounds.x;
|
|
int y = frames.getYOrigin(_orient, index) - tbounds.y;
|
|
return new SubmirageForwarder(frames.getTileMirage(_orient, index), x, y);
|
|
}
|
|
return new CompositedVolatileMirage(index);
|
|
}
|
|
|
|
/**
|
|
* A CompositedMirage that forwards all of its Mirage calls to a delegate Mirage.
|
|
*/
|
|
protected class SubmirageForwarder implements CompositedMirage {
|
|
|
|
public SubmirageForwarder(Mirage m, int x, int y) {
|
|
delegate = m;
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
|
|
public int getXOrigin ()
|
|
{
|
|
return x;
|
|
}
|
|
|
|
public int getYOrigin ()
|
|
{
|
|
return y;
|
|
}
|
|
|
|
public long getEstimatedMemoryUsage ()
|
|
{
|
|
return delegate.getEstimatedMemoryUsage();
|
|
}
|
|
|
|
public int getHeight ()
|
|
{
|
|
return delegate.getHeight();
|
|
}
|
|
|
|
public BufferedImage getSnapshot ()
|
|
{
|
|
return delegate.getSnapshot();
|
|
}
|
|
|
|
public int getWidth ()
|
|
{
|
|
return delegate.getWidth();
|
|
}
|
|
|
|
public boolean hitTest (int x, int y)
|
|
{
|
|
return delegate.hitTest(x, y);
|
|
}
|
|
|
|
public void paint (Graphics2D gfx, int x, int y)
|
|
{
|
|
delegate.paint(gfx, x, y);
|
|
}
|
|
|
|
protected int x, y;
|
|
|
|
protected Mirage delegate;
|
|
}
|
|
|
|
// documentation inherited
|
|
protected Mirage getFrame (int orient, int index)
|
|
{
|
|
return _images[index];
|
|
}
|
|
|
|
/** The image manager from whom we load our images. */
|
|
protected ImageManager _imgr;
|
|
|
|
/** The action frames from which we obtain our source imagery. */
|
|
protected ComponentFrames[] _sources;
|
|
|
|
/** The action we're compositing. */
|
|
protected String _action;
|
|
|
|
/** The orientation we're compositing. */
|
|
protected int _orient;
|
|
|
|
/** Our composited action frame images. */
|
|
protected CompositedMirage[] _images;
|
|
|
|
/**
|
|
* Used to create our mirage using the source action frame images.
|
|
*/
|
|
protected class CompositedVolatileMirage extends VolatileMirage
|
|
implements CompositedMirage, Comparator<ComponentFrames>
|
|
{
|
|
public CompositedVolatileMirage (int index)
|
|
{
|
|
super(CompositedMultiFrameImage.this._imgr,
|
|
new Rectangle(0, 0, 0, 0));
|
|
|
|
// keep this for later
|
|
_index = index;
|
|
|
|
// first we need to determine the bounds of the rectangle that
|
|
// will enclose all of our various components
|
|
Rectangle tbounds = new Rectangle();
|
|
int scount = _sources.length;
|
|
for (int ii = 0; ii < scount; ii++) {
|
|
TrimmedMultiFrameImage source =
|
|
_sources[ii].frames.getFrames(_orient);
|
|
source.getTrimmedBounds(index, tbounds);
|
|
_bounds = combineBounds(_bounds, tbounds);
|
|
}
|
|
if (_bounds.width <= 0) {
|
|
_bounds.width = 1;
|
|
}
|
|
if (_bounds.height <= 0) {
|
|
_bounds.height = 1;
|
|
}
|
|
|
|
// compute our new origin
|
|
_origin.x = (_sources[0].frames.getXOrigin(_orient, index) -
|
|
_bounds.x);
|
|
_origin.y = (_sources[0].frames.getYOrigin(_orient, index) -
|
|
_bounds.y);
|
|
// Log.info("New origin [x=" + _origin.x + ", y=" + _origin.y + "].");
|
|
|
|
// render our volatile image for the first time
|
|
createVolatileImage();
|
|
}
|
|
|
|
public int getXOrigin ()
|
|
{
|
|
return _origin.x;
|
|
}
|
|
|
|
public int getYOrigin ()
|
|
{
|
|
return _origin.y;
|
|
}
|
|
|
|
// documentation inherited from interface
|
|
public int compare (ComponentFrames cf1, ComponentFrames cf2)
|
|
{
|
|
return (cf1.ccomp.componentClass.getRenderPriority(_action, _orient) -
|
|
cf2.ccomp.componentClass.getRenderPriority(_action, _orient));
|
|
}
|
|
|
|
/**
|
|
* Combines the working bounds with a new set of bounds.
|
|
*/
|
|
protected Rectangle combineBounds (Rectangle bounds, Rectangle tbounds)
|
|
{
|
|
// the first one defines our initial bounds
|
|
if (bounds.width == 0 && bounds.height == 0) {
|
|
bounds.setBounds(tbounds);
|
|
} else {
|
|
bounds.add(tbounds);
|
|
}
|
|
return bounds;
|
|
}
|
|
|
|
// documentation inherited
|
|
protected int getTransparency ()
|
|
{
|
|
return Transparency.BITMASK;
|
|
}
|
|
|
|
// documentation inherited
|
|
protected void refreshVolatileImage ()
|
|
{
|
|
// long start = System.currentTimeMillis();
|
|
|
|
// sort the sources appropriately for this orientation
|
|
Arrays.sort(_sources, this);
|
|
|
|
// now render each of the components into a composited frame
|
|
int scount = _sources.length;
|
|
Graphics2D g = (Graphics2D)_image.getGraphics();
|
|
try {
|
|
for (int ii = 0; ii < scount; ii++) {
|
|
TrimmedMultiFrameImage source =
|
|
_sources[ii].frames.getFrames(_orient);
|
|
source.paintFrame(g, _index, -_bounds.x, -_bounds.y);
|
|
}
|
|
} finally {
|
|
// clean up after ourselves
|
|
if (g != null) {
|
|
g.dispose();
|
|
}
|
|
}
|
|
|
|
// Log.info("Composited [orient=" + _orient + ", index=" + _index +
|
|
// ", tbounds=" + StringUtil.toString(_bounds) + "].");
|
|
|
|
// long now = System.currentTimeMillis();
|
|
// Log.info("Composited " + scount + " frames in " +
|
|
// (now-start) + " millis.");
|
|
}
|
|
|
|
protected int _index;
|
|
protected Point _origin = new Point();
|
|
}
|
|
};
|