浏览代码

Automatic loading of both bone and object animations (no need to specify animations in blender key any more).

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8305 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
Kae..pl 14 年之前
父节点
当前提交
0b274b3c1b

+ 0 - 127
engine/src/blender/com/jme3/asset/BlenderKey.java

@@ -33,12 +33,8 @@ package com.jme3.asset;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Queue;
-import java.util.Set;
 
 import com.jme3.bounding.BoundingVolume;
 import com.jme3.collision.Collidable;
@@ -66,13 +62,6 @@ import com.jme3.texture.Texture;
 public class BlenderKey extends ModelKey {
 
 	protected static final int					DEFAULT_FPS				= 25;
-	/**
-	 * Animation definitions. The key is the object name that owns the animation. The value is a map between animation
-	 * name and its start and stop frames. Blender stores a pointer for animation within object. Therefore one object
-	 * can only have one animation at the time. We want to be able to switch between animations for one object so we
-	 * need to map the object name to animation names the object will use.
-	 */
-	protected Map<String, Map<String, int[]>>	animations;
 	/**
 	 * FramesPerSecond parameter describe how many frames there are in each second. It allows to calculate the time
 	 * between the frames.
@@ -126,76 +115,6 @@ public class BlenderKey extends ModelKey {
 		super(name);
 	}
 
-	/**
-	 * This method adds an animation definition. If a definition already eixists in the key then it is replaced.
-	 * @param objectName
-	 *        the name of animation's owner
-	 * @param name
-	 *        the name of the animation
-	 * @param start
-	 *        the start frame of the animation
-	 * @param stop
-	 *        the stop frame of the animation
-	 */
-	public synchronized void addAnimation(String objectName, String name, int start, int stop) {
-		if (objectName == null) {
-			throw new IllegalArgumentException("Object name cannot be null!");
-		}
-		if (name == null) {
-			throw new IllegalArgumentException("Animation name cannot be null!");
-		}
-		if (start > stop) {
-			throw new IllegalArgumentException("Start frame cannot be greater than stop frame!");
-		}
-		if (animations == null) {
-			animations = new HashMap<String, Map<String, int[]>>();
-			animations.put(objectName, new HashMap<String, int[]>());
-		}
-		Map<String, int[]> objectAnimations = animations.get(objectName);
-		if (objectAnimations == null) {
-			objectAnimations = new HashMap<String, int[]>();
-			animations.put(objectName, objectAnimations);
-		}
-		objectAnimations.put(name, new int[] { start, stop });
-	}
-
-	/**
-	 * This method returns the animation frames boundaries.
-	 * @param objectName
-	 *        the name of animation's owner
-	 * @param name
-	 *        animation name
-	 * @return animation frame boundaries in a table [start, stop] or null if animation of the given name does not
-	 *         exists
-	 */
-	public int[] getAnimationFrames(String objectName, String name) {
-		Map<String, int[]> objectAnimations = animations == null ? null : animations.get(objectName);
-		int[] frames = objectAnimations == null ? null : objectAnimations.get(name);
-		return frames == null ? null : frames.clone();
-	}
-
-	/**
-	 * This method returns the animation names for the given object name.
-	 * @param objectName
-	 *        the name of the object
-	 * @return an array of animations for this object
-	 */
-	public Set<String> getAnimationNames(String objectName) {
-		Map<String, int[]> objectAnimations = animations == null ? null : animations.get(objectName);
-		return objectAnimations == null ? null : objectAnimations.keySet();
-	}
-
-	/**
-	 * This method returns the animations map.
-	 * The key is the animated spatial name. The value is a map where the key
-	 * is the animation name and the value is 2-element array of int that has
-	 * start and stop frame of the animation.
-	 * @return the animations map
-	 */
-	public Map<String, Map<String, int[]>> getAnimations() {
-		return animations;
-	}
-
 	/**
 	 * This method returns frames per second amount. The default value is BlenderKey.DEFAULT_FPS = 25.
 	 * @return the frames per second amount
@@ -424,22 +343,6 @@ public class BlenderKey extends ModelKey {
 	public void write(JmeExporter e) throws IOException {
 		super.write(e);
 		OutputCapsule oc = e.getCapsule(this);
-		// saving animations
-		oc.write(animations == null ? 0 : animations.size(), "anim-size", 0);
-		if (animations != null) {
-			int objectCounter = 0;
-			for (Entry<String, Map<String, int[]>> animEntry : animations.entrySet()) {
-				oc.write(animEntry.getKey(), "animated-object-" + objectCounter, null);
-				int animsAmount = animEntry.getValue().size();
-				oc.write(animsAmount, "anims-amount-" + objectCounter, 0);
-				for (Entry<String, int[]> animsEntry : animEntry.getValue().entrySet()) {
-					oc.write(animsEntry.getKey(), "anim-name-" + objectCounter, null);
-					oc.write(animsEntry.getValue(), "anim-frames-" + objectCounter, null);
-				}
-				++objectCounter;
-			}
-		}
-		// saving the rest of the data
 		oc.write(fps, "fps", DEFAULT_FPS);
 		oc.write(generatedTextureWidth, "generated-texture-width", 20);
 		oc.write(generatedTextureHeight, "generated-texture-height", 20);
@@ -458,28 +361,6 @@ public class BlenderKey extends ModelKey {
 	public void read(JmeImporter e) throws IOException {
 		super.read(e);
 		InputCapsule ic = e.getCapsule(this);
-		// reading animations
-		int animSize = ic.readInt("anim-size", 0);
-		if (animSize > 0) {
-			if (animations == null) {
-				animations = new HashMap<String, Map<String, int[]>>(animSize);
-			} else {
-				animations.clear();
-			}
-			for (int i = 0; i < animSize; ++i) {
-				String objectName = ic.readString("animated-object-" + i, null);
-				int animationsAmount = ic.readInt("anims-amount-" + i, 0);
-				Map<String, int[]> objectAnimations = new HashMap<String, int[]>(animationsAmount);
-				for (int j = 0; j < animationsAmount; ++j) {
-					String animName = ic.readString("anim-name-" + i, null);
-					int[] animFrames = ic.readIntArray("anim-frames-" + i, null);
-					objectAnimations.put(animName, animFrames);
-				}
-				animations.put(objectName, objectAnimations);
-			}
-		}
-
-		// reading the rest of the data
 		fps = ic.readInt("fps", DEFAULT_FPS);
 		generatedTextureWidth = ic.readInt("generated-texture-width", 20);
 		generatedTextureHeight = ic.readInt("generated-texture-height", 20);
@@ -498,7 +379,6 @@ public class BlenderKey extends ModelKey {
 	public int hashCode() {
 		final int prime = 31;
 		int result = super.hashCode();
-		result = prime * result + (animations == null ? 0 : animations.hashCode());
 		result = prime * result + (assetRootPath == null ? 0 : assetRootPath.hashCode());
 		result = prime * result + (defaultMaterial == null ? 0 : defaultMaterial.hashCode());
 		result = prime * result + (faceCullMode == null ? 0 : faceCullMode.hashCode());
@@ -526,13 +406,6 @@ public class BlenderKey extends ModelKey {
 			return false;
 		}
 		BlenderKey other = (BlenderKey) obj;
-		if (animations == null) {
-			if (other.animations != null) {
-				return false;
-			}
-		} else if (!animations.equals(other.animations)) {
-			return false;
-		}
 		if (assetRootPath == null) {
 			if (other.assetRootPath != null) {
 				return false;

+ 12 - 26
engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java

@@ -39,7 +39,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.jme3.animation.Bone;
-import com.jme3.animation.BoneTrack;
+import com.jme3.animation.Track;
 import com.jme3.math.Matrix4f;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Vector3f;
@@ -320,20 +320,16 @@ public class ArmatureHelper extends AbstractBlenderHelper {
 	 *            the structure containing the tracks
 	 * @param blenderContext
 	 *            the blender context
-	 * @param objectName
-	 *            the name of the object that will use these tracks
-	 * @param animationName
-	 *            the animation name
 	 * @return a list of tracks for the specified animation
 	 * @throws BlenderFileException
 	 *             an exception is thrown when there are problems with the blend
 	 *             file
 	 */
-    public BoneTrack[] getTracks(Structure actionStructure, BlenderContext blenderContext, String objectName, String animationName) throws BlenderFileException {
+    public Track<?>[] getTracks(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
     	if (blenderVersion < 250) {
-            return this.getTracks249(actionStructure, blenderContext, objectName, animationName);
+            return this.getTracks249(actionStructure, blenderContext);
         } else {
-        	return this.getTracks250(actionStructure, blenderContext, objectName, animationName);
+        	return this.getTracks250(actionStructure, blenderContext);
         }
     }
     
@@ -344,26 +340,21 @@ public class ArmatureHelper extends AbstractBlenderHelper {
 	 *            the structure containing the tracks
 	 * @param blenderContext
 	 *            the blender context
-	 * @param objectName
-	 *            the name of the object that will use these tracks
-	 * @param animationName
-	 *            the animation name
 	 * @return a list of tracks for the specified animation
 	 * @throws BlenderFileException
 	 *             an exception is thrown when there are problems with the blend
 	 *             file
 	 */
-    private BoneTrack[] getTracks250(Structure actionStructure, BlenderContext blenderContext, String objectName, String animationName) throws BlenderFileException {
+    private Track<?>[] getTracks250(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
         LOGGER.log(Level.INFO, "Getting tracks!");
         int fps = blenderContext.getBlenderKey().getFps();
-        int[] animationFrames = blenderContext.getBlenderKey().getAnimationFrames(objectName, animationName);
         Structure groups = (Structure) actionStructure.getFieldValue("groups");
         List<Structure> actionGroups = groups.evaluateListBase(blenderContext);//bActionGroup
         if (actionGroups != null && actionGroups.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
             throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
         }
 
-        List<BoneTrack> tracks = new ArrayList<BoneTrack>();
+        List<Track<?>> tracks = new ArrayList<Track<?>>();
         for (Structure actionGroup : actionGroups) {
             String name = actionGroup.getFieldValue("name").toString();
             Integer boneIndex = bonesMap.get(name);
@@ -389,10 +380,10 @@ public class ArmatureHelper extends AbstractBlenderHelper {
                 }
 
                 Ipo ipo = new Ipo(bezierCurves);
-                tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));
+                tracks.add(ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
             }
         }
-        return tracks.toArray(new BoneTrack[tracks.size()]);
+        return tracks.toArray(new Track<?>[tracks.size()]);
     }
     
     /**
@@ -402,26 +393,21 @@ public class ArmatureHelper extends AbstractBlenderHelper {
 	 *            the structure containing the tracks
 	 * @param blenderContext
 	 *            the blender context
-	 * @param objectName
-	 *            the name of the object that will use these tracks
-	 * @param animationName
-	 *            the animation name
 	 * @return a list of tracks for the specified animation
 	 * @throws BlenderFileException
 	 *             an exception is thrown when there are problems with the blend
 	 *             file
 	 */
-    private BoneTrack[] getTracks249(Structure actionStructure, BlenderContext blenderContext, String objectName, String animationName) throws BlenderFileException {
+    private Track<?>[] getTracks249(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
     	LOGGER.log(Level.INFO, "Getting tracks!");
         IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
         int fps = blenderContext.getBlenderKey().getFps();
-        int[] animationFrames = blenderContext.getBlenderKey().getAnimationFrames(objectName, animationName);
         Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase");
         List<Structure> actionChannels = chanbase.evaluateListBase(blenderContext);//bActionChannel
         if (actionChannels != null && actionChannels.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
             throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
         }
-        List<BoneTrack> tracks = new ArrayList<BoneTrack>();
+        List<Track<?>> tracks = new ArrayList<Track<?>>();
         for (Structure bActionChannel : actionChannels) {
             String name = bActionChannel.getFieldValue("name").toString();
             Integer boneIndex = bonesMap.get(name);
@@ -430,11 +416,11 @@ public class ArmatureHelper extends AbstractBlenderHelper {
                 if (!p.isNull()) {
                     Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0);
                     Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
-                    tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));
+                    tracks.add(ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
                 }
             }
         }
-        return tracks.toArray(new BoneTrack[tracks.size()]);
+        return tracks.toArray(new Track<?>[tracks.size()]);
     }
 
     /**

+ 64 - 56
engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java

@@ -1,6 +1,8 @@
 package com.jme3.scene.plugins.blender.animations;
 
 import com.jme3.animation.BoneTrack;
+import com.jme3.animation.SpatialTrack;
+import com.jme3.animation.Track;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.plugins.blender.curves.BezierCurve;
@@ -28,7 +30,7 @@ public class Ipo {
     /** A list of bezier curves for this interpolation object. */
     private BezierCurve[] bezierCurves;
     /** Each ipo contains one bone track. */
-    private BoneTrack calculatedTrack;
+    private Track<?> calculatedTrack;
 
     /**
      * Constructor. Stores the bezier curves.
@@ -105,8 +107,9 @@ public class Ipo {
 
     /**
      * This method calculates the value of the curves as a bone track between the specified frames.
-     * @param boneIndex
-     *        the index of the bone for which the method calculates the tracks
+     * @param targetIndex
+     *        the index of the target for which the method calculates the tracks
+     *        IMPORTANT! Aet to -1 (or any negative number) if you want to load spatial animation.
      * @param startFrame
      *        the firs frame of tracks (inclusive)
      * @param stopFrame
@@ -115,63 +118,68 @@ public class Ipo {
      *        frame rate (frames per second)
      * @return bone track for the specified bone
      */
-    public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps) {
-        //preparing data for track
-        int framesAmount = stopFrame - startFrame;
-        float start = (startFrame - 1.0f) / fps;
-        float timeBetweenFrames = 1.0f / fps;
+    public Track<?> calculateTrack(int targetIndex, int startFrame, int stopFrame, int fps) {
+    	if(calculatedTrack == null) {
+    		//preparing data for track
+            int framesAmount = stopFrame - startFrame;
+            float start = (startFrame - 1.0f) / fps;
+            float timeBetweenFrames = 1.0f / fps;
 
-        float[] times = new float[framesAmount + 1];
-        Vector3f[] translations = new Vector3f[framesAmount + 1];
-        float[] translation = new float[3];
-        Quaternion[] rotations = new Quaternion[framesAmount + 1];
-        float[] quaternionRotation = new float[4];
-        float[] objectRotation = new float[3];
-        boolean bObjectRotation = false;
-        Vector3f[] scales = new Vector3f[framesAmount + 1];
-        float[] scale = new float[3];
+            float[] times = new float[framesAmount + 1];
+            Vector3f[] translations = new Vector3f[framesAmount + 1];
+            float[] translation = new float[3];
+            Quaternion[] rotations = new Quaternion[framesAmount + 1];
+            float[] quaternionRotation = new float[4];
+            float[] objectRotation = new float[3];
+            boolean bSpatialTrack = targetIndex < 0;
+            Vector3f[] scales = new Vector3f[framesAmount + 1];
+            float[] scale = new float[3];
 
-        //calculating track data
-        for (int frame = startFrame; frame <= stopFrame; ++frame) {
-            int index = frame - startFrame;
-            times[index] = start + (frame - 1) * timeBetweenFrames;
-            for (int j = 0; j < bezierCurves.length; ++j) {
-                double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);
-                switch (bezierCurves[j].getType()) {
-                    case AC_LOC_X:
-                    case AC_LOC_Y:
-                    case AC_LOC_Z:
-                        translation[bezierCurves[j].getType() - 1] = (float) value;
-                        break;
-                    case OB_ROT_X:
-                    case OB_ROT_Y:
-                    case OB_ROT_Z:
-                        objectRotation[bezierCurves[j].getType() - 7] = (float) value;
-                        bObjectRotation = true;
-                        break;
-                    case AC_SIZE_X:
-                    case AC_SIZE_Y:
-                    case AC_SIZE_Z:
-                        scale[bezierCurves[j].getType() - 13] = (float) value;
-                        break;
-                    case AC_QUAT_W:
-                        quaternionRotation[3] = (float) value;
-                        break;
-                    case AC_QUAT_X:
-                    case AC_QUAT_Y:
-                    case AC_QUAT_Z:
-                        quaternionRotation[bezierCurves[j].getType() - 26] = (float) value;
-                        break;
-                    default:
-                    //TODO: error? info? warning?
+            //calculating track data
+            for (int frame = startFrame; frame <= stopFrame; ++frame) {
+                int index = frame - startFrame;
+                times[index] = start + (frame - 1) * timeBetweenFrames;
+                for (int j = 0; j < bezierCurves.length; ++j) {
+                    double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);
+                    switch (bezierCurves[j].getType()) {
+                        case AC_LOC_X:
+                        case AC_LOC_Y:
+                        case AC_LOC_Z:
+                            translation[bezierCurves[j].getType() - 1] = (float) value;
+                            break;
+                        case OB_ROT_X:
+                        case OB_ROT_Y:
+                        case OB_ROT_Z:
+                            objectRotation[bezierCurves[j].getType() - 7] = (float) value;
+                            break;
+                        case AC_SIZE_X:
+                        case AC_SIZE_Y:
+                        case AC_SIZE_Z:
+                            scale[bezierCurves[j].getType() - 13] = (float) value;
+                            break;
+                        case AC_QUAT_W:
+                            quaternionRotation[3] = (float) value;
+                            break;
+                        case AC_QUAT_X:
+                        case AC_QUAT_Y:
+                        case AC_QUAT_Z:
+                            quaternionRotation[bezierCurves[j].getType() - 26] = (float) value;
+                            break;
+                        default:
+                        //TODO: error? info? warning?
+                    }
                 }
+                translations[index] = new Vector3f(translation[0], translation[1], translation[2]);
+                rotations[index] = bSpatialTrack ? new Quaternion().fromAngles(objectRotation)
+                        : new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);
+                scales[index] = new Vector3f(scale[0], scale[1], scale[2]);
             }
-            translations[index] = new Vector3f(translation[0], translation[1], translation[2]);
-            rotations[index] = bObjectRotation ? new Quaternion().fromAngles(objectRotation)
-                    : new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);
-            scales[index] = new Vector3f(scale[0], scale[1], scale[2]);
-        }
-        calculatedTrack = new BoneTrack(boneIndex, times, translations, rotations, scales);
+            if(bSpatialTrack) {
+            	calculatedTrack = new SpatialTrack(times, translations, rotations, scales);
+            } else {
+            	calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales);
+            }
+    	}
         return calculatedTrack;
     }
 }

