
com.threerings.cast.CompositedMultiFrameImage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nenya Show documentation
Show all versions of nenya Show documentation
Facilities for making networked multiplayer games.
The newest version!
//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2012 Three Rings Design, Inc., All Rights Reserved
// https://github.com/threerings/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.util.Arrays;
import java.util.Comparator;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import com.threerings.media.image.ImageManager;
import com.threerings.media.image.Mirage;
import com.threerings.media.image.VolatileMirage;
import com.threerings.cast.CompositedActionFrames.ComponentFrames;
import com.threerings.cast.bundle.BundledComponentRepository.TileSetFrameImage;
/**
* 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 (CompositedMirage element : _images) {
size += element.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
{
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.getRenderPriority(_action, _orient) -
cf2.ccomp.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;
}
@Override
protected int getTransparency ()
{
return Transparency.BITMASK;
}
@Override
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();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy