Browse Source

Many changes:
- simplified implementation for bones loading
- static bones poses discarded
- loading of object animation for blender 2.50+ added (didn't work for these versions before)
- several small bugfixes

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

Kae..pl 13 years ago
parent
commit
3a84693f68
35 changed files with 1104 additions and 912 deletions
  1. 28 0
      engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java
  2. 149 236
      engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java
  3. 204 0
      engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java
  4. 214 195
      engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java
  5. 180 101
      engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java
  6. 3 19
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java
  7. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintAction.java
  8. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintChildOf.java
  9. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintClampTo.java
  10. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDampTrack.java
  11. 11 17
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDistLimit.java
  12. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFollowPath.java
  13. 3 3
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java
  14. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintInverseKinematics.java
  15. 12 12
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLike.java
  16. 13 9
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLimit.java
  17. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLockTrack.java
  18. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintMinMax.java
  19. 1 4
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintNull.java
  20. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPivot.java
  21. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPython.java
  22. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRigidBodyJoint.java
  23. 11 11
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLike.java
  24. 19 15
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLimit.java
  25. 2 6
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintShrinkWrap.java
  26. 10 10
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLike.java
  27. 9 9
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLimit.java
  28. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSplineInverseKinematic.java
  29. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintStretchTo.java
  30. 1 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintTransform.java
  31. 12 4
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/Feature.java
  32. 38 42
      engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java
  33. 145 62
      engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ModifierHelper.java
  34. 25 58
      engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java
  35. 1 1
      engine/src/blender/com/jme3/scene/plugins/blender/objects/ObjectHelper.java

+ 28 - 0
engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java

@@ -46,6 +46,7 @@ import com.jme3.asset.AssetManager;
 import com.jme3.asset.BlenderKey;
 import com.jme3.material.Material;
 import com.jme3.math.ColorRGBA;
+import com.jme3.scene.plugins.blender.animations.BoneContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.constraints.Constraint;
 import com.jme3.scene.plugins.blender.file.BlenderInputStream;
@@ -112,6 +113,8 @@ public class BlenderContext {
 	private Map<Long, Skeleton>					skeletons				= new HashMap<Long, Skeleton>();
 	/** A map of mesh contexts. */
 	protected Map<Long, MeshContext>			meshContexts			= new HashMap<Long, MeshContext>();
+	/** A map of bone contexts. */
+	protected Map<Long, BoneContext>			boneContexts			= new HashMap<Long, BoneContext>();
 	/** A map of material contexts. */
 	protected Map<Material, MaterialContext>	materialContexts		= new HashMap<Material, MaterialContext>();
 	/** A map og helpers that perform loading. */
@@ -541,7 +544,32 @@ public class BlenderContext {
 	public MeshContext getMeshContext(Long meshOMA) {
 		return this.meshContexts.get(meshOMA);
 	}
+	
+	/**
+	 * This method sets the bone context for the given bone old memory address.
+	 * If the context is already set it will be replaced.
+	 * 
+	 * @param boneOMA
+	 *            the bone's old memory address
+	 * @param boneContext
+	 *            the bones's context
+	 */
+	public void setBoneContext(Long boneOMA, BoneContext boneContext) {
+		this.boneContexts.put(boneOMA, boneContext);
+	}
 
+	/**
+	 * This method returns the bone context for the given bone old memory
+	 * address. If no context exists then <b>null</b> is returned.
+	 * 
+	 * @param boneOMA
+	 *            the bone's old memory address
+	 * @return bone's context
+	 */
+	public BoneContext getBoneContext(Long boneOMA) {
+		return boneContexts.get(boneOMA);
+	}
+	
 	/**
 	 * This method sets the material context for the given material. If the
 	 * context is already set it will be replaced.

+ 149 - 236
engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java

@@ -42,44 +42,39 @@ import com.jme3.animation.Bone;
 import com.jme3.animation.BoneTrack;
 import com.jme3.animation.Skeleton;
 import com.jme3.math.Matrix4f;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Transform;
 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.curves.BezierCurve;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
-import com.jme3.scene.plugins.blender.file.BlenderInputStream;
-import com.jme3.scene.plugins.blender.file.DynamicArray;
-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.blender.objects.ObjectHelper;
 
 /**
- * This class defines the methods to calculate certain aspects of animation and armature functionalities.
+ * This class defines the methods to calculate certain aspects of animation and
+ * armature functionalities.
+ * 
  * @author Marcin Roguski (Kaelthas)
  */
 public class ArmatureHelper extends AbstractBlenderHelper {
-    private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName());
-    
-    /** A map of bones and their old memory addresses. */
-    private Map<Bone, Long> 		bonesOMAs = new HashMap<Bone, Long>();
-    /** Bone transforms need to be applied after the model is attached to the skeleton. Otherwise it will have no effect. */
-	private Map<Bone, Transform>	boneBindTransforms = new HashMap<Bone, Transform>();
-	
-    /**
-     * This constructor parses the given blender version and stores the result. Some functionalities may differ in
-     * different blender versions.
-     * @param blenderVersion
-     *        the version read from the blend file
-     * @param fixUpAxis
-     *        a variable that indicates if the Y asxis is the UP axis or not
-     */
-    public ArmatureHelper(String blenderVersion, boolean fixUpAxis) {
-        super(blenderVersion, fixUpAxis);
-    }
-    
-    /**
+	private static final Logger	LOGGER		= Logger.getLogger(ArmatureHelper.class.getName());
+
+	/** A map of bones and their old memory addresses. */
+	private Map<Bone, Long>		bonesOMAs	= new HashMap<Bone, Long>();
+
+	/**
+	 * This constructor parses the given blender version and stores the result.
+	 * Some functionalities may differ in different blender versions.
+	 * 
+	 * @param blenderVersion
+	 *            the version read from the blend file
+	 * @param fixUpAxis
+	 *            a variable that indicates if the Y asxis is the UP axis or not
+	 */
+	public ArmatureHelper(String blenderVersion, boolean fixUpAxis) {
+		super(blenderVersion, fixUpAxis);
+	}
+
+	/**
 	 * This method builds the object's bones structure.
 	 * 
 	 * @param boneStructure
@@ -96,119 +91,61 @@ public class ArmatureHelper extends AbstractBlenderHelper {
 	 *             an exception is thrown when there is problem with the blender
 	 *             file
 	 */
-	@SuppressWarnings("unchecked")
-	public void buildBones(Structure boneStructure, Bone parent, List<Bone> result, Matrix4f arbt,
-			final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
-		String boneName = boneStructure.getFieldValue("name").toString();
-		Long boneOMA = boneStructure.getOldMemoryAddress();
-		Bone bone = new Bone(boneName);
-		this.bonesOMAs.put(bone, boneOMA);
-		blenderContext.addLoadedFeatures(boneStructure.getOldMemoryAddress(), boneName, boneStructure, bone);
-		
-		ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
-		Matrix4f boneMatrix = arbt.mult(objectHelper.getMatrix(boneStructure, "arm_mat", true));
-		Pointer pParentStructure = (Pointer) boneStructure.getFieldValue("parent");
-		if(pParentStructure.isNotNull()) {
-			Structure parentStructure = pParentStructure.fetchData(blenderContext.getInputStream()).get(0);
-			Matrix4f parentArmMat = objectHelper.getMatrix(parentStructure, "arm_mat", true);
-			parentArmMat = arbt.mult(parentArmMat).invertLocal();
-			boneMatrix = parentArmMat.multLocal(boneMatrix);
-		}
-		
-		Transform baseTransform = new Transform(boneMatrix.toTranslationVector(), boneMatrix.toRotationQuat());
-		baseTransform.setScale(objectHelper.getScale(boneMatrix));
-		bone.setBindTransforms(baseTransform.getTranslation(), baseTransform.getRotation(), baseTransform.getScale());
-		
-		// loading poses
-		Structure poseChannel = bonesPoseChannels.get(boneStructure.getOldMemoryAddress());
-		DynamicArray<Number> loc = (DynamicArray<Number>) poseChannel.getFieldValue("loc");
-		DynamicArray<Number> size = (DynamicArray<Number>) poseChannel.getFieldValue("size");
-		DynamicArray<Number> quat = (DynamicArray<Number>) poseChannel.getFieldValue("quat");
-		Transform transform = new Transform();
-		if (blenderContext.getBlenderKey().isFixUpAxis()) {
-			transform.setTranslation(loc.get(0).floatValue(), -loc.get(2).floatValue(), loc.get(1).floatValue());
-			transform.setRotation(new Quaternion(quat.get(1).floatValue(), -quat.get(3).floatValue(), quat.get(2).floatValue(), quat.get(0).floatValue()));
-			transform.setScale(size.get(0).floatValue(), size.get(2).floatValue(), size.get(1).floatValue());
-		} else {
-			transform.setTranslation(loc.get(0).floatValue(), loc.get(1).floatValue(), loc.get(2).floatValue());
-			transform.setRotation(new Quaternion(quat.get(0).floatValue(), quat.get(1).floatValue(), quat.get(2).floatValue(), quat.get(3).floatValue()));
-			transform.setScale(size.get(0).floatValue(), size.get(1).floatValue(), size.get(2).floatValue());
-		}
-		
-		this.boneBindTransforms.put(bone, transform);
-		if (parent != null) {
-			parent.addChild(bone);
-		}
-		result.add(bone);
-		List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext);
-		for (Structure child : childbase) {
-			this.buildBones(child, bone, result, arbt, bonesPoseChannels, blenderContext);
-		}
-	}
-	
-	public Transform getLocalTransform(Bone bone) {
-		Transform transform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
-		transform.setScale(bone.getLocalScale());
-		return transform;
+	public void buildBones(Structure boneStructure, Bone parent, List<Bone> result, Matrix4f arbt, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
+		BoneContext bc = new BoneContext(boneStructure, arbt, bonesPoseChannels, blenderContext);
+		bc.buildBone(result, bonesOMAs, blenderContext);
 	}
 
-    /**
-     * This method returns the old memory address of a bone. If the bone does not exist in the blend file - zero is
-     * returned.
-     * @param bone
-     *        the bone whose old memory address we seek
-     * @return the old memory address of the given bone
-     */
-    public Long getBoneOMA(Bone bone) {
-        Long result = bonesOMAs.get(bone);
-        if (result == null) {
-            result = Long.valueOf(0);
-        }
-        return result;
-    }
-    
 	/**
-	 * This method returns the bind transform for the specified bone.
+	 * This method returns the old memory address of a bone. If the bone does
+	 * not exist in the blend file - zero is returned.
+	 * 
 	 * @param bone
-	 *            the bone
-	 * @return bone's bind transform
+	 *            the bone whose old memory address we seek
+	 * @return the old memory address of the given bone
+	 */
+	public Long getBoneOMA(Bone bone) {
+		Long result = bonesOMAs.get(bone);
+		if (result == null) {
+			result = Long.valueOf(0);
+		}
+		return result;
+	}
+
+	/**
+	 * This method returns a map where the key is the object's group index that
+	 * is used by a bone and the key is the bone index in the armature.
+	 * 
+	 * @param defBaseStructure
+	 *            a bPose structure of the object
+	 * @return bone group-to-index map
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blender file is somehow
+	 *             corrupted
 	 */
-    public Transform getBoneBindTransform(Bone bone) {
-    	return boneBindTransforms.get(bone);
-    }
+	public Map<Integer, Integer> getGroupToBoneIndexMap(Structure defBaseStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
+		Map<Integer, Integer> result = null;
+		if (skeleton.getBoneCount() != 0) {
+			result = new HashMap<Integer, Integer>();
+			List<Structure> deformGroups = defBaseStructure.evaluateListBase(blenderContext);// bDeformGroup
+			int groupIndex = 0;
+			for (Structure deformGroup : deformGroups) {
+				String deformGroupName = deformGroup.getFieldValue("name").toString();
+				Integer boneIndex = this.getBoneIndex(skeleton, deformGroupName);
+				if (boneIndex != null) {
+					result.put(Integer.valueOf(groupIndex), boneIndex);
+				}
+				++groupIndex;
+			}
+		}
+		return result;
+	}
 
-    /**
-     * This method returns a map where the key is the object's group index that is used by a bone and the key is the
-     * bone index in the armature.
-     * @param defBaseStructure
-     *        a bPose structure of the object
-     * @return bone group-to-index map
-     * @throws BlenderFileException
-     *         this exception is thrown when the blender file is somehow corrupted
-     */
-    public Map<Integer, Integer> getGroupToBoneIndexMap(Structure defBaseStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
-        Map<Integer, Integer> result = null;
-        if (skeleton.getBoneCount() != 0) {
-            result = new HashMap<Integer, Integer>();
-            List<Structure> deformGroups = defBaseStructure.evaluateListBase(blenderContext);//bDeformGroup
-            int groupIndex = 0;
-            for (Structure deformGroup : deformGroups) {
-                String deformGroupName = deformGroup.getFieldValue("name").toString();
-                Integer boneIndex = this.getBoneIndex(skeleton, deformGroupName);
-                if (boneIndex != null) {
-                    result.put(Integer.valueOf(groupIndex), boneIndex);
-                }
-                ++groupIndex;
-            }
-        }
-        return result;
-    }
+	@Override
+	public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
+		return true;
+	}
 
-    @Override
-    public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
-    	return true;
-    }
-    
 	/**
 	 * This method retuns the bone tracks for animation.
 	 * 
@@ -221,16 +158,17 @@ public class ArmatureHelper extends AbstractBlenderHelper {
 	 *             an exception is thrown when there are problems with the blend
 	 *             file
 	 */
-    public BoneTrack[] getTracks(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
-    	if (blenderVersion < 250) {
-            return this.getTracks249(actionStructure, skeleton, blenderContext);
-        } else {
-        	return this.getTracks250(actionStructure, skeleton, blenderContext);
-        }
-    }
-    
-    /**
-	 * This method retuns the bone tracks for animation for blender version 2.50 and higher.
+	public BoneTrack[] getTracks(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
+		if (blenderVersion < 250) {
+			return this.getTracks249(actionStructure, skeleton, blenderContext);
+		} else {
+			return this.getTracks250(actionStructure, skeleton, blenderContext);
+		}
+	}
+
+	/**
+	 * This method retuns the bone tracks for animation for blender version 2.50
+	 * and higher.
 	 * 
 	 * @param actionStructure
 	 *            the structure containing the tracks
@@ -241,45 +179,37 @@ public class ArmatureHelper extends AbstractBlenderHelper {
 	 *             an exception is thrown when there are problems with the blend
 	 *             file
 	 */
-    private BoneTrack[] getTracks250(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
-        LOGGER.log(Level.INFO, "Getting tracks!");
-        int fps = blenderContext.getBlenderKey().getFps();
-        Structure groups = (Structure) actionStructure.getFieldValue("groups");
-        List<Structure> actionGroups = groups.evaluateListBase(blenderContext);//bActionGroup
-        List<BoneTrack> tracks = new ArrayList<BoneTrack>();
-        for (Structure actionGroup : actionGroups) {
-            String name = actionGroup.getFieldValue("name").toString();
-            Integer boneIndex = this.getBoneIndex(skeleton, name);
-            if (boneIndex != null) {
-                List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(blenderContext);
-                BezierCurve[] bezierCurves = new BezierCurve[channels.size()];
-                int channelCounter = 0;
-                for (Structure c : channels) {
-                    //reading rna path first
-                    BlenderInputStream bis = blenderContext.getInputStream();
-                    int currentPosition = bis.getPosition();
-                    Pointer pRnaPath = (Pointer) c.getFieldValue("rna_path");
-                    FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pRnaPath.getOldMemoryAddress());
-                    bis.setPosition(dataFileBlock.getBlockPosition());
-                    String rnaPath = bis.readString();
-                    bis.setPosition(currentPosition);
-                    int arrayIndex = ((Number) c.getFieldValue("array_index")).intValue();
-                    int type = this.getCurveType(rnaPath, arrayIndex);
+	private BoneTrack[] getTracks250(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
+		LOGGER.log(Level.INFO, "Getting tracks!");
+		IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
+		int fps = blenderContext.getBlenderKey().getFps();
+		Structure groups = (Structure) actionStructure.getFieldValue("groups");
+		List<Structure> actionGroups = groups.evaluateListBase(blenderContext);// bActionGroup
+		List<BoneTrack> tracks = new ArrayList<BoneTrack>();
+		for (Structure actionGroup : actionGroups) {
+			String name = actionGroup.getFieldValue("name").toString();
+			int boneIndex = this.getBoneIndex(skeleton, name);
+			if (boneIndex >= 0) {
+				List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(blenderContext);
+				BezierCurve[] bezierCurves = new BezierCurve[channels.size()];
+				int channelCounter = 0;
+				for (Structure c : channels) {
+					int type = ipoHelper.getCurveType(c, blenderContext);
+					Pointer pBezTriple = (Pointer) c.getFieldValue("bezt");
+					List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
+					bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);
+				}
 
-                    Pointer pBezTriple = (Pointer) c.getFieldValue("bezt");
-                    List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
-                    bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);
-                }
+				Ipo ipo = new Ipo(bezierCurves, fixUpAxis);
+				tracks.add((BoneTrack) ipo.calculateTrack(boneIndex, 0, ipo.getLastFrame(), fps, false));
+			}
+		}
+		return tracks.toArray(new BoneTrack[tracks.size()]);
+	}
 
-                Ipo ipo = new Ipo(bezierCurves, fixUpAxis);
-                tracks.add((BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
-            }
-        }
-        return tracks.toArray(new BoneTrack[tracks.size()]);
-    }
-    
-    /**
-	 * This method retuns the bone tracks for animation for blender version 2.49 (and probably several lower versions too).
+	/**
+	 * This method retuns the bone tracks for animation for blender version 2.49
+	 * (and probably several lower versions too).
 	 * 
 	 * @param actionStructure
 	 *            the structure containing the tracks
@@ -290,61 +220,44 @@ public class ArmatureHelper extends AbstractBlenderHelper {
 	 *             an exception is thrown when there are problems with the blend
 	 *             file
 	 */
-    private BoneTrack[] getTracks249(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
-    	LOGGER.log(Level.INFO, "Getting tracks!");
-        IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
-        int fps = blenderContext.getBlenderKey().getFps();
-        Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase");
-        List<Structure> actionChannels = chanbase.evaluateListBase(blenderContext);//bActionChannel
-        List<BoneTrack> tracks = new ArrayList<BoneTrack>();
-        for (Structure bActionChannel : actionChannels) {
-            String name = bActionChannel.getFieldValue("name").toString();
-            Integer boneIndex = this.getBoneIndex(skeleton, name);
-            if (boneIndex != null && boneIndex.intValue() >= 0) {
-                Pointer p = (Pointer) bActionChannel.getFieldValue("ipo");
-                if (!p.isNull()) {
-                    Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0);
-                    Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
-                    tracks.add((BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
-                }
-            }
-        }
-        return tracks.toArray(new BoneTrack[tracks.size()]);
-    }
+	private BoneTrack[] getTracks249(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
+		LOGGER.log(Level.INFO, "Getting tracks!");
+		IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
+		int fps = blenderContext.getBlenderKey().getFps();
+		Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase");
+		List<Structure> actionChannels = chanbase.evaluateListBase(blenderContext);// bActionChannel
+		List<BoneTrack> tracks = new ArrayList<BoneTrack>();
+		for (Structure bActionChannel : actionChannels) {
+			String name = bActionChannel.getFieldValue("name").toString();
+			int boneIndex = this.getBoneIndex(skeleton, name);
+			if (boneIndex >= 0) {
+				Pointer p = (Pointer) bActionChannel.getFieldValue("ipo");
+				if (!p.isNull()) {
+					Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0);
+					Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext);
+					tracks.add((BoneTrack) ipo.calculateTrack(boneIndex, 0, ipo.getLastFrame(), fps, false));
+				}
+			}
+		}
+		return tracks.toArray(new BoneTrack[tracks.size()]);
+	}
 
-    /**
-     * This method returns the index of the bone in the given skeleton.
-     * @param skeleton the skeleton
-     * @param boneName the name of the bone
-     * @return the index of the bone
-     */
-    private int getBoneIndex(Skeleton skeleton, String boneName) {
-    	int result = -1;
-    	for(int i=0;i<skeleton.getBoneCount() && result==-1;++i) {
-    		if(boneName.equals(skeleton.getBone(i).getName())) {
-    			result = i;
-    		}
-    	}
-    	return result;
-    }
-    
-    /**
-     * This method parses the information stored inside the curve rna path and returns the proper type
-     * of the curve.
-     * @param rnaPath the curve's rna path
-     * @param arrayIndex the array index of the stored data
-     * @return the type of the curve
-     */
-    protected int getCurveType(String rnaPath, int arrayIndex) {
-        if (rnaPath.endsWith(".location")) {
-            return Ipo.AC_LOC_X + arrayIndex;
-        }
-        if (rnaPath.endsWith(".rotation_quaternion")) {
-            return Ipo.AC_QUAT_W + arrayIndex;
-        }
-        if (rnaPath.endsWith(".scale")) {
-            return Ipo.AC_SIZE_X + arrayIndex;
-        }
-        throw new IllegalStateException("Unknown curve rna path: " + rnaPath);
-    }
+	/**
+	 * This method returns the index of the bone in the given skeleton.
+	 * 
+	 * @param skeleton
+	 *            the skeleton
+	 * @param boneName
+	 *            the name of the bone
+	 * @return the index of the bone
+	 */
+	private int getBoneIndex(Skeleton skeleton, String boneName) {
+		int result = -1;
+		for (int i = 0; i < skeleton.getBoneCount() && result == -1; ++i) {
+			if (boneName.equals(skeleton.getBone(i).getName())) {
+				result = i;
+			}
+		}
+		return result;
+	}
 }

+ 204 - 0
engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java