+ 19 - 20
engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java

@@ -6,7 +6,6 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -15,6 +14,7 @@ import com.jme3.animation.Animation;
 import com.jme3.animation.Bone;
 import com.jme3.animation.Skeleton;
 import com.jme3.animation.SkeletonControl;
+import com.jme3.animation.Track;
 import com.jme3.math.Matrix4f;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.Mesh;
@@ -116,28 +116,27 @@ import com.jme3.util.BufferUtils;
 				this.readVerticesWeightsData(objectStructure, meshStructure, blenderContext);
 				
 				//read animations
-				String objectName = objectStructure.getName();
-				Set<String> animationNames = blenderContext.getBlenderKey().getAnimationNames(objectName);
-                                System.out.println("Loaded animation " + objectName);
-				if (animationNames != null && animationNames.size() > 0) {
-					ArrayList<Animation> animations = new ArrayList<Animation>();
-					List<FileBlockHeader> actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
-					for (FileBlockHeader header : actionHeaders) {
-						Structure actionStructure = header.getStructure(blenderContext);
-						String actionName = actionStructure.getName();
-						if (animationNames.contains(actionName)) {
-							int[] animationFrames = blenderContext.getBlenderKey().getAnimationFrames(objectName, actionName);
-							int fps = blenderContext.getBlenderKey().getFps();
-							float start = (float) animationFrames[0] / (float) fps;
-							float stop = (float) animationFrames[1] / (float) fps;
-							Animation boneAnimation = new Animation(actionName, stop - start);
-							boneAnimation.setTracks(armatureHelper.getTracks(actionStructure, blenderContext, objectName, actionName));
-							animations.add(boneAnimation);
-                                                 
+				ArrayList<Animation> animations = new ArrayList<Animation>();
+				List<FileBlockHeader> actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
+				for (FileBlockHeader header : actionHeaders) {
+					Structure actionStructure = header.getStructure(blenderContext);
+					String actionName = actionStructure.getName();
+					
+					Track<?>[] tracks = armatureHelper.getTracks(actionStructure, blenderContext);
+					//determining the animation  time
+					float maximumTrackLength = 0;
+					for(Track<?> track : tracks) {
+						float length = track.getLength();
+						if(length > maximumTrackLength) {
+							maximumTrackLength = length;
 						}
 					}
-					animData = new AnimData(new Skeleton(bones), animations);
+					
+					Animation boneAnimation = new Animation(actionName, maximumTrackLength);
+					boneAnimation.setTracks(tracks);
+					animations.add(boneAnimation);
 				}
+				animData = new AnimData(new Skeleton(bones), animations);
 			}
 		}
 	}

