1/*
2 * Copyright (c) 2009-2011 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32package com.jme3.animation;
33
34import com.jme3.export.*;
35import com.jme3.util.TempVars;
36import java.io.IOException;
37
38/**
39 * The animation class updates the animation target with the tracks of a given type.
40 *
41 * @author Kirill Vainer, Marcin Roguski (Kaelthas)
42 */
43public class Animation implements Savable, Cloneable {
44
45    /**
46     * The name of the animation.
47     */
48    private String name;
49
50    /**
51     * The length of the animation.
52     */
53    private float length;
54
55    /**
56     * The tracks of the animation.
57     */
58    private Track[] tracks;
59
60    /**
61     * Serialization-only. Do not use.
62     */
63    public Animation() {}
64
65    /**
66     * Creates a new <code>Animation</code> with the given name and length.
67     *
68     * @param name The name of the animation.
69     * @param length Length in seconds of the animation.
70     */
71    public Animation(String name, float length) {
72        this.name = name;
73        this.length = length;
74    }
75
76    /**
77     * The name of the bone animation
78     * @return name of the bone animation
79     */
80    public String getName() {
81    	return name;
82    }
83
84    /**
85     * Returns the length in seconds of this animation
86     *
87     * @return the length in seconds of this animation
88     */
89    public float getLength() {
90    	return length;
91    }
92
93    /**
94     * This method sets the current time of the animation.
95     * This method behaves differently for every known track type.
96     * Override this method if you have your own type of track.
97     *
98     * @param time the time of the animation
99     * @param blendAmount the blend amount factor
100     * @param control the animation control
101     * @param channel the animation channel
102     */
103    void setTime(float time, float blendAmount, AnimControl control, AnimChannel channel, TempVars vars) {
104        if (tracks == null)
105            return;
106
107        for (int i = 0; i < tracks.length; i++){
108            tracks[i].setTime(time, blendAmount, control, channel, vars);
109        }
110
111        /*
112        if (tracks != null && tracks.length > 0) {
113            Track<?> trackInstance = tracks[0];
114
115            if (trackInstance instanceof SpatialTrack) {
116                Spatial spatial = control.getSpatial();
117                if (spatial != null) {
118                    ((SpatialTrack) tracks[0]).setTime(time, spatial, blendAmount);
119                }
120            } else if (trackInstance instanceof BoneTrack) {
121                BitSet affectedBones = channel.getAffectedBones();
122                Skeleton skeleton = control.getSkeleton();
123                for (int i = 0; i < tracks.length; ++i) {
124                    if (affectedBones == null || affectedBones.get(((BoneTrack) tracks[i]).getTargetIndex())) {
125                        ((BoneTrack) tracks[i]).setTime(time, skeleton, blendAmount);
126                    }
127                }
128            } else if (trackInstance instanceof PoseTrack) {
129                Spatial spatial = control.getSpatial();
130                List<Mesh> meshes = new ArrayList<Mesh>();
131                this.getMeshes(spatial, meshes);
132                if (meshes.size() > 0) {
133                    Mesh[] targets = meshes.toArray(new Mesh[meshes.size()]);
134                    for (int i = 0; i < tracks.length; ++i) {
135                        ((PoseTrack) tracks[i]).setTime(time, targets, blendAmount);
136                    }
137                }
138            }
139        }
140        */
141    }
142
143    /**
144     * Set the {@link Track}s to be used by this animation.
145     * <p>
146     * The array should be organized so that the appropriate Track can
147     * be retrieved based on a bone index.
148     *
149     * @param tracks The tracks to set.
150     */
151    public void setTracks(Track[] tracks){
152        this.tracks = tracks;
153    }
154
155    /**
156     * Returns the tracks set in {@link #setTracks(com.jme3.animation.Track[]) }.
157     *
158     * @return the tracks set previously
159     */
160    public Track[] getTracks() {
161    	return tracks;
162    }
163
164    /**
165     * This method creates a clone of the current object.
166     * @return a clone of the current object
167     */
168   @Override
169   public Animation clone() {
170        try {
171            Animation result = (Animation) super.clone();
172            result.tracks = tracks.clone();
173            for (int i = 0; i < tracks.length; ++i) {
174                result.tracks[i] = this.tracks[i].clone();
175            }
176            return result;
177        } catch (CloneNotSupportedException e) {
178            throw new AssertionError();
179        }
180    }
181
182    @Override
183    public String toString() {
184        return getClass().getSimpleName() + "[name=" + name + ", length=" + length + ']';
185    }
186
187   @Override
188    public void write(JmeExporter ex) throws IOException {
189        OutputCapsule out = ex.getCapsule(this);
190        out.write(name, "name", null);
191        out.write(length, "length", 0f);
192        out.write(tracks, "tracks", null);
193    }
194
195    @Override
196    public void read(JmeImporter im) throws IOException {
197        InputCapsule in = im.getCapsule(this);
198        name = in.readString("name", null);
199        length = in.readFloat("length", 0f);
200
201        Savable[] arr = in.readSavableArray("tracks", null);
202        tracks = new Track[arr.length];
203        System.arraycopy(arr, 0, tracks, 0, arr.length);
204    }
205}
206