@@ -0,0 +1,204 @@
+package com.jme3.scene.plugins.blender.animations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import com.jme3.animation.Bone;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Transform;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
+import com.jme3.scene.plugins.blender.file.DynamicArray;
+import com.jme3.scene.plugins.blender.file.Structure;
+import com.jme3.scene.plugins.blender.objects.ObjectHelper;
+
+/**
+ * This class holds the basic data that describes a bone.
+ * 
+ * @author Marcin Roguski (Kaelthas)
+ */
+public class BoneContext {
+	/** The structure of the bone. */
+	private Structure			boneStructure;
+	/** Bone's pose channel structure. */
+	private Structure			poseChannel;
+	/** Bone's name. */
+	private String				boneName;
+	/** This variable indicates if the Y axis should be the UP axis. */
+	private boolean				fixUpAxis;
+	/** The bone's armature matrix. */
+	private Matrix4f			armatureMatrix;
+	/** The parent context. */
+	private BoneContext			parent;
+	/** The children of this context. */
+	private List<BoneContext>	children		= new ArrayList<BoneContext>();
+	/** Created bone (available after calling 'buildBone' method). */
+	private Bone				bone;
+	/** Bone's pose transform (available after calling 'buildBone' method). */
+	private Transform			poseTransform	= new Transform();
+	/** The bone's rest matrix. */
+	private Matrix4f			restMatrix;
+	/** Bone's total inverse transformation. */
+	private Matrix4f			inverseTotalTransformation;
+	/** Bone's parent inverse matrix. */
+	private Matrix4f			inverseParentMatrix;
+
+	/**
+	 * Constructor. Creates the basic set of bone's data.
+	 * 
+	 * @param boneStructure
+	 *            the bone's structure
+	 * @param objectToArmatureMatrix
+	 *            object-to-armature transformation matrix
+	 * @param bonesPoseChannels
+	 *            a map of pose channels for each bone OMA
+	 * @param blenderContext
+	 *            the blender context
+	 * @throws BlenderFileException
+	 *             an exception is thrown when problem with blender data reading
+	 *             occurs
+	 */
+	public BoneContext(Structure boneStructure, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
+		this(boneStructure, null, objectToArmatureMatrix, bonesPoseChannels, blenderContext);
+	}
+
+	/**
+	 * Constructor. Creates the basic set of bone's data.
+	 * 
+	 * @param boneStructure
+	 *            the bone's structure
+	 * @param parent
+	 *            bone's parent (null if the bone is the root bone)
+	 * @param objectToArmatureMatrix
+	 *            object-to-armature transformation matrix
+	 * @param bonesPoseChannels
+	 *            a map of pose channels for each bone OMA
+	 * @param blenderContext
+	 *            the blender context
+	 * @throws BlenderFileException
+	 *             an exception is thrown when problem with blender data reading
+	 *             occurs
+	 */
+	private BoneContext(Structure boneStructure, BoneContext parent, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
+		this.parent = parent;
+		this.boneStructure = boneStructure;
+		boneName = boneStructure.getFieldValue("name").toString();
+		ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
+		armatureMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", true);
+
+		fixUpAxis = blenderContext.getBlenderKey().isFixUpAxis();
+		this.computeRestMatrix(objectToArmatureMatrix);
+		List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext);
+		for (Structure child : childbase) {
+			this.children.add(new BoneContext(child, this, objectToArmatureMatrix, bonesPoseChannels, blenderContext));
+		}
+
+		poseChannel = bonesPoseChannels.get(boneStructure.getOldMemoryAddress());
+
+		blenderContext.setBoneContext(boneStructure.getOldMemoryAddress(), this);
+	}
+
+	/**
+	 * This method computes the rest matrix for the bone.
+	 * 
+	 * @param objectToArmatureMatrix
+	 *            object-to-armature transformation matrix
+	 */
+	private void computeRestMatrix(Matrix4f objectToArmatureMatrix) {
+		if (parent != null) {
+			inverseParentMatrix = parent.inverseTotalTransformation.clone();
+		} else if (fixUpAxis) {
+			inverseParentMatrix = objectToArmatureMatrix.clone();
+		} else {
+			inverseParentMatrix = Matrix4f.IDENTITY.clone();
+		}
+
+		restMatrix = armatureMatrix.clone();
+		inverseTotalTransformation = restMatrix.invert();
+
+		restMatrix = inverseParentMatrix.mult(restMatrix);
+
+		for (BoneContext child : this.children) {
+			child.computeRestMatrix(objectToArmatureMatrix);
+		}
+	}
+
+	/**
+	 * This method computes the pose transform for the bone.
+	 */
+	@SuppressWarnings("unchecked")
+	private void computePoseTransform() {
+		DynamicArray<Number> loc = (DynamicArray<Number>) poseChannel.getFieldValue("loc");
+		DynamicArray<Number> size = (DynamicArray<Number>) poseChannel.getFieldValue("size");
+		DynamicArray<Number> quat = (DynamicArray<Number>) poseChannel.getFieldValue("quat");
+		if (fixUpAxis) {
+			poseTransform.setTranslation(loc.get(0).floatValue(), -loc.get(2).floatValue(), loc.get(1).floatValue());
+			poseTransform.setRotation(new Quaternion(quat.get(1).floatValue(), quat.get(3).floatValue(), -quat.get(2).floatValue(), quat.get(0).floatValue()));
+			poseTransform.setScale(size.get(0).floatValue(), size.get(2).floatValue(), size.get(1).floatValue());
+		} else {
+			poseTransform.setTranslation(loc.get(0).floatValue(), loc.get(1).floatValue(), loc.get(2).floatValue());
+			poseTransform.setRotation(new Quaternion(quat.get(0).floatValue(), quat.get(1).floatValue(), quat.get(2).floatValue(), quat.get(3).floatValue()));
+			poseTransform.setScale(size.get(0).floatValue(), size.get(1).floatValue(), size.get(2).floatValue());
+		}
+
+		Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
+		localTransform.setScale(bone.getLocalScale());
+		localTransform.getTranslation().addLocal(poseTransform.getTranslation());
+		localTransform.getRotation().multLocal(poseTransform.getRotation());
+		localTransform.getScale().multLocal(poseTransform.getScale());
+
+		poseTransform.set(localTransform);
+	}
+
+	/**
+	 * This method builds the bone. It recursively builds the bone's children.
+	 * 
+	 * @param bones
+	 *            a list of bones where the newly created bone will be added
+	 * @param boneOMAs
+	 *            the map between bone and its old memory address
+	 * @param blenderContext
+	 *            the blender context
+	 * @return newly created bone
+	 */
+	public Bone buildBone(List<Bone> bones, Map<Bone, Long> boneOMAs, BlenderContext blenderContext) {
+		Long boneOMA = boneStructure.getOldMemoryAddress();
+		bone = new Bone(boneName);
+		bones.add(bone);
+		boneOMAs.put(bone, boneOMA);
+		blenderContext.addLoadedFeatures(boneOMA, boneName, boneStructure, bone);
+
+		Matrix4f pose = this.restMatrix.clone();
+		ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
+
+		Vector3f poseLocation = pose.toTranslationVector();
+		Quaternion rotation = pose.toRotationQuat();
+		Vector3f scale = objectHelper.getScale(pose);
+
+		bone.setBindTransforms(poseLocation, rotation, scale);
+		for (BoneContext child : children) {
+			bone.addChild(child.buildBone(bones, boneOMAs, blenderContext));
+		}
+
+		this.computePoseTransform();
+
+		return bone;
+	}
+
+	/**
+	 * @return bone's pose transformation
+	 */
+	public Transform getPoseTransform() {
+		return poseTransform;
+	}
+
+	/**
+	 * @return built bone (available after calling 'buildBone' method)
+	 */
+	public Bone getBone() {
+		return bone;
+	}
+}

+ 214 - 195
engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java

@@ -9,209 +9,228 @@ import com.jme3.math.Vector3f;
 import com.jme3.scene.plugins.blender.curves.BezierCurve;
 
 /**
- * This class is used to calculate bezier curves value for the given frames. The Ipo (interpolation object) consists
- * of several b-spline curves (connected 3rd degree bezier curves) of a different type.
+ * This class is used to calculate bezier curves value for the given frames. The
+ * Ipo (interpolation object) consists of several b-spline curves (connected 3rd
+ * degree bezier curves) of a different type.
+ * 
  * @author Marcin Roguski
  */
 public class Ipo {
 
-    public static final int AC_LOC_X = 1;
-    public static final int AC_LOC_Y = 2;
-    public static final int AC_LOC_Z = 3;
-    public static final int OB_ROT_X = 7;
-    public static final int OB_ROT_Y = 8;
-    public static final int OB_ROT_Z = 9;
-    public static final int AC_SIZE_X = 13;
-    public static final int AC_SIZE_Y = 14;
-    public static final int AC_SIZE_Z = 15;
-    public static final int AC_QUAT_W = 25;
-    public static final int AC_QUAT_X = 26;
-    public static final int AC_QUAT_Y = 27;
-    public static final int AC_QUAT_Z = 28;
-    
-    /** A list of bezier curves for this interpolation object. */
-    private BezierCurve[] bezierCurves;
-    /** Each ipo contains one bone track. */
-    private Track calculatedTrack;
-    /** This variable indicates if the Y asxis is the UP axis or not. */
-	protected boolean	fixUpAxis;
-	
-    /**
-     * Constructor. Stores the bezier curves.
-     * @param bezierCurves
-     *        a table of bezier curves
-     */
-    public Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis) {
-        this.bezierCurves = bezierCurves;
-        this.fixUpAxis = fixUpAxis;
-    }
+	public static final int	AC_LOC_X	= 1;
+	public static final int	AC_LOC_Y	= 2;
+	public static final int	AC_LOC_Z	= 3;
+	public static final int	OB_ROT_X	= 7;
+	public static final int	OB_ROT_Y	= 8;
+	public static final int	OB_ROT_Z	= 9;
+	public static final int	AC_SIZE_X	= 13;
+	public static final int	AC_SIZE_Y	= 14;
+	public static final int	AC_SIZE_Z	= 15;
+	public static final int	AC_QUAT_W	= 25;
+	public static final int	AC_QUAT_X	= 26;
+	public static final int	AC_QUAT_Y	= 27;
+	public static final int	AC_QUAT_Z	= 28;
 
-    /**
-     * This method calculates the ipo value for the first curve.
-     * @param frame
-     *        the frame for which the value is calculated
-     * @return calculated ipo value
-     */
-    public float calculateValue(int frame) {
-        return this.calculateValue(frame, 0);
-    }
+	/** A list of bezier curves for this interpolation object. */
+	private BezierCurve[]	bezierCurves;
+	/** Each ipo contains one bone track. */
+	private Track			calculatedTrack;
+	/** This variable indicates if the Y asxis is the UP axis or not. */
+	protected boolean		fixUpAxis;
 
-    /**
-     * This method calculates the ipo value for the curve of the specified index. Make sure you do not exceed the
-     * curves amount. Alway chech the amount of curves before calling this method.
-     * @param frame
-     *        the frame for which the value is calculated
-     * @param curveIndex
-     *        the index of the curve
-     * @return calculated ipo value
-     */
-    public float calculateValue(int frame, int curveIndex) {
-        return bezierCurves[curveIndex].evaluate(frame, BezierCurve.Y_VALUE);
-    }
+	/**
+	 * Constructor. Stores the bezier curves.
+	 * 
+	 * @param bezierCurves
+	 *            a table of bezier curves
+	 */
+	public Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis) {
+		this.bezierCurves = bezierCurves;
+		this.fixUpAxis = fixUpAxis;
+	}
 
-    /**
-     * This method returns the curves amount.
-     * @return the curves amount
-     */
-    public int getCurvesAmount() {
-        return bezierCurves.length;
-    }
+	/**
+	 * This method calculates the ipo value for the first curve.
+	 * 
+	 * @param frame
+	 *            the frame for which the value is calculated
+	 * @return calculated ipo value
+	 */
+	public float calculateValue(int frame) {
+		return this.calculateValue(frame, 0);
+	}
 
-    /**
-     * This method returns the frame where last bezier triple center point of the specified bezier curve is located.
-     * @return the frame number of the last defined bezier triple point for the specified ipo
-     */
-    public int getLastFrame() {
-        int result = 1;
-        for (int i = 0; i < bezierCurves.length; ++i) {
-            int tempResult = bezierCurves[i].getLastFrame();
-            if (tempResult > result) {
-                result = tempResult;
-            }
-        }
-        return result;
-    }
+	/**
+	 * This method calculates the ipo value for the curve of the specified
+	 * index. Make sure you do not exceed the curves amount. Alway chech the
+	 * amount of curves before calling this method.
+	 * 
+	 * @param frame
+	 *            the frame for which the value is calculated
+	 * @param curveIndex
+	 *            the index of the curve
+	 * @return calculated ipo value
+	 */
+	public float calculateValue(int frame, int curveIndex) {
+		return bezierCurves[curveIndex].evaluate(frame, BezierCurve.Y_VALUE);
+	}
 
-    /**
-     * This method calculates the value of the curves as a bone track between the specified frames.
-     * @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
-     *        the last frame of the tracks (inclusive)
-     * @param fps
-     *        frame rate (frames per second)
-     * @return bone track for the specified bone
-     */
-    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;
+	/**
+	 * This method returns the curves amount.
+	 * 
+	 * @return the curves amount
+	 */
+	public int getCurvesAmount() {
+		return bezierCurves.length;
+	}
 