+ 48 - 24
engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java

@@ -1,10 +1,22 @@
 package com.jme3.scene.plugins.blender.modifiers;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.Animation;
+import com.jme3.animation.Track;
 import com.jme3.scene.Node;
 import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.scene.plugins.blender.animations.Ipo;
+import com.jme3.scene.plugins.blender.animations.IpoHelper;
+import com.jme3.scene.plugins.blender.constraints.Constraint;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
+import com.jme3.scene.plugins.blender.file.FileBlockHeader;
+import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.ogre.AnimData;
 
@@ -41,13 +53,12 @@ import com.jme3.scene.plugins.ogre.AnimData;
 	 */
 	public ObjectAnimationModifier(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
 		LOGGER.warning("Object animation modifier not yet implemented!");
-		/*
+		
 		Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
 		if (pIpo.isNotNull()) {
 			// check if there is an action name connected with this ipo
 			String objectAnimationName = null;
-			List<FileBlockHeader> actionBlocks = blenderContext
-					.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
+			List<FileBlockHeader> actionBlocks = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
 			for (FileBlockHeader actionBlock : actionBlocks) {
 				Structure action = actionBlock.getStructure(blenderContext);
 				List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext);
@@ -68,38 +79,51 @@ import com.jme3.scene.plugins.ogre.AnimData;
 			IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
 			Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0);
 			Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
-			int[] animationFrames = blenderContext.getBlenderKey().getAnimationFrames(objectName, objectAnimationName);
-			if (animationFrames == null) {// if the name was created here there are no frames set for the animation
-				animationFrames = new int[] { 1, ipo.getLastFrame() };
-			}
 			int fps = blenderContext.getBlenderKey().getFps();
-			float start = (float) animationFrames[0] / (float) fps;
-			float stop = (float) animationFrames[1] / (float) fps;
 
 			// calculating track for the only bone in this skeleton
-			BoneTrack[] tracks = new BoneTrack[1];
-			tracks[0] = ipo.calculateTrack(0, animationFrames[0], animationFrames[1], fps);
-
-			BoneAnimation boneAnimation = new BoneAnimation(objectAnimationName, stop - start);
-			boneAnimation.setTracks(tracks);
+			Track<?> track = ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps);
+			
+			Animation animation = new Animation(objectAnimationName, ipo.getLastFrame() / fps);
+			animation.setTracks(new Track<?>[] { track });
 			ArrayList<Animation> animations = new ArrayList<Animation>(1);
-			animations.add(boneAnimation);
-
-			// preparing the object's bone
-			ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
-			Transform t = objectHelper.getTransformation(objectStructure, blenderContext);
-			Bone bone = new Bone(null);
-			bone.setBindTransforms(t.getTranslation(), t.getRotation(), t.getScale());
+			animations.add(animation);
 
-			animData = new AnimData(new Skeleton(new Bone[] { bone }), animations);
+			animData = new AnimData(null, animations);
 			objectOMA = objectStructure.getOldMemoryAddress();
 		}
-		*/
 	}
 	
 	@Override
 	public Node apply(Node node, BlenderContext blenderContext) {
-		LOGGER.warning("Object animation modifier not yet implemented!");
+		if(invalid) {
+			LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName());
+		}//if invalid, animData will be null
+		if(animData == null) {
+			return node;
+		}
+		
+		ArrayList<Animation> animList = animData.anims;
+		if (animList != null && animList.size() > 0) {
+			List<Constraint> constraints = blenderContext.getConstraints(this.objectOMA);
+			HashMap<String, Animation> anims = new HashMap<String, Animation>();
+			for (int i = 0; i < animList.size(); ++i) {
+				Animation animation = (Animation) animList.get(i).clone();
+
+				// baking constraints into animations
+				if (constraints != null && constraints.size() > 0) {
+					for (Constraint constraint : constraints) {
+						constraint.affectAnimation(animation, 0);
+					}
+				}
+
+				anims.put(animation.getName(), animation);
+			}
+
+			AnimControl control = new AnimControl(null);
+			control.setAnimations(anims);
+			node.addControl(control);
+		}
 		return node;
 	}