Browse Source

Animations refactoring.
- Track is a generic interface now
- all kinds of tracks implement Track<T>
- Animation is the only animation class that should be used now (other classes like BoneAnimation or SpatialAnimation are deprecated now)
- Pose and PoseTrack are made Cloneable to easier clone the tracks and Animation
- one update to OgreLoader (using Animation instead of BoneAnimation)
- one update to tests

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8302 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

Kae..pl 14 years ago
parent
commit
c773395ace

+ 164 - 5
engine/src/core/com/jme3/animation/Animation.java

@@ -31,15 +31,174 @@
  */
 package com.jme3.animation;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.List;
+
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
 import com.jme3.export.Savable;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
 
-public interface Animation extends Savable, Cloneable {
+/**
+ * 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 {
+	/** The name of the animation. */
+	private String name;
+	/** The length of the animation. */
+    private float length;
+    /** The tracks of the animation. */
+    private Track<?>[] tracks;
+    
+    /**
+     * Serialization-only. Do not use.
+     */
+    public Animation() {}
+    
+    /**
+     * Creates a new BoneAnimation with the given name and length.
+     * 
+     * @param name The name of the bone animation.
+     * @param length Length in seconds of the bone animation.
+     */
+    public Animation(String name, float length) {
+        this.name = name;
+        this.length = length;
+    }
+    
+    /**
+     * @return the name of the animation
+     */
+    public String getName() {
+    	return name;
+    }
     
-    public String getName();
+    /**
+     * @return the length of the animation
+     */
+    public float getLength() {
+    	return length;
+    }
     
-    public float getLength();
+    /**
+     * 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 nimation control
+     * @param channel the animation channel
+     */
+    void setTime(float time, float blendAmount, AnimControl control, AnimChannel channel) {
+    	if(tracks != null && tracks.length > 0) {
+    		Track<?> trackInstance = tracks[0];
+    		if(trackInstance instanceof SpatialTrack) {
+    			Spatial spatial = control.getSpatial();
+    			if (spatial != null) {
+    				((SpatialTrack)tracks[0]).setTime(time, spatial, blendAmount);
+    			}
+    		} else if(trackInstance instanceof BoneTrack) {
+    			BitSet affectedBones = channel.getAffectedBones();
+    	        Skeleton skeleton = control.getSkeleton();
+    	        for (int i = 0; i < tracks.length; ++i) {
+    	            if (affectedBones == null || affectedBones.get(((BoneTrack)tracks[i]).getTargetIndex())) {
+    	            	((BoneTrack)tracks[i]).setTime(time, skeleton, blendAmount);
+    	            }
+    	        }
+    		} else if(trackInstance instanceof PoseTrack) {
+    			Spatial spatial = control.getSpatial();
+    			List<Mesh> meshes = new ArrayList<Mesh>();
+    			this.getMeshes(spatial, meshes);
+    			if(meshes.size() > 0) {
+    				Mesh[] targets = meshes.toArray(new Mesh[meshes.size()]);
+    				for (int i = 0; i < tracks.length; ++i){
+        	            ((PoseTrack)tracks[i]).setTime(time, targets, blendAmount);
+        	        }
+    			}
+    		}
+    	}
+    }
     
-    public void setTime(float time, float blendAmount, AnimControl control, AnimChannel channel);
+    /**
+     * This method returns the meshes within the given spatial.
+     * @param spatial the spatial to search the meshes from
+     * @param meshes the collection that will have the found meshes
+     */
+    private void getMeshes(Spatial spatial, Collection<Mesh> meshes) {
+    	if(spatial instanceof Geometry) {
+    		meshes.add(((Geometry) spatial).getMesh());
+		} else if(spatial instanceof Node) {
+			for(Spatial child : ((Node) spatial).getChildren()) {
+				this.getMeshes(child, meshes);
+			}
+		}
+    }
     
-    public Animation clone();
+    /**
+     * Set the {@link Track}s to be used by this animation.
+     * <p>
+     * The array should be organized so that the appropriate BoneTrack can
+     * be retrieved based on a bone index. 
+     * 
+     * @param tracks the tracks to set
+     */
+    public void setTracks(Track<?>[] tracks){
+        this.tracks = tracks;
+    }
+    
+    /**
+     * @return the tracks of the animation
+     */
+    public Track<?>[] getTracks() {
+    	return tracks;
+    }
+    
+    /**
+     * This method creates a clone of the current object.
+     * @return a clone of the current object
+     */
+	public Animation clone() {
+    	try {
+    		Animation result = (Animation) super.clone();
+    		if (tracks != null) {
+    			result.tracks = tracks.clone();
+    			for (int i = 0; i < tracks.length; ++i) {
+    				result.tracks[i] = this.tracks[i].clone();
+                }
+            }
+    		return result;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Animation[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, "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);
+        tracks = (Track<?>[]) in.readSavableArray("tracks", null);
+	}
 }

+ 6 - 9
engine/src/core/com/jme3/animation/BoneAnimation.java

@@ -47,8 +47,10 @@ import java.util.BitSet;
  * to apply the animation.
  * 
  * @author Kirill Vainer
+ * @deprecated use Animation instead with tracks of selected type (ie. BoneTrack, SpatialTrack, MeshTrack)
  */
-public final class BoneAnimation implements Animation, Savable, Cloneable {
+@Deprecated
+public final class BoneAnimation extends Animation {
 
     private String name;
     private float length;
@@ -118,7 +120,7 @@ public final class BoneAnimation implements Animation, Savable, Cloneable {
         
         for (int i = 0; i < tracks.length; i++) {
             if (affectedBones == null
-                    || affectedBones.get(tracks[i].getTargetBoneIndex())) {
+                    || affectedBones.get(tracks[i].getTargetIndex())) {
                 tracks[i].setTime(time, skeleton, blendAmount);
             }
         }
@@ -131,12 +133,7 @@ public final class BoneAnimation implements Animation, Savable, Cloneable {
     
     @Override
     public BoneAnimation clone() {
-        BoneAnimation result;
-        try {
-            result = (BoneAnimation) super.clone();
-        } catch (CloneNotSupportedException e) {
-            throw new AssertionError();
-        }
+        BoneAnimation result = (BoneAnimation) super.clone();
         if (result.tracks == null) {
             result.tracks = new BoneTrack[tracks.length];
         }
@@ -157,7 +154,7 @@ public final class BoneAnimation implements Animation, Savable, Cloneable {
                 scales[j] = sourceScales != null ? sourceScales[j].clone() : new Vector3f(1.0f, 1.0f, 1.0f);
             }
             // times do not change, no need to clone them
-            result.tracks[i] = new BoneTrack(tracks[i].getTargetBoneIndex(), times,
+            result.tracks[i] = new BoneTrack(tracks[i].getTargetIndex(), times,
                     translations, rotations, scales);
         }
         return result;

+ 36 - 4
engine/src/core/com/jme3/animation/BoneTrack.java

@@ -45,7 +45,7 @@ import java.io.IOException;
  * 
  * @author Kirill Vainer
  */
-public final class BoneTrack implements Savable {
+public final class BoneTrack implements Track<Skeleton> {
 
     /**
      * Bone index in the skeleton which this track effects.
@@ -105,14 +105,22 @@ public final class BoneTrack implements Savable {
         this.targetBoneIndex = targetBoneIndex;
     }
 
-    /**
-     * returns the bone index of this bone track
-     * @return 
+	/**
+     * @return the bone index of this bone track
+     * @deprecated use getTargetIndex() instead
      */
+    @Deprecated
     public int getTargetBoneIndex() {
         return targetBoneIndex;
     }
 
+    /**
+	 * @return the bone index of this bone track
+	 */
+	public int getTargetIndex() {
+		return targetBoneIndex;
+	}
+
     /**
      * return the array of rotations of this track
      * @return 
@@ -245,6 +253,30 @@ public final class BoneTrack implements Savable {
         }
     }
 
+    /**
+     * This method creates a clone of the current object.
+     * @return a clone of the current object
+     */
+	public BoneTrack clone() {
+        int tablesLength = times.length;
+
+        float[] times = this.times.clone();
+        Vector3f[] sourceTranslations = this.getTranslations();
+        Quaternion[] sourceRotations = this.getRotations();
+        Vector3f[] sourceScales = this.getScales();
+
+        Vector3f[] translations = new Vector3f[tablesLength];
+        Quaternion[] rotations = new Quaternion[tablesLength];
+        Vector3f[] scales = new Vector3f[tablesLength];
+        for (int i = 0; i < tablesLength; ++i) {
+            translations[i] = sourceTranslations[i].clone();
+            rotations[i] = sourceRotations[i].clone();
+            scales[i] = sourceScales != null ? sourceScales[i].clone() : new Vector3f(1.0f, 1.0f, 1.0f);
+        }
+        //need to use the constructor here because of the final fields used in this class
+        return new BoneTrack(targetBoneIndex, times, translations, rotations, scales);
+	}
+    
     @Override
     public void write(JmeExporter ex) throws IOException {
         OutputCapsule oc = ex.getCapsule(this);

+ 14 - 22
engine/src/core/com/jme3/animation/MeshAnimation.java

@@ -32,21 +32,25 @@
 
 package com.jme3.animation;
 
+import java.io.IOException;
+
+import com.jme3.export.InputCapsule;
 import com.jme3.export.JmeExporter;
 import com.jme3.export.JmeImporter;
-import com.jme3.export.InputCapsule;
 import com.jme3.export.OutputCapsule;
-import com.jme3.export.Savable;
 import com.jme3.scene.Mesh;
-import java.io.IOException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 
-public class MeshAnimation implements Animation, Savable {
+/**
+ * 
+ * @author Kirill Vainer
+ * @deprecated use Animation instead with tracks of selected type (ie. BoneTrack, SpatialTrack, MeshTrack)
+ */
+@Deprecated
+public class MeshAnimation extends Animation {
 
     private String name;
     private float length;
-    private Track[] tracks;
+    private PoseTrack[] tracks;
 
     public MeshAnimation(String name, float length){
         this.name = name;
@@ -61,11 +65,11 @@ public class MeshAnimation implements Animation, Savable {
         return length;
     }
 
-    public void setTracks(Track[] tracks){
+    public void setTracks(PoseTrack[] tracks){
         this.tracks = tracks;
     }
 
-    public Track[] getTracks(){
+    public PoseTrack[] getTracks(){
         return tracks;
     }
 
@@ -92,18 +96,6 @@ public class MeshAnimation implements Animation, Savable {
         InputCapsule in = i.getCapsule(this);
         name = in.readString("name", "");
         length = in.readFloat("length", -1f);
-        tracks = (Track[]) in.readSavableArray("tracks", null);
+        tracks = (PoseTrack[]) in.readSavableArray("tracks", null);
     }
-
-    @Override
-    public Animation clone() {
-        try {
-            return (Animation) super.clone();
-        } catch (CloneNotSupportedException ex) {
-            throw new AssertionError();
-        }
-    }
-
-    
-
 }

+ 25 - 4
engine/src/core/com/jme3/animation/Pose.java

@@ -32,20 +32,21 @@
 
 package com.jme3.animation;
 
+import java.io.IOException;
+import java.nio.FloatBuffer;
+
+import com.jme3.export.InputCapsule;
 import com.jme3.export.JmeExporter;
 import com.jme3.export.JmeImporter;
-import com.jme3.export.InputCapsule;
 import com.jme3.export.OutputCapsule;
 import com.jme3.export.Savable;
 import com.jme3.math.Vector3f;
 import com.jme3.util.BufferUtils;
-import java.io.IOException;
-import java.nio.FloatBuffer;
 
 /**
  * A pose is a list of offsets that say where a mesh vertices should be for this pose.
  */
-public final class Pose implements Savable {
+public final class Pose implements Savable, Cloneable {
 
     private String name;
     private int targetMeshIndex;
@@ -91,6 +92,26 @@ public final class Pose implements Savable {
             BufferUtils.setInBuffer(tempVec2, vertbuf, vertIndex);
         }
     }
+    
+    /**
+     * This method creates a clone of the current object.
+     * @return a clone of the current object
+     */
+    public Pose clone() {
+		try {
+			Pose result = (Pose) super.clone();
+            result.indices = this.indices.clone();
+            if(this.offsets!=null) {
+            	result.offsets = new Vector3f[this.offsets.length];
+            	for(int i=0;i<this.offsets.length;++i) {
+            		result.offsets[i] = this.offsets[i].clone();
+            	}
+            }
+    		return result;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError();
+        }
+	}
 
     public void write(JmeExporter e) throws IOException {
         OutputCapsule out = e.getCapsule(this);

+ 80 - 3
engine/src/core/com/jme3/animation/PoseTrack.java

@@ -37,6 +37,8 @@ import com.jme3.export.JmeImporter;
 import com.jme3.export.InputCapsule;
 import com.jme3.export.OutputCapsule;
 import com.jme3.export.Savable;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.VertexBuffer.Type;
@@ -46,12 +48,13 @@ import java.nio.FloatBuffer;
 /**
  * A single track of pose animation associated with a certain mesh.
  */
-public final class PoseTrack extends Track {
+public final class PoseTrack implements Track<Mesh[]> {
     
+	protected int targetMeshIndex;
     private PoseFrame[] frames;
     private float[]     times;
 
-    public static class PoseFrame implements Savable {
+    public static class PoseFrame implements Savable, Cloneable {
 
         Pose[] poses;
         float[] weights;
@@ -60,6 +63,26 @@ public final class PoseTrack extends Track {
             this.poses = poses;
             this.weights = weights;
         }
+        
+        /**
+         * This method creates a clone of the current object.
+         * @return a clone of the current object
+         */
+        public PoseFrame clone() {
+    		try {
+    			PoseFrame result = (PoseFrame) super.clone();
+                result.weights = this.weights.clone();
+                if(this.poses != null) {
+                	result.poses = new Pose[this.poses.length];
+                	for(int i=0;i<this.poses.length;++i) {
+                		result.poses[i] = this.poses[i].clone();
+                	}
+                }
+        		return result;
+            } catch (CloneNotSupportedException e) {
+                throw new AssertionError();
+            }
+    	}
 
         public void write(JmeExporter e) throws IOException {
             OutputCapsule out = e.getCapsule(this);
@@ -75,10 +98,17 @@ public final class PoseTrack extends Track {
     }
 
     public PoseTrack(int targetMeshIndex, float[] times, PoseFrame[] frames){
-        super(targetMeshIndex);
+        this.targetMeshIndex = targetMeshIndex;
         this.times = times;
         this.frames = frames;
     }
+    
+    /**
+	 * @return the index of the target object for this track
+	 */
+	public int getTargetIndex() {
+		return targetMeshIndex;
+	}
 
     private void applyFrame(Mesh target, int frameIndex, float weight){
         PoseFrame frame = frames[frameIndex];
@@ -114,9 +144,30 @@ public final class PoseTrack extends Track {
         }
     }
 
+    /**
+     * This method creates a clone of the current object.
+     * @return a clone of the current object
+     */
+    public PoseTrack clone() {
+		try {
+			PoseTrack result = (PoseTrack) super.clone();
+            result.times = this.times.clone();
+            if(this.frames!=null) {
+            	result.frames = new PoseFrame[this.frames.length];
+            	for(int i=0;i<this.frames.length;++i) {
+            		result.frames[i] = this.frames[i].clone();
+            	}
+            }
+    		return result;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError();
+        }
+	}
+    
     @Override
     public void write(JmeExporter e) throws IOException {
         OutputCapsule out = e.getCapsule(this);
+        out.write(targetMeshIndex, "meshIndex", 0);
         out.write(frames, "frames", null);
         out.write(times, "times", null);
     }
@@ -124,7 +175,33 @@ public final class PoseTrack extends Track {
     @Override
     public void read(JmeImporter i) throws IOException {
         InputCapsule in = i.getCapsule(this);
+        targetMeshIndex = in.readInt("meshIndex", 0);
         frames = (PoseFrame[]) in.readSavableArray("frames", null);
         times = in.readFloatArray("times", null);
     }
+
+	@Override
+	public Quaternion[] getRotations() {
+		return null;
+	}
+
+	@Override
+	public Vector3f[] getScales() {
+		return null;
+	}
+
+	@Override
+	public float[] getTimes() {
+		return null;
+	}
+
+	@Override
+	public Vector3f[] getTranslations() {
+		return null;
+	}
+
+	@Override
+	public void setKeyframes(float[] times, Vector3f[] translations,
+			Quaternion[] rotations, Vector3f[] scales) {
+	}
 }

+ 10 - 17
engine/src/core/com/jme3/animation/SpatialAnimation.java

@@ -13,14 +13,16 @@ import com.jme3.scene.Spatial;
  * affected by their parent's movement.
  * 
  * @author Marcin Roguski (Kaelthas)
+ * @deprecated use Animation instead with tracks of selected type (ie. BoneTrack, SpatialTrack, MeshTrack)
  */
-public class SpatialAnimation implements Animation {
+@Deprecated
+public class SpatialAnimation extends Animation {
 	/** The name of the animation. */
 	private String name;
 	/** The length of the animation. */
 	private float length;
 	/** The track of the animation. */
-	private SpatialTrack track;
+	private SpatialTrack[] tracks;
 
 	/**
 	 * Constructor. Stores the name and length of the animation.
@@ -37,7 +39,7 @@ public class SpatialAnimation implements Animation {
 			AnimChannel channel) {
 		Spatial spatial = control.getSpatial();
 		if (spatial != null) {
-			track.setTime(time, spatial);
+			tracks[0].setTime(time, spatial, 0);
 		}
 	}
 
@@ -46,14 +48,14 @@ public class SpatialAnimation implements Animation {
 	 * @param track the animation track
 	 */
 	public void setTrack(SpatialTrack track) {
-		this.track = track;
+		this.tracks[0] = track;
 	}
 
 	/**
 	 * @return the animation track
 	 */
-	public SpatialTrack getTracks() {
-		return track;
+	public SpatialTrack[] getTracks() {
+		return tracks;
 	}
 
 	@Override
@@ -71,21 +73,12 @@ public class SpatialAnimation implements Animation {
 		return "SpatialAnim[name=" + name + ", length=" + length + "]";
 	}
 
-	@Override
-	public Animation clone() {
-		try {
-			return (Animation) super.clone();
-		} catch (CloneNotSupportedException e) {
-			throw new AssertionError();
-		}
-	}
-
 	@Override
 	public void write(JmeExporter ex) throws IOException {
 		OutputCapsule oc = ex.getCapsule(this);
 		oc.write(name, "name", null);
 		oc.write(length, "length", 0);
-		oc.write(track, "track", null);
+		oc.write(tracks, "tracks", null);
 	}
 
 	@Override
@@ -93,6 +86,6 @@ public class SpatialAnimation implements Animation {
 		InputCapsule in = im.getCapsule(this);
 		name = in.readString("name", null);
 		length = in.readFloat("length", 0);
-		track = (SpatialTrack) in.readSavable("track", null);
+		tracks = (SpatialTrack[]) in.readSavableArray("track", null);
 	}
 }

+ 33 - 3
engine/src/core/com/jme3/animation/SpatialTrack.java

@@ -6,7 +6,6 @@ import com.jme3.export.InputCapsule;
 import com.jme3.export.JmeExporter;
 import com.jme3.export.JmeImporter;
 import com.jme3.export.OutputCapsule;
-import com.jme3.export.Savable;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.Spatial;
@@ -16,7 +15,7 @@ import com.jme3.scene.Spatial;
  * 
  * @author Marcin Roguski (Kaelthas)
  */
-public class SpatialTrack implements Savable {
+public class SpatialTrack implements Track<Spatial> {
 	/** Translations of the track. */
 	private CompactVector3Array translations;
 	/** Rotations of the track. */
@@ -63,7 +62,7 @@ public class SpatialTrack implements Savable {
 	 * @param spatial
 	 *            the spatial that should be animated with this track
 	 */
-	public void setTime(float time, Spatial spatial) {
+	public void setTime(float time, Spatial spatial, float weight) {
 		int lastFrame = times.length - 1;
 		if (time < 0 || lastFrame == 0) {
 			rotations.get(0, tempQ);
@@ -147,6 +146,13 @@ public class SpatialTrack implements Savable {
 		}
 	}
 
+	/**
+	 * @return the index of the target object for this track
+	 */
+	public int getTargetIndex() {
+		return 0;
+	}
+	
 	/**
 	 * @return the array of rotations of this track
 	 */
@@ -175,6 +181,30 @@ public class SpatialTrack implements Savable {
 		return translations.toObjectArray();
 	}
 
+	/**
+     * This method creates a clone of the current object.
+     * @return a clone of the current object
+     */
+	public SpatialTrack clone() {
+        int tablesLength = times.length;
+
+        float[] times = this.times.clone();
+        Vector3f[] sourceTranslations = this.getTranslations();
+        Quaternion[] sourceRotations = this.getRotations();
+        Vector3f[] sourceScales = this.getScales();
+
+        Vector3f[] translations = new Vector3f[tablesLength];
+        Quaternion[] rotations = new Quaternion[tablesLength];
+        Vector3f[] scales = new Vector3f[tablesLength];
+        for (int i = 0; i < tablesLength; ++i) {
+            translations[i] = sourceTranslations[i].clone();
+            rotations[i] = sourceRotations[i].clone();
+            scales[i] = sourceScales != null ? sourceScales[i].clone() : new Vector3f(1.0f, 1.0f, 1.0f);
+        }
+        //need to use the constructor here because of the final fields used in this class
+        return new SpatialTrack(times, translations, rotations, scales);
+	}
+	
 	@Override
 	public void write(JmeExporter ex) throws IOException {
 		OutputCapsule oc = ex.getCapsule(this);

+ 49 - 32
engine/src/core/com/jme3/animation/Track.java

@@ -31,49 +31,66 @@
  */
 package com.jme3.animation;
 
-import com.jme3.export.JmeExporter;
-import com.jme3.export.JmeImporter;
 import com.jme3.export.Savable;
-import com.jme3.scene.Mesh;
-import java.io.IOException;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
 
 /**
  * A single track of mesh animation (either morph or pose based).
  * Currently morph animations are not supported (only pose).
  */
-public abstract class Track implements Savable {
-
-    protected int targetMeshIndex;
-
-    /**
-     * build a track for a an index
-     * @param targetMeshIndex 
-     */
-    public Track(int targetMeshIndex) {
-        this.targetMeshIndex = targetMeshIndex;
-    }
-
-    /**
-     * return the mesh index
-     * @return 
-     */
-    public int getTargetMeshIndex() {
-        return targetMeshIndex;
-    }
-
+public interface Track<T> extends Savable, Cloneable {
     /**
      * sets time for this track
      * @param time
-     * @param targets
+     * @param target
      * @param weight 
      */
-    public abstract void setTime(float time, Mesh[] targets, float weight);
+    void setTime(float time, T target, float weight);
+    
+    /**
+	 * Set the translations, rotations and scales for this track.
+	 * 
+	 * @param times
+	 *            a float array with the time of each frame
+	 * @param translations
+	 *            the translation of the bone for each frame
+	 * @param rotations
+	 *            the rotation of the bone for each frame
+	 * @param scales
+	 *            the scale of the bone for each frame
+	 */
+	void setKeyframes(float[] times, Vector3f[] translations,
+					  Quaternion[] rotations, Vector3f[] scales);
+    
+	/**
+	 * @return the index of the target object for this track
+	 */
+	int getTargetIndex();
+	
+    /**
+	 * @return the array of rotations of this track
+	 */
+	Quaternion[] getRotations();
+
+	/**
+	 * @return the array of scales for this track
+	 */
+	Vector3f[] getScales();
 
-    public void write(JmeExporter ex) throws IOException {
-        ex.getCapsule(this).write(targetMeshIndex, "meshIndex", 0);
-    }
+	/**
+	 * @return the arrays of time for this track
+	 */
+	float[] getTimes();
 
-    public void read(JmeImporter im) throws IOException {
-        targetMeshIndex = im.getCapsule(this).readInt("meshIndex", 0);
-    }
+	/**
+	 * @return the array of translations of this track
+	 */
+	Vector3f[] getTranslations();
+	
+	/**
+     * This method creates a clone of the current object.
+     * @return a clone of the current object
+     */
+	Track<T> clone();
 }

+ 13 - 17
engine/src/ogre/com/jme3/scene/plugins/ogre/SkeletonLoader.java

@@ -31,30 +31,16 @@
  */
 package com.jme3.scene.plugins.ogre;
 
-import com.jme3.animation.Animation;
-import com.jme3.animation.Bone;
-import com.jme3.animation.BoneAnimation;
-import com.jme3.animation.BoneTrack;
-import com.jme3.animation.Skeleton;
-import com.jme3.asset.AssetInfo;
-import com.jme3.asset.AssetLoader;
-import com.jme3.asset.AssetManager;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Vector3f;
-import com.jme3.system.JmeSystem;
-import com.jme3.util.xml.SAXUtil;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
 import java.util.Stack;
 import java.util.logging.Logger;
 
 import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
 import org.xml.sax.Attributes;
@@ -62,7 +48,17 @@ import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.helpers.XMLReaderFactory;
+
+import com.jme3.animation.Animation;
+import com.jme3.animation.Bone;
+import com.jme3.animation.BoneTrack;
+import com.jme3.animation.Skeleton;
+import com.jme3.asset.AssetInfo;
+import com.jme3.asset.AssetLoader;
+import com.jme3.asset.AssetManager;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.util.xml.SAXUtil;
 
 public class SkeletonLoader extends DefaultHandler implements AssetLoader {
 
@@ -73,7 +69,7 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
     private HashMap<String, Bone> nameToBone = new HashMap<String, Bone>();
     private BoneTrack track;
     private ArrayList<BoneTrack> tracks = new ArrayList<BoneTrack>();
-    private BoneAnimation animation;
+    private Animation animation;
     private ArrayList<Animation> animations;
     private Bone bone;
     private Skeleton skeleton;
@@ -132,7 +128,7 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
             assert elementStack.peek().equals("animations");
             String name = SAXUtil.parseString(attribs.getValue("name"));
             float length = SAXUtil.parseFloat(attribs.getValue("length"));
-            animation = new BoneAnimation(name, length);
+            animation = new Animation(name, length);
         } else if (qName.equals("bonehierarchy")) {
             assert elementStack.peek().equals("skeleton");
         } else if (qName.equals("animations")) {

+ 2 - 3
engine/src/test/jme3test/model/anim/TestSpatialAnim.java

@@ -4,7 +4,6 @@ import java.util.HashMap;
 
 import com.jme3.animation.AnimControl;
 import com.jme3.animation.Animation;
-import com.jme3.animation.SpatialAnimation;
 import com.jme3.animation.SpatialTrack;
 import com.jme3.app.SimpleApplication;
 import com.jme3.light.AmbientLight;
@@ -71,8 +70,8 @@ public class TestSpatialAnim extends SimpleApplication {
         SpatialTrack spatialTrack = new SpatialTrack(times, translations, rotations, scales);
         
         //creating the animation
-        SpatialAnimation spatialAnimation = new SpatialAnimation("anim", animTime);
-        spatialAnimation.setTrack(spatialTrack);
+        Animation spatialAnimation = new Animation("anim", animTime);
+        spatialAnimation.setTracks(new SpatialTrack[] { spatialTrack });
         
         //create spatial animation control
         AnimControl control = new AnimControl();