-            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[] {1.0f, 1.0f, 1.0f};
-            float degreeToRadiansFactor = FastMath.DEG_TO_RAD * 10;//the values in blender are divided by 10, so we need to mult it here
-            
-            //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()) {
-                    	//LOCATION
-                        case AC_LOC_X:
-                        	translation[0] = (float) value;
-                        	break;
-                        case AC_LOC_Y:
-                        	if(fixUpAxis) {
-                        		translation[2] = (float) -value;
-                        	} else {
-                        		translation[1] = (float) value;
-                        	}
-                        	break;
-                        case AC_LOC_Z:
-                        	translation[fixUpAxis ? 1 : 2] = (float) value;
-                            break;
-                            
-                        //ROTATION (used with object animation)
-                        //the value here is in degrees divided by 10 (so in example: 9 = PI/2)
-                        case OB_ROT_X:
-                        	objectRotation[0] = (float) value * degreeToRadiansFactor;
-                            break;
-                        case OB_ROT_Y:
-                        	if(fixUpAxis) {
-                        		objectRotation[2] = (float) -value * degreeToRadiansFactor;
-                        	} else {
-                        		objectRotation[1] = (float) value * degreeToRadiansFactor;
-                        	}
-                        	break;
-                        case OB_ROT_Z:
-                        	objectRotation[fixUpAxis ? 1 : 2] = (float) value * degreeToRadiansFactor;
-                            break;
-                            
-                        //SIZE
-                        case AC_SIZE_X:
-                        	scale[0] = (float) value;
-                        	break;
-                        case AC_SIZE_Y:
-                        	if(fixUpAxis) {
-                        		scale[2] = (float) value;
-                        	} else {
-                        		scale[1] = (float) value;
-                        	}
-                        	break;
-                        case AC_SIZE_Z:
-                        	scale[fixUpAxis ? 1 : 2] = (float) value;
-                            break;
-                            
-                        //QUATERNION ROTATION (used with bone animation)
-                        case AC_QUAT_W:
-                            quaternionRotation[3] = (float) value;
-                            break;
-                        case AC_QUAT_X:
-                        	quaternionRotation[0] = (float) value;
-                        	break;
-                        case AC_QUAT_Y:
-                        	if(fixUpAxis) {
-                        		quaternionRotation[2] = -(float) value;
-                        	} else {
-                        		quaternionRotation[1] = (float) value;
-                        	}
-                        	break;
-                        case AC_QUAT_Z:
-                        	if(fixUpAxis) {
-                        		quaternionRotation[1] = (float) value;
-                        	} else {
-                        		quaternionRotation[2] = (float) value;
-                        	}
-                            break;
-                        default:
-                        	throw new IllegalStateException("Unknown ipo curve type: " + bezierCurves[j].getType());
-                    }
-                }
-                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]);
-            }
-            if(bSpatialTrack) {
-            	calculatedTrack = new SpatialTrack(times, translations, rotations, scales);
-            } else {
-            	calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales);
-            }
-    	}
-        return calculatedTrack;
-    }
+	/**
+	 * This method returns the frame where last bezier triple center point of
+	 * the specified bezier curve is located.
+	 * 
+	 * @return the frame number of the last defined bezier triple point for the
+	 *         specified ipo
+	 */
+	public int getLastFrame() {
+		int result = 1;
+		for (int i = 0; i < bezierCurves.length; ++i) {
+			int tempResult = bezierCurves[i].getLastFrame();
+			if (tempResult > result) {
+				result = tempResult;
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * This method calculates the value of the curves as a bone track between
+	 * the specified frames.
+	 * 
+	 * @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
+	 *            the last frame of the tracks (inclusive)
+	 * @param fps
+	 *            frame rate (frames per second)
+	 * @param spatialTrack
+	 *            this flag indicates if the track belongs to a spatial or to a
+	 *            bone; the diference is important because it appears that bones
+	 *            in blender have the same type of coordinate system (Y as UP)
+	 *            as jme while other features have different one (Z is UP)
+	 * @return bone track for the specified bone
+	 */
+	public Track calculateTrack(int targetIndex, int startFrame, int stopFrame, int fps, boolean spatialTrack) {
+		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];
+			Vector3f[] scales = new Vector3f[framesAmount + 1];
+			float[] scale = new float[] { 1.0f, 1.0f, 1.0f };
+			float degreeToRadiansFactor = FastMath.DEG_TO_RAD * 10;// the values in blender are divided by 10, so we need to mult it here
+
+			// 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()) {
+					// LOCATION
+						case AC_LOC_X:
+							translation[0] = (float) value;
+							break;
+						case AC_LOC_Y:
+							if (fixUpAxis && spatialTrack) {
+								translation[2] = (float) -value;
+							} else {
+								translation[1] = (float) value;
+							}
+							break;
+						case AC_LOC_Z:
+							translation[fixUpAxis && spatialTrack ? 1 : 2] = (float) value;
+							break;
+
+						// ROTATION (used with object animation)
+						// the value here is in degrees divided by 10 (so in
+						// example: 9 = PI/2)
+						case OB_ROT_X:
+							objectRotation[0] = (float) value * degreeToRadiansFactor;
+							break;
+						case OB_ROT_Y:
+							if (fixUpAxis) {
+								objectRotation[2] = (float) -value * degreeToRadiansFactor;
+							} else {
+								objectRotation[1] = (float) value * degreeToRadiansFactor;
+							}
+							break;
+						case OB_ROT_Z:
+							objectRotation[fixUpAxis ? 1 : 2] = (float) value * degreeToRadiansFactor;
+							break;
+
+						// SIZE
+						case AC_SIZE_X:
+							scale[0] = (float) value;
+							break;
+						case AC_SIZE_Y:
+							if (fixUpAxis && spatialTrack) {
+								scale[2] = (float) value;
+							} else {
+								scale[1] = (float) value;
+							}
+							break;
+						case AC_SIZE_Z:
+							scale[fixUpAxis && spatialTrack ? 1 : 2] = (float) value;
+							break;
+
+						// QUATERNION ROTATION (used with bone animation), dunno
+						// why but here we shouldn't check the
+						// spatialTrack flag value
+						case AC_QUAT_W:
+							quaternionRotation[3] = (float) value;
+							break;
+						case AC_QUAT_X:
+							quaternionRotation[0] = (float) value;
+							break;
+						case AC_QUAT_Y:
+							if (fixUpAxis) {
+								quaternionRotation[2] = -(float) value;
+							} else {
+								quaternionRotation[1] = (float) value;
+							}
+							break;
+						case AC_QUAT_Z:
+							if (fixUpAxis) {
+								quaternionRotation[1] = (float) value;
+							} else {
+								quaternionRotation[2] = (float) value;
+							}
+							break;
+						default:
+							throw new IllegalStateException("Unknown ipo curve type: " + bezierCurves[j].getType());
+					}
+				}
+				translations[index] = new Vector3f(translation[0], translation[1], translation[2]);
+				rotations[index] = spatialTrack ? new Quaternion().fromAngles(objectRotation) : new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);
+				scales[index] = new Vector3f(scale[0], scale[1], scale[2]);
+			}
+			if (spatialTrack) {
+				calculatedTrack = new SpatialTrack(times, translations, rotations, scales);
+			} else {
+				calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales);
+			}
+		}
+		return calculatedTrack;
+	}
 }

+ 180 - 101
engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java

@@ -7,114 +7,193 @@ import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.curves.BezierCurve;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
+import com.jme3.scene.plugins.blender.file.BlenderInputStream;
+import com.jme3.scene.plugins.blender.file.FileBlockHeader;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Structure;
 
 /**
- * This class helps to compute values from interpolation curves for features like animation or constraint influence. The
- * curves are 3rd degree bezier curves.
+ * This class helps to compute values from interpolation curves for features
+ * like animation or constraint influence. The curves are 3rd degree bezier
+ * curves.
+ * 
  * @author Marcin Roguski
  */
 public class IpoHelper extends AbstractBlenderHelper {
 
 	/**
-     * This constructor parses the given blender version and stores the result. Some functionalities may differ in
-     * different blender versions.
-     * @param blenderVersion
-     *        the version read from the blend file
-     * @param fixUpAxis
-     *        a variable that indicates if the Y asxis is the UP axis or not
-     */
-    public IpoHelper(String blenderVersion, boolean fixUpAxis) {
-        super(blenderVersion, fixUpAxis);
-    }
-
-    /**
-     * This method creates an ipo object used for interpolation calculations.
-     * @param ipoStructure
-     *        the structure with ipo definition
-     * @param blenderContext
-     *        the blender context
-     * @return the ipo object
-     * @throws BlenderFileException
-     *         this exception is thrown when the blender file is somehow corrupted
-     */
-    public Ipo createIpo(Structure ipoStructure, BlenderContext blenderContext) throws BlenderFileException {
-        Structure curvebase = (Structure) ipoStructure.getFieldValue("curve");
-
-        //preparing bezier curves
-        Ipo result = null;
-        List<Structure> curves = curvebase.evaluateListBase(blenderContext);//IpoCurve
-        if (curves.size() > 0) {
-            BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
-            int frame = 0;
-            for (Structure curve : curves) {
-                Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
-                List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
-                int type = ((Number) curve.getFieldValue("adrcode")).intValue();
-                bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
-            }
-            curves.clear();
-            result = new Ipo(bezierCurves, fixUpAxis);
-            blenderContext.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result);
-        }
-        return result;
-    }
-
-    /**
-     * This method creates an ipo with only a single value. No track type is specified so do not use it for calculating
-     * tracks.
-     * @param constValue
-     *        the value of this ipo
-     * @return constant ipo
-     */
-    public Ipo createIpo(float constValue) {
-        return new ConstIpo(constValue);
-    }
-
-    @Override
-    public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
-    	return true;
-    }
-    
-    /**
-     * Ipo constant curve. This is a curve with only one value and no specified type. This type of ipo cannot be used to
-     * calculate tracks. It should only be used to calculate single value for a given frame.
-     * @author Marcin Roguski
-     */
-    private class ConstIpo extends Ipo {
-
-        /** The constant value of this ipo. */
-        private float constValue;
-
-        /**
-         * Constructor. Stores the constant value of this ipo.
-         * @param constValue
-         *        the constant value of this ipo
-         */
-        public ConstIpo(float constValue) {
-            super(null, false);
-            this.constValue = constValue;
-        }
-
-        @Override
-        public float calculateValue(int frame) {
-            return constValue;
-        }
-
-        @Override
-        public float calculateValue(int frame, int curveIndex) {
-            return constValue;
-        }
-
-        @Override
-        public int getCurvesAmount() {
-            return 0;
-        }
-
-        @Override
-        public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps) {
-            throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!");
-        }
-    }
+	 * This constructor parses the given blender version and stores the result.
+	 * Some functionalities may differ in different blender versions.
+	 * 
+	 * @param blenderVersion
+	 *            the version read from the blend file
+	 * @param fixUpAxis
+	 *            a variable that indicates if the Y asxis is the UP axis or not
+	 */
+	public IpoHelper(String blenderVersion, boolean fixUpAxis) {
+		super(blenderVersion, fixUpAxis);
+	}
+
+	/**
+	 * This method creates an ipo object used for interpolation calculations.
+	 * 
+	 * @param ipoStructure
+	 *            the structure with ipo definition
+	 * @param blenderContext
+	 *            the blender context
+	 * @return the ipo object
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blender file is somehow
+	 *             corrupted
+	 */
+	public Ipo fromIpoStructure(Structure ipoStructure, BlenderContext blenderContext) throws BlenderFileException {
+		Structure curvebase = (Structure) ipoStructure.getFieldValue("curve");
+
+		// preparing bezier curves
+		Ipo result = null;
+		List<Structure> curves = curvebase.evaluateListBase(blenderContext);// IpoCurve
+		if (curves.size() > 0) {
+			BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
+			int frame = 0;
+			for (Structure curve : curves) {
+				Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
+				List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
+				int type = ((Number) curve.getFieldValue("adrcode")).intValue();
+				bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
+			}
+			curves.clear();
+			result = new Ipo(bezierCurves, fixUpAxis);
+			blenderContext.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result);
+		}
+		return result;
+	}
+
+	/**
+	 * This method creates an ipo object used for interpolation calculations. It
+	 * should be called for blender version 2.50 and higher.
+	 * 
+	 * @param actionStructure
+	 *            the structure with action definition
+	 * @param blenderContext
+	 *            the blender context
+	 * @return the ipo object
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blender file is somehow
+	 *             corrupted
+	 */
+	public Ipo fromAction(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
+		Ipo result = null;
+		List<Structure> curves = ((Structure) actionStructure.getFieldValue("curves")).evaluateListBase(blenderContext);// FCurve
+		if (curves.size() > 0) {
+			BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
+			int frame = 0;
+			for (Structure curve : curves) {
+				Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
+				List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
+				int type = this.getCurveType(curve, blenderContext);
+				bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
+			}
+			curves.clear();
+			result = new Ipo(bezierCurves, fixUpAxis);
+		}
+		return result;
+	}
+
+	/**
+	 * This method returns the type of the ipo curve.
+	 * 
+	 * @param structure
+	 *            the structure must contain the 'rna_path' field and
+	 *            'array_index' field (the type is not important here)
+	 * @param blenderContext
+	 *            the blender context
+	 * @return the type of the curve
+	 */
+	public int getCurveType(Structure structure, BlenderContext blenderContext) {
+		// reading rna path first
+		BlenderInputStream bis = blenderContext.getInputStream();
+		int currentPosition = bis.getPosition();
+		Pointer pRnaPath = (Pointer) structure.getFieldValue("rna_path");
+		FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pRnaPath.getOldMemoryAddress());
+		bis.setPosition(dataFileBlock.getBlockPosition());
+		String rnaPath = bis.readString();
+		bis.setPosition(currentPosition);
+		int arrayIndex = ((Number) structure.getFieldValue("array_index")).intValue();
+
+		// determining the curve type
+		if (rnaPath.endsWith("location")) {
+			return Ipo.AC_LOC_X + arrayIndex;
+		}
+		if (rnaPath.endsWith("rotation_quaternion")) {
+			return Ipo.AC_QUAT_W + arrayIndex;
+		}
+		if (rnaPath.endsWith("scale")) {
+			return Ipo.AC_SIZE_X + arrayIndex;
+		}
+		if (rnaPath.endsWith("rotation")) {
+			return Ipo.OB_ROT_X + arrayIndex;
+		}
+		throw new IllegalStateException("Unknown curve rna path: " + rnaPath);
+	}
+
+	/**
+	 * This method creates an ipo with only a single value. No track type is
+	 * specified so do not use it for calculating tracks.
+	 * 
+	 * @param constValue
+	 *            the value of this ipo
+	 * @return constant ipo
+	 */
+	public Ipo fromValue(float constValue) {
+		return new ConstIpo(constValue);
+	}
+
+	@Override
+	public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
+		return true;
+	}
+
+	/**
+	 * Ipo constant curve. This is a curve with only one value and no specified
+	 * type. This type of ipo cannot be used to calculate tracks. It should only
+	 * be used to calculate single value for a given frame.
+	 * 
+	 * @author Marcin Roguski
+	 */
+	private class ConstIpo extends Ipo {
+
+		/** The constant value of this ipo. */
+		private float	constValue;
+
+		/**
+		 * Constructor. Stores the constant value of this ipo.
+		 * 
+		 * @param constValue
+		 *            the constant value of this ipo
+		 */
+		public ConstIpo(float constValue) {
+			super(null, false);
+			this.constValue = constValue;
+		}
+
+		@Override
+		public float calculateValue(int frame) {
+			return constValue;
+		}
+
+		@Override
+		public float calculateValue(int frame, int curveIndex) {
+			return constValue;
+		}
+
+		@Override
+		public int getCurvesAmount() {
+			return 0;
+		}
+
+		@Override
+		public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps, boolean boneTrack) {
+			throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!");
+		}
+	}
 }

