// // 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.Map; import com.samskivert.util.StringUtil; import com.threerings.util.DirectionCodes; import com.threerings.media.image.Colorization; import com.threerings.media.image.ImageManager; import com.threerings.media.util.MultiFrameImage; /** * 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 { /** Used to associate a {@link CharacterComponent} with its {@link * ActionFrames} for a particular action. */ public static class ComponentFrames { public CharacterComponent ccomp; public ActionFrames frames; public ComponentFrames () { } public ComponentFrames ( CharacterComponent ccomp, ActionFrames frames) { this.ccomp = ccomp; this.frames = frames; } @Override public String toString () { return ccomp + ":" + frames; } } /** * 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 ( ImageManager imgr, Map<CompositedFramesKey, CompositedMultiFrameImage> frameCache, String action, ComponentFrames[] sources) { // sanity check if (sources == null || sources.length == 0) { String errmsg = "Requested to composite invalid set of source " + "frames! [action=" + action + ", sources=" + StringUtil.toString(sources) + "]."; throw new RuntimeException(errmsg); } _imgr = imgr; _frameCache = frameCache; _sources = sources; _action = action; // the sources must all have the same orientation count, so we // just use the first _orientCount = _sources[0].frames.getOrientationCount(); } // documentation inherited from interface public int getOrientationCount () { return _orientCount; } // documentation inherited from interface public TrimmedMultiFrameImage getFrames (int orient) { _key.setOrient(orient); CompositedMultiFrameImage cmfi = _frameCache.get(_key); if (cmfi == null) { cmfi = createFrames(orient); _frameCache.put(new CompositedFramesKey(orient), cmfi); } return cmfi; } // documentation inherited from interface public int getXOrigin (int orient, int frameIdx) { CompositedMultiFrameImage cmfi = (CompositedMultiFrameImage) getFrames(orient); return cmfi.getXOrigin(frameIdx); } // documentation inherited from interface public int getYOrigin (int orient, int frameIdx) { CompositedMultiFrameImage cmfi = (CompositedMultiFrameImage) getFrames(orient); return cmfi.getYOrigin(frameIdx); } // documentation inherited from interface public ActionFrames cloneColorized (Colorization[] zations) { throw new RuntimeException("What you talkin' about Willis?"); } // documentation inherited from interface public ActionFrames cloneTranslated (int dx, int dy) { ComponentFrames[] tsources = new ComponentFrames[_sources.length]; for (int ii = 0; ii < _sources.length; ii++) { tsources[ii] = new ComponentFrames( _sources[ii].ccomp, _sources[ii].frames.cloneTranslated(dx, dy)); } return new CompositedActionFrames(_imgr, _frameCache, _action, tsources); } /** * Creates our underlying multi-frame image for a particular orientation. */ protected CompositedMultiFrameImage createFrames (int orient) { return new CompositedMultiFrameImage(_imgr, _sources, _action, orient); } /** Used to cache composited frames for a particular action and * orientation. */ protected class CompositedFramesKey { public CompositedFramesKey (int orient) { _orient = orient; } public void setOrient (int orient) { _orient = orient; } public CompositedActionFrames getOwner () { return CompositedActionFrames.this; } @Override public boolean equals (Object other) { CompositedFramesKey okey = (CompositedFramesKey)other; return ((getOwner() == okey.getOwner()) && (_orient == okey._orient)); } @Override public int hashCode () { return CompositedActionFrames.this.hashCode() ^ _orient; } protected int _orient; } /** The image manager from whom we can obtain prepared volatile images * onto which to render our composited actions. */ protected ImageManager _imgr; /** Used to cache our composited action frame images. */ protected Map<CompositedFramesKey, CompositedMultiFrameImage> _frameCache; /** The action for which we're compositing frames. */ protected String _action; /** The number of orientations. */ protected int _orientCount; /** Our source components and action frames. */ protected ComponentFrames[] _sources; /** Used to avoid creating a new key object every time we do a cache * lookup. */ protected CompositedFramesKey _key = new CompositedFramesKey(0); }