/* * Copyright (c) 2009-2012 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'jMonkeyEngine' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.jme3.animation; import com.jme3.export.*; import com.jme3.scene.Spatial; import com.jme3.util.SafeArrayList; import com.jme3.util.TempVars; import com.jme3.util.clone.Cloner; import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** * The animation class updates the animation target with the tracks of a given type. * * @author Kirill Vainer, Marcin Roguski (Kaelthas) */ public class Animation implements Savable, Cloneable, JmeCloneable { /** * The name of the animation. */ private String name; /** * The length of the animation. */ private float length; /** * The tracks of the animation. */ private SafeArrayList<Track> tracks = new SafeArrayList<Track>(Track.class); /** * Serialization-only. Do not use. */ public Animation() { } /** * Creates a new <code>Animation</code> with the given name and length. * * @param name The name of the animation. * @param length Length in seconds of the animation. */ public Animation(String name, float length) { this.name = name; this.length = length; } /** * The name of the bone animation * @return name of the bone animation */ public String getName() { return name; } /** * Returns the length in seconds of this animation * * @return the length in seconds of this animation */ public float getLength() { return length; } /** * This method sets the current time of the animation. * This method behaves differently for every known track type. * Override this method if you have your own type of track. * * @param time the time of the animation * @param blendAmount the blend amount factor * @param control the animation control * @param channel the animation channel */ void setTime(float time, float blendAmount, AnimControl control, AnimChannel channel, TempVars vars) { if (tracks == null) { return; } for (Track track : tracks) { track.setTime(time, blendAmount, control, channel, vars); } } /** * Set the {@link Track}s to be used by this animation. * * @param tracksArray The tracks to set. */ public void setTracks(Track[] tracksArray) { for (Track track : tracksArray) { tracks.add(track); } } /** * Adds a track to this animation * @param track the track to add */ public void addTrack(Track track) { tracks.add(track); } /** * removes a track from this animation * @param track the track to remove */ public void removeTrack(Track track) { tracks.remove(track); if (track instanceof ClonableTrack) { ((ClonableTrack) track).cleanUp(); } } /** * Returns the tracks set in {@link #setTracks(com.jme3.animation.Track[]) }. * * @return the tracks set previously */ public Track[] getTracks() { return tracks.getArray(); } /** * This method creates a clone of the current object. * @return a clone of the current object */ @Override public Animation clone() { try { Animation result = (Animation) super.clone(); result.tracks = new SafeArrayList<Track>(Track.class); for (Track track : tracks) { result.tracks.add(track.clone()); } return result; } catch (CloneNotSupportedException e) { throw new AssertionError(); } } /** * * @param spat * @return */ public Animation cloneForSpatial(Spatial spat) { try { Animation result = (Animation) super.clone(); result.tracks = new SafeArrayList<Track>(Track.class); for (Track track : tracks) { if (track instanceof ClonableTrack) { result.tracks.add(((ClonableTrack) track).cloneForSpatial(spat)); } else { result.tracks.add(track); } } return result; } catch (CloneNotSupportedException e) { throw new AssertionError(); } } @Override public Object jmeClone() { try { return super.clone(); } catch( CloneNotSupportedException e ) { throw new RuntimeException("Error cloning", e); } } @Override public void cloneFields( Cloner cloner, Object original ) { // There is some logic here that I'm copying but I'm not sure if // it's a mistake or not. If a track is not a CloneableTrack then it // isn't cloned at all... even though they all implement clone() methods. -pspeed SafeArrayList<Track> newTracks = new SafeArrayList<>(Track.class); for( Track track : tracks ) { if( track instanceof ClonableTrack ) { newTracks.add(cloner.clone(track)); } else { // this is the part that seems fishy newTracks.add(track); } } this.tracks = newTracks; } @Override public String toString() { return getClass().getSimpleName() + "[name=" + name + ", length=" + length + ']'; } @Override public void write(JmeExporter ex) throws IOException { OutputCapsule out = ex.getCapsule(this); out.write(name, "name", null); out.write(length, "length", 0f); out.write(tracks.getArray(), "tracks", null); } @Override public void read(JmeImporter im) throws IOException { InputCapsule in = im.getCapsule(this); name = in.readString("name", null); length = in.readFloat("length", 0f); Savable[] arr = in.readSavableArray("tracks", null); if (arr != null) { // NOTE: Backward compat only .. Some animations have no // tracks set at all even though it makes no sense. // Since there's a null check in setTime(), // its only appropriate that the check is made here as well. tracks = new SafeArrayList<Track>(Track.class); for (Savable savable : arr) { tracks.add((Track) savable); } } } }