+ 3 - 19
engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java

@@ -20,9 +20,6 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
  * @author Marcin Roguski (Kaelthas)
  */
 public abstract class Constraint {
-	public static final int BAKE_DYNAMIC = 0x01;
-	public static final int BAKE_STATIC  = 0x02;
-	
 	/** The name of this constraint. */
 	protected final String name;
 	/** The constraint's owner. */
@@ -79,32 +76,19 @@ public abstract class Constraint {
 
 	/**
 	 * This method bakes the required sontraints into its owner.
-	 * @param bakeFlag the bake type flag support the following values:
-	 * <li> BAKE_DYNAMIC  - bake animation's constraints
-	 * <li> BAKE_STATIC   - bake static constraints
 	 */
-	public void bake(int bakeFlag) {
+	public void bake() {
 		this.owner.update();
 		if(this.target != null) {
 			this.target.update();
 		}
-		if((bakeFlag & BAKE_DYNAMIC) != 0) {
-			this.bakeDynamic();
-		}
-		if((bakeFlag & BAKE_STATIC) != 0) {
-			this.bakeStatic();
-		}
+		this.bakeConstraint();
 	}
 	
 	/**
 	 * Bake the animation's constraints into its owner.
 	 */
-	protected abstract void bakeDynamic();
-	
-	/**
-	 * Bake the static constraints into its owner.
-	 */
-	protected abstract void bakeStatic();
+	protected abstract void bakeConstraint();
 	
     /**
      * This method returns the bone traces for the bone that is affected by the given constraint.

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintAction.java

@@ -35,13 +35,7 @@ import java.util.logging.Logger;
 	}
 	
 	@Override
-	protected void bakeDynamic() {
-		// TODO: implement 'Action' constraint
-		LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
-	}
-	
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		// TODO: implement 'Action' constraint
 		LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
 	}

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintChildOf.java

@@ -35,13 +35,7 @@ import java.util.logging.Logger;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		// TODO: implement ChildOf constraint
-		LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
-	}
-	
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		// TODO: implement ChildOf constraint
 		LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
 	}

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintClampTo.java

@@ -36,13 +36,7 @@ import java.util.logging.Logger;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		//TODO: implement when curves are implemented
-		LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", name);
-	}
-	
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		//TODO: implement when curves are implemented
 		LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", name);
 	}

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDampTrack.java

@@ -36,13 +36,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		// TODO Auto-generated method stub
-		LOGGER.log(Level.WARNING, "'Damp Track' constraint NOT implemented!");
-	}
-
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		// TODO Auto-generated method stub
 		LOGGER.log(Level.WARNING, "'Damp Track' constraint NOT implemented!");
 	}

+ 11 - 17
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDistLimit.java

@@ -1,7 +1,6 @@
 package com.jme3.scene.plugins.blender.constraints;
 
 import com.jme3.animation.Animation;
-import com.jme3.animation.Bone;
 import com.jme3.math.Matrix4f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.Spatial;
@@ -47,10 +46,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
 	}
 
 	@Override
-	protected void bakeDynamic() {
+	protected void bakeConstraint() {
+		Object owner = this.owner.getObject();
 		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
 		if(animData != null) {
-			Object owner = this.owner.getObject();
 			if(owner instanceof Spatial) {
 				Vector3f targetLocation = ((Spatial) owner).getWorldTranslation();
 				for(Animation animation : animData.anims) {
@@ -66,22 +65,17 @@ import com.jme3.scene.plugins.ogre.AnimData;
 				}
 			}
 		}
-	}
-	
-	@Override
-	protected void bakeStatic() {
-		Matrix4f targetWorldMatrix = target.getWorldTransformMatrix();
-		Vector3f targetLocation = targetWorldMatrix.toTranslationVector();
-		Matrix4f m = owner.getParentWorldTransformMatrix();
-		m.invertLocal();
-		Matrix4f ownerWorldMatrix = owner.getWorldTransformMatrix();
-		Vector3f ownerLocation = ownerWorldMatrix.toTranslationVector();
-		this.distLimit(ownerLocation, targetLocation, ipo.calculateValue(0));
-		Object owner = this.owner.getObject();
+		
+		// apply static constraint only to spatials
 		if(owner instanceof Spatial) {
+			Matrix4f targetWorldMatrix = target.getWorldTransformMatrix();
+			Vector3f targetLocation = targetWorldMatrix.toTranslationVector();
+			Matrix4f m = this.owner.getParentWorldTransformMatrix();
+			m.invertLocal();
+			Matrix4f ownerWorldMatrix = this.owner.getWorldTransformMatrix();
+			Vector3f ownerLocation = ownerWorldMatrix.toTranslationVector();
+			this.distLimit(ownerLocation, targetLocation, ipo.calculateValue(0));
 			((Spatial) owner).setLocalTranslation(m.mult(ownerLocation));
-		} else {
-			((Bone) owner).setBindTransforms(m.mult(ownerLocation), ((Bone) owner).getLocalRotation(), ((Bone) owner).getLocalScale());
 		}
 	}
 	

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFollowPath.java

@@ -35,13 +35,7 @@ import java.util.logging.Logger;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		//TODO: implement when curves are implemented
-		LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!");
-	}
-	
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		//TODO: implement when curves are implemented
 		LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!");
 	}

+ 3 - 3
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java

@@ -93,7 +93,7 @@ public class ConstraintHelper extends AbstractBlenderHelper {
 						Pointer pIpo = (Pointer) constraintChannel.getFieldValue("ipo");
 						if (pIpo.isNotNull()) {
 							String constraintName = constraintChannel.getFieldValue("name").toString();
-							Ipo ipo = ipoHelper.createIpo(pIpo.fetchData(blenderContext.getInputStream()).get(0), blenderContext);
+							Ipo ipo = ipoHelper.fromIpoStructure(pIpo.fetchData(blenderContext.getInputStream()).get(0), blenderContext);
 							ipos.put(constraintName, ipo);
 						}
 					}
@@ -120,7 +120,7 @@ public class ConstraintHelper extends AbstractBlenderHelper {
 					Ipo ipo = ipoMap==null ? null : ipoMap.get(constraintName);
 					if (ipo == null) {
 						float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
-						ipo = ipoHelper.createIpo(enforce);
+						ipo = ipoHelper.fromValue(enforce);
 					}
 					constraintsList.add(this.createConstraint(constraint, boneOMA, ipo, blenderContext));
 				}
@@ -140,7 +140,7 @@ public class ConstraintHelper extends AbstractBlenderHelper {
 			Ipo ipo = objectConstraintsIpos!=null ? objectConstraintsIpos.get(constraintName) : null;
 			if (ipo == null) {
 				float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
-				ipo = ipoHelper.createIpo(enforce);
+				ipo = ipoHelper.fromValue(enforce);
 			}
 			constraintsList.add(this.createConstraint(constraint, objectStructure.getOldMemoryAddress(), ipo, blenderContext));
 		}

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintInverseKinematics.java

@@ -38,7 +38,7 @@ import java.util.logging.Logger;
 	}
 
 	@Override
-	protected void bakeDynamic() {
+	protected void bakeConstraint() {
 //		try {
 			// IK solver is only attached to bones
 //			Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE);
@@ -127,12 +127,6 @@ import java.util.logging.Logger;
 //		}
 	}
 	
-	@Override
-	protected void bakeStatic() {
-		// TODO Auto-generated method stub
-		
-	}
-	
 	/**
 	 * This method returns bones used for rotation calculations.
 	 * @param bone

+ 12 - 12
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLike.java

@@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints;
 import com.jme3.animation.Animation;
 import com.jme3.math.Transform;
 import com.jme3.math.Vector3f;
+import com.jme3.scene.Spatial;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -61,10 +62,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		AnimData animData = blenderContext.getAnimData(owner.getOma());
+	protected void bakeConstraint() {
+		Object owner = this.owner.getObject();
+		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
 		if(animData != null) {
-			Object owner = this.owner.getObject();
 			Transform targetTransform = this.target.getTransform();
 			for(Animation animation : animData.anims) {
 				BlenderTrack blenderTrack = this.getTrack(owner, animData.skeleton, animation);
@@ -76,15 +77,14 @@ import com.jme3.scene.plugins.ogre.AnimData;
 				blenderTrack.setKeyframes(blenderTrack.getTimes(), translations, blenderTrack.getRotations(), blenderTrack.getScales());
 			}
 		}
-	}
-	
-	@Override
-	protected void bakeStatic() {
-		Transform targetTransform = this.target.getTransform();
-		Transform ownerTransform = this.owner.getTransform();
-		Vector3f ownerLocation = ownerTransform.getTranslation();
-		this.locLike(ownerLocation, targetTransform.getTranslation(), ipo.calculateValue(0));
-		this.owner.applyTransform(ownerTransform);
+		
+		if(owner instanceof Spatial) {
+			Transform targetTransform = this.target.getTransform();
+			Transform ownerTransform = this.owner.getTransform();
+			Vector3f ownerLocation = ownerTransform.getTranslation();
+			this.locLike(ownerLocation, targetTransform.getTranslation(), ipo.calculateValue(0));
+			this.owner.applyTransform(ownerTransform);
+		}
 	}
 	
 	private void locLike(Vector3f ownerLocation, Vector3f targetLocation, float influence) {

+ 13 - 9
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLimit.java

@@ -1,8 +1,11 @@
 package com.jme3.scene.plugins.blender.constraints;
 
+import java.util.Arrays;
+
 import com.jme3.animation.Animation;
 import com.jme3.math.Transform;
 import com.jme3.math.Vector3f;
+import com.jme3.scene.Spatial;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -73,7 +76,7 @@ import com.jme3.scene.plugins.ogre.AnimData;
 	}
 
 	@Override
-	protected void bakeDynamic() {
+	protected void bakeConstraint() {
 		Object owner = this.owner.getObject();
 		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
 		if(animData != null) {
@@ -82,19 +85,20 @@ import com.jme3.scene.plugins.ogre.AnimData;
 				Vector3f[] translations = track.getTranslations();
 				int maxFrames = translations.length;
 				for (int frame = 0; frame < maxFrames; ++frame) {
+					System.out.print(translations[frame] + "\t\t");
 					this.locLimit(translations[frame], ipo.calculateValue(frame));
+					System.out.println(translations[frame]);
 				}
 				track.setKeyframes(track.getTimes(), translations, track.getRotations(), track.getScales());
 			}
 		}
-	}
-	
-	@Override
-	protected void bakeStatic() {
-		Transform ownerTransform = this.owner.getTransform();
-		Vector3f ownerLocation = ownerTransform.getTranslation();
-		this.locLimit(ownerLocation, ipo.calculateValue(0));
-		this.owner.applyTransform(ownerTransform);
+		
+		if(owner instanceof Spatial) {
+			Transform ownerTransform = this.owner.getTransform();
+			Vector3f ownerLocation = ownerTransform.getTranslation();
+			this.locLimit(ownerLocation, ipo.calculateValue(0));
+			this.owner.applyTransform(ownerTransform);
+		}
 	}
 	
 	/**

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLockTrack.java

@@ -36,13 +36,7 @@ import java.util.logging.Logger;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		// TODO: implement 'Lock track' constraint
-		LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!");
-	}
-	
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		// TODO: implement 'Lock track' constraint
 		LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!");
 	}

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintMinMax.java

@@ -35,13 +35,7 @@ import java.util.logging.Logger;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		// TODO: implement 'Min max' constraint
-		LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!");
-	}
-	
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		// TODO: implement 'Min max' constraint
 		LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!");
 	}

+ 1 - 4
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintNull.java

@@ -33,8 +33,5 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	}
 
 	@Override
-	protected void bakeDynamic() {}
-	
-	@Override
-	protected void bakeStatic() {}
+	protected void bakeConstraint() {}
 }

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPivot.java

@@ -37,13 +37,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		// TODO Auto-generated method stub
-		LOGGER.log(Level.WARNING, "'Pivot' constraint NOT implemented!");
-	}
-
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		// TODO Auto-generated method stub
 		LOGGER.log(Level.WARNING, "'Pivot' constraint NOT implemented!");
 	}

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPython.java

@@ -35,13 +35,7 @@ import java.util.logging.Logger;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		// TODO: implement 'Python' constraint
-		LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
-	}
-	
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		// TODO: implement 'Python' constraint
 		LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
 	}

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRigidBodyJoint.java

@@ -35,13 +35,7 @@ import java.util.logging.Logger;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		// TODO: implement 'Rigid body joint' constraint
-		LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!");
-	}
-	
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		// TODO: implement 'Rigid body joint' constraint
 		LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!");
 	}

+ 11 - 11
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLike.java

@@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints;
 import com.jme3.animation.Animation;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Transform;
+import com.jme3.scene.Spatial;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -47,10 +48,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
 	}
 
 	@Override
-	protected void bakeDynamic() {
+	protected void bakeConstraint() {
+		Object owner = this.owner.getObject();
 		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
 		if(animData != null) {
-			Object owner = this.owner.getObject();
 			Transform targetTransform = this.target.getTransform();
 			Quaternion targetRotation = targetTransform.getRotation();
 			for(Animation animation : animData.anims) {
@@ -66,15 +67,14 @@ import com.jme3.scene.plugins.ogre.AnimData;
 				track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
 			}
 		}
-	}
-	
-	@Override
-	protected void bakeStatic() {
-		Transform targetTransform = this.target.getTransform();
-		Transform ownerTransform = this.owner.getTransform();
-		Quaternion ownerRotation = ownerTransform.getRotation();
-		this.rotLike(ownerRotation, ownerRotation.toAngles(null), targetTransform.getRotation().toAngles(null), ipo.calculateValue(0));
-		this.owner.applyTransform(ownerTransform);
+		
+		if(owner instanceof Spatial) {
+			Transform targetTransform = this.target.getTransform();
+			Transform ownerTransform = this.owner.getTransform();
+			Quaternion ownerRotation = ownerTransform.getRotation();
+			this.rotLike(ownerRotation, ownerRotation.toAngles(null), targetTransform.getRotation().toAngles(null), ipo.calculateValue(0));
+			this.owner.applyTransform(ownerTransform);
+		}
 	}
 	
 	private void rotLike(Quaternion ownerRotation, float[] ownerAngles, float[] targetAngles, float influence) {

+ 19 - 15
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLimit.java

@@ -1,9 +1,12 @@
 package com.jme3.scene.plugins.blender.constraints;
 
+import java.util.Arrays;
+
 import com.jme3.animation.Animation;
 import com.jme3.math.FastMath;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Transform;
+import com.jme3.scene.Spatial;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -68,10 +71,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		AnimData animData = blenderContext.getAnimData(owner.getOma());
+	protected void bakeConstraint() {
+		Object owner = this.owner.getObject();
+		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
 		if(animData != null) {
-			Object owner = this.owner.getObject();
 			for(Animation animation : animData.anims) {
 				BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
 				Quaternion[] rotations = track.getRotations();
@@ -79,21 +82,22 @@ import com.jme3.scene.plugins.ogre.AnimData;
 				int maxFrames = rotations.length;
 				for (int frame = 0; frame < maxFrames; ++frame) {
 					rotations[frame].toAngles(angles);
+					System.out.print(Arrays.toString(angles) + "\t\t");
 					this.rotLimit(angles, ipo.calculateValue(frame));
+					System.out.println(Arrays.toString(angles));
 					rotations[frame].fromAngles(angles);
 				}
 				track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
 			}
 		}
-	}
-	
-	@Override
-	protected void bakeStatic() {
-		Transform ownerTransform = this.owner.getTransform();
-		float[] angles = ownerTransform.getRotation().toAngles(null);
-		this.rotLimit(angles, ipo.calculateValue(0));
-		ownerTransform.getRotation().fromAngles(angles);
-		this.owner.applyTransform(ownerTransform);
+		
+		if(owner instanceof Spatial) {
+			Transform ownerTransform = this.owner.getTransform();
+			float[] angles = ownerTransform.getRotation().toAngles(null);
+			this.rotLimit(angles, ipo.calculateValue(0));
+			ownerTransform.getRotation().fromAngles(angles);
+			this.owner.applyTransform(ownerTransform);
+		}
 	}
 	
 	/**
@@ -114,7 +118,7 @@ import com.jme3.scene.plugins.ogre.AnimData;
 			}
 			angles[0] -= difference;
 		}
-		if ((flag & LIMIT_YROT) != 0) {
+		if ((flag & LIMIT_ZROT) != 0) {
 			float difference = 0.0f;
 			if (angles[1] < limits[1][0]) {
 				difference = (angles[1] - limits[1][0]) * influence;
@@ -123,7 +127,7 @@ import com.jme3.scene.plugins.ogre.AnimData;
 			}
 			angles[1] -= difference;
 		}
-		if ((flag & LIMIT_ZROT) != 0) {
+		/*if ((flag & LIMIT_ZROT) != 0) {
 			float difference = 0.0f;
 			if (angles[2] < limits[2][0]) {
 				difference = (angles[2] - limits[2][0]) * influence;
@@ -131,6 +135,6 @@ import com.jme3.scene.plugins.ogre.AnimData;
 				difference = (angles[2] - limits[2][1]) * influence;
 			}
 			angles[2] -= difference;
-		}
+		}*/
 	}
 }

+ 2 - 6
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintShrinkWrap.java

@@ -45,7 +45,7 @@ import com.jme3.scene.plugins.ogre.AnimData;
 	}
 
 	@Override
-	protected void bakeDynamic() {
+	protected void bakeConstraint() {
 		//loading mesh points (blender ensures that the target is a mesh-object)
 		List<Vector3f> pts = new ArrayList<Vector3f>();
 		Node target = (Node) this.target.getObject();
@@ -86,11 +86,7 @@ import com.jme3.scene.plugins.ogre.AnimData;
 				track.setKeyframes(track.getTimes(), translations, rotations, track.getScales());
 			}
 		}
-	}
-	
-	@Override
-	protected void bakeStatic() {
-		// TODO Auto-generated method stub
 		
+		//TODO: static constraint for spatials
 	}
 }

+ 10 - 10
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLike.java

@@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints;
 import com.jme3.animation.Animation;
 import com.jme3.math.Transform;
 import com.jme3.math.Vector3f;
+import com.jme3.scene.Spatial;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -52,10 +53,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
 	}
 
 	@Override
-	protected void bakeDynamic() {
+	protected void bakeConstraint() {
+		Object owner = this.owner.getObject();
 		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
 		if(animData != null) {
-			Object owner = this.owner.getObject();
 			Transform targetTransform = this.target.getTransform();
 			Vector3f targetScale = targetTransform.getScale();
 			for(Animation animation : animData.anims) {
@@ -68,14 +69,13 @@ import com.jme3.scene.plugins.ogre.AnimData;
 				track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
 			}
 		}
-	}
-	
-	@Override
-	protected void bakeStatic() {
-		Transform targetTransform = this.target.getTransform();
-		Transform ownerTransform = this.owner.getTransform();
-		this.sizeLike(ownerTransform.getScale(), targetTransform.getScale(), ipo.calculateValue(0));
-		this.owner.applyTransform(ownerTransform);
+		
+		if(owner instanceof Spatial) {
+			Transform targetTransform = this.target.getTransform();
+			Transform ownerTransform = this.owner.getTransform();
+			this.sizeLike(ownerTransform.getScale(), targetTransform.getScale(), ipo.calculateValue(0));
+			this.owner.applyTransform(ownerTransform);
+		}
 	}
 	
 	private void sizeLike(Vector3f ownerScale, Vector3f targetScale, float influence) {

+ 9 - 9
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLimit.java

@@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints;
 import com.jme3.animation.Animation;
 import com.jme3.math.Transform;
 import com.jme3.math.Vector3f;
+import com.jme3.scene.Spatial;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -73,10 +74,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
 	}
 
 	@Override
-	protected void bakeDynamic() {
+	protected void bakeConstraint() {
+		Object owner = this.owner.getObject();
 		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
 		if(animData != null) {
-			Object owner = this.owner.getObject();
 			for(Animation animation : animData.anims) {
 				BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
 				Vector3f[] scales = track.getScales();
@@ -87,13 +88,12 @@ import com.jme3.scene.plugins.ogre.AnimData;
 				track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
 			}
 		}
-	}
-	
-	@Override
-	protected void bakeStatic() {
-		Transform ownerTransform = this.owner.getTransform();
-		this.sizeLimit(ownerTransform.getScale(), ipo.calculateValue(0));
-		this.owner.applyTransform(ownerTransform);
+		
+		if(owner instanceof Spatial) {
+			Transform ownerTransform = this.owner.getTransform();
+			this.sizeLimit(ownerTransform.getScale(), ipo.calculateValue(0));
+			this.owner.applyTransform(ownerTransform);
+		}
 	}
 	
 	private void sizeLimit(Vector3f scale, float influence) {

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSplineInverseKinematic.java

@@ -37,14 +37,8 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	}
 
 	@Override
-	protected void bakeDynamic() {
+	protected void bakeConstraint() {
 		// TODO Auto-generated method stub
 		LOGGER.log(Level.WARNING, "'Splie IK' constraint NOT implemented!");
 	}
-
-	@Override
-	protected void bakeStatic() {
-		// TODO Auto-generated method stub
-		LOGGER.log(Level.WARNING, "'Spline IK' constraint NOT implemented!");
-	}
 }

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintStretchTo.java

@@ -35,13 +35,7 @@ import java.util.logging.Logger;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		// TODO: implement 'Stretch to' constraint
-		LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!");
-	}
-	
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		// TODO: implement 'Stretch to' constraint
 		LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!");
 	}

+ 1 - 7
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintTransform.java

@@ -35,13 +35,7 @@ import java.util.logging.Logger;
 	}
 
 	@Override
-	protected void bakeDynamic() {
-		// TODO: implement 'Transform' constraint
-		LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
-	}
-	
-	@Override
-	protected void bakeStatic() {
+	protected void bakeConstraint() {
 		// TODO: implement 'Transform' constraint
 		LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
 	}

+ 12 - 4
engine/src/blender/com/jme3/scene/plugins/blender/constraints/Feature.java

@@ -1,6 +1,7 @@
 package com.jme3.scene.plugins.blender.constraints;
 
 import com.jme3.animation.Bone;
+import com.jme3.math.FastMath;
 import com.jme3.math.Matrix4f;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Transform;
@@ -8,6 +9,7 @@ import com.jme3.math.Vector3f;
 import com.jme3.scene.Spatial;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
+import com.jme3.scene.plugins.blender.animations.BoneContext;
 import com.jme3.scene.plugins.blender.constraints.Constraint.Space;
 import com.jme3.scene.plugins.blender.file.DynamicArray;
 import com.jme3.scene.plugins.blender.file.Structure;
@@ -156,6 +158,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
 			}
 		}
 		// Bone
+		BoneContext boneContext = blenderContext.getBoneContext(oma);
 		switch (space) {
 			case CONSTRAINT_SPACE_LOCAL:
 				Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
@@ -173,8 +176,9 @@ import com.jme3.scene.plugins.blender.file.Structure;
 				worldTransform.setScale(bone.getWorldBindScale());
 				return worldTransform;
 			case CONSTRAINT_SPACE_POSE:
-				// TODO
-				return null;
+				Transform poseTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
+				poseTransform.setScale(bone.getLocalScale());
+				return poseTransform;
 			case CONSTRAINT_SPACE_PARLOCAL:
 				Transform parentLocalTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
 				parentLocalTransform.setScale(bone.getLocalScale());
@@ -228,11 +232,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
 					break;
 				case CONSTRAINT_SPACE_WORLD:
 					Matrix4f m = this.getParentWorldTransformMatrix();
-					m.invertLocal();
+//					m.invertLocal();
 					transform.setTranslation(m.mult(transform.getTranslation()));
 					transform.setRotation(m.mult(transform.getRotation(), null));
 					transform.setScale(transform.getScale());
 					bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale());
+//					float x = FastMath.HALF_PI/2;
+//					float y = -FastMath.HALF_PI;
+//					float z = -FastMath.HALF_PI/2;
+//					bone.setBindTransforms(new Vector3f(0,0,0), new Quaternion().fromAngles(x, y, z), new Vector3f(1,1,1));
 					break;
 				case CONSTRAINT_SPACE_PARLOCAL:
 					Vector3f parentLocalTranslation = bone.getLocalPosition().add(transform.getTranslation());
@@ -240,7 +248,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
 					bone.setBindTransforms(parentLocalTranslation, parentLocalRotation, transform.getScale());
 					break;
 				case CONSTRAINT_SPACE_POSE:
-					// TODO:
+					bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale());
 					break;
 				default:
 					throw new IllegalStateException("Invalid space type for target object: " + space.toString());

+ 38 - 42
engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java

@@ -42,8 +42,8 @@ import com.jme3.util.BufferUtils;
  * @author Marcin Roguski (Kaelthas)
  */
 /* package */class ArmatureModifier extends Modifier {
-	private static final Logger		LOGGER						= Logger.getLogger(ArmatureModifier.class.getName());
-	private static final int		MAXIMUM_WEIGHTS_PER_VERTEX	= 4;	
+	private static final Logger	LOGGER						= Logger.getLogger(ArmatureModifier.class.getName());
+	private static final int	MAXIMUM_WEIGHTS_PER_VERTEX	= 4;
 	// @Marcin it was an Ogre limitation, but as long as we use a MaxNumWeight
 	// variable in mesh,
 	// i guess this limitation has no sense for the blender loader...so i guess
@@ -55,17 +55,18 @@ import com.jme3.util.BufferUtils;
 	// Rémy
 
 	/** Loaded animation data. */
-	private AnimData				animData;
+	private AnimData			animData;
 	/** Old memory address of the mesh that will have the skeleton applied. */
-	private Long					meshOMA;
+	private Long				meshOMA;
 	/**
-	 * The maxiumum amount of bone groups applied to a single vertex (max = MAXIMUM_WEIGHTS_PER_VERTEX).
+	 * The maxiumum amount of bone groups applied to a single vertex (max =
+	 * MAXIMUM_WEIGHTS_PER_VERTEX).
 	 */
-	private int						boneGroups;
+	private int					boneGroups;
 	/** The weights of vertices. */
-	private VertexBuffer			verticesWeights;
+	private VertexBuffer		verticesWeights;
 	/** The indexes of bones applied to vertices. */
-	private VertexBuffer			verticesWeightsIndices;
+	private VertexBuffer		verticesWeightsIndices;
 
 	/**
 	 * This constructor reads animation data from the object structore. The
@@ -83,9 +84,12 @@ import com.jme3.util.BufferUtils;
 	 */
 	public ArmatureModifier(Structure objectStructure, Structure modifierStructure, BlenderContext blenderContext) throws BlenderFileException {
 		Structure meshStructure = ((Pointer) objectStructure.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
-		Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
-		
-		//if pDvert==null then there are not vertex groups and no need to load skeleton (untill bone envelopes are supported)
+		Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert
+																		// =
+																		// DeformVERTices
+
+		// if pDvert==null then there are not vertex groups and no need to load
+		// skeleton (untill bone envelopes are supported)
 		if (this.validate(modifierStructure, blenderContext) && pDvert.isNotNull()) {
 			Pointer pArmatureObject = (Pointer) modifierStructure.getFieldValue("object");
 			if (pArmatureObject.isNotNull()) {
@@ -109,15 +113,16 @@ import com.jme3.util.BufferUtils;
 				Matrix4f armatureObjectMatrix = objectHelper.getMatrix(armatureObject, "obmat", true);
 				Matrix4f inverseMeshObjectMatrix = objectHelper.getMatrix(objectStructure, "obmat", true).invertLocal();
 				Matrix4f objectToArmatureTransformation = armatureObjectMatrix.multLocal(inverseMeshObjectMatrix);
-				
+
 				List<Structure> bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase(blenderContext);
 				List<Bone> bonesList = new ArrayList<Bone>();
 				for (int i = 0; i < bonebase.size(); ++i) {
 					armatureHelper.buildBones(bonebase.get(i), null, bonesList, objectToArmatureTransformation, bonesPoseChannels, blenderContext);
 				}
 				bonesList.add(0, new Bone(""));
-				Skeleton skeleton = new Skeleton(bonesList.toArray(new Bone[bonesList.size()]));
-				
+				Bone[] bones = bonesList.toArray(new Bone[bonesList.size()]);
+				Skeleton skeleton = new Skeleton(bones);
+
 				// read mesh indexes
 				this.meshOMA = meshStructure.getOldMemoryAddress();
 				this.readVerticesWeightsData(objectStructure, meshStructure, skeleton, blenderContext);
@@ -132,25 +137,30 @@ import com.jme3.util.BufferUtils;
 						String actionName = actionStructure.getName();
 
 						BoneTrack[] tracks = armatureHelper.getTracks(actionStructure, skeleton, blenderContext);
-						// determining the animation time
-						float maximumTrackLength = 0;
-						for (BoneTrack track : tracks) {
-							float length = track.getLength();
-							if (length > maximumTrackLength) {
-								maximumTrackLength = length;
+						if(tracks != null && tracks.length > 0) {
+							// determining the animation time
+							float maximumTrackLength = 0;
+							for (BoneTrack track : tracks) {
+								float length = track.getLength();
+								if (length > maximumTrackLength) {
+									maximumTrackLength = length;
+								}
 							}
-						}
 
-						Animation boneAnimation = new Animation(actionName, maximumTrackLength);
-						boneAnimation.setTracks(tracks);
-						animations.add(boneAnimation);
+							Animation boneAnimation = new Animation(actionName, maximumTrackLength);
+							boneAnimation.setTracks(tracks);
+							animations.add(boneAnimation);
+						}
 					}
 				}
 				animData = new AnimData(skeleton, animations);
 
 				// store the animation data for each bone
-				for (Structure boneStructure : bonebase) {
-					blenderContext.setAnimData(boneStructure.getOldMemoryAddress(), animData);
+				for (Bone bone : bones) {
+					Long boneOma = armatureHelper.getBoneOMA(bone);
+					if (boneOma != null) {
+						blenderContext.setAnimData(boneOma, animData);
+					}
 				}
 			}
 		}
@@ -177,28 +187,14 @@ import com.jme3.util.BufferUtils;
 			}
 		}
 
-		// applying bone transforms before constraints are baked
+		// applying constraints to Bones
 		ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
-		//TODO: should we apply static bone poses ??? (this breaks the animation)
-//		for (int i = 0; i < animData.skeleton.getBoneCount(); ++i) {
-//			Bone bone = animData.skeleton.getBone(i);
-//			Transform transform = armatureHelper.getBoneBindTransform(bone);
-//			Transform boneTransform = armatureHelper.getLocalTransform(bone);
-//			if(transform!=null && boneTransform!=null) {
-//				bone.setBindTransforms(boneTransform.getTranslation().addLocal(transform.getTranslation()), 
-//						boneTransform.getRotation().multLocal(transform.getRotation()),
-//						boneTransform.getScale().multLocal(transform.getScale()));
-//			}
-//		}
-
-		// applying constraints to Bones (and only to bones, object constraints
-		// are applied in the ObjectHelper)
 		for (int i = 0; i < animData.skeleton.getBoneCount(); ++i) {
 			Long boneOMA = armatureHelper.getBoneOMA(animData.skeleton.getBone(i));
 			List<Constraint> constraints = blenderContext.getConstraints(boneOMA);
 			if (constraints != null && constraints.size() > 0) {
 				for (Constraint constraint : constraints) {
-					constraint.bake(Constraint.BAKE_DYNAMIC | Constraint.BAKE_STATIC);
+					constraint.bake();
 				}
 			}
 		}

+ 145 - 62
engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ModifierHelper.java

@@ -31,82 +31,165 @@
  */
 package com.jme3.scene.plugins.blender.modifiers;
 
-import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
-import com.jme3.scene.plugins.blender.BlenderContext;
-import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
-import com.jme3.scene.plugins.blender.file.Pointer;
-import com.jme3.scene.plugins.blender.file.Structure;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
+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.exceptions.BlenderFileException;
+import com.jme3.scene.plugins.blender.file.Pointer;
+import com.jme3.scene.plugins.blender.file.Structure;
+
 /**
  * A class that is used in modifiers calculations.
+ * 
  * @author Marcin Roguski
  */
 public class ModifierHelper extends AbstractBlenderHelper {
 
-    private static final Logger LOGGER = Logger.getLogger(ModifierHelper.class.getName());
+	private static final Logger	LOGGER	= Logger.getLogger(ModifierHelper.class.getName());
+
+	/**
+	 * This constructor parses the given blender version and stores the result.
+	 * Some functionalities may differ in different blender versions.
+	 * 
+	 * @param blenderVersion
+	 *            the version read from the blend file
+	 * @param fixUpAxis
+	 *            a variable that indicates if the Y asxis is the UP axis or not
+	 */
+	public ModifierHelper(String blenderVersion, boolean fixUpAxis) {
+		super(blenderVersion, fixUpAxis);
+	}
+
+	/**
+	 * This method reads the given object's modifiers.
+	 * 
+	 * @param objectStructure
+	 *            the object structure
+	 * @param blenderContext
+	 *            the blender context
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blender file is somehow
+	 *             corrupted
+	 */
+	public Collection<Modifier> readModifiers(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
+		Collection<Modifier> result = new ArrayList<Modifier>();
+		Structure modifiersListBase = (Structure) objectStructure.getFieldValue("modifiers");
+		List<Structure> modifiers = modifiersListBase.evaluateListBase(blenderContext);
+		for (Structure modifierStructure : modifiers) {
+			Modifier modifier = null;
+			if (Modifier.ARRAY_MODIFIER_DATA.equals(modifierStructure.getType())) {
+				modifier = new ArrayModifier(modifierStructure, blenderContext);
+			} else if (Modifier.MIRROR_MODIFIER_DATA.equals(modifierStructure.getType())) {
+				modifier = new MirrorModifier(modifierStructure, blenderContext);
+			} else if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifierStructure.getType())) {
+				modifier = new ArmatureModifier(objectStructure, modifierStructure, blenderContext);
+			} else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifierStructure.getType())) {
+				modifier = new ParticlesModifier(modifierStructure, blenderContext);
+			}
+
+			if (modifier != null) {
+				result.add(modifier);
+				blenderContext.addModifier(objectStructure.getOldMemoryAddress(), modifier);
+			} else {
+				LOGGER.log(Level.WARNING, "Unsupported modifier type: {0}", modifierStructure.getType());
+			}
+		}
 
-    /**
-     * This constructor parses the given blender version and stores the result. Some functionalities may differ in
-     * different blender versions.
-     * @param blenderVersion
-     *        the version read from the blend file
-     * @param fixUpAxis
-     *        a variable that indicates if the Y asxis is the UP axis or not
-     */
-    public ModifierHelper(String blenderVersion, boolean fixUpAxis) {
-        super(blenderVersion, fixUpAxis);
-    }
+		// at the end read object's animation modifier (object animation is
+		// either described by action or by ipo of the object)
+		Modifier modifier;
+		if (blenderVersion <= 249) {
+			modifier = this.readAnimationModifier249(objectStructure, blenderContext);
+		} else {
+			modifier = this.readAnimationModifier250(objectStructure, blenderContext);
+		}
+		if (modifier != null) {
+			result.add(modifier);
+		}
+		return result;
+	}
 
-    /**
-     * This method reads the given object's modifiers.
-     * @param objectStructure
-     *        the object structure
-     * @param blenderContext
-     *        the blender context
-     * @throws BlenderFileException
-     *         this exception is thrown when the blender file is somehow corrupted
-     */
-    public Collection<Modifier> readModifiers(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
-    	Collection<Modifier> result = new ArrayList<Modifier>();
-    	Structure modifiersListBase = (Structure) objectStructure.getFieldValue("modifiers");
-        List<Structure> modifiers = modifiersListBase.evaluateListBase(blenderContext);
-        for (Structure modifierStructure : modifiers) {
-            Modifier modifier = null;
-            if (Modifier.ARRAY_MODIFIER_DATA.equals(modifierStructure.getType())) {
-            	modifier = new ArrayModifier(modifierStructure, blenderContext);
-            } else if (Modifier.MIRROR_MODIFIER_DATA.equals(modifierStructure.getType())) {
-            	modifier = new MirrorModifier(modifierStructure, blenderContext);
-            } else if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifierStructure.getType())) {
-            	modifier = new ArmatureModifier(objectStructure, modifierStructure, blenderContext);
-            } else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifierStructure.getType())) {
-            	modifier = new ParticlesModifier(modifierStructure, blenderContext);
-            }
-            
-            if(modifier != null) {
-            	result.add(modifier);
-            	blenderContext.addModifier(objectStructure.getOldMemoryAddress(), modifier);
-            } else {
-            	LOGGER.log(Level.WARNING, "Unsupported modifier type: {0}", modifierStructure.getType());
-            }
-        }
+	@Override
+	public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
+		return true;
+	}
 
-        //at the end read object's animation modifier
-        Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
-        if (pIpo.isNotNull()) {
-        	Modifier modifier = new ObjectAnimationModifier(objectStructure, blenderContext);
-        	result.add(modifier);
-        	blenderContext.addModifier(objectStructure.getOldMemoryAddress(), modifier);
-        }
-        return result;
-    }
+	/**
+	 * This method reads the object's animation modifier for blender version
+	 * 2.49 and lower.
+	 * 
+	 * @param objectStructure
+	 *            the object's structure
+	 * @param blenderContext
+	 *            the blender context
+	 * @return loaded modifier
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blender file is somehow
+	 *             corrupted
+	 */
+	private Modifier readAnimationModifier249(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
+		Modifier result = null;
+		Pointer pAction = (Pointer) objectStructure.getFieldValue("action");
+		IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
+		if (pAction.isNotNull()) {
+			Structure action = pAction.fetchData(blenderContext.getInputStream()).get(0);
+			List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext);
+			if (actionChannels.size() == 1) {// object's animtion action has
+												// only one channel
+				Pointer pChannelIpo = (Pointer) actionChannels.get(0).getFieldValue("ipo");
+				Structure ipoStructure = pChannelIpo.fetchData(blenderContext.getInputStream()).get(0);
+				Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext);
+				result = new ObjectAnimationModifier(ipo, action.getName(), objectStructure.getOldMemoryAddress(), blenderContext);
+				blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result);
+			} else {
+				throw new IllegalStateException("Object's action cannot have more than one channel!");
+			}
+		} else {
+			Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
+			if (pIpo.isNotNull()) {
+				Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0);
+				Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext);
+				result = new ObjectAnimationModifier(ipo, objectStructure.getName(), objectStructure.getOldMemoryAddress(), blenderContext);
+				blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result);
+			}
+		}
+		return result;
+	}
 
-    @Override
-    public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
-    	return true;
-    }
+	/**
+	 * This method reads the object's animation modifier for blender version
+	 * 2.50 and higher.
+	 * 
+	 * @param objectStructure
+	 *            the object's structure
+	 * @param blenderContext
+	 *            the blender context
+	 * @return loaded modifier
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blender file is somehow
+	 *             corrupted
+	 */
+	private Modifier readAnimationModifier250(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
+		Modifier result = null;
+		Pointer pAnimData = (Pointer) objectStructure.getFieldValue("adt");
+		if (pAnimData.isNotNull()) {
+			Structure animData = pAnimData.fetchData(blenderContext.getInputStream()).get(0);
+			Pointer pAction = (Pointer) animData.getFieldValue("action");
+			if (pAction.isNotNull()) {
+				Structure actionStructure = pAction.fetchData(blenderContext.getInputStream()).get(0);
+				IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
+				Ipo ipo = ipoHelper.fromAction(actionStructure, blenderContext);
+				result = new ObjectAnimationModifier(ipo, actionStructure.getName(), objectStructure.getOldMemoryAddress(), blenderContext);
+				blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result);
+			}
+		}
+		return result;
+	}
 }

+ 25 - 58
engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java

@@ -2,7 +2,6 @@ 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;
 
@@ -12,11 +11,7 @@ import com.jme3.animation.SpatialTrack;
 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.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;
 
 /**
@@ -25,13 +20,11 @@ import com.jme3.scene.plugins.ogre.AnimData;
  * @author Marcin Roguski (Kaelthas)
  */
 /* package */class ObjectAnimationModifier extends Modifier {
-	private static final Logger LOGGER = Logger.getLogger(ObjectAnimationModifier.class.getName());
+	private static final Logger	LOGGER	= Logger.getLogger(ObjectAnimationModifier.class.getName());
 
 	/** Loaded animation data. */
-	private AnimData animData;
-	/** Old memory address of the object structure that will have the modifier applied. */
-	private Long objectOMA;
-	
+	private AnimData			animData;
+
 	/**
 	 * This constructor reads animation of the object itself (without bones) and
 	 * stores it as an ArmatureModifierData modifier. The animation is returned
@@ -40,67 +33,41 @@ import com.jme3.scene.plugins.ogre.AnimData;
 	 * animation should be working. The stored modifier is an anim data and
 	 * additional data is given object's OMA.
 	 * 
-	 * @param objectStructure
-	 *            the structure of the object
+	 * @param ipo
+	 *            the object's interpolation curves
+	 * @param objectAnimationName
+	 *            the name of object's animation
+	 * @param objectOMA
+	 *            the OMA of the object
 	 * @param blenderContext
 	 *            the blender context
-	 * @return animation modifier is returned, it should be separately applied
-	 *         when the object is loaded
 	 * @throws BlenderFileException
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 */
-	public ObjectAnimationModifier(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
-		objectOMA = objectStructure.getOldMemoryAddress();
-		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));
-			if(actionBlocks != null) {
-				for (FileBlockHeader actionBlock : actionBlocks) {
-					Structure action = actionBlock.getStructure(blenderContext);
-					List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext);
-					if (actionChannels.size() == 1) {// object's animtion action has only one channel
-						Pointer pChannelIpo = (Pointer) actionChannels.get(0).getFieldValue("ipo");
-						if (pChannelIpo.equals(pIpo)) {
-							objectAnimationName = action.getName();
-							break;
-						}
-					}
-				}
-			}
+	public ObjectAnimationModifier(Ipo ipo, String objectAnimationName, Long objectOMA, BlenderContext blenderContext) throws BlenderFileException {
+		int fps = blenderContext.getBlenderKey().getFps();
 
-			String objectName = objectStructure.getName();
-			if (objectAnimationName == null) {// set the object's animation name to object's name
-				objectAnimationName = objectName;
-			}
+		// calculating track
+		SpatialTrack track = (SpatialTrack) ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps, true);
 
-			IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
-			Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0);
-			Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
-			int fps = blenderContext.getBlenderKey().getFps();
-			
-			// calculating track for the only bone in this skeleton
-			SpatialTrack track = (SpatialTrack) ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps);
-			
-			Animation animation = new Animation(objectAnimationName, ipo.getLastFrame() / fps);
-			animation.setTracks(new SpatialTrack[] { track });
-			ArrayList<Animation> animations = new ArrayList<Animation>(1);
-			animations.add(animation);
+		Animation animation = new Animation(objectAnimationName, ipo.getLastFrame() / fps);
+		animation.setTracks(new SpatialTrack[] { track });
+		ArrayList<Animation> animations = new ArrayList<Animation>(1);
+		animations.add(animation);
 
-			animData = new AnimData(null, animations);
-			blenderContext.setAnimData(objectOMA, animData);
-		}
+		animData = new AnimData(null, animations);
+		blenderContext.setAnimData(objectOMA, animData);
 	}
-	
+
 	@Override
 	public Node apply(Node node, BlenderContext blenderContext) {
-		if(invalid) {
+		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) {
-			//INFO: constraints for this modifier are applied in the ObjectHelper when the whole object is loaded
+		}// if invalid, animData will be null
+		if (animData != null) {
+			// INFO: constraints for this modifier are applied in the
+			// ObjectHelper when the whole object is loaded
 			ArrayList<Animation> animList = animData.anims;
 			if (animList != null && animList.size() > 0) {
 				HashMap<String, Animation> anims = new HashMap<String, Animation>();

+ 1 - 1
engine/src/blender/com/jme3/scene/plugins/blender/objects/ObjectHelper.java

@@ -261,7 +261,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
 			List<Constraint> objectConstraints = blenderContext.getConstraints(objectStructure.getOldMemoryAddress());
 			if(objectConstraints!=null) {
 				for(Constraint objectConstraint : objectConstraints) {
-					objectConstraint.bake(Constraint.BAKE_STATIC);
+					objectConstraint.bake();
 				}
 			}