Pārlūkot izejas kodu

Many changes to blender importer:
- constraints refactoring (easier use and less code)
- constraints support for blender 2.50+ (although not all of the constraints are supported)
- Y is up axis issue fixed for animations
- owner and target spaces evaluation support for constraints (two bone space modes still to do)
- simplified code for bones loading (though still needs some refactoring)

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

Kae..pl 14 gadi atpakaļ
vecāks
revīzija
a1d73d159d
47 mainītis faili ar 2494 papildinājumiem un 1800 dzēšanām
  1. 3 9
      engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java
  2. 510 408
      engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java
  3. 12 22
      engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java
  4. 138 228
      engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java
  5. 61 37
      engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java
  6. 8 5
      engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java
  7. 4 2
      engine/src/blender/com/jme3/scene/plugins/blender/cameras/CameraHelper.java
  8. 147 0
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/BlenderTrack.java
  9. 61 156
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java
  10. 8 8
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintAction.java
  11. 7 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintChildOf.java
  12. 8 8
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintClampTo.java
  13. 49 0
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDampTrack.java
  14. 83 40
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDistLimit.java
  15. 0 78
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFactory.java
  16. 7 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFollowPath.java
  17. 112 48
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java
  18. 44 33
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintInverseKinematics.java
  19. 74 38
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLike.java
  20. 93 50
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLimit.java
  21. 8 8
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLockTrack.java
  22. 7 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintMinMax.java
  23. 5 8
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintNull.java
  24. 50 0
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPivot.java
  25. 7 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPython.java
  26. 7 7
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRigidBodyJoint.java
  27. 67 40
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLike.java
  28. 91 49
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLimit.java
  29. 26 28
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintShrinkWrap.java
  30. 53 28
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLike.java
  31. 84 50
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLimit.java
  32. 50 0
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSplineInverseKinematic.java
  33. 9 10
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintStretchTo.java
  34. 8 8
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintTransform.java
  35. 0 145
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintType.java
  36. 274 0
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/Feature.java
  37. 5 3
      engine/src/blender/com/jme3/scene/plugins/blender/curves/CurvesHelper.java
  38. 4 2
      engine/src/blender/com/jme3/scene/plugins/blender/lights/LightHelper.java
  39. 4 4
      engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialHelper.java
  40. 4 2
      engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java
  41. 180 130
      engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java
  42. 4 2
      engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ModifierHelper.java
  43. 30 39
      engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java
  44. 79 34
      engine/src/blender/com/jme3/scene/plugins/blender/objects/ObjectHelper.java
  45. 4 2
      engine/src/blender/com/jme3/scene/plugins/blender/particles/ParticlesHelper.java
  46. 1 1
      engine/src/blender/com/jme3/scene/plugins/blender/textures/NoiseGenerator.java
  47. 4 2
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java

+ 3 - 9
engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java

@@ -60,17 +60,11 @@ public abstract class AbstractBlenderHelper {
 	 * versions.
 	 * versions.
 	 * @param blenderVersion
 	 * @param blenderVersion
 	 *        the version read from the blend file
 	 *        the version read from the blend file
-	 */
-	public AbstractBlenderHelper(String blenderVersion) {
-		this.blenderVersion = Integer.parseInt(blenderVersion);
-	}
-
-	/**
-	 * This method sets the Y is UP axis. By default the UP axis is Z (just like in blender).
 	 * @param fixUpAxis
 	 * @param fixUpAxis
-	 *        a variable that indicates if the Y asxis is the UP axis or not
+     *        a variable that indicates if the Y asxis is the UP axis or not
 	 */
 	 */
-	public void setyIsUpAxis(boolean fixUpAxis) {
+	public AbstractBlenderHelper(String blenderVersion, boolean fixUpAxis) {
+		this.blenderVersion = Integer.parseInt(blenderVersion);
 		this.fixUpAxis = fixUpAxis;
 		this.fixUpAxis = fixUpAxis;
 		if(fixUpAxis) {
 		if(fixUpAxis) {
 			upAxisRotationQuaternion = new Quaternion().fromAngles(-FastMath.HALF_PI, 0, 0);
 			upAxisRotationQuaternion = new Quaternion().fromAngles(-FastMath.HALF_PI, 0, 0);

+ 510 - 408
engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java

@@ -31,6 +31,16 @@
  */
  */
 package com.jme3.scene.plugins.blender;
 package com.jme3.scene.plugins.blender;
 
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
 import com.jme3.asset.AssetManager;
 import com.jme3.asset.AssetManager;
 import com.jme3.asset.BlenderKey;
 import com.jme3.asset.BlenderKey;
 import com.jme3.material.Material;
 import com.jme3.material.Material;
@@ -44,446 +54,538 @@ import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.materials.MaterialContext;
 import com.jme3.scene.plugins.blender.materials.MaterialContext;
 import com.jme3.scene.plugins.blender.meshes.MeshContext;
 import com.jme3.scene.plugins.blender.meshes.MeshContext;
 import com.jme3.scene.plugins.blender.modifiers.Modifier;
 import com.jme3.scene.plugins.blender.modifiers.Modifier;
-import java.io.IOException;
-import java.util.*;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import com.jme3.scene.plugins.ogre.AnimData;
 
 
 /**
 /**
- * The class that stores temporary data and manages it during loading the belnd file. This class is intended to be used
- * in a single loading thread. It holds the state of loading operations.
+ * The class that stores temporary data and manages it during loading the belnd
+ * file. This class is intended to be used in a single loading thread. It holds
+ * the state of loading operations.
+ * 
  * @author Marcin Roguski (Kaelthas)
  * @author Marcin Roguski (Kaelthas)
  */
  */
 public class BlenderContext {
 public class BlenderContext {
-	private static final Logger LOGGER = Logger.getLogger(BlenderContext.class.getName());
-	
-    /** The blender key. */
-    private BlenderKey blenderKey;
-    /** The header of the file block. */
-    private DnaBlockData dnaBlockData;
-    /** The input stream of the blend file. */
-    private BlenderInputStream inputStream;
-    /** The asset manager. */
-    private AssetManager assetManager;
-    /** A map containing the file block headers. The key is the old pointer address. */
-    private Map<Long, FileBlockHeader> fileBlockHeadersByOma = new HashMap<Long, FileBlockHeader>();
-    /** A map containing the file block headers. The key is the block code. */
-    private Map<Integer, List<FileBlockHeader>> fileBlockHeadersByCode = new HashMap<Integer, List<FileBlockHeader>>();
-    /**
-     * This map stores the loaded features by their old memory address. The first object in the value table is the
-     * loaded structure and the second - the structure already converted into proper data.
-     */
-    private Map<Long, Object[]> loadedFeatures = new HashMap<Long, Object[]>();
-    /**
-     * This map stores the loaded features by their name. Only features with ID structure can be stored here.
-     * The first object in the value table is the
-     * loaded structure and the second - the structure already converted into proper data.
-     */
-    private Map<String, Object[]> loadedFeaturesByName = new HashMap<String, Object[]>();
-    /** A stack that hold the parent structure of currently loaded feature. */
-    private Stack<Structure> parentStack = new Stack<Structure>();
-    /** A map storing loaded ipos. The key is the ipo's owner old memory address and the value is the ipo. */
-    private Map<Long, Ipo> loadedIpos = new HashMap<Long, Ipo>();
-    /** A list of modifiers for the specified object. */
-    protected Map<Long, List<Modifier>> modifiers = new HashMap<Long, List<Modifier>>();
-    /** A list of constraints for the specified object. */
-    protected Map<Long, List<Constraint>> constraints = new HashMap<Long, List<Constraint>>();
-    /** A map of mesh contexts. */
-    protected Map<Long, MeshContext> meshContexts = new HashMap<Long, MeshContext>();
-    /** A map of material contexts. */
-    protected Map<Material, MaterialContext> materialContexts = new HashMap<Material, MaterialContext>();
-    /** A map og helpers that perform loading. */
-    private Map<String, AbstractBlenderHelper> helpers = new HashMap<String, AbstractBlenderHelper>();
-
-    /**
-     * This method sets the blender key.
-     * @param blenderKey
-     * 		  the blender key
-     */
-    public void setBlenderKey(BlenderKey blenderKey) {
-        this.blenderKey = blenderKey;
-    }
-
-    /**
-     * This method returns the blender key.
-     * @return the blender key
-     */
-    public BlenderKey getBlenderKey() {
-        return blenderKey;
-    }
-
-    /**
-     * This method sets the dna block data.
-     * @param dnaBlockData
-     *        the dna block data
-     */
-    public void setBlockData(DnaBlockData dnaBlockData) {
-        this.dnaBlockData = dnaBlockData;
-    }
-
-    /**
-     * This method returns the dna block data.
-     * @return the dna block data
-     */
-    public DnaBlockData getDnaBlockData() {
-        return dnaBlockData;
-    }
-
-    /**
-     * This method returns the asset manager.
-     * @return the asset manager
-     */
-    public AssetManager getAssetManager() {
-        return assetManager;
-    }
-
-    /**
-     * This method sets the asset manager.
-     * @param assetManager
-     *        the asset manager
-     */
-    public void setAssetManager(AssetManager assetManager) {
-        this.assetManager = assetManager;
-    }
-
-    /**
-     * This method returns the input stream of the blend file.
-     * @return the input stream of the blend file
-     */
-    public BlenderInputStream getInputStream() {
-        return inputStream;
-    }
-
-    /**
-     * This method sets the input stream of the blend file.
-     * @param inputStream
-     *        the input stream of the blend file
-     */
-    public void setInputStream(BlenderInputStream inputStream) {
-        this.inputStream = inputStream;
-    }
-
-    /**
-     * This method adds a file block header to the map. Its old memory address is the key.
-     * @param oldMemoryAddress
-     *        the address of the block header
-     * @param fileBlockHeader
-     *        the block header to store
-     */
-    public void addFileBlockHeader(Long oldMemoryAddress, FileBlockHeader fileBlockHeader) {
-        fileBlockHeadersByOma.put(oldMemoryAddress, fileBlockHeader);
-        List<FileBlockHeader> headers = fileBlockHeadersByCode.get(Integer.valueOf(fileBlockHeader.getCode()));
-        if (headers == null) {
-            headers = new ArrayList<FileBlockHeader>();
-            fileBlockHeadersByCode.put(Integer.valueOf(fileBlockHeader.getCode()), headers);
-        }
-        headers.add(fileBlockHeader);
-    }
-
-    /**
-     * This method returns the block header of a given memory address. If the header is not present then null is
-     * returned.
-     * @param oldMemoryAddress
-     *        the address of the block header
-     * @return loaded header or null if it was not yet loaded
-     */
-    public FileBlockHeader getFileBlock(Long oldMemoryAddress) {
-        return fileBlockHeadersByOma.get(oldMemoryAddress);
-    }
-
-    /**
-     * This method returns a list of file blocks' headers of a specified code.
-     * @param code
-     *        the code of file blocks
-     * @return a list of file blocks' headers of a specified code
-     */
-    public List<FileBlockHeader> getFileBlocks(Integer code) {
-        return fileBlockHeadersByCode.get(code);
-    }
-
-    /**
-     * This method clears the saved block headers stored in the features map.
-     */
-    public void clearFileBlocks() {
-        fileBlockHeadersByOma.clear();
-        fileBlockHeadersByCode.clear();
-    }
-
-    /**
-     * This method adds a helper instance to the helpers' map.
-     * @param <T>
-     *        the type of the helper
-     * @param clazz
-     *        helper's class definition
-     * @param helper
-     *        the helper instance
-     */
-    public <T> void putHelper(Class<T> clazz, AbstractBlenderHelper helper) {
-        helpers.put(clazz.getSimpleName(), helper);
-    }
-
-    @SuppressWarnings("unchecked")
-    public <T> T getHelper(Class<?> clazz) {
-        return (T) helpers.get(clazz.getSimpleName());
-    }
-
-    /**
-     * This method adds a loaded feature to the map. The key is its unique old memory address.
-     * @param oldMemoryAddress
-     *        the address of the feature
-     * @param featureName the name of the feature
-     * @param structure
-     *        the filled structure of the feature
-     * @param feature
-     *        the feature we want to store
-     */
-    public void addLoadedFeatures(Long oldMemoryAddress, String featureName, Structure structure, Object feature) {
-        if (oldMemoryAddress == null || structure == null || feature == null) {
-            throw new IllegalArgumentException("One of the given arguments is null!");
-        }
-        Object[] storedData = new Object[]{structure, feature};
-        loadedFeatures.put(oldMemoryAddress, storedData);
-        if (featureName != null) {
-            loadedFeaturesByName.put(featureName, storedData);
-        }
-    }
-
-    /**
-     * This method returns the feature of a given memory address. If the feature is not yet loaded then null is
-     * returned.
-     * @param oldMemoryAddress
-     *        the address of the feature
-     * @param loadedFeatureDataType
-     *        the type of data we want to retreive it can be either filled structure or already converted feature
-     * @return loaded feature or null if it was not yet loaded
-     */
-    public Object getLoadedFeature(Long oldMemoryAddress, LoadedFeatureDataType loadedFeatureDataType) {
-        Object[] result = loadedFeatures.get(oldMemoryAddress);
-        if (result != null) {
-            return result[loadedFeatureDataType.getIndex()];
-        }
-        return null;
-    }
-
-    /**
-     * This method returns the feature of a given name. If the feature is not yet loaded then null is
-     * returned.
-     * @param featureName
-     *        the name of the feature
-     * @param loadedFeatureDataType
-     *        the type of data we want to retreive it can be either filled structure or already converted feature
-     * @return loaded feature or null if it was not yet loaded
-     */
-    public Object getLoadedFeature(String featureName, LoadedFeatureDataType loadedFeatureDataType) {
-        Object[] result = loadedFeaturesByName.get(featureName);
-        if (result != null) {
-            return result[loadedFeatureDataType.getIndex()];
-        }
-        return null;
-    }
-
-    /**
-     * This method clears the saved features stored in the features map.
-     */
-    public void clearLoadedFeatures() {
-        loadedFeatures.clear();
-    }
-
-    /**
-     * This method adds the structure to the parent stack.
-     * @param parent
-     *        the structure to be added to the stack
-     */
-    public void pushParent(Structure parent) {
-        parentStack.push(parent);
-    }
-
-    /**
-     * This method removes the structure from the top of the parent's stack.
-     * @return the structure that was removed from the stack
-     */
-    public Structure popParent() {
-        try {
-            return parentStack.pop();
-        } catch (EmptyStackException e) {
-            return null;
-        }
-    }
-
-    /**
-     * This method retreives the structure at the top of the parent's stack but does not remove it.
-     * @return the structure from the top of the stack
-     */
-    public Structure peekParent() {
-        try {
-            return parentStack.peek();
-        } catch (EmptyStackException e) {
-            return null;
-        }
-    }
-
-    public void addIpo(Long ownerOMA, Ipo ipo) {
-        loadedIpos.put(ownerOMA, ipo);
-    }
-
-    public Ipo removeIpo(Long ownerOma) {
-        return loadedIpos.remove(ownerOma);
-    }
-
-    public Ipo getIpo(Long ownerOMA) {
-        return loadedIpos.get(ownerOMA);
-    }
-
-    /**
-     * This method adds a new modifier to the list.
-     * @param ownerOMA
-     *        the owner's old memory address
-     * @param modifier
-     * 		  the object's modifier
-     */
-    public void addModifier(Long ownerOMA, Modifier modifier) {
-        List<Modifier> objectModifiers = this.modifiers.get(ownerOMA);
-        if (objectModifiers == null) {
-            objectModifiers = new ArrayList<Modifier>();
-            this.modifiers.put(ownerOMA, objectModifiers);
-        }
-        objectModifiers.add(modifier);
-    }
-
-    /**
-     * This method returns modifiers for the object specified by its old memory address and the modifier type. If no
-     * modifiers are found - empty list is returned. If the type is null - all modifiers for the object are returned.
-     * @param objectOMA
-     *        object's old memory address
-     * @param type
-     *        the type of the modifier
-     * @return the list of object's modifiers
-     */
-    public List<Modifier> getModifiers(Long objectOMA, String type) {
-        List<Modifier> result = new ArrayList<Modifier>();
-        List<Modifier> readModifiers = modifiers.get(objectOMA);
-        if (readModifiers != null && readModifiers.size() > 0) {
-            for (Modifier modifier : readModifiers) {
-                if (type == null || type.isEmpty() || modifier.getType().equals(type)) {
-                    result.add(modifier);
-                }
-            }
-        }
-        return result;
-    }
-    
-    /**
-     * This method adds a new modifier to the list.
-     * @param ownerOMA
-     *        the owner's old memory address
-     * @param constraints
-     * 		  the object's constraints
-     */
-    public void addConstraints(Long ownerOMA, List<Constraint> constraints) {
-        List<Constraint> objectConstraints = this.constraints.get(ownerOMA);
-        if (objectConstraints == null) {
-            objectConstraints = new ArrayList<Constraint>();
-            this.constraints.put(ownerOMA, objectConstraints);
-        }
-        objectConstraints.addAll(constraints);
-    }
-
-    /**
-     * This method returns constraints for the object specified by its old memory address. If no
-     * modifiers are found - <b>null</b> is returned.
-     * @param objectOMA
-     *        object's old memory address
-     * @return the list of object's modifiers or null
-     */
-    public List<Constraint> getConstraints(Long objectOMA) {
-    	return constraints.get(objectOMA);
-    }
-    
-    /**
+	private static final Logger					LOGGER					= Logger.getLogger(BlenderContext.class.getName());
+
+	/** The blender key. */
+	private BlenderKey							blenderKey;
+	/** The header of the file block. */
+	private DnaBlockData						dnaBlockData;
+	/** The input stream of the blend file. */
+	private BlenderInputStream					inputStream;
+	/** The asset manager. */
+	private AssetManager						assetManager;
+	/**
+	 * A map containing the file block headers. The key is the old pointer
+	 * address.
+	 */
+	private Map<Long, FileBlockHeader>			fileBlockHeadersByOma	= new HashMap<Long, FileBlockHeader>();
+	/** A map containing the file block headers. The key is the block code. */
+	private Map<Integer, List<FileBlockHeader>>	fileBlockHeadersByCode	= new HashMap<Integer, List<FileBlockHeader>>();
+	/**
+	 * This map stores the loaded features by their old memory address. The
+	 * first object in the value table is the loaded structure and the second -
+	 * the structure already converted into proper data.
+	 */
+	private Map<Long, Object[]>					loadedFeatures			= new HashMap<Long, Object[]>();
+	/**
+	 * This map stores the loaded features by their name. Only features with ID
+	 * structure can be stored here. The first object in the value table is the
+	 * loaded structure and the second - the structure already converted into
+	 * proper data.
+	 */
+	private Map<String, Object[]>				loadedFeaturesByName	= new HashMap<String, Object[]>();
+	/** A stack that hold the parent structure of currently loaded feature. */
+	private Stack<Structure>					parentStack				= new Stack<Structure>();
+	/**
+	 * A map storing loaded ipos. The key is the ipo's owner old memory address
+	 * and the value is the ipo.
+	 */
+	private Map<Long, Ipo>						loadedIpos				= new HashMap<Long, Ipo>();
+	/** A list of modifiers for the specified object. */
+	protected Map<Long, List<Modifier>>			modifiers				= new HashMap<Long, List<Modifier>>();
+	/** A list of constraints for the specified object. */
+	protected Map<Long, List<Constraint>>		constraints				= new HashMap<Long, List<Constraint>>();
+	/** Anim data loaded for features. */
+	private Map<Long, AnimData>					animData				= new HashMap<Long, AnimData>();
+	/** A map of mesh contexts. */
+	protected Map<Long, MeshContext>			meshContexts			= new HashMap<Long, MeshContext>();
+	/** A map of material contexts. */
+	protected Map<Material, MaterialContext>	materialContexts		= new HashMap<Material, MaterialContext>();
+	/** A map og helpers that perform loading. */
+	private Map<String, AbstractBlenderHelper>	helpers					= new HashMap<String, AbstractBlenderHelper>();
+
+	/**
+	 * This method sets the blender key.
+	 * 
+	 * @param blenderKey
+	 *            the blender key
+	 */
+	public void setBlenderKey(BlenderKey blenderKey) {
+		this.blenderKey = blenderKey;
+	}
+
+	/**
+	 * This method returns the blender key.
+	 * 
+	 * @return the blender key
+	 */
+	public BlenderKey getBlenderKey() {
+		return blenderKey;
+	}
+
+	/**
+	 * This method sets the dna block data.
+	 * 
+	 * @param dnaBlockData
+	 *            the dna block data
+	 */
+	public void setBlockData(DnaBlockData dnaBlockData) {
+		this.dnaBlockData = dnaBlockData;
+	}
+
+	/**
+	 * This method returns the dna block data.
+	 * 
+	 * @return the dna block data
+	 */
+	public DnaBlockData getDnaBlockData() {
+		return dnaBlockData;
+	}
+
+	/**
+	 * This method returns the asset manager.
+	 * 
+	 * @return the asset manager
+	 */
+	public AssetManager getAssetManager() {
+		return assetManager;
+	}
+
+	/**
+	 * This method sets the asset manager.
+	 * 
+	 * @param assetManager
+	 *            the asset manager
+	 */
+	public void setAssetManager(AssetManager assetManager) {
+		this.assetManager = assetManager;
+	}
+
+	/**
+	 * This method returns the input stream of the blend file.
+	 * 
+	 * @return the input stream of the blend file
+	 */
+	public BlenderInputStream getInputStream() {
+		return inputStream;
+	}
+
+	/**
+	 * This method sets the input stream of the blend file.
+	 * 
+	 * @param inputStream
+	 *            the input stream of the blend file
+	 */
+	public void setInputStream(BlenderInputStream inputStream) {
+		this.inputStream = inputStream;
+	}
+
+	/**
+	 * This method adds a file block header to the map. Its old memory address
+	 * is the key.
+	 * 
+	 * @param oldMemoryAddress
+	 *            the address of the block header
+	 * @param fileBlockHeader
+	 *            the block header to store
+	 */
+	public void addFileBlockHeader(Long oldMemoryAddress, FileBlockHeader fileBlockHeader) {
+		fileBlockHeadersByOma.put(oldMemoryAddress, fileBlockHeader);
+		List<FileBlockHeader> headers = fileBlockHeadersByCode.get(Integer.valueOf(fileBlockHeader.getCode()));
+		if (headers == null) {
+			headers = new ArrayList<FileBlockHeader>();
+			fileBlockHeadersByCode.put(Integer.valueOf(fileBlockHeader.getCode()), headers);
+		}
+		headers.add(fileBlockHeader);
+	}
+
+	/**
+	 * This method returns the block header of a given memory address. If the
+	 * header is not present then null is returned.
+	 * 
+	 * @param oldMemoryAddress
+	 *            the address of the block header
+	 * @return loaded header or null if it was not yet loaded
+	 */
+	public FileBlockHeader getFileBlock(Long oldMemoryAddress) {
+		return fileBlockHeadersByOma.get(oldMemoryAddress);
+	}
+
+	/**
+	 * This method returns a list of file blocks' headers of a specified code.
+	 * 
+	 * @param code
+	 *            the code of file blocks
+	 * @return a list of file blocks' headers of a specified code
+	 */
+	public List<FileBlockHeader> getFileBlocks(Integer code) {
+		return fileBlockHeadersByCode.get(code);
+	}
+
+	/**
+	 * This method clears the saved block headers stored in the features map.
+	 */
+	public void clearFileBlocks() {
+		fileBlockHeadersByOma.clear();
+		fileBlockHeadersByCode.clear();
+	}
+
+	/**
+	 * This method adds a helper instance to the helpers' map.
+	 * 
+	 * @param <T>
+	 *            the type of the helper
+	 * @param clazz
+	 *            helper's class definition
+	 * @param helper
+	 *            the helper instance
+	 */
+	public <T> void putHelper(Class<T> clazz, AbstractBlenderHelper helper) {
+		helpers.put(clazz.getSimpleName(), helper);
+	}
+
+	@SuppressWarnings("unchecked")
+	public <T> T getHelper(Class<?> clazz) {
+		return (T) helpers.get(clazz.getSimpleName());
+	}
+
+	/**
+	 * This method adds a loaded feature to the map. The key is its unique old
+	 * memory address.
+	 * 
+	 * @param oldMemoryAddress
+	 *            the address of the feature
+	 * @param featureName
+	 *            the name of the feature
+	 * @param structure
+	 *            the filled structure of the feature
+	 * @param feature
+	 *            the feature we want to store
+	 */
+	public void addLoadedFeatures(Long oldMemoryAddress, String featureName, Structure structure, Object feature) {
+		if (oldMemoryAddress == null || structure == null || feature == null) {
+			throw new IllegalArgumentException("One of the given arguments is null!");
+		}
+		Object[] storedData = new Object[] { structure, feature };
+		loadedFeatures.put(oldMemoryAddress, storedData);
+		if (featureName != null) {
+			loadedFeaturesByName.put(featureName, storedData);
+		}
+	}
+
+	/**
+	 * This method returns the feature of a given memory address. If the feature
+	 * is not yet loaded then null is returned.
+	 * 
+	 * @param oldMemoryAddress
+	 *            the address of the feature
+	 * @param loadedFeatureDataType
+	 *            the type of data we want to retreive it can be either filled
+	 *            structure or already converted feature
+	 * @return loaded feature or null if it was not yet loaded
+	 */
+	public Object getLoadedFeature(Long oldMemoryAddress, LoadedFeatureDataType loadedFeatureDataType) {
+		Object[] result = loadedFeatures.get(oldMemoryAddress);
+		if (result != null) {
+			return result[loadedFeatureDataType.getIndex()];
+		}
+		return null;
+	}
+
+	/**
+	 * This method returns the feature of a given name. If the feature is not
+	 * yet loaded then null is returned.
+	 * 
+	 * @param featureName
+	 *            the name of the feature
+	 * @param loadedFeatureDataType
+	 *            the type of data we want to retreive it can be either filled
+	 *            structure or already converted feature
+	 * @return loaded feature or null if it was not yet loaded
+	 */
+	public Object getLoadedFeature(String featureName, LoadedFeatureDataType loadedFeatureDataType) {
+		Object[] result = loadedFeaturesByName.get(featureName);
+		if (result != null) {
+			return result[loadedFeatureDataType.getIndex()];
+		}
+		return null;
+	}
+
+	/**
+	 * This method clears the saved features stored in the features map.
+	 */
+	public void clearLoadedFeatures() {
+		loadedFeatures.clear();
+	}
+
+	/**
+	 * This method adds the structure to the parent stack.
+	 * 
+	 * @param parent
+	 *            the structure to be added to the stack
+	 */
+	public void pushParent(Structure parent) {
+		parentStack.push(parent);
+	}
+
+	/**
+	 * This method removes the structure from the top of the parent's stack.
+	 * 
+	 * @return the structure that was removed from the stack
+	 */
+	public Structure popParent() {
+		try {
+			return parentStack.pop();
+		} catch (EmptyStackException e) {
+			return null;
+		}
+	}
+
+	/**
+	 * This method retreives the structure at the top of the parent's stack but
+	 * does not remove it.
+	 * 
+	 * @return the structure from the top of the stack
+	 */
+	public Structure peekParent() {
+		try {
+			return parentStack.peek();
+		} catch (EmptyStackException e) {
+			return null;
+		}
+	}
+
+	/**
+	 * This method adds new ipo curve for the feature.
+	 * 
+	 * @param ownerOMA
+	 *            the OMA of blender feature that owns the ipo
+	 * @param ipo
+	 *            the ipo to be added
+	 */
+	public void addIpo(Long ownerOMA, Ipo ipo) {
+		loadedIpos.put(ownerOMA, ipo);
+	}
+
+	/**
+	 * This method removes the ipo curve from the feature.
+	 * 
+	 * @param ownerOMA
+	 *            the OMA of blender feature that owns the ipo
+	 * @param ipo
+	 *            the ipo that was just removed
+	 */
+	public Ipo removeIpo(Long ownerOma) {
+		return loadedIpos.remove(ownerOma);
+	}
+
+	/**
+	 * This method returns the ipo curve of the feature.
+	 * 
+	 * @param ownerOMA
+	 *            the OMA of blender feature that owns the ipo
+	 * @param ipo
+	 *            the ipo that belongs to the specified owner
+	 */
+	public Ipo getIpo(Long ownerOMA) {
+		return loadedIpos.get(ownerOMA);
+	}
+
+	/**
+	 * This method adds a new modifier to the list.
+	 * 
+	 * @param ownerOMA
+	 *            the owner's old memory address
+	 * @param modifier
+	 *            the object's modifier
+	 */
+	public void addModifier(Long ownerOMA, Modifier modifier) {
+		List<Modifier> objectModifiers = this.modifiers.get(ownerOMA);
+		if (objectModifiers == null) {
+			objectModifiers = new ArrayList<Modifier>();
+			this.modifiers.put(ownerOMA, objectModifiers);
+		}
+		objectModifiers.add(modifier);
+	}
+
+	/**
+	 * This method returns modifiers for the object specified by its old memory
+	 * address and the modifier type. If no modifiers are found - empty list is
+	 * returned. If the type is null - all modifiers for the object are
+	 * returned.
+	 * 
+	 * @param objectOMA
+	 *            object's old memory address
+	 * @param type
+	 *            the type of the modifier
+	 * @return the list of object's modifiers
+	 */
+	public List<Modifier> getModifiers(Long objectOMA, String type) {
+		List<Modifier> result = new ArrayList<Modifier>();
+		List<Modifier> readModifiers = modifiers.get(objectOMA);
+		if (readModifiers != null && readModifiers.size() > 0) {
+			for (Modifier modifier : readModifiers) {
+				if (type == null || type.isEmpty() || modifier.getType().equals(type)) {
+					result.add(modifier);
+				}
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * This method adds a new modifier to the list.
+	 * 
+	 * @param ownerOMA
+	 *            the owner's old memory address
+	 * @param constraints
+	 *            the object's constraints
+	 */
+	public void addConstraints(Long ownerOMA, List<Constraint> constraints) {
+		List<Constraint> objectConstraints = this.constraints.get(ownerOMA);
+		if (objectConstraints == null) {
+			objectConstraints = new ArrayList<Constraint>();
+			this.constraints.put(ownerOMA, objectConstraints);
+		}
+		objectConstraints.addAll(constraints);
+	}
+
+	/**
+	 * This method returns constraints for the object specified by its old
+	 * memory address. If no modifiers are found - <b>null</b> is returned.
+	 * 
+	 * @param objectOMA
+	 *            object's old memory address
+	 * @return the list of object's modifiers or null
+	 */
+	public List<Constraint> getConstraints(Long objectOMA) {
+		return objectOMA == null ? null : constraints.get(objectOMA);
+	}
+
+	/**
+	 * This method sets the anim data for the specified OMA of its owner.
+	 * 
+	 * @param ownerOMA
+	 *            the owner's old memory address
+	 * @param animData
+	 *            the animation data for the feature specified by ownerOMA
+	 */
+	public void setAnimData(Long ownerOMA, AnimData animData) {
+		this.animData.put(ownerOMA, animData);
+	}
+
+	/**
+	 * This method returns the animation data for the specified owner.
+	 * 
+	 * @param ownerOMA
+	 *            the old memory address of the animation data owner
+	 * @return the animation data or null if none exists
+	 */
+	public AnimData getAnimData(Long ownerOMA) {
+		return this.animData.get(ownerOMA);
+	}
+
+	/**
 	 * This method sets the mesh context for the given mesh old memory address.
 	 * This method sets the mesh context for the given mesh old memory address.
 	 * If the context is already set it will be replaced.
 	 * If the context is already set it will be replaced.
+	 * 
 	 * @param meshOMA
 	 * @param meshOMA
-	 *        the mesh's old memory address
+	 *            the mesh's old memory address
 	 * @param meshContext
 	 * @param meshContext
-	 *        the mesh's context
-	 */
-    public void setMeshContext(Long meshOMA, MeshContext meshContext) {
-    	this.meshContexts.put(meshOMA, meshContext);
-    }
-    
-    /**
-	 * This method returns the mesh context for the given mesh old memory address.
-	 * If no context exists then <b>null</b> is returned.
+	 *            the mesh's context
+	 */
+	public void setMeshContext(Long meshOMA, MeshContext meshContext) {
+		this.meshContexts.put(meshOMA, meshContext);
+	}
+
+	/**
+	 * This method returns the mesh context for the given mesh old memory
+	 * address. If no context exists then <b>null</b> is returned.
+	 * 
 	 * @param meshOMA
 	 * @param meshOMA
-	 *        the mesh's old memory address
+	 *            the mesh's old memory address
 	 * @return mesh's context
 	 * @return mesh's context
 	 */
 	 */
-    public MeshContext getMeshContext(Long meshOMA) {
-    	return this.meshContexts.get(meshOMA);
-    }
-    
+	public MeshContext getMeshContext(Long meshOMA) {
+		return this.meshContexts.get(meshOMA);
+	}
+
 	/**
 	/**
-	 * This method sets the material context for the given material.
-	 * If the context is already set it will be replaced.
+	 * This method sets the material context for the given material. If the
+	 * context is already set it will be replaced.
+	 * 
 	 * @param material
 	 * @param material
-	 *        the material
+	 *            the material
 	 * @param materialContext
 	 * @param materialContext
-	 *        the material's context
+	 *            the material's context
 	 */
 	 */
 	public void setMaterialContext(Material material, MaterialContext materialContext) {
 	public void setMaterialContext(Material material, MaterialContext materialContext) {
 		this.materialContexts.put(material, materialContext);
 		this.materialContexts.put(material, materialContext);
 	}
 	}
 
 
 	/**
 	/**
-	 * This method returns the material context for the given material.
-	 * If no context exists then <b>null</b> is returned.
+	 * This method returns the material context for the given material. If no
+	 * context exists then <b>null</b> is returned.
+	 * 
 	 * @param material
 	 * @param material
-	 *        the material
+	 *            the material
 	 * @return material's context
 	 * @return material's context
 	 */
 	 */
 	public MaterialContext getMaterialContext(Material material) {
 	public MaterialContext getMaterialContext(Material material) {
 		return materialContexts.get(material);
 		return materialContexts.get(material);
 	}
 	}
 
 
-    /**
-     * This metod returns the default material.
-     * @return the default material
-     */
-    public synchronized Material getDefaultMaterial() {
-        if (blenderKey.getDefaultMaterial() == null) {
-            Material defaultMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
-            defaultMaterial.setColor("Color", ColorRGBA.DarkGray);
-            blenderKey.setDefaultMaterial(defaultMaterial);
-        }
-        return blenderKey.getDefaultMaterial();
-    }
-    
-    public void dispose() {
-    	try {
+	/**
+	 * This metod returns the default material.
+	 * 
+	 * @return the default material
+	 */
+	public synchronized Material getDefaultMaterial() {
+		if (blenderKey.getDefaultMaterial() == null) {
+			Material defaultMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+			defaultMaterial.setColor("Color", ColorRGBA.DarkGray);
+			blenderKey.setDefaultMaterial(defaultMaterial);
+		}
+		return blenderKey.getDefaultMaterial();
+	}
+
+	public void dispose() {
+		try {
 			inputStream.close();
 			inputStream.close();
 		} catch (IOException e) {
 		} catch (IOException e) {
 			LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e);
 			LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e);
 		}
 		}
 		loadedFeatures.clear();
 		loadedFeatures.clear();
 		loadedFeaturesByName.clear();
 		loadedFeaturesByName.clear();
-    }
-
-    /**
-     * This enum defines what loaded data type user wants to retreive. It can be either filled structure or already
-     * converted data.
-     * @author Marcin Roguski
-     */
-    public static enum LoadedFeatureDataType {
-
-        LOADED_STRUCTURE(0), LOADED_FEATURE(1);
-        private int index;
-
-        private LoadedFeatureDataType(int index) {
-            this.index = index;
-        }
-
-        public int getIndex() {
-            return index;
-        }
-    }
+	}
+
+	/**
+	 * This enum defines what loaded data type user wants to retreive. It can be
+	 * either filled structure or already converted data.
+	 * 
+	 * @author Marcin Roguski
+	 */
+	public static enum LoadedFeatureDataType {
+
+		LOADED_STRUCTURE(0), LOADED_FEATURE(1);
+		private int	index;
+
+		private LoadedFeatureDataType(int index) {
+			this.index = index;
+		}
+
+		public int getIndex() {
+			return index;
+		}
+	}
 }
 }

+ 12 - 22
engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java

@@ -189,30 +189,20 @@ public class BlenderLoader extends AbstractBlenderLoader {
 		blenderContext.setBlenderKey(blenderKey);
 		blenderContext.setBlenderKey(blenderKey);
 
 
 		// creating helpers
 		// creating helpers
-		blenderContext.putHelper(ArmatureHelper.class, new ArmatureHelper(inputStream.getVersionNumber()));
-		blenderContext.putHelper(TextureHelper.class, new TextureHelper(inputStream.getVersionNumber()));
-		blenderContext.putHelper(MeshHelper.class, new MeshHelper(inputStream.getVersionNumber()));
-		blenderContext.putHelper(ObjectHelper.class, new ObjectHelper(inputStream.getVersionNumber()));
-		blenderContext.putHelper(CurvesHelper.class, new CurvesHelper(inputStream.getVersionNumber()));
-		blenderContext.putHelper(LightHelper.class, new LightHelper(inputStream.getVersionNumber()));
-		blenderContext.putHelper(CameraHelper.class, new CameraHelper(inputStream.getVersionNumber()));
-		blenderContext.putHelper(ModifierHelper.class, new ModifierHelper(inputStream.getVersionNumber()));
-		blenderContext.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber()));
-		blenderContext.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), blenderContext));
-		blenderContext.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber()));
-		blenderContext.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber()));
+		blenderContext.putHelper(ArmatureHelper.class, new ArmatureHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
+		blenderContext.putHelper(TextureHelper.class, new TextureHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
+		blenderContext.putHelper(MeshHelper.class, new MeshHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
+		blenderContext.putHelper(ObjectHelper.class, new ObjectHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
+		blenderContext.putHelper(CurvesHelper.class, new CurvesHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
+		blenderContext.putHelper(LightHelper.class, new LightHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
+		blenderContext.putHelper(CameraHelper.class, new CameraHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
+		blenderContext.putHelper(ModifierHelper.class, new ModifierHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
+		blenderContext.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
+		blenderContext.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), blenderContext, blenderKey.isFixUpAxis()));
+		blenderContext.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
+		blenderContext.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
 
 
 		// setting additional data to helpers
 		// setting additional data to helpers
-		if (blenderKey.isFixUpAxis()) {
-			AbstractBlenderHelper helper = blenderContext.getHelper(ObjectHelper.class);
-			helper.setyIsUpAxis(true);
-			helper = blenderContext.getHelper(CurvesHelper.class);
-			helper.setyIsUpAxis(true);
-			helper = blenderContext.getHelper(ArmatureHelper.class);
-			helper.setyIsUpAxis(true);
-			helper = blenderContext.getHelper(MeshHelper.class);
-			helper.setyIsUpAxis(true);
-		}
 		MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
 		MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
 		materialHelper.setFaceCullMode(blenderKey.getFaceCullMode());
 		materialHelper.setFaceCullMode(blenderKey.getFaceCullMode());
 
 

+ 138 - 228
engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java

@@ -31,50 +31,126 @@
  */
  */
 package com.jme3.scene.plugins.blender.animations;
 package com.jme3.scene.plugins.blender.animations;
 
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
 import com.jme3.animation.Bone;
 import com.jme3.animation.Bone;
 import com.jme3.animation.BoneTrack;
 import com.jme3.animation.BoneTrack;
+import com.jme3.animation.Skeleton;
 import com.jme3.math.Matrix4f;
 import com.jme3.math.Matrix4f;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Quaternion;
-import com.jme3.math.Vector3f;
+import com.jme3.math.Transform;
 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.curves.BezierCurve;
 import com.jme3.scene.plugins.blender.curves.BezierCurve;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
-import com.jme3.scene.plugins.blender.file.*;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+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
+ * @author Marcin Roguski (Kaelthas)
  */
  */
 public class ArmatureHelper extends AbstractBlenderHelper {
 public class ArmatureHelper extends AbstractBlenderHelper {
-
     private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName());
     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
      * This constructor parses the given blender version and stores the result. Some functionalities may differ in
      * different blender versions.
      * different blender versions.
      * @param blenderVersion
      * @param blenderVersion
      *        the version read from the blend file
      *        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) {
-        super(blenderVersion);
+    public ArmatureHelper(String blenderVersion, boolean fixUpAxis) {
+        super(blenderVersion, fixUpAxis);
     }
     }
-
+    
     /**
     /**
-     * The map of the bones. Maps a bone name to its index in the armature. Should be cleared after the object had been
-     * read. TODO: probably bones can have identical names in different armatures
-     */
-    protected Map<String, Integer> bonesMap = new HashMap<String, Integer>();
-    /** A map of bones and their old memory addresses. */
-    protected Map<Bone, Long> bonesOMAs = new HashMap<Bone, Long>();
-    /** This list contains bones hierarchy and their matrices. It is later converted into jme bones. */
-    protected List<BoneTransformationData> boneDataRoots = new ArrayList<BoneTransformationData>();
+	 * This method builds the object's bones structure.
+	 * 
+	 * @param boneStructure
+	 *            the structure containing the bones' data
+	 * @param parent
+	 *            the parent bone
+	 * @param result
+	 *            the list where the newly created bone will be added
+	 * @param bonesPoseChannels
+	 *            a map of bones poses channels
+	 * @param blenderContext
+	 *            the blender context
+	 * @throws BlenderFileException
+	 *             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;
+	}
 
 
     /**
     /**
      * This method returns the old memory address of a bone. If the bone does not exist in the blend file - zero is
      * This method returns the old memory address of a bone. If the bone does not exist in the blend file - zero is
@@ -90,6 +166,16 @@ public class ArmatureHelper extends AbstractBlenderHelper {
         }
         }
         return result;
         return result;
     }
     }
+    
+	/**
+	 * This method returns the bind transform for the specified bone.
+	 * @param bone
+	 *            the bone
+	 * @return bone's bind transform
+	 */
+    public Transform getBoneBindTransform(Bone bone) {
+    	return boneBindTransforms.get(bone);
+    }
 
 
     /**
     /**
      * 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
      * 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
@@ -100,15 +186,15 @@ public class ArmatureHelper extends AbstractBlenderHelper {
      * @throws BlenderFileException
      * @throws BlenderFileException
      *         this exception is thrown when the blender file is somehow corrupted
      *         this exception is thrown when the blender file is somehow corrupted
      */
      */
-    public Map<Integer, Integer> getGroupToBoneIndexMap(Structure defBaseStructure, BlenderContext blenderContext) throws BlenderFileException {
+    public Map<Integer, Integer> getGroupToBoneIndexMap(Structure defBaseStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
         Map<Integer, Integer> result = null;
         Map<Integer, Integer> result = null;
-        if (bonesMap != null && bonesMap.size() != 0) {
+        if (skeleton.getBoneCount() != 0) {
             result = new HashMap<Integer, Integer>();
             result = new HashMap<Integer, Integer>();
             List<Structure> deformGroups = defBaseStructure.evaluateListBase(blenderContext);//bDeformGroup
             List<Structure> deformGroups = defBaseStructure.evaluateListBase(blenderContext);//bDeformGroup
             int groupIndex = 0;
             int groupIndex = 0;
             for (Structure deformGroup : deformGroups) {
             for (Structure deformGroup : deformGroups) {
                 String deformGroupName = deformGroup.getFieldValue("name").toString();
                 String deformGroupName = deformGroup.getFieldValue("name").toString();
-                Integer boneIndex = bonesMap.get(deformGroupName);
+                Integer boneIndex = this.getBoneIndex(skeleton, deformGroupName);
                 if (boneIndex != null) {
                 if (boneIndex != null) {
                     result.put(Integer.valueOf(groupIndex), boneIndex);
                     result.put(Integer.valueOf(groupIndex), boneIndex);
                 }
                 }
@@ -118,191 +204,6 @@ public class ArmatureHelper extends AbstractBlenderHelper {
         return result;
         return result;
     }
     }
 
 
-    /**
-     * This bone returns transformation matrix of the bone that is relative to
-     * its armature object.
-     * @param boneStructure the bone's structure
-     * @return bone's transformation matrix in armature space
-     */
-    @SuppressWarnings("unchecked")
-    protected Matrix4f getArmatureMatrix(Structure boneStructure) {
-        DynamicArray<Number> boneMat = (DynamicArray<Number>) boneStructure.getFieldValue("arm_mat");
-        Matrix4f m = new Matrix4f();
-        for (int i = 0; i < 4; ++i) {
-            for (int j = 0; j < 4; ++j) {
-                m.set(i, j, boneMat.get(j, i).floatValue());
-            }
-        }
-        
-        if(fixUpAxis) {
-        	Vector3f translation = m.toTranslationVector();
-            Quaternion rotation = m.toRotationQuat();
-            
-            float y = translation.y;
-    		translation.y = translation.z;
-    		translation.z = -y;
-    		
-    		rotation = upAxisRotationQuaternion.mult(rotation);
-    		
-    		m.setRotationQuaternion(rotation);
-    		m.setTranslation(translation);
-    		//TODO: what about scale ??
-        }     
-        return m;
-    }
-
-    /**
-     * This method reads the bone with its children.
-     * @param boneStructure
-     *        a structure containing the bone data
-     * @param parent
-     *        the bone parent; if null then we read the root bone
-     * @param blenderContext
-     *        the blender context
-     * @return the bone transformation data; contains bone chierarchy and the bone's matrices
-     * @throws BlenderFileException
-     *         this exception is thrown when the blender file is somehow corrupted
-     */
-    @SuppressWarnings("unchecked")
-    public BoneTransformationData readBoneAndItsChildren(Structure boneStructure, BoneTransformationData parent, BlenderContext blenderContext) throws BlenderFileException {
-        String name = boneStructure.getFieldValue("name").toString();
-        Bone bone = new Bone(name);
-        int bonesAmount = bonesOMAs.size();
-        bonesOMAs.put(bone, boneStructure.getOldMemoryAddress());
-        if (bonesAmount == bonesOMAs.size()) {
-            throw new IllegalStateException("Two bones has the same hash value and thereforw a bone was overriden in the bones<->OMA map! Improve the hash algorithm!");
-        }
-        Matrix4f boneArmatureMatrix = this.getArmatureMatrix(boneStructure);
-        DynamicArray<Float> sizeArray = (DynamicArray<Float>) boneStructure.getFieldValue("size");
-        Vector3f size = new Vector3f(sizeArray.get(0), sizeArray.get(1), sizeArray.get(2));
-        BoneTransformationData boneTransformationData = new BoneTransformationData(boneArmatureMatrix, size, bone, parent);
-        blenderContext.addLoadedFeatures(boneStructure.getOldMemoryAddress(), name, boneStructure, bone);
-
-        Structure childbase = (Structure) boneStructure.getFieldValue("childbase");
-        List<Structure> children = childbase.evaluateListBase(blenderContext);//Bone
-        for (Structure boneChild : children) {
-            this.readBoneAndItsChildren(boneChild, boneTransformationData, blenderContext);
-        }
-        return boneTransformationData;
-    }
-
-    /**
-     * This method assigns transformations to the bone.
-     * @param btd
-     *        the bone data containing the bone we assign transformation to
-     * @param additionalRootBoneTransformation
-     *        additional bone transformation which indicates it's mesh parent and armature object transformations
-     * @param boneList
-     *        a list of all read bones
-     */
-    protected void assignBonesMatrices(BoneTransformationData btd, Matrix4f additionalRootBoneTransformation, List<Bone> boneList) {
-        LOGGER.info("[" + btd.bone.getName() + "]  additionalRootBoneTransformation =\n" + additionalRootBoneTransformation);
-        Matrix4f totalInverseParentMatrix = btd.parent != null ? btd.parent.totalInverseBoneParentMatrix : Matrix4f.IDENTITY;
-        LOGGER.info("[" + btd.bone.getName() + "]  totalInverseParentMatrix =\n" + totalInverseParentMatrix);
-        Matrix4f restMatrix = additionalRootBoneTransformation.mult(btd.boneArmatureMatrix);
-        LOGGER.info("[" + btd.bone.getName() + "]  restMatrix =\n" + restMatrix);
-        btd.totalInverseBoneParentMatrix = restMatrix.clone().invert();
-        restMatrix = totalInverseParentMatrix.mult(restMatrix);
-        LOGGER.info("[" + btd.bone.getName() + "]  resultMatrix =\n" + restMatrix);
-        btd.bone.setBindTransforms(restMatrix.toTranslationVector(), restMatrix.toRotationQuat(), btd.size);
-        boneList.add(btd.bone);
-        bonesMap.put(btd.bone.getName(), Integer.valueOf(boneList.size() - 1));
-        if (btd.children != null && btd.children.size() > 0) {
-            for (BoneTransformationData child : btd.children) {
-                this.assignBonesMatrices(child, additionalRootBoneTransformation, boneList);
-                btd.bone.addChild(child.bone);
-            }
-        }
-    }
-
-    public void addBoneDataRoot(BoneTransformationData dataRoot) {
-    	this.boneDataRoots.add(dataRoot);
-    }
-    
-    /**
-     * This method returns bone transformation data for the bone of a given index.
-     * @param index
-     *        the index of the bone
-     * @return bone's transformation data
-     */
-    public BoneTransformationData getBoneTransformationDataRoot(int index) {
-        return boneDataRoots.get(index);
-    }
-
-    /**
-     * This method returns the amount of bones transformations roots.
-     * @return the amount of bones transformations roots
-     */
-    public int getBoneTransformationDataRootsSize() {
-        return boneDataRoots.size();
-    }
-
-    /**
-     * This class holds the data needed later for bone transformation calculation and to bind parent with children.
-     * @author Marcin Roguski
-     */
-    public static class BoneTransformationData {
-
-        /** Inverse matrix of bone's parent bone. */
-        private Matrix4f totalInverseBoneParentMatrix;
-        /** Bone's matrix in armature's space. */
-        private Matrix4f boneArmatureMatrix;
-        /** Bone's size (apparently it is held outside the transformation matrix. */
-        private Vector3f size;
-        /** The bone the data applies to. */
-        private Bone bone;
-        /** The parent of the above mentioned bone (not assigned yet). */
-        private BoneTransformationData parent;
-        /** The children of the current bone. */
-        private List<BoneTransformationData> children;
-
-        /**
-         * Private constructor creates the object and assigns the given data.
-         * @param boneArmatureMatrix
-         *        the matrix of the current bone
-         * @param size
-         * 		  the bone's size
-         * @param bone
-         *        the current bone
-         * @param parent
-         *        the parent structure of the bone
-         */
-        private BoneTransformationData(Matrix4f boneArmatureMatrix, Vector3f size, Bone bone, BoneTransformationData parent) {
-            this.boneArmatureMatrix = boneArmatureMatrix;
-            this.size = size;
-            this.bone = bone;
-            this.parent = parent;
-            this.children = new ArrayList<ArmatureHelper.BoneTransformationData>();
-            if (this.parent != null) {
-                this.parent.children.add(this);
-            }
-        }
-    }
-
-    /**
-     * This method creates the whole bones structure. Assignes transformations to bones and combines children with
-     * parents.
-     * @param armatureOMA
-     *        old memory address of bones' armature object
-     * @param additionalRootBoneTransformation
-     *        additional bone transformation which indicates it's mesh parent and armature object transformations
-     * @return
-     */
-    public Bone[] buildBonesStructure(Long armatureOMA, Matrix4f additionalRootBoneTransformation) {
-        List<Bone> bones = new ArrayList<Bone>(boneDataRoots.size() + 1);
-        bones.add(new Bone(""));
-        for (BoneTransformationData btd : boneDataRoots) {
-            this.assignBonesMatrices(btd, additionalRootBoneTransformation, bones);
-        }
-        return bones.toArray(new Bone[bones.size()]);
-    }
-
-    @Override
-    public void clearState() {
-        bonesMap.clear();
-        boneDataRoots.clear();
-    }
-    
     @Override
     @Override
     public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
     public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
     	return true;
     	return true;
@@ -320,11 +221,11 @@ public class ArmatureHelper extends AbstractBlenderHelper {
 	 *             an exception is thrown when there are problems with the blend
 	 *             an exception is thrown when there are problems with the blend
 	 *             file
 	 *             file
 	 */
 	 */
-    public BoneTrack[] getTracks(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
+    public BoneTrack[] getTracks(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
     	if (blenderVersion < 250) {
     	if (blenderVersion < 250) {
-            return this.getTracks249(actionStructure, blenderContext);
+            return this.getTracks249(actionStructure, skeleton, blenderContext);
         } else {
         } else {
-        	return this.getTracks250(actionStructure, blenderContext);
+        	return this.getTracks250(actionStructure, skeleton, blenderContext);
         }
         }
     }
     }
     
     
@@ -340,19 +241,15 @@ public class ArmatureHelper extends AbstractBlenderHelper {
 	 *             an exception is thrown when there are problems with the blend
 	 *             an exception is thrown when there are problems with the blend
 	 *             file
 	 *             file
 	 */
 	 */
-    private BoneTrack[] getTracks250(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
+    private BoneTrack[] getTracks250(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
         LOGGER.log(Level.INFO, "Getting tracks!");
         LOGGER.log(Level.INFO, "Getting tracks!");
         int fps = blenderContext.getBlenderKey().getFps();
         int fps = blenderContext.getBlenderKey().getFps();
         Structure groups = (Structure) actionStructure.getFieldValue("groups");
         Structure groups = (Structure) actionStructure.getFieldValue("groups");
         List<Structure> actionGroups = groups.evaluateListBase(blenderContext);//bActionGroup
         List<Structure> actionGroups = groups.evaluateListBase(blenderContext);//bActionGroup
-        if (actionGroups != null && actionGroups.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
-            throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
-        }
-
         List<BoneTrack> tracks = new ArrayList<BoneTrack>();
         List<BoneTrack> tracks = new ArrayList<BoneTrack>();
         for (Structure actionGroup : actionGroups) {
         for (Structure actionGroup : actionGroups) {
             String name = actionGroup.getFieldValue("name").toString();
             String name = actionGroup.getFieldValue("name").toString();
-            Integer boneIndex = bonesMap.get(name);
+            Integer boneIndex = this.getBoneIndex(skeleton, name);
             if (boneIndex != null) {
             if (boneIndex != null) {
                 List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(blenderContext);
                 List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(blenderContext);
                 BezierCurve[] bezierCurves = new BezierCurve[channels.size()];
                 BezierCurve[] bezierCurves = new BezierCurve[channels.size()];
@@ -374,8 +271,8 @@ public class ArmatureHelper extends AbstractBlenderHelper {
                     bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);
                     bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);
                 }
                 }
 
 
-                Ipo ipo = new Ipo(bezierCurves);
-                tracks.add( (BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps) );
+                Ipo ipo = new Ipo(bezierCurves, fixUpAxis);
+                tracks.add((BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
             }
             }
         }
         }
         return tracks.toArray(new BoneTrack[tracks.size()]);
         return tracks.toArray(new BoneTrack[tracks.size()]);
@@ -393,31 +290,44 @@ public class ArmatureHelper extends AbstractBlenderHelper {
 	 *             an exception is thrown when there are problems with the blend
 	 *             an exception is thrown when there are problems with the blend
 	 *             file
 	 *             file
 	 */
 	 */
-    private BoneTrack[] getTracks249(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
+    private BoneTrack[] getTracks249(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
     	LOGGER.log(Level.INFO, "Getting tracks!");
     	LOGGER.log(Level.INFO, "Getting tracks!");
         IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
         IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
         int fps = blenderContext.getBlenderKey().getFps();
         int fps = blenderContext.getBlenderKey().getFps();
         Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase");
         Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase");
         List<Structure> actionChannels = chanbase.evaluateListBase(blenderContext);//bActionChannel
         List<Structure> actionChannels = chanbase.evaluateListBase(blenderContext);//bActionChannel
-        if (actionChannels != null && actionChannels.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
-            throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
-        }
         List<BoneTrack> tracks = new ArrayList<BoneTrack>();
         List<BoneTrack> tracks = new ArrayList<BoneTrack>();
         for (Structure bActionChannel : actionChannels) {
         for (Structure bActionChannel : actionChannels) {
             String name = bActionChannel.getFieldValue("name").toString();
             String name = bActionChannel.getFieldValue("name").toString();
-            Integer boneIndex = bonesMap.get(name);
-            if (boneIndex != null) {
+            Integer boneIndex = this.getBoneIndex(skeleton, name);
+            if (boneIndex != null && boneIndex.intValue() >= 0) {
                 Pointer p = (Pointer) bActionChannel.getFieldValue("ipo");
                 Pointer p = (Pointer) bActionChannel.getFieldValue("ipo");
                 if (!p.isNull()) {
                 if (!p.isNull()) {
                     Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0);
                     Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0);
                     Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
                     Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
-                    tracks.add( (BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
+                    tracks.add((BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
                 }
                 }
             }
             }
         }
         }
         return tracks.toArray(new BoneTrack[tracks.size()]);
         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
      * This method parses the information stored inside the curve rna path and returns the proper type
      * of the curve.
      * of the curve.

+ 61 - 37
engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java

@@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.animations;
 import com.jme3.animation.BoneTrack;
 import com.jme3.animation.BoneTrack;
 import com.jme3.animation.SpatialTrack;
 import com.jme3.animation.SpatialTrack;
 import com.jme3.animation.Track;
 import com.jme3.animation.Track;
+import com.jme3.math.FastMath;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.plugins.blender.curves.BezierCurve;
 import com.jme3.scene.plugins.blender.curves.BezierCurve;
@@ -28,23 +29,21 @@ public class Ipo {
     public static final int AC_QUAT_Y = 27;
     public static final int AC_QUAT_Y = 27;
     public static final int AC_QUAT_Z = 28;
     public static final int AC_QUAT_Z = 28;
     
     
-    /** 
-     * A list of bezier curves for this interpolation object. 
-     */
+    /** A list of bezier curves for this interpolation object. */
     private BezierCurve[] bezierCurves;
     private BezierCurve[] bezierCurves;
-    
-    /** 
-     * Each ipo contains one bone track. 
-     */
+    /** Each ipo contains one bone track. */
     private Track calculatedTrack;
     private Track calculatedTrack;
-
+    /** This variable indicates if the Y asxis is the UP axis or not. */
+	protected boolean	fixUpAxis;
+	
     /**
     /**
      * Constructor. Stores the bezier curves.
      * Constructor. Stores the bezier curves.
      * @param bezierCurves
      * @param bezierCurves
      *        a table of bezier curves
      *        a table of bezier curves
      */
      */
-    public Ipo(BezierCurve[] bezierCurves) {
+    public Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis) {
         this.bezierCurves = bezierCurves;
         this.bezierCurves = bezierCurves;
+        this.fixUpAxis = fixUpAxis;
     }
     }
 
 
     /**
     /**
@@ -93,26 +92,6 @@ public class Ipo {
         return result;
         return result;
     }
     }
 
 
-    /*
-    public void modifyTranslation(int frame, Vector3f translation) {
-        if (calculatedTrack != null) {
-            calculatedTrack.getTranslations()[frame].set(translation);
-        }
-    }
-
-    public void modifyRotation(int frame, Quaternion rotation) {
-        if (calculatedTrack != null) {
-            calculatedTrack.getRotations()[frame].set(rotation);
-        }
-    }
-
-    public void modifyScale(int frame, Vector3f scale) {
-        if (calculatedTrack != null) {
-            calculatedTrack.getScales()[frame].set(scale);
-        }
-    }
-    */
-
     /**
     /**
      * This method calculates the value of the curves as a bone track between the specified frames.
      * This method calculates the value of the curves as a bone track between the specified frames.
      * @param targetIndex
      * @param targetIndex
@@ -141,40 +120,85 @@ public class Ipo {
             float[] objectRotation = new float[3];
             float[] objectRotation = new float[3];
             boolean bSpatialTrack = targetIndex < 0;
             boolean bSpatialTrack = targetIndex < 0;
             Vector3f[] scales = new Vector3f[framesAmount + 1];
             Vector3f[] scales = new Vector3f[framesAmount + 1];
-            float[] scale = new float[3];
-
+            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
             //calculating track data
             for (int frame = startFrame; frame <= stopFrame; ++frame) {
             for (int frame = startFrame; frame <= stopFrame; ++frame) {
                 int index = frame - startFrame;
                 int index = frame - startFrame;
                 times[index] = start + (frame - 1) * timeBetweenFrames;
                 times[index] = start + (frame - 1) * timeBetweenFrames;
-                for (int j = 0; j < bezierCurves.length; ++j) {
+            	for (int j = 0; j < bezierCurves.length; ++j) {
                     double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);
                     double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);
                     switch (bezierCurves[j].getType()) {
                     switch (bezierCurves[j].getType()) {
+                    	//LOCATION
                         case AC_LOC_X:
                         case AC_LOC_X:
+                        	translation[0] = (float) value;
+                        	break;
                         case AC_LOC_Y:
                         case AC_LOC_Y:
+                        	if(fixUpAxis) {
+                        		translation[2] = (float) -value;
+                        	} else {
+                        		translation[1] = (float) value;
+                        	}
+                        	break;
                         case AC_LOC_Z:
                         case AC_LOC_Z:
-                            translation[bezierCurves[j].getType() - 1] = (float) value;
+                        	translation[fixUpAxis ? 1 : 2] = (float) value;
                             break;
                             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:
                         case OB_ROT_X:
+                        	objectRotation[0] = (float) value * degreeToRadiansFactor;
+                            break;
                         case OB_ROT_Y:
                         case OB_ROT_Y:
+                        	if(fixUpAxis) {
+                        		objectRotation[2] = (float) -value * degreeToRadiansFactor;
+                        	} else {
+                        		objectRotation[1] = (float) value * degreeToRadiansFactor;
+                        	}
+                        	break;
                         case OB_ROT_Z:
                         case OB_ROT_Z:
-                            objectRotation[bezierCurves[j].getType() - 7] = (float) value;
+                        	objectRotation[fixUpAxis ? 1 : 2] = (float) value * degreeToRadiansFactor;
                             break;
                             break;
+                            
+                        //SIZE
                         case AC_SIZE_X:
                         case AC_SIZE_X:
+                        	scale[0] = (float) value;
+                        	break;
                         case AC_SIZE_Y:
                         case AC_SIZE_Y:
+                        	if(fixUpAxis) {
+                        		scale[2] = (float) value;
+                        	} else {
+                        		scale[1] = (float) value;
+                        	}
+                        	break;
                         case AC_SIZE_Z:
                         case AC_SIZE_Z:
-                            scale[bezierCurves[j].getType() - 13] = (float) value;
+                        	scale[fixUpAxis ? 1 : 2] = (float) value;
                             break;
                             break;
+                            
+                        //QUATERNION ROTATION (used with bone animation)
                         case AC_QUAT_W:
                         case AC_QUAT_W:
                             quaternionRotation[3] = (float) value;
                             quaternionRotation[3] = (float) value;
                             break;
                             break;
                         case AC_QUAT_X:
                         case AC_QUAT_X:
+                        	quaternionRotation[0] = (float) value;
+                        	break;
                         case AC_QUAT_Y:
                         case AC_QUAT_Y:
+                        	if(fixUpAxis) {
+                        		quaternionRotation[2] = -(float) value;
+                        	} else {
+                        		quaternionRotation[1] = (float) value;
+                        	}
+                        	break;
                         case AC_QUAT_Z:
                         case AC_QUAT_Z:
-                            quaternionRotation[bezierCurves[j].getType() - 26] = (float) value;
+                        	if(fixUpAxis) {
+                        		quaternionRotation[1] = (float) value;
+                        	} else {
+                        		quaternionRotation[2] = (float) value;
+                        	}
                             break;
                             break;
                         default:
                         default:
-                        //TODO: error? info? warning?
+                        	throw new IllegalStateException("Unknown ipo curve type: " + bezierCurves[j].getType());
                     }
                     }
                 }
                 }
                 translations[index] = new Vector3f(translation[0], translation[1], translation[2]);
                 translations[index] = new Vector3f(translation[0], translation[1], translation[2]);

+ 8 - 5
engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java

@@ -1,5 +1,7 @@
 package com.jme3.scene.plugins.blender.animations;
 package com.jme3.scene.plugins.blender.animations;
 
 
+import java.util.List;
+
 import com.jme3.animation.BoneTrack;
 import com.jme3.animation.BoneTrack;
 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
@@ -7,7 +9,6 @@ import com.jme3.scene.plugins.blender.curves.BezierCurve;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
-import java.util.List;
 
 
 /**
 /**
  * This class helps to compute values from interpolation curves for features like animation or constraint influence. The
  * This class helps to compute values from interpolation curves for features like animation or constraint influence. The
@@ -21,9 +22,11 @@ public class IpoHelper extends AbstractBlenderHelper {
      * different blender versions.
      * different blender versions.
      * @param blenderVersion
      * @param blenderVersion
      *        the version read from the blend file
      *        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) {
-        super(blenderVersion);
+    public IpoHelper(String blenderVersion, boolean fixUpAxis) {
+        super(blenderVersion, fixUpAxis);
     }
     }
 
 
     /**
     /**
@@ -52,7 +55,7 @@ public class IpoHelper extends AbstractBlenderHelper {
                 bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
                 bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
             }
             }
             curves.clear();
             curves.clear();
-            result = new Ipo(bezierCurves);
+            result = new Ipo(bezierCurves, fixUpAxis);
             blenderContext.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result);
             blenderContext.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result);
         }
         }
         return result;
         return result;
@@ -90,7 +93,7 @@ public class IpoHelper extends AbstractBlenderHelper {
          *        the constant value of this ipo
          *        the constant value of this ipo
          */
          */
         public ConstIpo(float constValue) {
         public ConstIpo(float constValue) {
-            super(null);
+            super(null, false);
             this.constValue = constValue;
             this.constValue = constValue;
         }
         }
 
 

+ 4 - 2
engine/src/blender/com/jme3/scene/plugins/blender/cameras/CameraHelper.java

@@ -24,9 +24,11 @@ public class CameraHelper extends AbstractBlenderHelper {
      * different blender versions.
      * different blender versions.
      * @param blenderVersion
      * @param blenderVersion
      *        the version read from the blend file
      *        the version read from the blend file
+     * @param fixUpAxis
+     *        a variable that indicates if the Y asxis is the UP axis or not
      */
      */
-    public CameraHelper(String blenderVersion) {
-        super(blenderVersion);
+    public CameraHelper(String blenderVersion, boolean fixUpAxis) {
+        super(blenderVersion, fixUpAxis);
     }
     }
     
     
 	/**
 	/**

+ 147 - 0
engine/src/blender/com/jme3/scene/plugins/blender/constraints/BlenderTrack.java

@@ -0,0 +1,147 @@
+package com.jme3.scene.plugins.blender.constraints;
+
+import java.io.IOException;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.BoneTrack;
+import com.jme3.animation.SpatialTrack;
+import com.jme3.animation.Track;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.util.TempVars;
+
+/**
+ * This class holds either the bone track or spatial track. Is made to improve
+ * code readability.
+ * 
+ * @author Marcin Roguski (Kaelthas)
+ */
+/* package */final class BlenderTrack implements Track {
+	/** The spatial track. */
+	private SpatialTrack spatialTrack;
+	/** The bone track. */
+	private BoneTrack boneTrack;
+
+	/**
+	 * Constructs the object using spatial track (bone track is null).
+	 * 
+	 * @param spatialTrack
+	 *            the spatial track
+	 */
+	public BlenderTrack(SpatialTrack spatialTrack) {
+		this.spatialTrack = spatialTrack;
+	}
+
+	/**
+	 * Constructs the object using bone track (spatial track is null).
+	 * 
+	 * @param spatialTrack
+	 *            the spatial track
+	 */
+	public BlenderTrack(BoneTrack boneTrack) {
+		this.boneTrack = boneTrack;
+	}
+
+	/**
+	 * @return the stored track (either bone or spatial)
+	 */
+	public Track getTrack() {
+		return boneTrack != null ? boneTrack : spatialTrack;
+	}
+
+	/**
+	 * @return the array of rotations of this track
+	 */
+	public Quaternion[] getRotations() {
+		if (boneTrack != null) {
+			return boneTrack.getRotations();
+		}
+		return spatialTrack.getRotations();
+	}
+
+	/**
+	 * @return the array of scales for this track
+	 */
+	public Vector3f[] getScales() {
+		if (boneTrack != null) {
+			return boneTrack.getScales();
+		}
+		return spatialTrack.getScales();
+	}
+
+	/**
+	 * @return the arrays of time for this track
+	 */
+	public float[] getTimes() {
+		if (boneTrack != null) {
+			return boneTrack.getTimes();
+		}
+		return spatialTrack.getTimes();
+	}
+
+	/**
+	 * @return the array of translations of this track
+	 */
+	public Vector3f[] getTranslations() {
+		if (boneTrack != null) {
+			return boneTrack.getTranslations();
+		}
+		return spatialTrack.getTranslations();
+	}
+
+	/**
+	 * Set the translations, rotations and scales for this bone track
+	 * 
+	 * @param times
+	 *            a float array with the time of each frame
+	 * @param translations
+	 *            the translation of the bone for each frame
+	 * @param rotations
+	 *            the rotation of the bone for each frame
+	 * @param scales
+	 *            the scale of the bone for each frame
+	 */
+	public void setKeyframes(float[] times, Vector3f[] translations,
+			Quaternion[] rotations, Vector3f[] scales) {
+		if (boneTrack != null) {
+			boneTrack.setKeyframes(times, translations, rotations, scales);
+		} else {
+			spatialTrack.setKeyframes(times, translations, rotations, scales);
+		}
+	}
+
+	@Override
+	public void write(JmeExporter ex) throws IOException {
+	}
+
+	@Override
+	public void read(JmeImporter im) throws IOException {
+	}
+
+	@Override
+	public void setTime(float time, float weight, AnimControl control,
+			AnimChannel channel, TempVars vars) {
+		if (boneTrack != null) {
+			boneTrack.setTime(time, weight, control, channel, vars);
+		} else {
+			spatialTrack.setTime(time, weight, control, channel, vars);
+		}
+	}
+
+	@Override
+	public float getLength() {
+		return spatialTrack == null ? boneTrack.getLength() : spatialTrack
+				.getLength();
+	}
+
+	@Override
+	public BlenderTrack clone() {
+		if (boneTrack != null) {
+			return new BlenderTrack(boneTrack.clone());
+		}
+		return new BlenderTrack(spatialTrack.clone());
+	}
+}

+ 61 - 156
engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java

@@ -1,11 +1,12 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
 import com.jme3.animation.Animation;
 import com.jme3.animation.Animation;
+import com.jme3.animation.Bone;
 import com.jme3.animation.BoneTrack;
 import com.jme3.animation.BoneTrack;
+import com.jme3.animation.Skeleton;
+import com.jme3.animation.SpatialTrack;
 import com.jme3.animation.Track;
 import com.jme3.animation.Track;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Vector3f;
-import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
@@ -17,27 +18,29 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
 /**
 /**
  * The implementation of a constraint.
  * The implementation of a constraint.
  * 
  * 
- * @author Marcin Roguski
+ * @author Marcin Roguski (Kaelthas)
  */
  */
 public abstract class Constraint {
 public abstract class Constraint {
-
+	
 	/** The name of this constraint. */
 	/** The name of this constraint. */
 	protected final String name;
 	protected final String name;
-	/** The old memory address of the constraint's owner. */
-	protected Long boneOMA = -1L;
-	protected final Space ownerSpace;
-	protected final Space targetSpace;
+	/** The constraint's owner. */
+	protected final Feature owner;
+	/** The constraint's target. */
+	protected final Feature target;
 	/** The structure with constraint's data. */
 	/** The structure with constraint's data. */
 	protected final Structure data;
 	protected final Structure data;
 	/** The ipo object defining influence. */
 	/** The ipo object defining influence. */
 	protected final Ipo ipo;
 	protected final Ipo ipo;
-	protected BlenderContext blenderContext;
+	/** The blender context. */
+	protected final BlenderContext blenderContext;
+	
 	/**
 	/**
 	 * This constructor creates the constraint instance.
 	 * This constructor creates the constraint instance.
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -47,51 +50,47 @@ public abstract class Constraint {
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public Constraint(Structure constraintStructure, Long boneOMA,
+	public Constraint(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
+		this.blenderContext = blenderContext;
 		this.name = constraintStructure.getFieldValue("name").toString();
 		this.name = constraintStructure.getFieldValue("name").toString();
-		ConstraintType constraintType = ConstraintType.valueOf(((Number)constraintStructure.getFieldValue("type")).intValue());
-		if(constraintType != this.getType()) {
-			throw new IllegalStateException("Constraint structure does not match its type for constraint: " + name);
-		}
 		Pointer pData = (Pointer) constraintStructure.getFieldValue("data");
 		Pointer pData = (Pointer) constraintStructure.getFieldValue("data");
 		if (pData.isNotNull()) {
 		if (pData.isNotNull()) {
 			data = pData.fetchData(blenderContext.getInputStream()).get(0);
 			data = pData.fetchData(blenderContext.getInputStream()).get(0);
+			Pointer pTar = (Pointer)data.getFieldValue("tar");
+			if(pTar!= null && pTar.isNotNull()) {
+				Structure targetStructure = pTar.fetchData(blenderContext.getInputStream()).get(0);
+				Long targetOMA = pTar.getOldMemoryAddress();
+				Space targetSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("tarspace")).byteValue());
+				ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
+				Spatial target = (Spatial) objectHelper.toObject(targetStructure, blenderContext);
+				this.target = new Feature(target, targetSpace, targetOMA, blenderContext);
+			} else {
+				this.target = null;
+			}
 		} else {
 		} else {
 			throw new BlenderFileException("The constraint has no data specified!");
 			throw new BlenderFileException("The constraint has no data specified!");
 		}
 		}
-		this.boneOMA = boneOMA;
-		this.ownerSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("ownspace")).byteValue());
-		this.targetSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("tarspace")).byteValue());
+		Space ownerSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("ownspace")).byteValue());
+		Object owner = blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE);
+		if(owner instanceof Spatial) {
+			this.owner = new Feature((Spatial)owner, ownerSpace, ownerOMA, blenderContext);
+		} else {
+			this.owner = new Feature((Bone)owner, ownerSpace, ownerOMA, blenderContext);
+		}
 		this.ipo = influenceIpo;
 		this.ipo = influenceIpo;
 	}
 	}
 
 
 	/**
 	/**
-	 * This method returns the name of the constraint.
-	 * 
-	 * @return the name of the constraint
-	 */
-	public String getName() {
-		return name;
-	}
-
-	/**
-	 * This method returns the old memoty address of the bone this constraint
-	 * affects.
-	 * 
-	 * @return the old memory address of the bone this constraint affects
+	 * Bake the animation's constraints into its owner.
 	 */
 	 */
-	public Long getBoneOMA() {
-		return boneOMA;
-	}
-
+	public abstract void bakeDynamic();
+	
 	/**
 	/**
-	 * This method returns the type of the constraint.
-	 * 
-	 * @return the type of the constraint
+	 * Bake the static constraints into its owner.
 	 */
 	 */
-	public abstract ConstraintType getType();
-
+	public abstract void bakeStatic();
+	
     /**
     /**
      * This method returns the bone traces for the bone that is affected by the given constraint.
      * This method returns the bone traces for the bone that is affected by the given constraint.
      * @param skeleton
      * @param skeleton
@@ -100,118 +99,24 @@ public abstract class Constraint {
      *        the bone animation that affects the skeleton
      *        the bone animation that affects the skeleton
      * @return the bone track for the bone that is being affected by the constraint
      * @return the bone track for the bone that is being affected by the constraint
      */
      */
-    protected Track getTrack(Animation animation, int targetIndex) {
-        if (boneOMA >= 0) {//bone animation
-            for (Track track : animation.getTracks()) {
-                if (((BoneTrack) track).getTargetBoneIndex() == targetIndex) {
-                    return track;
+    protected BlenderTrack getTrack(Object owner, Skeleton skeleton, Animation animation) {
+    	if(owner instanceof Bone) {
+    		int boneIndex = skeleton.getBoneIndex((Bone) owner);
+    		for (Track track : animation.getTracks()) {
+                if (((BoneTrack) track).getTargetBoneIndex() == boneIndex) {
+                    return new BlenderTrack(((BoneTrack) track));
                 }
                 }
             }
             }
-        } else {//spatial animation
-            return animation.getTracks()[0];
-        }
-        return null;
+    		throw new IllegalStateException("Cannot find track for: " + owner);
+    	} else {
+    		return new BlenderTrack((SpatialTrack)animation.getTracks()[0]);
+    	}
     }
     }
     
     
-    /**
-     * This method returns the target or subtarget object (if specified).
-     * @param loadedFeatureDataType
-     * @return target or subtarget feature
-     * @throws BlenderFileException this exception is thrown if the blend file is somehow corrupted
-     */
-    protected Object getTarget(LoadedFeatureDataType loadedFeatureDataType) throws BlenderFileException {
-    	//load the feature through objectHelper, this way we are certain the object loads and has
-    	//his own constraints applied to traces
-    	ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
-    	//always load the target first
-    	Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
-        Structure objectStructure = blenderContext.getFileBlock(targetOMA).getStructure(blenderContext);
-        Object result = objectHelper.toObject(objectStructure, blenderContext);
-    	
-    	//subtarget should be loaded alogn with target
-    	Object subtarget = data.getFieldValue("subtarget");
-    	String subtargetName = subtarget==null ? null : subtarget.toString();
-        if (subtargetName!=null && subtargetName.length() > 0) {
-            result = blenderContext.getLoadedFeature(subtargetName, loadedFeatureDataType);
-        }
-        return result;
-    }
-	
-	/**
-     * This method returns target's object location.
-     * @return target's object location
-     */
-    protected Vector3f getTargetLocation() {
-        Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
-        Node targetObject = (Node) blenderContext.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
-        switch (targetSpace) {
-            case CONSTRAINT_SPACE_LOCAL:
-                return targetObject.getLocalTranslation();
-            case CONSTRAINT_SPACE_WORLD:
-                return targetObject.getWorldTranslation();
-            default:
-                throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
-        }
-    }
-
-    /**
-     * This method returns target's object location in the specified frame.
-     * @param frame
-     *        the frame number
-     * @return target's object location
-     */
-    protected Vector3f getTargetLocation(int frame) {
-        return this.getTargetLocation();//TODO: implement getting location in a specified frame
-    }
-
-    /**
-     * This method returns target's object rotation.
-     * @return target's object rotation
-     */
-    protected Quaternion getTargetRotation() {
-        Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
-        Node targetObject = (Node) blenderContext.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
-        switch (targetSpace) {
-            case CONSTRAINT_SPACE_LOCAL:
-                return targetObject.getLocalRotation();
-            case CONSTRAINT_SPACE_WORLD:
-                return targetObject.getWorldRotation();
-            default:
-                throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
-        }
-    }
-
-    /**
-     * This method returns target's object scale.
-     * @return target's object scale
-     */
-    protected Vector3f getTargetScale() {
-        Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
-        Node targetObject = (Node) blenderContext.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
-        switch (targetSpace) {
-            case CONSTRAINT_SPACE_LOCAL:
-                return targetObject.getLocalScale();
-            case CONSTRAINT_SPACE_WORLD:
-                return targetObject.getWorldScale();
-            default:
-                throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
-        }
-    }
-    
-	/**
-	 * This method affects the bone animation tracks for the given skeleton.
-	 * 
-	 * @param animation
-	 *            the bone animation baked traces
-	 * @param targetIndex
-	 * 			  the index of the constraint's target object
-	 */
-	public abstract void affectAnimation(Animation animation, int targetIndex);
-
 	/**
 	/**
 	 * The space of target or owner transformation.
 	 * The space of target or owner transformation.
 	 * 
 	 * 
-	 * @author Marcin Roguski
+	 * @author Marcin Roguski (Kaelthas)
 	 */
 	 */
 	public static enum Space {
 	public static enum Space {
 
 
@@ -227,16 +132,16 @@ public abstract class Constraint {
 		 */
 		 */
 		public static Space valueOf(byte c) {
 		public static Space valueOf(byte c) {
 			switch (c) {
 			switch (c) {
-			case 0:
-				return CONSTRAINT_SPACE_WORLD;
-			case 1:
-				return CONSTRAINT_SPACE_LOCAL;
-			case 2:
-				return CONSTRAINT_SPACE_POSE;
-			case 3:
-				return CONSTRAINT_SPACE_PARLOCAL;
-			default:
-				return CONSTRAINT_SPACE_INVALID;
+				case 0:
+					return CONSTRAINT_SPACE_WORLD;
+				case 1:
+					return CONSTRAINT_SPACE_LOCAL;
+				case 2:
+					return CONSTRAINT_SPACE_POSE;
+				case 3:
+					return CONSTRAINT_SPACE_PARLOCAL;
+				default:
+					return CONSTRAINT_SPACE_INVALID;
 			}
 			}
 		}
 		}
 	}
 	}

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

@@ -1,6 +1,5 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
-import com.jme3.animation.Animation;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -20,7 +19,7 @@ import java.util.logging.Logger;
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -30,19 +29,20 @@ import java.util.logging.Logger;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintAction(Structure constraintStructure, Long boneOMA,
+	public ConstraintAction(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
-
+	
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 		// TODO: implement 'Action' constraint
 		// TODO: implement 'Action' constraint
 		LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
 		LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_ACTION;
+	public void bakeStatic() {
+		// TODO: implement 'Action' constraint
+		LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
 	}
 	}
 }
 }

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

@@ -1,6 +1,5 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
-import com.jme3.animation.Animation;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -20,7 +19,7 @@ import java.util.logging.Logger;
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -30,19 +29,20 @@ import java.util.logging.Logger;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintChildOf(Structure constraintStructure, Long boneOMA,
+	public ConstraintChildOf(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 		// TODO: implement ChildOf constraint
 		// TODO: implement ChildOf constraint
 		LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
 		LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_CHILDOF;
+	public void bakeStatic() {
+		// TODO: implement ChildOf constraint
+		LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
 	}
 	}
 }
 }

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

@@ -1,6 +1,5 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
-import com.jme3.animation.Animation;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -20,7 +19,7 @@ import java.util.logging.Logger;
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -30,20 +29,21 @@ import java.util.logging.Logger;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintClampTo(Structure constraintStructure, Long boneOMA,
+	public ConstraintClampTo(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext)
 			Ipo influenceIpo, BlenderContext blenderContext)
 			throws BlenderFileException {
 			throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 		//TODO: implement when curves are implemented
 		//TODO: implement when curves are implemented
-		LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", this.getName());
+		LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", name);
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_CLAMPTO;
+	public void bakeStatic() {
+		//TODO: implement when curves are implemented
+		LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", name);
 	}
 	}
 }
 }

+ 49 - 0
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDampTrack.java

@@ -0,0 +1,49 @@
+package com.jme3.scene.plugins.blender.constraints;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.scene.plugins.blender.animations.Ipo;
+import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
+import com.jme3.scene.plugins.blender.file.Structure;
+
+/**
+ * The damp track constraint. Available for blender 2.50+.
+ * @author Marcin Roguski (Kaelthas)
+ */
+/*package*/ class ConstraintDampTrack extends Constraint {
+	private static final Logger LOGGER = Logger.getLogger(ConstraintDampTrack.class.getName());
+	
+	/**
+	 * This constructor creates the constraint instance.
+	 * 
+	 * @param constraintStructure
+	 *            the constraint's structure (bConstraint clss in blender 2.49).
+	 * @param ownerOMA
+	 *            the old memory address of the constraint owner
+	 * @param influenceIpo
+	 *            the ipo curve of the influence factor
+	 * @param blenderContext
+	 *            the blender context
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blender file is somehow
+	 *             corrupted
+	 */
+	public ConstraintDampTrack(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
+		// TODO Auto-generated constructor stub
+	}
+
+	@Override
+	public void bakeDynamic() {
+		// TODO Auto-generated method stub
+		LOGGER.log(Level.WARNING, "'Damp Track' constraint NOT implemented!");
+	}
+
+	@Override
+	public void bakeStatic() {
+		// TODO Auto-generated method stub
+		LOGGER.log(Level.WARNING, "'Damp Track' constraint NOT implemented!");
+	}
+}

+ 83 - 40
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDistLimit.java

@@ -1,12 +1,15 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
 import com.jme3.animation.Animation;
 import com.jme3.animation.Animation;
-import com.jme3.animation.BoneTrack;
+import com.jme3.animation.Bone;
+import com.jme3.math.Matrix4f;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
+import com.jme3.scene.Spatial;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
+import com.jme3.scene.plugins.ogre.AnimData;
 
 
 /**
 /**
  * This class represents 'Dist limit' constraint type in blender.
  * This class represents 'Dist limit' constraint type in blender.
@@ -17,12 +20,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	private static final int LIMITDIST_OUTSIDE = 1;
 	private static final int LIMITDIST_OUTSIDE = 1;
 	private static final int LIMITDIST_ONSURFACE = 2;
 	private static final int LIMITDIST_ONSURFACE = 2;
     
     
-    /**
+	protected int mode;
+	protected float dist;
+	
+	/**
 	 * This constructor creates the constraint instance.
 	 * This constructor creates the constraint instance.
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -32,52 +38,89 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintDistLimit(Structure constraintStructure, Long boneOMA,
+	public ConstraintDistLimit(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
+		
+		mode = ((Number) data.getFieldValue("mode")).intValue();
+		dist = ((Number) data.getFieldValue("dist")).floatValue();
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
-		Vector3f targetLocation = this.getTargetLocation();
-		BoneTrack boneTrack = (BoneTrack) this.getTrack(animation, targetIndex);
-		if (boneTrack != null) {
-			//TODO: target vertex group !!!
-			float dist = ((Number) data.getFieldValue("dist")).floatValue();
-			int mode = ((Number) data.getFieldValue("mode")).intValue();
-
-			int maxFrames = boneTrack.getTimes().length;
-			Vector3f[] translations = boneTrack.getTranslations();
-			for (int frame = 0; frame < maxFrames; ++frame) {
-				Vector3f v = translations[frame].subtract(targetLocation);
-				float currentDistance = v.length();
-				float influence = ipo.calculateValue(frame);
-				float modifier = 0.0f;
-				switch (mode) {
-					case LIMITDIST_INSIDE:
-						if (currentDistance >= dist) {
-							modifier = (dist - currentDistance) / currentDistance;
-						}
-						break;
-					case LIMITDIST_ONSURFACE:
-						modifier = (dist - currentDistance) / currentDistance;
-						break;
-					case LIMITDIST_OUTSIDE:
-						if (currentDistance <= dist) {
-							modifier = (dist - currentDistance) / currentDistance;
-						}
-						break;
-					default:
-						throw new IllegalStateException("Unknown distance limit constraint mode: " + mode);
+	public void bakeDynamic() {
+		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) {
+					BlenderTrack blenderTrack = this.getTrack(owner, animData.skeleton, animation);
+					int maxFrames = blenderTrack.getTimes().length;
+					Vector3f[] translations = blenderTrack.getTranslations();
+					for (int frame = 0; frame < maxFrames; ++frame) {
+						Vector3f v = translations[frame].subtract(targetLocation);
+						this.distLimit(v, targetLocation, ipo.calculateValue(frame));
+						translations[frame].addLocal(v);
+					}
+					blenderTrack.setKeyframes(blenderTrack.getTimes(), translations, blenderTrack.getRotations(), blenderTrack.getScales());
 				}
 				}
-				translations[frame].addLocal(v.multLocal(modifier * influence));
 			}
 			}
-			boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());
 		}
 		}
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_DISTLIMIT;
+	public 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();
+		if(owner instanceof Spatial) {
+			((Spatial) owner).setLocalTranslation(m.mult(ownerLocation));
+		} else {
+			((Bone) owner).setBindTransforms(m.mult(ownerLocation), ((Bone) owner).getLocalRotation(), ((Bone) owner).getLocalScale());
+		}
+	}
+	
+	/**
+	 * 
+	 * @param currentLocation
+	 * @param targetLocation
+	 * @param influence
+	 */
+	private void distLimit(Vector3f currentLocation, Vector3f targetLocation, float influence) {
+		Vector3f v = currentLocation.subtract(targetLocation);
+		float currentDistance = v.length();
+		
+		switch (mode) {
+			case LIMITDIST_INSIDE:
+				if (currentDistance >= dist) {
+					v.normalizeLocal();
+					v.multLocal(dist + (currentDistance - dist) * (1.0f - influence));
+					currentLocation.set(v.addLocal(targetLocation));
+				}
+				break;
+			case LIMITDIST_ONSURFACE:
+				if (currentDistance > dist) {
+					v.normalizeLocal();
+					v.multLocal(dist + (currentDistance - dist) * (1.0f - influence));
+					currentLocation.set(v.addLocal(targetLocation));
+				} else if(currentDistance < dist) {
+					v.normalizeLocal().multLocal(dist * influence);
+					currentLocation.set(targetLocation.add(v));
+				}
+				break;
+			case LIMITDIST_OUTSIDE:
+				if (currentDistance <= dist) {
+					v = targetLocation.subtract(currentLocation).normalizeLocal().multLocal(dist * influence);
+					currentLocation.set(targetLocation.add(v));
+				}
+				break;
+			default:
+				throw new IllegalStateException("Unknown distance limit constraint mode: " + mode);
+		}
 	}
 	}
 }
 }

+ 0 - 78
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFactory.java

@@ -1,78 +0,0 @@
-package com.jme3.scene.plugins.blender.constraints;
-
-import com.jme3.scene.plugins.blender.BlenderContext;
-import com.jme3.scene.plugins.blender.animations.Ipo;
-import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
-import com.jme3.scene.plugins.blender.file.Structure;
-
-/**
- * A factory class to create new instances of constraints depending on the type from the constraint's structure.
- * This class has a package scope.
- * @author Marcin Roguski (Kaelthas)
- */
-/*package*/ final class ConstraintFactory {
-	
-	/**
-	 * This method creates the constraint instance.
-	 * 
-	 * @param constraintStructure
-	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
-	 *            the old memory address of the constraint owner
-	 * @param influenceIpo
-	 *            the ipo curve of the influence factor
-	 * @param blenderContext
-	 *            the blender context
-	 * @throws BlenderFileException
-	 *             this exception is thrown when the blender file is somehow
-	 *             corrupted
-	 */
-	public static Constraint createConstraint(Structure constraintStructure, Long boneOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		int type = ((Number)constraintStructure.getFieldValue("type")).intValue();
-		ConstraintType constraintType = ConstraintType.valueOf(type);
-			switch(constraintType) {
-				case CONSTRAINT_TYPE_ACTION:
-					return new ConstraintAction(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_CHILDOF:
-					return new ConstraintChildOf(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_CLAMPTO:
-					return new ConstraintClampTo(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_DISTLIMIT:
-					return new ConstraintDistLimit(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_FOLLOWPATH:
-					return new ConstraintFollowPath(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_KINEMATIC:
-					return new ConstraintInverseKinematics(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_LOCKTRACK:
-					return new ConstraintLockTrack(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_LOCLIKE:
-					return new ConstraintLocLike(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_LOCLIMIT:
-					return new ConstraintLocLimit(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_MINMAX:
-					return new ConstraintMinMax(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_NULL:
-					return new ConstraintNull(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_PYTHON:
-					return new ConstraintPython(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_RIGIDBODYJOINT:
-					return new ConstraintRigidBodyJoint(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_ROTLIKE:
-					return new ConstraintRotLike(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_ROTLIMIT:
-					return new ConstraintRotLimit(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_SHRINKWRAP:
-					return new ConstraintShrinkWrap(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_SIZELIKE:
-					return new ConstraintSizeLike(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_SIZELIMIT:
-					return new ConstraintSizeLimit(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_STRETCHTO:
-					return new ConstraintStretchTo(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				case CONSTRAINT_TYPE_TRANSFORM:
-					return new ConstraintTransform(constraintStructure, boneOMA, influenceIpo, blenderContext);
-				default:
-					throw new IllegalStateException("Unknown constraint type: " + constraintType);
-		}
-	}
-}

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

@@ -1,6 +1,5 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
-import com.jme3.animation.Animation;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -20,7 +19,7 @@ import java.util.logging.Logger;
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -30,19 +29,20 @@ import java.util.logging.Logger;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintFollowPath(Structure constraintStructure, Long boneOMA,
+	public ConstraintFollowPath(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 		//TODO: implement when curves are implemented
 		//TODO: implement when curves are implemented
 		LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!");
 		LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!");
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_FOLLOWPATH;
+	public void bakeStatic() {
+		//TODO: implement when curves are implemented
+		LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!");
 	}
 	}
 }
 }

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

@@ -1,5 +1,12 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
@@ -7,19 +14,42 @@ import com.jme3.scene.plugins.blender.animations.IpoHelper;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.logging.Logger;
 
 
 /**
 /**
  * This class should be used for constraint calculations.
  * This class should be used for constraint calculations.
- * @author Marcin Roguski
+ * @author Marcin Roguski (Kaelthas)
  */
  */
 public class ConstraintHelper extends AbstractBlenderHelper {
 public class ConstraintHelper extends AbstractBlenderHelper {
 	private static final Logger LOGGER = Logger.getLogger(ConstraintHelper.class.getName());
 	private static final Logger LOGGER = Logger.getLogger(ConstraintHelper.class.getName());
 	
 	
+	private static final Map<String, Class<? extends Constraint>> constraintClasses = new HashMap<String, Class<? extends Constraint>>(22);
+	static {
+		constraintClasses.put("bActionConstraint", ConstraintAction.class);
+		constraintClasses.put("bChildOfConstraint", ConstraintChildOf.class);
+		constraintClasses.put("bClampToConstraint", ConstraintClampTo.class);
+		constraintClasses.put("bDistLimitConstraint", ConstraintDistLimit.class);
+		constraintClasses.put("bFollowPathConstraint", ConstraintFollowPath.class);
+		constraintClasses.put("bKinematicConstraint", ConstraintInverseKinematics.class);
+		constraintClasses.put("bLockTrackConstraint", ConstraintLockTrack.class);
+		constraintClasses.put("bLocateLikeConstraint", ConstraintLocLike.class);
+		constraintClasses.put("bLocLimitConstraint", ConstraintLocLimit.class);
+		constraintClasses.put("bMinMaxConstraint", ConstraintMinMax.class);
+		constraintClasses.put("bNullConstraint", ConstraintNull.class);
+		constraintClasses.put("bPythonConstraint", ConstraintPython.class);
+		constraintClasses.put("bRigidBodyJointConstraint", ConstraintRigidBodyJoint.class);
+		constraintClasses.put("bRotateLikeConstraint", ConstraintRotLike.class);
+		constraintClasses.put("bShrinkWrapConstraint", ConstraintShrinkWrap.class);
+		constraintClasses.put("bSizeLikeConstraint", ConstraintSizeLike.class);
+		constraintClasses.put("bSizeLimitConstraint", ConstraintSizeLimit.class);
+		constraintClasses.put("bStretchToConstraint", ConstraintStretchTo.class);
+		constraintClasses.put("bTransformConstraint", ConstraintTransform.class);
+		constraintClasses.put("bRotLimitConstraint", ConstraintRotLimit.class);
+		//Blender 2.50+
+		constraintClasses.put("bSplineIKConstraint", ConstraintSplineInverseKinematic.class);
+		constraintClasses.put("bDampTrackConstraint", ConstraintDampTrack.class);
+		constraintClasses.put("bPivotConstraint", ConstraintDampTrack.class);
+	}
+	
 	/**
 	/**
 	 * Helper constructor. It's main task is to generate the affection functions. These functions are common to all
 	 * Helper constructor. It's main task is to generate the affection functions. These functions are common to all
 	 * ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall
 	 * ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall
@@ -27,27 +57,25 @@ public class ConstraintHelper extends AbstractBlenderHelper {
 	 * functionalities may differ in different blender versions.
 	 * functionalities may differ in different blender versions.
 	 * @param blenderVersion
 	 * @param blenderVersion
 	 *        the version read from the blend file
 	 *        the version read from the blend file
+	 * @param fixUpAxis
+     *        a variable that indicates if the Y asxis is the UP axis or not
 	 */
 	 */
-	public ConstraintHelper(String blenderVersion, BlenderContext blenderContext) {
-		super(blenderVersion);
+	public ConstraintHelper(String blenderVersion, BlenderContext blenderContext, boolean fixUpAxis) {
+		super(blenderVersion, fixUpAxis);
 	}
 	}
 
 
 	/**
 	/**
-	 * This method reads constraints for for the given structure. The constraints are loaded only once for object/bone.
-	 * @param ownerOMA
-	 *        the owner's old memory address
+	 * This method reads constraints for for the given structure. The
+	 * constraints are loaded only once for object/bone.
+	 * 
 	 * @param objectStructure
 	 * @param objectStructure
-	 *        the structure we read constraint's for
+	 *            the structure we read constraint's for
 	 * @param blenderContext
 	 * @param blenderContext
-	 *        the blender context
+	 *            the blender context
 	 * @throws BlenderFileException
 	 * @throws BlenderFileException
 	 */
 	 */
-	public Map<Long, List<Constraint>> loadConstraints(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
-		if (blenderVersion >= 250) {//TODO
-			LOGGER.warning("Loading of constraints not yet implemented for version 2.5x !");
-			return new HashMap<Long, List<Constraint>>(0);
-		}
-		
+	public void loadConstraints(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
+		LOGGER.fine("Loading constraints.");
 		// reading influence ipos for the constraints
 		// reading influence ipos for the constraints
 		IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
 		IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
 		Map<String, Map<String, Ipo>> constraintsIpos = new HashMap<String, Map<String, Ipo>>();
 		Map<String, Map<String, Ipo>> constraintsIpos = new HashMap<String, Map<String, Ipo>>();
@@ -74,11 +102,9 @@ public class ConstraintHelper extends AbstractBlenderHelper {
 				}
 				}
 			}
 			}
 		}
 		}
-
-		Map<Long, List<Constraint>> result = new HashMap<Long, List<Constraint>>();
 		
 		
 		//loading constraints connected with the object's bones
 		//loading constraints connected with the object's bones
-		Pointer pPose = (Pointer) objectStructure.getFieldValue("pose");//TODO: what if the object has two armatures ????
+		Pointer pPose = (Pointer) objectStructure.getFieldValue("pose");
 		if (pPose.isNotNull()) {
 		if (pPose.isNotNull()) {
 			List<Structure> poseChannels = ((Structure) pPose.fetchData(blenderContext.getInputStream()).get(0).getFieldValue("chanbase")).evaluateListBase(blenderContext);
 			List<Structure> poseChannels = ((Structure) pPose.fetchData(blenderContext.getInputStream()).get(0).getFieldValue("chanbase")).evaluateListBase(blenderContext);
 			for (Structure poseChannel : poseChannels) {
 			for (Structure poseChannel : poseChannels) {
@@ -96,40 +122,78 @@ public class ConstraintHelper extends AbstractBlenderHelper {
 						float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
 						float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
 						ipo = ipoHelper.createIpo(enforce);
 						ipo = ipoHelper.createIpo(enforce);
 					}
 					}
-					constraintsList.add(ConstraintFactory.createConstraint(constraint, boneOMA, ipo, blenderContext));
+					constraintsList.add(this.createConstraint(constraint, boneOMA, ipo, blenderContext));
 				}
 				}
-				
-				result.put(boneOMA, constraintsList);
 				blenderContext.addConstraints(boneOMA, constraintsList);
 				blenderContext.addConstraints(boneOMA, constraintsList);
 			}
 			}
 		}
 		}
-		// TODO: reading constraints for objects (implement when object's animation will be available)
-		List<Structure> constraintChannels = ((Structure)objectStructure.getFieldValue("constraintChannels")).evaluateListBase(blenderContext);
-		for(Structure constraintChannel : constraintChannels) {
-			System.out.println(constraintChannel);
-		}
 
 
-		//loading constraints connected with the object itself (TODO: test this)
-		if(!result.containsKey(objectStructure.getOldMemoryAddress())) {
-			List<Structure> constraints = ((Structure)objectStructure.getFieldValue("constraints")).evaluateListBase(blenderContext);
-			List<Constraint> constraintsList = new ArrayList<Constraint>(constraints.size());
+		//loading constraints connected with the object itself
+		List<Structure> constraints = ((Structure)objectStructure.getFieldValue("constraints")).evaluateListBase(blenderContext);
+		List<Constraint> constraintsList = new ArrayList<Constraint>(constraints.size());
+		
+		for(Structure constraint : constraints) {
+			String constraintName = constraint.getFieldValue("name").toString();
+			String objectName = objectStructure.getName();
 			
 			
-			for(Structure constraint : constraints) {
-				String constraintName = constraint.getFieldValue("name").toString();
-				String objectName = objectStructure.getName();
-				
-				Map<String, Ipo> objectConstraintsIpos = constraintsIpos.get(objectName);
-				Ipo ipo = objectConstraintsIpos!=null ? objectConstraintsIpos.get(constraintName) : null;
-				if (ipo == null) {
-					float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
-					ipo = ipoHelper.createIpo(enforce);
-				}
-				constraintsList.add(ConstraintFactory.createConstraint(constraint, null, ipo, blenderContext));
+			Map<String, Ipo> objectConstraintsIpos = constraintsIpos.get(objectName);
+			Ipo ipo = objectConstraintsIpos!=null ? objectConstraintsIpos.get(constraintName) : null;
+			if (ipo == null) {
+				float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
+				ipo = ipoHelper.createIpo(enforce);
 			}
 			}
-			result.put(objectStructure.getOldMemoryAddress(), constraintsList);
-			blenderContext.addConstraints(objectStructure.getOldMemoryAddress(), constraintsList);
+			constraintsList.add(this.createConstraint(constraint, objectStructure.getOldMemoryAddress(), ipo, blenderContext));
+		}
+		blenderContext.addConstraints(objectStructure.getOldMemoryAddress(), constraintsList);
+	}
+	
+	/**
+	 * This method creates the constraint instance.
+	 * 
+	 * @param constraintStructure
+	 *            the constraint's structure (bConstraint clss in blender 2.49).
+	 * @param ownerOMA
+	 *            the old memory address of the constraint's owner
+	 * @param influenceIpo
+	 *            the ipo curve of the influence factor
+	 * @param blenderContext
+	 *            the blender context
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blender file is somehow
+	 *             corrupted
+	 */
+	protected Constraint createConstraint(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, 
+						BlenderContext blenderContext) throws BlenderFileException {
+		String constraintClassName = this.getConstraintClassName(constraintStructure, blenderContext);
+		Class<? extends Constraint> constraintClass = constraintClasses.get(constraintClassName);
+		if(constraintClass != null) {
+			try {
+				return (Constraint) constraintClass.getDeclaredConstructors()[0].newInstance(constraintStructure, ownerOMA, influenceIpo, 
+						blenderContext);
+			} catch (IllegalArgumentException e) {
+				throw new BlenderFileException(e.getLocalizedMessage(), e);
+			} catch (SecurityException e) {
+				throw new BlenderFileException(e.getLocalizedMessage(), e);
+			} catch (InstantiationException e) {
+				throw new BlenderFileException(e.getLocalizedMessage(), e);
+			} catch (IllegalAccessException e) {
+				throw new BlenderFileException(e.getLocalizedMessage(), e);
+			} catch (InvocationTargetException e) {
+				throw new BlenderFileException(e.getLocalizedMessage(), e);
+			}
+		} else {
+			throw new BlenderFileException("Unknown constraint type: " + constraintClassName);
+		}
+	}
+	
+	protected String getConstraintClassName(Structure constraintStructure, BlenderContext blenderContext) throws BlenderFileException {
+		Pointer pData = (Pointer)constraintStructure.getFieldValue("data");
+		if(pData.isNotNull()) {
+			Structure data = pData.fetchData(blenderContext.getInputStream()).get(0);
+			return data.getType();
+			
 		}
 		}
-		return result;
+		return constraintStructure.getType();
 	}
 	}
 	
 	
 	@Override
 	@Override

+ 44 - 33
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintInverseKinematics.java

@@ -1,7 +1,9 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
 import com.jme3.animation.Animation;
 import com.jme3.animation.Animation;
+import com.jme3.animation.Skeleton;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.scene.plugins.blender.animations.CalculationBone;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
@@ -20,7 +22,7 @@ import java.util.logging.Logger;
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -31,23 +33,30 @@ import java.util.logging.Logger;
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
 	public ConstraintInverseKinematics(Structure constraintStructure,
 	public ConstraintInverseKinematics(Structure constraintStructure,
-			Long boneOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+			Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 //		try {
 //		try {
 			// IK solver is only attached to bones
 			// IK solver is only attached to bones
-//			Bone ownerBone = (Bone) blenderContext.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);
-//
-//			// get the target point
+//			Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE);
+//			AnimData animData = blenderContext.getAnimData(ownerOMA);
+//			if(animData == null) {
+				//TODO: to nie mo¿e byæ null, utworzyæ dane bez ruchu, w zale¿noœci czy target siê rusza
+//			}
+			
+			//prepare a list of all parents of this bone
+//			CalculationBone[] bones = this.getBonesToCalculate(skeleton, boneAnimation);
+			
+			// get the target point
 //			Object targetObject = this.getTarget(LoadedFeatureDataType.LOADED_FEATURE);
 //			Object targetObject = this.getTarget(LoadedFeatureDataType.LOADED_FEATURE);
 //			Vector3f pt = null;// Point Target
 //			Vector3f pt = null;// Point Target
 //			if (targetObject instanceof Bone) {
 //			if (targetObject instanceof Bone) {
 //				pt = ((Bone) targetObject).getModelSpacePosition();
 //				pt = ((Bone) targetObject).getModelSpacePosition();
-//			} else if (targetObject instanceof Node) {
-//				pt = ((Node) targetObject).getWorldTranslation();
+//			} else if (targetObject instanceof Spatial) {
+//				pt = ((Spatial) targetObject).getWorldTranslation();
 //			} else if (targetObject instanceof Skeleton) {
 //			} else if (targetObject instanceof Skeleton) {
 //				Structure armatureNodeStructure = (Structure) this.getTarget(LoadedFeatureDataType.LOADED_STRUCTURE);
 //				Structure armatureNodeStructure = (Structure) this.getTarget(LoadedFeatureDataType.LOADED_STRUCTURE);
 //				ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
 //				ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
@@ -106,7 +115,7 @@ import java.util.logging.Logger;
 //			for (CalculationBone bone : bones) {
 //			for (CalculationBone bone : bones) {
 //				bone.applyCalculatedTracks();
 //				bone.applyCalculatedTracks();
 //			}
 //			}
-
+//
 //			System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
 //			System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
 //			for (int i = 0; i < bones.length; ++i) {
 //			for (int i = 0; i < bones.length; ++i) {
 //				System.out.println(Arrays.toString(bones[i].track.getTranslations()));
 //				System.out.println(Arrays.toString(bones[i].track.getTranslations()));
@@ -118,40 +127,42 @@ import java.util.logging.Logger;
 //		}
 //		}
 	}
 	}
 	
 	
-//	/**
-//	 * This method returns bones used for rotation calculations.
-//	 * @param bone
-//	 *        the bone to which the constraint is applied
-//	 * @param skeleton
-//	 *        the skeleton owning the bone and its ancestors
-//	 * @param boneAnimation
-//	 *        the bone animation data that stores the traces for the skeleton's bones
-//	 * @return a list of bones to imitate the bone's movement during IK solving
-//	 */
-//	private CalculationBone[] getBonesToCalculate(Bone bone, Skeleton skeleton, Animation boneAnimation) {
+	@Override
+	public void bakeStatic() {
+		// TODO Auto-generated method stub
+		
+	}
+	
+	/**
+	 * This method returns bones used for rotation calculations.
+	 * @param bone
+	 *        the bone to which the constraint is applied
+	 * @param skeleton
+	 *        the skeleton owning the bone and its ancestors
+	 * @param boneAnimation
+	 *        the bone animation data that stores the traces for the skeleton's bones
+	 * @return a list of bones to imitate the bone's movement during IK solving
+	 */
+	private CalculationBone[] getBonesToCalculate(Skeleton skeleton, Animation boneAnimation) {
+//		Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE);
 //		List<CalculationBone> bonesList = new ArrayList<CalculationBone>();
 //		List<CalculationBone> bonesList = new ArrayList<CalculationBone>();
-//		Bone currentBone = bone;
 //		do {
 //		do {
-//			bonesList.add(new CalculationBone(currentBone, 1));
-//			int boneIndex = skeleton.getBoneIndex(currentBone);
+//			bonesList.add(new CalculationBone(ownerBone, 1));
+//			int boneIndex = skeleton.getBoneIndex(ownerBone);
 //			for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
 //			for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
-//				if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) {
-//					bonesList.add(new CalculationBone(currentBone, boneAnimation.getTracks()[i]));
+//				if (((BoneTrack[])boneAnimation.getTracks())[i].getTargetBoneIndex() == boneIndex) {
+//					bonesList.add(new CalculationBone(ownerBone, (BoneTrack)boneAnimation.getTracks()[i]));
 //					break;
 //					break;
 //				}
 //				}
 //			}
 //			}
-//			currentBone = currentBone.getParent();
-//		} while (currentBone != null);
+//			ownerBone = ownerBone.getParent();
+//		} while (ownerBone != null);
 //		//attaching children
 //		//attaching children
 //		CalculationBone[] result = bonesList.toArray(new CalculationBone[bonesList.size()]);
 //		CalculationBone[] result = bonesList.toArray(new CalculationBone[bonesList.size()]);
 //		for (int i = result.length - 1; i > 0; --i) {
 //		for (int i = result.length - 1; i > 0; --i) {
 //			result[i].attachChild(result[i - 1]);
 //			result[i].attachChild(result[i - 1]);
 //		}
 //		}
 //		return result;
 //		return result;
-//	}
-	
-	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_KINEMATIC;
+		return null;
 	}
 	}
 }
 }

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

@@ -1,12 +1,13 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
 import com.jme3.animation.Animation;
 import com.jme3.animation.Animation;
-import com.jme3.animation.BoneTrack;
+import com.jme3.math.Transform;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
+import com.jme3.scene.plugins.ogre.AnimData;
 
 
 /**
 /**
  * This class represents 'Loc like' constraint type in blender.
  * This class represents 'Loc like' constraint type in blender.
@@ -16,19 +17,20 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	private static final int LOCLIKE_X = 0x01;
 	private static final int LOCLIKE_X = 0x01;
 	private static final int LOCLIKE_Y = 0x02;
 	private static final int LOCLIKE_Y = 0x02;
 	private static final int LOCLIKE_Z = 0x04;
 	private static final int LOCLIKE_Z = 0x04;
-	/* LOCLIKE_TIP is a depreceated option... use headtail=1.0f instead */
-    //protected static final int LOCLIKE_TIP = 0x08;
+    //protected static final int LOCLIKE_TIP = 0x08;//this is deprecated in blender
     private static final int LOCLIKE_X_INVERT = 0x10;
     private static final int LOCLIKE_X_INVERT = 0x10;
     private static final int LOCLIKE_Y_INVERT = 0x20;
     private static final int LOCLIKE_Y_INVERT = 0x20;
     private static final int LOCLIKE_Z_INVERT = 0x40;
     private static final int LOCLIKE_Z_INVERT = 0x40;
     private static final int LOCLIKE_OFFSET = 0x80;
     private static final int LOCLIKE_OFFSET = 0x80;
     
     
+    protected int flag;
+    
 	/**
 	/**
 	 * This constructor creates the constraint instance.
 	 * This constructor creates the constraint instance.
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -38,49 +40,83 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintLocLike(Structure constraintStructure, Long boneOMA,
+	public ConstraintLocLike(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
+		
+		flag = ((Number) data.getFieldValue("flag")).intValue();
+		
+		if(blenderContext.getBlenderKey().isFixUpAxis()) {
+			//swapping Y and X limits flag in the bitwise flag
+			int y = flag & LOCLIKE_Y;
+			int invY = flag & LOCLIKE_Y_INVERT;
+			int z = flag & LOCLIKE_Z;
+			int invZ = flag & LOCLIKE_Z_INVERT;
+			flag &= LOCLIKE_X | LOCLIKE_X_INVERT | LOCLIKE_OFFSET;//clear the other flags to swap them
+			flag |= y << 2;
+			flag |= invY << 2;
+			flag |= z >> 2;
+			flag |= invZ >> 2;
+		}
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
-		BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
-		if (track != null) {
-			Vector3f targetLocation = this.getTargetLocation();
-			int flag = ((Number) data.getFieldValue("flag")).intValue();
-			Vector3f[] translations = track.getTranslations();
-			int maxFrames = translations.length;
-			for (int frame = 0; frame < maxFrames; ++frame) {
-				Vector3f offset = Vector3f.ZERO;
-				if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original location to the copied location
-					offset = translations[frame].clone();
-				}
-
-				if ((flag & LOCLIKE_X) != 0) {
-					translations[frame].x = targetLocation.x;
-					if ((flag & LOCLIKE_X_INVERT) != 0) {
-						translations[frame].x = -translations[frame].x;
-					}
-				} else if ((flag & LOCLIKE_Y) != 0) {
-					translations[frame].y = targetLocation.y;
-					if ((flag & LOCLIKE_Y_INVERT) != 0) {
-						translations[frame].y = -translations[frame].y;
-					}
-				} else if ((flag & LOCLIKE_Z) != 0) {
-					translations[frame].z = targetLocation.z;
-					if ((flag & LOCLIKE_Z_INVERT) != 0) {
-						translations[frame].z = -translations[frame].z;
-					}
+	public void bakeDynamic() {
+		AnimData animData = blenderContext.getAnimData(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);
+				Vector3f[] translations = blenderTrack.getTranslations();
+				int maxFrames = translations.length;
+				for (int frame = 0; frame < maxFrames; ++frame) {
+					this.locLike(translations[frame], targetTransform.getTranslation(), ipo.calculateValue(frame));
 				}
 				}
-				translations[frame].addLocal(offset);//TODO: ipo influence
+				blenderTrack.setKeyframes(blenderTrack.getTimes(), translations, blenderTrack.getRotations(), blenderTrack.getScales());
 			}
 			}
-			track.setKeyframes(track.getTimes(), translations, track.getRotations(), track.getScales());
 		}
 		}
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_LOCLIKE;
+	public 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);
+	}
+	
+	private void locLike(Vector3f ownerLocation, Vector3f targetLocation, float influence) {
+		Vector3f startLocation = ownerLocation.clone();
+		Vector3f offset = Vector3f.ZERO;
+		if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original location to the copied location
+			offset = startLocation;
+		}
+
+		if ((flag & LOCLIKE_X) != 0) {
+			ownerLocation.x = targetLocation.x;
+			if ((flag & LOCLIKE_X_INVERT) != 0) {
+				ownerLocation.x = -ownerLocation.x;
+			}
+		}
+		if ((flag & LOCLIKE_Y) != 0) {
+			ownerLocation.y = targetLocation.y;
+			if ((flag & LOCLIKE_Y_INVERT) != 0) {
+				ownerLocation.y = -ownerLocation.y;
+			}
+		}
+		if ((flag & LOCLIKE_Z) != 0) {
+			ownerLocation.z = targetLocation.z;
+			if ((flag & LOCLIKE_Z_INVERT) != 0) {
+				ownerLocation.z = -ownerLocation.z;
+			}
+		}
+		ownerLocation.addLocal(offset);
+		
+		if(influence < 1.0f) {
+			startLocation.subtractLocal(ownerLocation).normalizeLocal().mult(influence);
+			ownerLocation.addLocal(startLocation);
+		}
 	}
 	}
 }
 }

+ 93 - 50
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLimit.java

@@ -1,12 +1,14 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
 import com.jme3.animation.Animation;
 import com.jme3.animation.Animation;
-import com.jme3.animation.BoneTrack;
+import com.jme3.animation.Track;
+import com.jme3.math.Transform;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
+import com.jme3.scene.plugins.ogre.AnimData;
 
 
 /**
 /**
  * This class represents 'Loc limit' constraint type in blender.
  * This class represents 'Loc limit' constraint type in blender.
@@ -20,12 +22,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
     private static final int LIMIT_ZMIN = 0x10;
     private static final int LIMIT_ZMIN = 0x10;
     private static final int LIMIT_ZMAX = 0x20;
     private static final int LIMIT_ZMAX = 0x20;
     
     
+    protected float[][] limits = new float[3][2];
+    protected int flag;
+    
 	/**
 	/**
 	 * This constructor creates the constraint instance.
 	 * This constructor creates the constraint instance.
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -35,63 +40,101 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintLocLimit(Structure constraintStructure, Long boneOMA,
+	public ConstraintLocLimit(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
+		
+		flag = ((Number) data.getFieldValue("flag")).intValue();
+		if(blenderContext.getBlenderKey().isFixUpAxis()) {
+			limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
+			limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
+			limits[2][0] = -((Number) data.getFieldValue("ymin")).floatValue();
+			limits[2][1] = -((Number) data.getFieldValue("ymax")).floatValue();
+			limits[1][0] = ((Number) data.getFieldValue("zmin")).floatValue();
+			limits[1][1] = ((Number) data.getFieldValue("zmax")).floatValue();
+			
+			//swapping Y and X limits flag in the bitwise flag
+			int ymin = flag & LIMIT_YMIN;
+			int ymax = flag & LIMIT_YMAX;
+			int zmin = flag & LIMIT_ZMIN;
+			int zmax = flag & LIMIT_ZMAX;
+			flag &= LIMIT_XMIN | LIMIT_XMAX;//clear the other flags to swap them
+			flag |= ymin << 2;
+			flag |= ymax << 2;
+			flag |= zmin >> 2;
+			flag |= zmax >> 2;
+		} else {
+			limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
+			limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
+			limits[1][0] = ((Number) data.getFieldValue("ymin")).floatValue();
+			limits[1][1] = ((Number) data.getFieldValue("ymax")).floatValue();
+			limits[2][0] = ((Number) data.getFieldValue("zmin")).floatValue();
+			limits[2][1] = ((Number) data.getFieldValue("zmax")).floatValue();
+		}
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
-		BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
-		if (track != null) {
-			int flag = ((Number) data.getFieldValue("flag")).intValue();
-			Vector3f[] translations = track.getTranslations();
-			int maxFrames = translations.length;
-			for (int frame = 0; frame < maxFrames; ++frame) {
-				float influence = ipo.calculateValue(frame);
-				if ((flag & LIMIT_XMIN) != 0) {
-					float xmin = ((Number) data.getFieldValue("xmin")).floatValue();
-					if (translations[frame].x < xmin) {
-						translations[frame].x -= (translations[frame].x - xmin) * influence;
-					}
-				}
-				if ((flag & LIMIT_XMAX) != 0) {
-					float xmax = ((Number) data.getFieldValue("xmax")).floatValue();
-					if (translations[frame].x > xmax) {
-						translations[frame].x -= (translations[frame].x - xmax) * influence;
-					}
-				}
-				if ((flag & LIMIT_YMIN) != 0) {
-					float ymin = ((Number) data.getFieldValue("ymin")).floatValue();
-					if (translations[frame].y < ymin) {
-						translations[frame].y -= (translations[frame].y - ymin) * influence;
-					}
-				}
-				if ((flag & LIMIT_YMAX) != 0) {
-					float ymax = ((Number) data.getFieldValue("ymax")).floatValue();
-					if (translations[frame].y > ymax) {
-						translations[frame].y -= (translations[frame].y - ymax) * influence;
-					}
-				}
-				if ((flag & LIMIT_ZMIN) != 0) {
-					float zmin = ((Number) data.getFieldValue("zmin")).floatValue();
-					if (translations[frame].z < zmin) {
-						translations[frame].z -= (translations[frame].z - zmin) * influence;
-					}
+	public void bakeDynamic() {
+		Object owner = this.owner.getObject();
+		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
+		if(animData != null) {
+			for(Animation animation : animData.anims) {
+				BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
+				Vector3f[] translations = track.getTranslations();
+				int maxFrames = translations.length;
+				for (int frame = 0; frame < maxFrames; ++frame) {
+					this.locLimit(translations[frame], ipo.calculateValue(frame));
 				}
 				}
-				if ((flag & LIMIT_ZMAX) != 0) {
-					float zmax = ((Number) data.getFieldValue("zmax")).floatValue();
-					if (translations[frame].z > zmax) {
-						translations[frame].z -= (translations[frame].z - zmax) * influence;
-					}
-				}//TODO: consider constraint space !!!
+				track.setKeyframes(track.getTimes(), translations, track.getRotations(), track.getScales());
+				translations = track.getTranslations();
+				animation.setTracks(new Track[] {track.getTrack()});
 			}
 			}
-			track.setKeyframes(track.getTimes(), translations, track.getRotations(), track.getScales());
 		}
 		}
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_LOCLIMIT;
+	public void bakeStatic() {
+		Transform ownerTransform = this.owner.getTransform();
+		Vector3f ownerLocation = ownerTransform.getTranslation();
+		this.locLimit(ownerLocation, ipo.calculateValue(0));
+		this.owner.applyTransform(ownerTransform);
+	}
+	
+	/**
+	 * This method modifies the given translation.
+	 * @param translation the translation to be modified.
+	 * @param influence the influence value
+	 */
+	private void locLimit(Vector3f translation, float influence) {
+		if ((flag & LIMIT_XMIN) != 0) {
+			if (translation.x < limits[0][0]) {
+				translation.x -= (translation.x - limits[0][0]) * influence;
+			}
+		}
+		if ((flag & LIMIT_XMAX) != 0) {
+			if (translation.x > limits[0][1]) {
+				translation.x -= (translation.x - limits[0][1]) * influence;
+			}
+		}
+		if ((flag & LIMIT_YMIN) != 0) {
+			if (translation.y < limits[1][0]) {
+				translation.y -= (translation.y - limits[1][0]) * influence;
+			}
+		}
+		if ((flag & LIMIT_YMAX) != 0) {
+			if (translation.y > limits[1][1]) {
+				translation.y -= (translation.y - limits[1][1]) * influence;
+			}
+		}
+		if ((flag & LIMIT_ZMIN) != 0) {
+			if (translation.z < limits[2][0]) {
+				translation.z -= (translation.z - limits[2][0]) * influence;
+			}
+		}
+		if ((flag & LIMIT_ZMAX) != 0) {
+			if (translation.z > limits[2][1]) {
+				translation.z -= (translation.z - limits[2][1]) * influence;
+			}
+		}
 	}
 	}
 }
 }

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

@@ -1,6 +1,5 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
-import com.jme3.animation.Animation;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -20,7 +19,7 @@ import java.util.logging.Logger;
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -30,20 +29,21 @@ import java.util.logging.Logger;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintLockTrack(Structure constraintStructure, Long boneOMA,
+	public ConstraintLockTrack(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext)
 			Ipo influenceIpo, BlenderContext blenderContext)
 			throws BlenderFileException {
 			throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 		// TODO: implement 'Lock track' constraint
 		// TODO: implement 'Lock track' constraint
 		LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!");
 		LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!");
 	}
 	}
-
+	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_LOCKTRACK;
+	public void bakeStatic() {
+		// TODO: implement 'Lock track' constraint
+		LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!");
 	}
 	}
 }
 }

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

@@ -1,6 +1,5 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
-import com.jme3.animation.Animation;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -20,7 +19,7 @@ import java.util.logging.Logger;
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -30,19 +29,20 @@ import java.util.logging.Logger;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintMinMax(Structure constraintStructure, Long boneOMA,
+	public ConstraintMinMax(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 		// TODO: implement 'Min max' constraint
 		// TODO: implement 'Min max' constraint
 		LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!");
 		LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!");
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_MINMAX;
+	public void bakeStatic() {
+		// TODO: implement 'Min max' constraint
+		LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!");
 	}
 	}
 }
 }

+ 5 - 8
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintNull.java

@@ -1,6 +1,5 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
-import com.jme3.animation.Animation;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -17,7 +16,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -27,17 +26,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintNull(Structure constraintStructure, Long boneOMA,
+	public ConstraintNull(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext)
 			Ipo influenceIpo, BlenderContext blenderContext)
 			throws BlenderFileException {
 			throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {}
+	public void bakeDynamic() {}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_NULL;
-	}
+	public void bakeStatic() {}
 }
 }

+ 50 - 0
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPivot.java

@@ -0,0 +1,50 @@
+package com.jme3.scene.plugins.blender.constraints;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.scene.plugins.blender.animations.Ipo;
+import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
+import com.jme3.scene.plugins.blender.file.Structure;
+
+/**
+ * The pivot constraint. Available for blender 2.50+.
+ * @author Marcin Roguski (Kaelthas)
+ */
+/*package*/ class ConstraintPivot extends Constraint {
+	private static final Logger LOGGER = Logger.getLogger(ConstraintPivot.class.getName());
+	
+	/**
+	 * This constructor creates the constraint instance.
+	 * 
+	 * @param constraintStructure
+	 *            the constraint's structure (bConstraint clss in blender 2.49).
+	 * @param ownerOMA
+	 *            the old memory address of the constraint owner
+	 * @param influenceIpo
+	 *            the ipo curve of the influence factor
+	 * @param blenderContext
+	 *            the blender context
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blender file is somehow
+	 *             corrupted
+	 */
+	public ConstraintPivot(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo,
+			BlenderContext blenderContext) throws BlenderFileException {
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
+		// TODO Auto-generated constructor stub
+	}
+
+	@Override
+	public void bakeDynamic() {
+		// TODO Auto-generated method stub
+		LOGGER.log(Level.WARNING, "'Pivot' constraint NOT implemented!");
+	}
+
+	@Override
+	public void bakeStatic() {
+		// TODO Auto-generated method stub
+		LOGGER.log(Level.WARNING, "'Pivot' constraint NOT implemented!");
+	}
+}

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

@@ -1,6 +1,5 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
-import com.jme3.animation.Animation;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -20,7 +19,7 @@ import java.util.logging.Logger;
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -30,19 +29,20 @@ import java.util.logging.Logger;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintPython(Structure constraintStructure, Long boneOMA,
+	public ConstraintPython(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 		// TODO: implement 'Python' constraint
 		// TODO: implement 'Python' constraint
 		LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
 		LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_PYTHON;
+	public void bakeStatic() {
+		// TODO: implement 'Python' constraint
+		LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
 	}
 	}
 }
 }

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

@@ -1,6 +1,5 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
-import com.jme3.animation.Animation;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -20,7 +19,7 @@ import java.util.logging.Logger;
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -31,18 +30,19 @@ import java.util.logging.Logger;
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
 	public ConstraintRigidBodyJoint(Structure constraintStructure,
 	public ConstraintRigidBodyJoint(Structure constraintStructure,
-			Long boneOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+			Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 		// TODO: implement 'Rigid body joint' constraint
 		// TODO: implement 'Rigid body joint' constraint
 		LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!");
 		LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!");
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_RIGIDBODYJOINT;
+	public void bakeStatic() {
+		// TODO: implement 'Rigid body joint' constraint
+		LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!");
 	}
 	}
 }
 }

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

@@ -1,12 +1,13 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
 import com.jme3.animation.Animation;
 import com.jme3.animation.Animation;
-import com.jme3.animation.BoneTrack;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Quaternion;
+import com.jme3.math.Transform;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
+import com.jme3.scene.plugins.ogre.AnimData;
 
 
 /**
 /**
  * This class represents 'Rot like' constraint type in blender.
  * This class represents 'Rot like' constraint type in blender.
@@ -21,12 +22,14 @@ import com.jme3.scene.plugins.blender.file.Structure;
     private static final int ROTLIKE_Z_INVERT = 0x40;
     private static final int ROTLIKE_Z_INVERT = 0x40;
     private static final int ROTLIKE_OFFSET = 0x80;
     private static final int ROTLIKE_OFFSET = 0x80;
     
     
-    /**
+    protected int flag;
+    
+	/**
 	 * This constructor creates the constraint instance.
 	 * This constructor creates the constraint instance.
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -36,52 +39,76 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintRotLike(Structure constraintStructure, Long boneOMA,
+	public ConstraintRotLike(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
+		
+		flag = ((Number) data.getFieldValue("flag")).intValue();
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
-		BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
-		if (track != null) {
-			Quaternion targetRotation = this.getTargetRotation();
-			int flag = ((Number) data.getFieldValue("flag")).intValue();
-			float[] targetAngles = targetRotation.toAngles(null);
-			Quaternion[] rotations = track.getRotations();
-			int maxFrames = rotations.length;
-			for (int frame = 0; frame < maxFrames; ++frame) {
-				float[] angles = rotations[frame].toAngles(null);
-
-				Quaternion offset = Quaternion.IDENTITY;
-				if ((flag & ROTLIKE_OFFSET) != 0) {//we add the original rotation to the copied rotation
-					offset = rotations[frame].clone();
-				}
-
-				if ((flag & ROTLIKE_X) != 0) {
-					angles[0] = targetAngles[0];
-					if ((flag & ROTLIKE_X_INVERT) != 0) {
-						angles[0] = -angles[0];
-					}
-				} else if ((flag & ROTLIKE_Y) != 0) {
-					angles[1] = targetAngles[1];
-					if ((flag & ROTLIKE_Y_INVERT) != 0) {
-						angles[1] = -angles[1];
-					}
-				} else if ((flag & ROTLIKE_Z) != 0) {
-					angles[2] = targetAngles[2];
-					if ((flag & ROTLIKE_Z_INVERT) != 0) {
-						angles[2] = -angles[2];
-					}
+	public void bakeDynamic() {
+		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) {
+				BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
+				float[] targetAngles = targetRotation.toAngles(null);
+				Quaternion[] rotations = track.getRotations();
+				int maxFrames = rotations.length;
+				float[] angles = new float[3];
+				for (int frame = 0; frame < maxFrames; ++frame) {
+					rotations[frame].toAngles(angles);
+					this.rotLike(rotations[frame], angles, targetAngles, ipo.calculateValue(frame));
 				}
 				}
-				rotations[frame].fromAngles(angles).multLocal(offset);//TODO: ipo influence
+				track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
 			}
 			}
-			track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
 		}
 		}
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_ROTLIKE;
+	public 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);
+	}
+	
+	private void rotLike(Quaternion ownerRotation, float[] ownerAngles, float[] targetAngles, float influence) {
+		Quaternion startRotation = ownerRotation.clone();
+		Quaternion offset = Quaternion.IDENTITY;
+		if ((flag & ROTLIKE_OFFSET) != 0) {//we add the original rotation to the copied rotation
+			offset = startRotation;
+		}
+
+		if ((flag & ROTLIKE_X) != 0) {
+			ownerAngles[0] = targetAngles[0];
+			if ((flag & ROTLIKE_X_INVERT) != 0) {
+				ownerAngles[0] = -ownerAngles[0];
+			}
+		}
+		if ((flag & ROTLIKE_Y) != 0) {
+			ownerAngles[1] = targetAngles[1];
+			if ((flag & ROTLIKE_Y_INVERT) != 0) {
+				ownerAngles[1] = -ownerAngles[1];
+			}
+		}
+		if ((flag & ROTLIKE_Z) != 0) {
+			ownerAngles[2] = targetAngles[2];
+			if ((flag & ROTLIKE_Z_INVERT) != 0) {
+				ownerAngles[2] = -ownerAngles[2];
+			}
+		}
+		ownerRotation.fromAngles(ownerAngles).multLocal(offset);
+
+		if(influence < 1.0f) {
+			
+//			startLocation.subtractLocal(ownerLocation).normalizeLocal().mult(influence);
+//			ownerLocation.addLocal(startLocation);
+			//TODO
+		}
 	}
 	}
 }
 }

+ 91 - 49
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLimit.java

@@ -1,13 +1,14 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
 import com.jme3.animation.Animation;
 import com.jme3.animation.Animation;
-import com.jme3.animation.BoneTrack;
 import com.jme3.math.FastMath;
 import com.jme3.math.FastMath;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Quaternion;
+import com.jme3.math.Transform;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
+import com.jme3.scene.plugins.ogre.AnimData;
 
 
 /**
 /**
  * This class represents 'Rot limit' constraint type in blender.
  * This class represents 'Rot limit' constraint type in blender.
@@ -18,12 +19,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	private static final int LIMIT_YROT = 0x02;
 	private static final int LIMIT_YROT = 0x02;
 	private static final int LIMIT_ZROT = 0x04;
 	private static final int LIMIT_ZROT = 0x04;
     
     
+	protected float[][] limits = new float[3][2];
+    protected int flag;
+	
 	/**
 	/**
 	 * This constructor creates the constraint instance.
 	 * This constructor creates the constraint instance.
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -33,62 +37,100 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintRotLimit(Structure constraintStructure, Long boneOMA,
+	public ConstraintRotLimit(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
+		
+		if(blenderContext.getBlenderKey().isFixUpAxis()) {
+			limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue() * FastMath.DEG_TO_RAD;
+			limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue() * FastMath.DEG_TO_RAD;
+			limits[2][0] = -((Number) data.getFieldValue("ymin")).floatValue() * FastMath.DEG_TO_RAD;
+			limits[2][1] = -((Number) data.getFieldValue("ymax")).floatValue() * FastMath.DEG_TO_RAD;
+			limits[1][0] = ((Number) data.getFieldValue("zmin")).floatValue() * FastMath.DEG_TO_RAD;
+			limits[1][1] = ((Number) data.getFieldValue("zmax")).floatValue() * FastMath.DEG_TO_RAD;
+		} else {
+			limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue() * FastMath.DEG_TO_RAD;
+			limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue() * FastMath.DEG_TO_RAD;
+			limits[1][0] = ((Number) data.getFieldValue("ymin")).floatValue() * FastMath.DEG_TO_RAD;
+			limits[1][1] = ((Number) data.getFieldValue("ymax")).floatValue() * FastMath.DEG_TO_RAD;
+			limits[2][0] = ((Number) data.getFieldValue("zmin")).floatValue() * FastMath.DEG_TO_RAD;
+			limits[2][1] = ((Number) data.getFieldValue("zmax")).floatValue() * FastMath.DEG_TO_RAD;
+		}
+		flag = ((Number) data.getFieldValue("flag")).intValue();
+		if(blenderContext.getBlenderKey().isFixUpAxis()) {
+			//swapping Y and X limits flag in the bitwise flag
+			int limitY = flag & LIMIT_YROT;
+			int limitZ = flag & LIMIT_ZROT;
+			flag &= LIMIT_XROT;//clear the other flags to swap them
+			flag |= limitY << 1;
+			flag |= limitZ >> 1;
+		}
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
-		BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
-		if (track != null) {
-			int flag = ((Number) data.getFieldValue("flag")).intValue();
-			Quaternion[] rotations = track.getRotations();
-			int maxFrames = rotations.length;
-			for (int frame = 0; frame < maxFrames; ++frame) {
-				float[] angles = rotations[frame].toAngles(null);
-				float influence = ipo.calculateValue(frame);
-				if ((flag & LIMIT_XROT) != 0) {
-					float xmin = ((Number) data.getFieldValue("xmin")).floatValue() * FastMath.DEG_TO_RAD;
-					float xmax = ((Number) data.getFieldValue("xmax")).floatValue() * FastMath.DEG_TO_RAD;
-					float difference = 0.0f;
-					if (angles[0] < xmin) {
-						difference = (angles[0] - xmin) * influence;
-					} else if (angles[0] > xmax) {
-						difference = (angles[0] - xmax) * influence;
-					}
-					angles[0] -= difference;
-				}
-				if ((flag & LIMIT_YROT) != 0) {
-					float ymin = ((Number) data.getFieldValue("ymin")).floatValue() * FastMath.DEG_TO_RAD;
-					float ymax = ((Number) data.getFieldValue("ymax")).floatValue() * FastMath.DEG_TO_RAD;
-					float difference = 0.0f;
-					if (angles[1] < ymin) {
-						difference = (angles[1] - ymin) * influence;
-					} else if (angles[1] > ymax) {
-						difference = (angles[1] - ymax) * influence;
-					}
-					angles[1] -= difference;
+	public void bakeDynamic() {
+		AnimData animData = blenderContext.getAnimData(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();
+				float[] angles = new float[3];
+				int maxFrames = rotations.length;
+				for (int frame = 0; frame < maxFrames; ++frame) {
+					rotations[frame].toAngles(angles);
+					this.rotLimit(angles, ipo.calculateValue(frame));
+					rotations[frame].fromAngles(angles);
 				}
 				}
-				if ((flag & LIMIT_ZROT) != 0) {
-					float zmin = ((Number) data.getFieldValue("zmin")).floatValue() * FastMath.DEG_TO_RAD;
-					float zmax = ((Number) data.getFieldValue("zmax")).floatValue() * FastMath.DEG_TO_RAD;
-					float difference = 0.0f;
-					if (angles[2] < zmin) {
-						difference = (angles[2] - zmin) * influence;
-					} else if (angles[2] > zmax) {
-						difference = (angles[2] - zmax) * influence;
-					}
-					angles[2] -= difference;
-				}
-				rotations[frame].fromAngles(angles);//TODO: consider constraint space !!!
+				track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
 			}
 			}
-			track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
 		}
 		}
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_ROTLIMIT;
+	public 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);
+	}
+	
+	/**
+	 * This method computes new constrained angles.
+	 * 
+	 * @param angles
+	 *            angles to be altered
+	 * @param influence
+	 *            the alteration influence
+	 */
+	private void rotLimit(float[] angles, float influence) {
+		if ((flag & LIMIT_XROT) != 0) {
+			float difference = 0.0f;
+			if (angles[0] < limits[0][0]) {
+				difference = (angles[0] - limits[0][0]) * influence;
+			} else if (angles[0] > limits[0][1]) {
+				difference = (angles[0] - limits[0][1]) * influence;
+			}
+			angles[0] -= difference;
+		}
+		if ((flag & LIMIT_YROT) != 0) {
+			float difference = 0.0f;
+			if (angles[1] < limits[1][0]) {
+				difference = (angles[1] - limits[1][0]) * influence;
+			} else if (angles[1] > limits[1][1]) {
+				difference = (angles[1] - limits[1][1]) * influence;
+			}
+			angles[1] -= difference;
+		}
+		if ((flag & LIMIT_ZROT) != 0) {
+			float difference = 0.0f;
+			if (angles[2] < limits[2][0]) {
+				difference = (angles[2] - limits[2][0]) * influence;
+			} else if (angles[2] > limits[2][1]) {
+				difference = (angles[2] - limits[2][1]) * influence;
+			}
+			angles[2] -= difference;
+		}
 	}
 	}
 }
 }

+ 26 - 28
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintShrinkWrap.java

@@ -1,7 +1,10 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
 import com.jme3.animation.Animation;
 import com.jme3.animation.Animation;
-import com.jme3.animation.BoneTrack;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.Geometry;
@@ -10,28 +13,23 @@ import com.jme3.scene.Node;
 import com.jme3.scene.Spatial;
 import com.jme3.scene.Spatial;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
-import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
-import java.nio.FloatBuffer;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Logger;
+import com.jme3.scene.plugins.ogre.AnimData;
 
 
 /**
 /**
  * This class represents 'Shrink wrap' constraint type in blender.
  * This class represents 'Shrink wrap' constraint type in blender.
  * @author Marcin Roguski (Kaelthas)
  * @author Marcin Roguski (Kaelthas)
  */
  */
 /*package*/ class ConstraintShrinkWrap extends Constraint {
 /*package*/ class ConstraintShrinkWrap extends Constraint {
-	private static final Logger LOGGER = Logger.getLogger(ConstraintShrinkWrap.class.getName());
 	
 	
 	/**
 	/**
 	 * This constructor creates the constraint instance.
 	 * This constructor creates the constraint instance.
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -41,30 +39,31 @@ import java.util.logging.Logger;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintShrinkWrap(Structure constraintStructure, Long boneOMA,
+	public ConstraintShrinkWrap(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 		//loading mesh points (blender ensures that the target is a mesh-object)
 		//loading mesh points (blender ensures that the target is a mesh-object)
 		List<Vector3f> pts = new ArrayList<Vector3f>();
 		List<Vector3f> pts = new ArrayList<Vector3f>();
-		try {
-			Node node = (Node)this.getTarget(LoadedFeatureDataType.LOADED_FEATURE);
-			for(Spatial spatial : node.getChildren()) {
-				if(spatial instanceof Geometry) {
-					Mesh mesh = ((Geometry) spatial).getMesh();
-					FloatBuffer floatBuffer = mesh.getFloatBuffer(Type.Position);
-					for(int i=0;i<floatBuffer.limit();i+=3) {
-						pts.add(new Vector3f(floatBuffer.get(i), floatBuffer.get(i + 1), floatBuffer.get(i + 2)));
-					}
+		Node target = (Node) this.target.getObject();
+		for(Spatial spatial : target.getChildren()) {
+			if(spatial instanceof Geometry) {
+				Mesh mesh = ((Geometry) spatial).getMesh();
+				FloatBuffer floatBuffer = mesh.getFloatBuffer(Type.Position);
+				for(int i=0;i<floatBuffer.limit();i+=3) {
+					pts.add(new Vector3f(floatBuffer.get(i), floatBuffer.get(i + 1), floatBuffer.get(i + 2)));
 				}
 				}
 			}
 			}
-			
-			//modifying traces
-			BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
-			if (track != null) {
+		}
+		
+		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[] translations = track.getTranslations();
 				Vector3f[] translations = track.getTranslations();
 				Quaternion[] rotations = track.getRotations();
 				Quaternion[] rotations = track.getRotations();
 				int maxFrames = translations.length;
 				int maxFrames = translations.length;
@@ -86,13 +85,12 @@ import java.util.logging.Logger;
 				
 				
 				track.setKeyframes(track.getTimes(), translations, rotations, track.getScales());
 				track.setKeyframes(track.getTimes(), translations, rotations, track.getScales());
 			}
 			}
-		} catch (BlenderFileException e) {
-			LOGGER.severe(e.getLocalizedMessage());
 		}
 		}
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_SHRINKWRAP;
+	public void bakeStatic() {
+		// TODO Auto-generated method stub
+		
 	}
 	}
 }
 }

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

@@ -1,12 +1,13 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
 import com.jme3.animation.Animation;
 import com.jme3.animation.Animation;
-import com.jme3.animation.BoneTrack;
+import com.jme3.math.Transform;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
+import com.jme3.scene.plugins.ogre.AnimData;
 
 
 /**
 /**
  * This class represents 'Size like' constraint type in blender.
  * This class represents 'Size like' constraint type in blender.
@@ -18,12 +19,14 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	private static final int SIZELIKE_Z = 0x04;
 	private static final int SIZELIKE_Z = 0x04;
 	private static final int LOCLIKE_OFFSET = 0x80;
 	private static final int LOCLIKE_OFFSET = 0x80;
     
     
+	protected int flag;
+	
 	/**
 	/**
 	 * This constructor creates the constraint instance.
 	 * This constructor creates the constraint instance.
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -33,41 +36,63 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintSizeLike(Structure constraintStructure, Long boneOMA,
+	public ConstraintSizeLike(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
+		
+		flag = ((Number) data.getFieldValue("flag")).intValue();
+		if(blenderContext.getBlenderKey().isFixUpAxis()) {
+			//swapping Y and X limits flag in the bitwise flag
+			int y = flag & SIZELIKE_Y;
+			int z = flag & SIZELIKE_Z;
+			flag &= SIZELIKE_X | LOCLIKE_OFFSET;//clear the other flags to swap them
+			flag |= y << 1;
+			flag |= z >> 1;
+		}
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
-		Vector3f targetScale = this.getTargetLocation();
-		BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
-		if (track != null) {
-			int flag = ((Number) data.getFieldValue("flag")).intValue();
-			Vector3f[] scales = track.getScales();
-			int maxFrames = scales.length;
-			for (int frame = 0; frame < maxFrames; ++frame) {
-				Vector3f offset = Vector3f.ZERO;
-				if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original scale to the copied scale
-					offset = scales[frame].clone();
-				}
-
-				if ((flag & SIZELIKE_X) != 0) {
-					scales[frame].x = targetScale.x;
-				} else if ((flag & SIZELIKE_Y) != 0) {
-					scales[frame].y = targetScale.y;
-				} else if ((flag & SIZELIKE_Z) != 0) {
-					scales[frame].z = targetScale.z;
+	public void bakeDynamic() {
+		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) {
+				BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
+				Vector3f[] scales = track.getScales();
+				int maxFrames = scales.length;
+				for (int frame = 0; frame < maxFrames; ++frame) {
+					this.sizeLike(scales[frame], targetScale, ipo.calculateValue(frame));
 				}
 				}
-				scales[frame].addLocal(offset);//TODO: ipo influence
-				//TODO: add or multiply???
+				track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
 			}
 			}
-			track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
 		}
 		}
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_SIZELIKE;
+	public 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);
+	}
+	
+	private void sizeLike(Vector3f ownerScale, Vector3f targetScale, float influence) {
+		Vector3f offset = Vector3f.ZERO;
+		if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original scale to the copied scale
+			offset = ownerScale.clone();
+		}
+
+		if ((flag & SIZELIKE_X) != 0) {
+			ownerScale.x = targetScale.x * influence + (1.0f - influence) * ownerScale.x;
+		}
+		if ((flag & SIZELIKE_Y) != 0) {
+			ownerScale.y = targetScale.y * influence + (1.0f - influence) * ownerScale.y;
+		}
+		if ((flag & SIZELIKE_Z) != 0) {
+			ownerScale.z = targetScale.z * influence + (1.0f - influence) * ownerScale.z;
+		}
+		ownerScale.addLocal(offset);
 	}
 	}
 }
 }

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

@@ -1,12 +1,13 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
 import com.jme3.animation.Animation;
 import com.jme3.animation.Animation;
-import com.jme3.animation.BoneTrack;
+import com.jme3.math.Transform;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
+import com.jme3.scene.plugins.ogre.AnimData;
 
 
 /**
 /**
  * This class represents 'Size limit' constraint type in blender.
  * This class represents 'Size limit' constraint type in blender.
@@ -20,12 +21,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	private static final int LIMIT_ZMIN = 0x10;
 	private static final int LIMIT_ZMIN = 0x10;
 	private static final int LIMIT_ZMAX = 0x20;
 	private static final int LIMIT_ZMAX = 0x20;
 	
 	
+	protected float[][] limits = new float[3][2];
+    protected int flag;
+	
 	/**
 	/**
 	 * This constructor creates the constraint instance.
 	 * This constructor creates the constraint instance.
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
 	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -35,63 +39,93 @@ import com.jme3.scene.plugins.blender.file.Structure;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintSizeLimit(Structure constraintStructure, Long boneOMA,
+	public ConstraintSizeLimit(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
+		
+		flag = ((Number) data.getFieldValue("flag")).intValue();
+		if(blenderContext.getBlenderKey().isFixUpAxis()) {
+			limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
+			limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
+			limits[2][0] = -((Number) data.getFieldValue("ymin")).floatValue();
+			limits[2][1] = -((Number) data.getFieldValue("ymax")).floatValue();
+			limits[1][0] = ((Number) data.getFieldValue("zmin")).floatValue();
+			limits[1][1] = ((Number) data.getFieldValue("zmax")).floatValue();
+			
+			//swapping Y and X limits flag in the bitwise flag
+			int ymin = flag & LIMIT_YMIN;
+			int ymax = flag & LIMIT_YMAX;
+			int zmin = flag & LIMIT_ZMIN;
+			int zmax = flag & LIMIT_ZMAX;
+			flag &= LIMIT_XMIN | LIMIT_XMAX;//clear the other flags to swap them
+			flag |= ymin << 2;
+			flag |= ymax << 2;
+			flag |= zmin >> 2;
+			flag |= zmax >> 2;
+		} else {
+			limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
+			limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
+			limits[1][0] = ((Number) data.getFieldValue("ymin")).floatValue();
+			limits[1][1] = ((Number) data.getFieldValue("ymax")).floatValue();
+			limits[2][0] = ((Number) data.getFieldValue("zmin")).floatValue();
+			limits[2][1] = ((Number) data.getFieldValue("zmax")).floatValue();
+		}
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
-		BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
-		if (track != null) {
-			int flag = ((Number) data.getFieldValue("flag")).intValue();
-			Vector3f[] scales = track.getScales();
-			int maxFrames = scales.length;
-			for (int frame = 0; frame < maxFrames; ++frame) {
-				float influence = ipo.calculateValue(frame);
-				if ((flag & LIMIT_XMIN) != 0) {
-					float xmin = ((Number) data.getFieldValue("xmin")).floatValue();
-					if (scales[frame].x < xmin) {
-						scales[frame].x -= (scales[frame].x - xmin) * influence;
-					}
-				}
-				if ((flag & LIMIT_XMAX) != 0) {
-					float xmax = ((Number) data.getFieldValue("xmax")).floatValue();
-					if (scales[frame].x > xmax) {
-						scales[frame].x -= (scales[frame].x - xmax) * influence;
-					}
-				}
-				if ((flag & LIMIT_YMIN) != 0) {
-					float ymin = ((Number) data.getFieldValue("ymin")).floatValue();
-					if (scales[frame].y < ymin) {
-						scales[frame].y -= (scales[frame].y - ymin) * influence;
-					}
-				}
-				if ((flag & LIMIT_YMAX) != 0) {
-					float ymax = ((Number) data.getFieldValue("ymax")).floatValue();
-					if (scales[frame].y > ymax) {
-						scales[frame].y -= (scales[frame].y - ymax) * influence;
-					}
+	public void bakeDynamic() {
+		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();
+				int maxFrames = scales.length;
+				for (int frame = 0; frame < maxFrames; ++frame) {
+					this.sizeLimit(scales[frame], ipo.calculateValue(frame));
 				}
 				}
-				if ((flag & LIMIT_ZMIN) != 0) {
-					float zmin = ((Number) data.getFieldValue("zmin")).floatValue();
-					if (scales[frame].z < zmin) {
-						scales[frame].z -= (scales[frame].z - zmin) * influence;
-					}
-				}
-				if ((flag & LIMIT_ZMAX) != 0) {
-					float zmax = ((Number) data.getFieldValue("zmax")).floatValue();
-					if (scales[frame].z > zmax) {
-						scales[frame].z -= (scales[frame].z - zmax) * influence;
-					}
-				}//TODO: consider constraint space !!!
+				track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
 			}
 			}
-			track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
 		}
 		}
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_SIZELIMIT;
+	public void bakeStatic() {
+		Transform ownerTransform = this.owner.getTransform();
+		this.sizeLimit(ownerTransform.getScale(), ipo.calculateValue(0));
+		this.owner.applyTransform(ownerTransform);
+	}
+	
+	private void sizeLimit(Vector3f scale, float influence) {
+		if ((flag & LIMIT_XMIN) != 0) {
+			if (scale.x < limits[0][0]) {
+				scale.x -= (scale.x - limits[0][0]) * influence;
+			}
+		}
+		if ((flag & LIMIT_XMAX) != 0) {
+			if (scale.x > limits[0][1]) {
+				scale.x -= (scale.x - limits[0][1]) * influence;
+			}
+		}
+		if ((flag & LIMIT_YMIN) != 0) {
+			if (scale.y < limits[1][0]) {
+				scale.y -= (scale.y - limits[1][0]) * influence;
+			}
+		}
+		if ((flag & LIMIT_YMAX) != 0) {
+			if (scale.y > limits[1][1]) {
+				scale.y -= (scale.y - limits[1][1]) * influence;
+			}
+		}
+		if ((flag & LIMIT_ZMIN) != 0) {
+			if (scale.z < limits[2][0]) {
+				scale.z -= (scale.z - limits[2][0]) * influence;
+			}
+		}
+		if ((flag & LIMIT_ZMAX) != 0) {
+			if (scale.z > limits[2][1]) {
+				scale.z -= (scale.z - limits[2][1]) * influence;
+			}
+		}
 	}
 	}
 }
 }

+ 50 - 0
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSplineInverseKinematic.java

@@ -0,0 +1,50 @@
+package com.jme3.scene.plugins.blender.constraints;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.scene.plugins.blender.animations.Ipo;
+import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
+import com.jme3.scene.plugins.blender.file.Structure;
+
+/**
+ * The spline inverse kinematic constraint. Available for blender 2.50+.
+ * @author Marcin Roguski (Kaelthas)
+ */
+/*package*/ class ConstraintSplineInverseKinematic extends Constraint {
+	private static final Logger LOGGER = Logger.getLogger(ConstraintSplineInverseKinematic.class.getName());
+	
+	/**
+	 * This constructor creates the constraint instance.
+	 * 
+	 * @param constraintStructure
+	 *            the constraint's structure (bConstraint clss in blender 2.49).
+	 * @param ownerOMA
+	 *            the old memory address of the constraint owner
+	 * @param influenceIpo
+	 *            the ipo curve of the influence factor
+	 * @param blenderContext
+	 *            the blender context
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blender file is somehow
+	 *             corrupted
+	 */
+	public ConstraintSplineInverseKinematic(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo,
+			BlenderContext blenderContext) throws BlenderFileException {
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
+		// TODO Auto-generated constructor stub
+	}
+
+	@Override
+	public void bakeDynamic() {
+		// TODO Auto-generated method stub
+		LOGGER.log(Level.WARNING, "'Splie IK' constraint NOT implemented!");
+	}
+
+	@Override
+	public void bakeStatic() {
+		// TODO Auto-generated method stub
+		LOGGER.log(Level.WARNING, "'Spline IK' constraint NOT implemented!");
+	}
+}

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

@@ -1,6 +1,5 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
-import com.jme3.animation.Animation;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -19,8 +18,8 @@ import java.util.logging.Logger;
 	 * This constructor creates the constraint instance.
 	 * This constructor creates the constraint instance.
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
-	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 *            the constraint's structure
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -30,20 +29,20 @@ import java.util.logging.Logger;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintStretchTo(Structure constraintStructure, Long boneOMA,
-			Ipo influenceIpo, BlenderContext blenderContext)
-			throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+	public ConstraintStretchTo(Structure constraintStructure, Long ownerOMA,
+			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 		// TODO: implement 'Stretch to' constraint
 		// TODO: implement 'Stretch to' constraint
 		LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!");
 		LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!");
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_STRETCHTO;
+	public void bakeStatic() {
+		// TODO: implement 'Stretch to' constraint
+		LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!");
 	}
 	}
 }
 }

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

@@ -1,6 +1,5 @@
 package com.jme3.scene.plugins.blender.constraints;
 package com.jme3.scene.plugins.blender.constraints;
 
 
-import com.jme3.animation.Animation;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -19,8 +18,8 @@ import java.util.logging.Logger;
 	 * This constructor creates the constraint instance.
 	 * This constructor creates the constraint instance.
 	 * 
 	 * 
 	 * @param constraintStructure
 	 * @param constraintStructure
-	 *            the constraint's structure (bConstraint clss in blender 2.49).
-	 * @param boneOMA
+	 *            the constraint's structure
+	 * @param ownerOMA
 	 *            the old memory address of the constraint owner
 	 *            the old memory address of the constraint owner
 	 * @param influenceIpo
 	 * @param influenceIpo
 	 *            the ipo curve of the influence factor
 	 *            the ipo curve of the influence factor
@@ -30,19 +29,20 @@ import java.util.logging.Logger;
 	 *             this exception is thrown when the blender file is somehow
 	 *             this exception is thrown when the blender file is somehow
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
-	public ConstraintTransform(Structure constraintStructure, Long boneOMA,
+	public ConstraintTransform(Structure constraintStructure, Long ownerOMA,
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
 			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
-		super(constraintStructure, boneOMA, influenceIpo, blenderContext);
+		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
 	}
 	}
 
 
 	@Override
 	@Override
-	public void affectAnimation(Animation animation, int targetIndex) {
+	public void bakeDynamic() {
 		// TODO: implement 'Transform' constraint
 		// TODO: implement 'Transform' constraint
 		LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
 		LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
 	}
 	}
 	
 	
 	@Override
 	@Override
-	public ConstraintType getType() {
-		return ConstraintType.CONSTRAINT_TYPE_TRANSFORM;
+	public void bakeStatic() {
+		// TODO: implement 'Transform' constraint
+		LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
 	}
 	}
 }
 }

+ 0 - 145
engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintType.java

@@ -1,145 +0,0 @@
-package com.jme3.scene.plugins.blender.constraints;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Constraint types. Definitions taken from blender sources, file: DNA_constraint_types.h. Constraint id's the same as
- * used in blender. The constraints might have duplicated type ids, depending on the blender version. The purpose of
- * this enum is to combine class name and the constraint type (id).
- * @author Marcin Roguski
- */
-public enum ConstraintType {
-    /* Invalid/legacy constraint */
-
-    CONSTRAINT_TYPE_NULL(0, "bNullConstraint"),
-    /* Unimplemented non longer :) - during constraints recode, Aligorith */
-    CONSTRAINT_TYPE_CHILDOF(1, "bChildOfConstraint"),
-    CONSTRAINT_TYPE_KINEMATIC(3, "bKinematicConstraint"),
-    CONSTRAINT_TYPE_FOLLOWPATH(4, "bFollowPathConstraint"),
-    /* Unimplemented no longer :) - Aligorith */
-    CONSTRAINT_TYPE_ROTLIMIT(5, "bRotLimitConstraint"),
-    /* Unimplemented no longer :) - Aligorith */
-    CONSTRAINT_TYPE_LOCLIMIT(6, "bLocLimitConstraint"),
-    /* Unimplemented no longer :) - Aligorith */
-    CONSTRAINT_TYPE_SIZELIMIT(7, "bSizeLimitConstraint"),
-    CONSTRAINT_TYPE_ROTLIKE(8, "bRotateLikeConstraint"),
-    CONSTRAINT_TYPE_LOCLIKE(9, "bLocateLikeConstraint"),
-    CONSTRAINT_TYPE_SIZELIKE(10, "bSizeLikeConstraint"),
-    /* Unimplemented no longer :) - Aligorith. Scripts */
-    CONSTRAINT_TYPE_PYTHON(11, "bPythonConstraint"),
-    CONSTRAINT_TYPE_ACTION(12, "bActionConstraint"),
-    /* New Tracking constraint that locks an axis in place - theeth */
-    CONSTRAINT_TYPE_LOCKTRACK(13, "bLockTrackConstraint"),
-    /* limit distance */
-    CONSTRAINT_TYPE_DISTLIMIT(14, "bDistLimitConstraint"),
-    /* claiming this to be mine :) is in tuhopuu bjornmose */
-    CONSTRAINT_TYPE_STRETCHTO(15, "bStretchToConstraint"),
-    /* floor constraint */
-    CONSTRAINT_TYPE_MINMAX(16, "bMinMaxConstraint"),
-    /* rigidbody constraint */
-    CONSTRAINT_TYPE_RIGIDBODYJOINT(17, "bRigidBodyConstraint"),
-    /* clampto constraint */
-    CONSTRAINT_TYPE_CLAMPTO(18, "bClampToConstraint"),
-    /* transformation (loc/rot/size -> loc/rot/size) constraint */
-    CONSTRAINT_TYPE_TRANSFORM(19, "bTransformConstraint"),
-    /* shrinkwrap (loc/rot) constraint */
-    CONSTRAINT_TYPE_SHRINKWRAP(20, "bShrinkwrapConstraint");
-    /** The constraint's id (in blender known as 'type'). */
-    private int constraintId;
-    /** The name of constraint class used by blender. */
-    private String className;
-    /** The map containing class names and types of constraints. */
-    private static final Map<String, ConstraintType> typesMap = new HashMap<String, ConstraintType>(ConstraintType.values().length);
-    /** The map containing class names and types of constraints. */
-    private static final Map<Integer, ConstraintType> idsMap = new HashMap<Integer, ConstraintType>(ConstraintType.values().length);
-
-    static {
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_NULL.constraintId), CONSTRAINT_TYPE_NULL);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_CHILDOF.constraintId), CONSTRAINT_TYPE_CHILDOF);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_KINEMATIC.constraintId), CONSTRAINT_TYPE_KINEMATIC);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_FOLLOWPATH.constraintId), CONSTRAINT_TYPE_FOLLOWPATH);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ROTLIMIT.constraintId), CONSTRAINT_TYPE_ROTLIMIT);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCLIMIT.constraintId), CONSTRAINT_TYPE_LOCLIMIT);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SIZELIMIT.constraintId), CONSTRAINT_TYPE_SIZELIMIT);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ROTLIKE.constraintId), CONSTRAINT_TYPE_ROTLIKE);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCLIKE.constraintId), CONSTRAINT_TYPE_LOCLIKE);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SIZELIKE.constraintId), CONSTRAINT_TYPE_SIZELIKE);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_PYTHON.constraintId), CONSTRAINT_TYPE_PYTHON);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ACTION.constraintId), CONSTRAINT_TYPE_ACTION);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCKTRACK.constraintId), CONSTRAINT_TYPE_LOCKTRACK);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_DISTLIMIT.constraintId), CONSTRAINT_TYPE_DISTLIMIT);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_STRETCHTO.constraintId), CONSTRAINT_TYPE_STRETCHTO);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_MINMAX.constraintId), CONSTRAINT_TYPE_MINMAX);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_RIGIDBODYJOINT.constraintId), CONSTRAINT_TYPE_RIGIDBODYJOINT);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_CLAMPTO.constraintId), CONSTRAINT_TYPE_CLAMPTO);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_TRANSFORM.constraintId), CONSTRAINT_TYPE_TRANSFORM);
-        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SHRINKWRAP.constraintId), CONSTRAINT_TYPE_SHRINKWRAP);
-    }
-
-    /**
-     * Constructor. Stores constraint type and class name.
-     * @param constraintId
-     *        the constraint's type
-     * @param className
-     *        the constraint's type name
-     */
-    private ConstraintType(int constraintId, String className) {
-        this.constraintId = constraintId;
-        this.className = className;
-    }
-
-    /**
-     * This method returns the type by given constraint id.
-     * @param constraintId
-     *        the id of the constraint
-     * @return the constraint type enum value
-     */
-    public static ConstraintType valueOf(int constraintId) {
-        return idsMap.get(Integer.valueOf(constraintId));
-    }
-
-    /**
-     * This method returns the constraint's id (type).
-     * @return the constraint's id (type)
-     */
-    public int getConstraintId() {
-        return constraintId;
-    }
-
-    /**
-     * This method returns the constraint's class name.
-     * @return the constraint's class name
-     */
-    public String getClassName() {
-        return className;
-    }
-
-    /**
-     * This method returns constraint enum type by the given class name.
-     * @param className
-     *        the blender's constraint class name
-     * @return the constraint enum type of the specified class name
-     */
-    public static ConstraintType getByBlenderClassName(String className) {
-        ConstraintType result = typesMap.get(className);
-        if (result == null) {
-            ConstraintType[] constraints = ConstraintType.values();
-            for (ConstraintType constraint : constraints) {
-                if (constraint.className.equals(className)) {
-                    return constraint;
-                }
-            }
-        }
-        return result;
-    }
-
-    /**
-     * This method returns the type value of the last defined constraint. It can be used for allocating tables for
-     * storing constraint procedures since not all type values from 0 to the last value are used.
-     * @return the type value of the last defined constraint
-     */
-    public static int getLastDefinedTypeValue() {
-        return CONSTRAINT_TYPE_SHRINKWRAP.getConstraintId();
-    }
-}

+ 274 - 0
engine/src/blender/com/jme3/scene/plugins/blender/constraints/Feature.java

@@ -0,0 +1,274 @@
+package com.jme3.scene.plugins.blender.constraints;
+
+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.Spatial;
+import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
+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;
+
+/**
+ * This class represents either owner or target of the constraint. It has the
+ * common methods that take the evalueation space of the feature.
+ * 
+ * @author Marcin Roguski (Kaelthas)
+ */
+/* package */class Feature {
+	/** The evalueation space. */
+	protected Space				space;
+	/** Old memory address of the feature. */
+	protected Long				oma;
+	/** The spatial that is hold by the Feature. */
+	protected Spatial			spatial;
+	/** The bone that is hold by the Feature. */
+	protected Bone				bone;
+	/** The blender context. */
+	protected BlenderContext	blenderContext;
+
+	/**
+	 * Constructs the feature based on spatial.
+	 * 
+	 * @param spatial
+	 *            the spatial
+	 * @param space
+	 *            the spatial's evaluation space
+	 * @param oma
+	 *            the spatial's old memory address
+	 * @param blenderContext
+	 *            the blender context
+	 */
+	public Feature(Spatial spatial, Space space, Long oma, BlenderContext blenderContext) {
+		this.space = space;
+		this.oma = oma;
+		this.spatial = spatial;
+		this.blenderContext = blenderContext;
+	}
+
+	/**
+	 * Constructs the feature based on bone.
+	 * 
+	 * @param bone
+	 *            the bone
+	 * @param space
+	 *            the bone evaluation space
+	 * @param oma
+	 *            the bone old memory address
+	 * @param blenderContext
+	 *            the blender context
+	 */
+	public Feature(Bone bone, Space space, Long oma, BlenderContext blenderContext) {
+		this.space = space;
+		this.oma = oma;
+		this.blenderContext = blenderContext;
+		this.bone = bone;
+	}
+
+	/**
+	 * @return the feature's old memory address
+	 */
+	public Long getOma() {
+		return oma;
+	}
+
+	/**
+	 * @return the object held by the feature (either bone or spatial)
+	 */
+	public Object getObject() {
+		if (spatial != null) {
+			return spatial;
+		}
+		return bone;
+	}
+
+	/**
+	 * @return the feature's transform depending on the evaluation space
+	 */
+	@SuppressWarnings("unchecked")
+	public Transform getTransform() {
+		if (spatial != null) {
+			switch (space) {
+				case CONSTRAINT_SPACE_LOCAL:
+					Structure targetStructure = (Structure) blenderContext.getLoadedFeature(oma, LoadedFeatureDataType.LOADED_STRUCTURE);
+
+					DynamicArray<Number> locArray = ((DynamicArray<Number>) targetStructure.getFieldValue("loc"));
+					Vector3f loc = new Vector3f(locArray.get(0).floatValue(), locArray.get(1).floatValue(), locArray.get(2).floatValue());
+					DynamicArray<Number> rotArray = ((DynamicArray<Number>) targetStructure.getFieldValue("rot"));
+					Quaternion rot = new Quaternion(new float[] { rotArray.get(0).floatValue(), rotArray.get(1).floatValue(), rotArray.get(2).floatValue() });
+					DynamicArray<Number> sizeArray = ((DynamicArray<Number>) targetStructure.getFieldValue("size"));
+					Vector3f size = new Vector3f(sizeArray.get(0).floatValue(), sizeArray.get(1).floatValue(), sizeArray.get(2).floatValue());
+
+					if (blenderContext.getBlenderKey().isFixUpAxis()) {
+						float y = loc.y;
+						loc.y = loc.z;
+						loc.z = -y;
+
+						y = rot.getY();
+						float z = rot.getZ();
+						rot.set(rot.getX(), z, -y, rot.getW());
+
+						y = size.y;
+						size.y = size.z;
+						size.z = y;
+					}
+
+					Transform result = new Transform(loc, rot);
+					result.setScale(size);
+					return result;
+				case CONSTRAINT_SPACE_WORLD:
+					return spatial.getWorldTransform();
+				default:
+					throw new IllegalStateException("Invalid space type for target object: " + space.toString());
+			}
+		}
+		// Bone
+		switch (space) {
+			case CONSTRAINT_SPACE_LOCAL:
+				Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
+				localTransform.setScale(bone.getLocalScale());
+				return localTransform;
+			case CONSTRAINT_SPACE_WORLD:
+				if(bone.getParent()!=null) {
+					System.out.println(bone.getParent().getLocalRotation());
+					System.out.println(bone.getParent().getWorldBindRotation());
+					System.out.println(bone.getParent().getModelSpaceRotation());
+					System.out.println(bone.getParent().getWorldBindInverseRotation());
+				}
+				
+				Transform worldTransform = new Transform(bone.getWorldBindPosition(), bone.getWorldBindRotation());
+				worldTransform.setScale(bone.getWorldBindScale());
+				return worldTransform;
+			case CONSTRAINT_SPACE_POSE:
+				// TODO
+				return null;
+			case CONSTRAINT_SPACE_PARLOCAL:
+				Transform parentLocalTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
+				parentLocalTransform.setScale(bone.getLocalScale());
+				return parentLocalTransform;
+			default:
+				throw new IllegalStateException("Invalid space type for target object: " + space.toString());
+		}
+	}
+
+	/**
+	 * This method applies the given transform to the feature in the proper
+	 * evaluation space.
+	 * 
+	 * @param transform
+	 *            the transform to be applied
+	 */
+	public void applyTransform(Transform transform) {
+		if (spatial != null) {
+			switch (space) {
+				case CONSTRAINT_SPACE_LOCAL:
+					Transform ownerLocalTransform = spatial.getLocalTransform();
+					ownerLocalTransform.getTranslation().addLocal(transform.getTranslation());
+					ownerLocalTransform.getRotation().multLocal(transform.getRotation());
+					ownerLocalTransform.getScale().multLocal(transform.getScale());
+					break;
+				case CONSTRAINT_SPACE_WORLD:
+					Matrix4f m = this.getParentWorldTransformMatrix();
+					m.invertLocal();
+					Matrix4f matrix = this.toMatrix(transform);
+					m.multLocal(matrix);
+
+					float scaleX = (float) Math.sqrt(m.m00 * m.m00 + m.m10 * m.m10 + m.m20 * m.m20);
+					float scaleY = (float) Math.sqrt(m.m01 * m.m01 + m.m11 * m.m11 + m.m21 * m.m21);
+					float scaleZ = (float) Math.sqrt(m.m02 * m.m02 + m.m12 * m.m12 + m.m22 * m.m22);
+
+					transform.setTranslation(m.toTranslationVector());
+					transform.setRotation(m.toRotationQuat());
+					transform.setScale(scaleX, scaleY, scaleZ);
+					spatial.setLocalTransform(transform);
+					break;
+				case CONSTRAINT_SPACE_PARLOCAL:
+				case CONSTRAINT_SPACE_POSE:
+					throw new IllegalStateException("Invalid space type (" + space.toString() + ") for owner object.");
+				default:
+					throw new IllegalStateException("Invalid space type for target object: " + space.toString());
+			}
+		} else {// Bone
+			switch (space) {
+				case CONSTRAINT_SPACE_LOCAL:
+					bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale());
+					break;
+				case CONSTRAINT_SPACE_WORLD:
+					Matrix4f m = this.getParentWorldTransformMatrix();
+					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());
+					break;
+				case CONSTRAINT_SPACE_PARLOCAL:
+					Vector3f parentLocalTranslation = bone.getLocalPosition().add(transform.getTranslation());
+					Quaternion parentLocalRotation = bone.getLocalRotation().mult(transform.getRotation());
+					bone.setBindTransforms(parentLocalTranslation, parentLocalRotation, transform.getScale());
+					break;
+				case CONSTRAINT_SPACE_POSE:
+					// TODO:
+					break;
+				default:
+					throw new IllegalStateException("Invalid space type for target object: " + space.toString());
+			}
+		}
+	}
+
+	/**
+	 * @return world transform matrix of the feature
+	 */
+	public Matrix4f getWorldTransformMatrix() {
+		if (spatial != null) {
+			Matrix4f result = new Matrix4f();
+			Transform t = spatial.getWorldTransform();
+			result.setTransform(t.getTranslation(), t.getScale(), t.getRotation().toRotationMatrix());
+			return result;
+		}
+		// Bone
+		Matrix4f result = new Matrix4f();
+		result.setTransform(bone.getWorldBindPosition(), bone.getWorldBindScale(), bone.getWorldBindRotation().toRotationMatrix());
+		return result;
+	}
+
+	/**
+	 * @return world transform matrix of the feature's parent or identity matrix
+	 *         if the feature has no parent
+	 */
+	public Matrix4f getParentWorldTransformMatrix() {
+		Matrix4f result = new Matrix4f();
+		if (spatial != null) {
+			if (spatial.getParent() != null) {
+				Transform t = spatial.getParent().getWorldTransform();
+				result.setTransform(t.getTranslation(), t.getScale(), t.getRotation().toRotationMatrix());
+			}
+		} else {// Bone
+			Bone parent = bone.getParent();
+			if (parent != null) {
+				result.setTransform(parent.getWorldBindPosition(), parent.getWorldBindScale(), parent.getWorldBindRotation().toRotationMatrix());
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * Converts given transform to the matrix.
+	 * 
+	 * @param transform
+	 *            the transform to be converted
+	 * @return 4x4 matri that represents the given transform
+	 */
+	protected Matrix4f toMatrix(Transform transform) {
+		Matrix4f result = Matrix4f.IDENTITY;
+		if (transform != null) {
+			result = new Matrix4f();
+			result.setTranslation(transform.getTranslation());
+			result.setRotationQuaternion(transform.getRotation());
+			result.setScale(transform.getScale());
+		}
+		return result;
+	}
+}

+ 5 - 3
engine/src/blender/com/jme3/scene/plugins/blender/curves/CurvesHelper.java

@@ -43,9 +43,11 @@ public class CurvesHelper extends AbstractBlenderHelper {
      * different blender versions.
      * different blender versions.
      * @param blenderVersion
      * @param blenderVersion
      *        the version read from the blend file
      *        the version read from the blend file
+     * @param fixUpAxis
+     *        a variable that indicates if the Y asxis is the UP axis or not
      */
      */
-    public CurvesHelper(String blenderVersion) {
-        super(blenderVersion);
+    public CurvesHelper(String blenderVersion, boolean fixUpAxis) {
+        super(blenderVersion, fixUpAxis);
     }
     }
 
 
     /**
     /**
@@ -457,7 +459,7 @@ public class CurvesHelper extends AbstractBlenderHelper {
                     temp[1] = vertices[j * 3 + 1] * taperScale;
                     temp[1] = vertices[j * 3 + 1] * taperScale;
                     temp[2] = 0;
                     temp[2] = 0;
                     m.mult(temp);//the result is stored in the array
                     m.mult(temp);//the result is stored in the array
-                    if (fixUpAxis) {
+                    if (fixUpAxis) {//TODO: not the other way ???
                         verts[j] = new Vector3f(temp[0], temp[1], temp[2]);
                         verts[j] = new Vector3f(temp[0], temp[1], temp[2]);
                     } else {
                     } else {
                         verts[j] = new Vector3f(temp[0], temp[2], -temp[1]);
                         verts[j] = new Vector3f(temp[0], temp[2], -temp[1]);

+ 4 - 2
engine/src/blender/com/jme3/scene/plugins/blender/lights/LightHelper.java

@@ -59,9 +59,11 @@ public class LightHelper extends AbstractBlenderHelper {
      * different blender versions.
      * different blender versions.
      * @param blenderVersion
      * @param blenderVersion
      *        the version read from the blend file
      *        the version read from the blend file
+     * @param fixUpAxis
+     *        a variable that indicates if the Y asxis is the UP axis or not
      */
      */
-    public LightHelper(String blenderVersion) {
-        super(blenderVersion);
+    public LightHelper(String blenderVersion, boolean fixUpAxis) {
+        super(blenderVersion, fixUpAxis);
     }
     }
 
 
     public Light toLight(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
     public Light toLight(Structure structure, BlenderContext blenderContext) throws BlenderFileException {

+ 4 - 4
engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialHelper.java

@@ -45,7 +45,6 @@ import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
-import com.jme3.scene.plugins.blender.textures.TextureHelper;
 import com.jme3.shader.VarType;
 import com.jme3.shader.VarType;
 import com.jme3.texture.Image;
 import com.jme3.texture.Image;
 import com.jme3.texture.Image.Format;
 import com.jme3.texture.Image.Format;
@@ -101,9 +100,11 @@ public class MaterialHelper extends AbstractBlenderHelper {
 	 * 
 	 * 
 	 * @param blenderVersion
 	 * @param blenderVersion
 	 *        the version read from the blend file
 	 *        the version read from the blend file
+	 * @param fixUpAxis
+     *        a variable that indicates if the Y asxis is the UP axis or not
 	 */
 	 */
-	public MaterialHelper(String blenderVersion) {
-		super(blenderVersion);
+	public MaterialHelper(String blenderVersion, boolean fixUpAxis) {
+		super(blenderVersion, false);
 		// setting alpha masks
 		// setting alpha masks
 		alphaMasks.put(ALPHA_MASK_NONE, new IAlphaMask() {
 		alphaMasks.put(ALPHA_MASK_NONE, new IAlphaMask() {
 			@Override
 			@Override
@@ -204,7 +205,6 @@ public class MaterialHelper extends AbstractBlenderHelper {
 		// texture
 		// texture
 		Type colorTextureType = null;
 		Type colorTextureType = null;
 		Map<String, Texture> texturesMap = new HashMap<String, Texture>();
 		Map<String, Texture> texturesMap = new HashMap<String, Texture>();
-		TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
 		for(Entry<Number, Texture> textureEntry : materialContext.loadedTextures.entrySet()) {
 		for(Entry<Number, Texture> textureEntry : materialContext.loadedTextures.entrySet()) {
 			int mapto = textureEntry.getKey().intValue();
 			int mapto = textureEntry.getKey().intValue();
 			Texture texture = textureEntry.getValue();
 			Texture texture = textureEntry.getValue();

+ 4 - 2
engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java

@@ -74,9 +74,11 @@ public class MeshHelper extends AbstractBlenderHelper {
      * 
      * 
      * @param blenderVersion
      * @param blenderVersion
      *            the version read from the blend file
      *            the version read from the blend file
+     * @param fixUpAxis
+     *        a variable that indicates if the Y asxis is the UP axis or not
      */
      */
-    public MeshHelper(String blenderVersion) {
-        super(blenderVersion);
+    public MeshHelper(String blenderVersion, boolean fixUpAxis) {
+        super(blenderVersion,fixUpAxis);
     }
     }
 
 
     /**
     /**

+ 180 - 130
engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java

@@ -1,6 +1,20 @@
 package com.jme3.scene.plugins.blender.modifiers;
 package com.jme3.scene.plugins.blender.modifiers;
 
 
-import com.jme3.animation.*;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.Animation;
+import com.jme3.animation.Bone;
+import com.jme3.animation.BoneTrack;
+import com.jme3.animation.Skeleton;
+import com.jme3.animation.SkeletonControl;
 import com.jme3.math.Matrix4f;
 import com.jme3.math.Matrix4f;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.Mesh;
@@ -12,8 +26,8 @@ import com.jme3.scene.VertexBuffer.Usage;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
 import com.jme3.scene.plugins.blender.animations.ArmatureHelper;
 import com.jme3.scene.plugins.blender.animations.ArmatureHelper;
-import com.jme3.scene.plugins.blender.animations.ArmatureHelper.BoneTransformationData;
 import com.jme3.scene.plugins.blender.constraints.Constraint;
 import com.jme3.scene.plugins.blender.constraints.Constraint;
+import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.FileBlockHeader;
 import com.jme3.scene.plugins.blender.file.FileBlockHeader;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Pointer;
@@ -22,14 +36,6 @@ import com.jme3.scene.plugins.blender.meshes.MeshContext;
 import com.jme3.scene.plugins.blender.objects.ObjectHelper;
 import com.jme3.scene.plugins.blender.objects.ObjectHelper;
 import com.jme3.scene.plugins.ogre.AnimData;
 import com.jme3.scene.plugins.ogre.AnimData;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.BufferUtils;
-import java.nio.ByteBuffer;
-import java.nio.FloatBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 
 
 /**
 /**
  * This modifier allows to add bone animation to the object.
  * This modifier allows to add bone animation to the object.
@@ -37,34 +43,30 @@ import java.util.logging.Logger;
  * @author Marcin Roguski (Kaelthas)
  * @author Marcin Roguski (Kaelthas)
  */
  */
 /* package */class ArmatureModifier extends Modifier {
 /* package */class ArmatureModifier extends Modifier {
-	private static final Logger LOGGER = Logger.getLogger(ArmatureModifier.class.getName());
-	private static final int	MAXIMUM_WEIGHTS_PER_VERTEX	= 4;	// have no idea why 4, could someone please explain ?
-        //@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 it's up to you. You'll have to deternine the max weight according to the provided blend file
-        //I added a check to avoid crash when loading a model that has more than 4 weight per vertex on line 258
-        //If you decide to remove this limitation, remove this code.
-        //Rémy
-        
-	
+	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
+	// it's up to you. You'll have to deternine the max weight according to the
+	// provided blend file
+	// I added a check to avoid crash when loading a model that has more than 4
+	// weight per vertex on line 258
+	// If you decide to remove this limitation, remove this code.
+	// Rémy
+
 	/** Loaded animation data. */
 	/** Loaded animation data. */
-	private AnimData animData;
-	/** Old memory address of the armature's object. */
-	private Long armatureObjectOMA;
+	private AnimData				animData;
 	/** Old memory address of the mesh that will have the skeleton applied. */
 	/** Old memory address of the mesh that will have the skeleton applied. */
-	private Long meshOMA;
-	/** The maxiumum amount of bone groups applied to a single vertex (max = MAXIMUM_WEIGHTS_PER_VERTEX). */
-	private int boneGroups;
-	/** The weights of vertices. */
-	private VertexBuffer verticesWeights;
-	/** The indexes of bones applied to vertices. */
-	private VertexBuffer verticesWeightsIndices;
-	
+	private Long					meshOMA;
 	/**
 	/**
-	 * This constructor is only temporary. It will be removed when object
-	 * animation is implemented in jme. TODO!!!!!!!
+	 * The maxiumum amount of bone groups applied to a single vertex (max = MAXIMUM_WEIGHTS_PER_VERTEX).
 	 */
 	 */
-	/* package */ArmatureModifier() {
-	}
+	private int						boneGroups;
+	/** The weights of vertices. */
+	private VertexBuffer			verticesWeights;
+	/** The indexes of bones applied to vertices. */
+	private VertexBuffer			verticesWeightsIndices;
 
 
 	/**
 	/**
 	 * This constructor reads animation data from the object structore. The
 	 * This constructor reads animation data from the object structore. The
@@ -81,75 +83,94 @@ import java.util.logging.Logger;
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
 	public ArmatureModifier(Structure objectStructure, Structure modifierStructure, BlenderContext blenderContext) throws BlenderFileException {
 	public ArmatureModifier(Structure objectStructure, Structure modifierStructure, BlenderContext blenderContext) throws BlenderFileException {
-		if(this.validate(modifierStructure, blenderContext)) {
+		if (this.validate(modifierStructure, blenderContext)) {
 			Pointer pArmatureObject = (Pointer) modifierStructure.getFieldValue("object");
 			Pointer pArmatureObject = (Pointer) modifierStructure.getFieldValue("object");
 			if (pArmatureObject.isNotNull()) {
 			if (pArmatureObject.isNotNull()) {
-				ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
 				ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
 				ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
-				
+
 				Structure armatureObject = pArmatureObject.fetchData(blenderContext.getInputStream()).get(0);
 				Structure armatureObject = pArmatureObject.fetchData(blenderContext.getInputStream()).get(0);
-				this.armatureObjectOMA = armatureObject.getOldMemoryAddress();
-	
-				//read skeleton
-				// changing bones matrices so that they fit the current object
-				Structure armatureStructure = ((Pointer)armatureObject.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
-				Structure bonebase = (Structure) armatureStructure.getFieldValue("bonebase");
-		        List<Structure> bonesStructures = bonebase.evaluateListBase(blenderContext);
-		        for (Structure boneStructure : bonesStructures) {
-		            BoneTransformationData rootBoneTransformationData = armatureHelper.readBoneAndItsChildren(boneStructure, null, blenderContext);
-		            armatureHelper.addBoneDataRoot(rootBoneTransformationData);
-		        }
-				Matrix4f armatureObjectMatrix = objectHelper.getTransformationMatrix(armatureObject);
-				Matrix4f inverseMeshObjectMatrix = objectHelper.getTransformationMatrix(objectStructure).invert();
-				Matrix4f additionalRootBoneTransformation = inverseMeshObjectMatrix.multLocal(armatureObjectMatrix);
-				Bone[] bones = armatureHelper.buildBonesStructure(Long.valueOf(0L), additionalRootBoneTransformation);
-	
-				//read mesh indexes
-				Structure meshStructure = ((Pointer)objectStructure.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
-				this.meshOMA = meshStructure.getOldMemoryAddress();
-				this.readVerticesWeightsData(objectStructure, meshStructure, blenderContext);
+
+				// load skeleton
+				Structure armatureStructure = ((Pointer) armatureObject.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
+
+				Structure pose = ((Pointer) armatureObject.getFieldValue("pose")).fetchData(blenderContext.getInputStream()).get(0);
+				List<Structure> chanbase = ((Structure) pose.getFieldValue("chanbase")).evaluateListBase(blenderContext);
+
+				Map<Long, Structure> bonesPoseChannels = new HashMap<Long, Structure>(chanbase.size());
+				for (Structure poseChannel : chanbase) {
+					Pointer pBone = (Pointer) poseChannel.getFieldValue("bone");
+					bonesPoseChannels.put(pBone.getOldMemoryAddress(), poseChannel);
+				}
+
+				ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
+				Matrix4f armatureObjectMatrix = objectHelper.getMatrix(armatureObject, "obmat", true);//TODO: fixupaxis ???
+				Matrix4f inverseMeshObjectMatrix = objectHelper.getMatrix(objectStructure, "obmat", true).invertLocal();
+				Matrix4f objectToArmatureTransformation = armatureObjectMatrix.multLocal(inverseMeshObjectMatrix);
 				
 				
-				//read animations
+				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()]));
+
+				// read mesh indexes
+				Structure meshStructure = ((Pointer) objectStructure.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
+				this.meshOMA = meshStructure.getOldMemoryAddress();
+				this.readVerticesWeightsData(objectStructure, meshStructure, skeleton, blenderContext);
+
+				// read animations
 				ArrayList<Animation> animations = new ArrayList<Animation>();
 				ArrayList<Animation> animations = new ArrayList<Animation>();
 				List<FileBlockHeader> actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
 				List<FileBlockHeader> actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
-				if(actionHeaders != null) {//it may happen that the model has armature with no actions
+				if (actionHeaders != null) {// it may happen that the model has
+											// armature with no actions
 					for (FileBlockHeader header : actionHeaders) {
 					for (FileBlockHeader header : actionHeaders) {
 						Structure actionStructure = header.getStructure(blenderContext);
 						Structure actionStructure = header.getStructure(blenderContext);
 						String actionName = actionStructure.getName();
 						String actionName = actionStructure.getName();
-						
-						BoneTrack[] tracks = armatureHelper.getTracks(actionStructure, blenderContext);
-						//determining the animation  time
+
+						BoneTrack[] tracks = armatureHelper.getTracks(actionStructure, skeleton, blenderContext);
+						// determining the animation time
 						float maximumTrackLength = 0;
 						float maximumTrackLength = 0;
-						for(BoneTrack track : tracks) {
+						for (BoneTrack track : tracks) {
 							float length = track.getLength();
 							float length = track.getLength();
-							if(length > maximumTrackLength) {
+							if (length > maximumTrackLength) {
 								maximumTrackLength = length;
 								maximumTrackLength = length;
 							}
 							}
 						}
 						}
-						
+
 						Animation boneAnimation = new Animation(actionName, maximumTrackLength);
 						Animation boneAnimation = new Animation(actionName, maximumTrackLength);
 						boneAnimation.setTracks(tracks);
 						boneAnimation.setTracks(tracks);
 						animations.add(boneAnimation);
 						animations.add(boneAnimation);
 					}
 					}
 				}
 				}
-				animData = new AnimData(new Skeleton(bones), animations);
+				animData = new AnimData(skeleton, animations);
+
+				// store the animation data for each bone
+				for (Structure boneStructure : bonebase) {
+					blenderContext.setAnimData(boneStructure.getOldMemoryAddress(), animData);
+				}
+
+				// loading constraints connected with this object
+				ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
+				constraintHelper.loadConstraints(armatureObject, blenderContext);
 			}
 			}
 		}
 		}
 	}
 	}
-	
+
 	@Override
 	@Override
 	@SuppressWarnings("unchecked")
 	@SuppressWarnings("unchecked")
 	public Node apply(Node node, BlenderContext blenderContext) {
 	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());
 			LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName());
-		}//if invalid, animData will be null
-		if(animData == null) {
+		}// if invalid, animData will be null
+		if (animData == null) {
 			return node;
 			return node;
 		}
 		}
-		
+
 		// setting weights for bones
 		// setting weights for bones
 		List<Geometry> geomList = (List<Geometry>) blenderContext.getLoadedFeature(this.meshOMA, LoadedFeatureDataType.LOADED_FEATURE);
 		List<Geometry> geomList = (List<Geometry>) blenderContext.getLoadedFeature(this.meshOMA, LoadedFeatureDataType.LOADED_FEATURE);
-		for(Geometry geom : geomList) {
+		for (Geometry geom : geomList) {
 			Mesh mesh = geom.getMesh();
 			Mesh mesh = geom.getMesh();
 			if (this.verticesWeights != null) {
 			if (this.verticesWeights != null) {
 				mesh.setMaxNumWeights(this.boneGroups);
 				mesh.setMaxNumWeights(this.boneGroups);
@@ -157,85 +178,109 @@ import java.util.logging.Logger;
 				mesh.setBuffer(this.verticesWeightsIndices);
 				mesh.setBuffer(this.verticesWeightsIndices);
 			}
 			}
 		}
 		}
-		
+
+		// applying bone transforms before constraints are baked
+		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.bakeDynamic();
+					constraint.bakeStatic();
+				}
+			}
+		}
+
+		// applying animations
 		ArrayList<Animation> animList = animData.anims;
 		ArrayList<Animation> animList = animData.anims;
 		if (animList != null && animList.size() > 0) {
 		if (animList != null && animList.size() > 0) {
-			List<Constraint> constraints = blenderContext.getConstraints(this.armatureObjectOMA);
-			HashMap<String, Animation> anims = new HashMap<String, Animation>();
+			HashMap<String, Animation> anims = new HashMap<String, Animation>(animList.size());
 			for (int i = 0; i < animList.size(); ++i) {
 			for (int i = 0; i < animList.size(); ++i) {
-				Animation animation = (Animation) animList.get(i).clone();
-
-				// baking constraints into animations
-				if (constraints != null && constraints.size() > 0) {
-					for (Constraint constraint : constraints) {
-						Long boneOMA = constraint.getBoneOMA();
-						Bone bone = (Bone) blenderContext.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);
-						int targetIndex = bone==null ? 0 : animData.skeleton.getBoneIndex(bone);//bone==null may mean the object animation
-						constraint.affectAnimation(animation, targetIndex);
-					}
-				}
-
+				Animation animation = animList.get(i);
 				anims.put(animation.getName(), animation);
 				anims.put(animation.getName(), animation);
 			}
 			}
 
 
-			// applying the control to the node
-			SkeletonControl skeletonControl = new SkeletonControl(animData.skeleton);
 			AnimControl control = new AnimControl(animData.skeleton);
 			AnimControl control = new AnimControl(animData.skeleton);
-
 			control.setAnimations(anims);
 			control.setAnimations(anims);
 			node.addControl(control);
 			node.addControl(control);
-			node.addControl(skeletonControl);
+			node.addControl(new SkeletonControl(animData.skeleton));
 		}
 		}
+
 		return node;
 		return node;
 	}
 	}
-	
+
 	/**
 	/**
 	 * This method reads mesh indexes
 	 * This method reads mesh indexes
-	 * @param objectStructure structure of the object that has the armature modifier applied
-	 * @param meshStructure the structure of the object's mesh
-	 * @param blenderContext the blender context
+	 * 
+	 * @param objectStructure
+	 *            structure of the object that has the armature modifier applied
+	 * @param meshStructure
+	 *            the structure of the object's mesh
+	 * @param blenderContext
+	 *            the blender context
 	 * @throws BlenderFileException
 	 * @throws BlenderFileException
-	 * 		   this exception is thrown when the blend file structure is somehow invalid or corrupted
+	 *             this exception is thrown when the blend file structure is
+	 *             somehow invalid or corrupted
 	 */
 	 */
-	private void readVerticesWeightsData(Structure objectStructure, Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
+	private void readVerticesWeightsData(Structure objectStructure, Structure meshStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
 		ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
 		ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
 		Structure defBase = (Structure) objectStructure.getFieldValue("defbase");
 		Structure defBase = (Structure) objectStructure.getFieldValue("defbase");
-		Map<Integer, Integer> groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, blenderContext);
+		Map<Integer, Integer> groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, skeleton, blenderContext);
 
 
 		int[] bonesGroups = new int[] { 0 };
 		int[] bonesGroups = new int[] { 0 };
 		MeshContext meshContext = blenderContext.getMeshContext(meshStructure.getOldMemoryAddress());
 		MeshContext meshContext = blenderContext.getMeshContext(meshStructure.getOldMemoryAddress());
-		
-		VertexBuffer[] boneWeightsAndIndex = this.getBoneWeightAndIndexBuffer(meshStructure, meshContext.getVertexList().size(), bonesGroups,
-				meshContext.getVertexReferenceMap(), groupToBoneIndexMap, blenderContext);
+
+		VertexBuffer[] boneWeightsAndIndex = this.getBoneWeightAndIndexBuffer(meshStructure, meshContext.getVertexList().size(), bonesGroups, meshContext.getVertexReferenceMap(), groupToBoneIndexMap, blenderContext);
 		this.verticesWeights = boneWeightsAndIndex[0];
 		this.verticesWeights = boneWeightsAndIndex[0];
 		this.verticesWeightsIndices = boneWeightsAndIndex[1];
 		this.verticesWeightsIndices = boneWeightsAndIndex[1];
 		this.boneGroups = bonesGroups[0];
 		this.boneGroups = bonesGroups[0];
 	}
 	}
 
 
 	/**
 	/**
-	 * This method returns an array of size 2. The first element is a vertex buffer holding bone weights for every vertex in the model. The
-	 * second element is a vertex buffer holding bone indices for vertices (the indices of bones the vertices are assigned to).
+	 * This method returns an array of size 2. The first element is a vertex
+	 * buffer holding bone weights for every vertex in the model. The second
+	 * element is a vertex buffer holding bone indices for vertices (the indices
+	 * of bones the vertices are assigned to).
 	 * 
 	 * 
 	 * @param meshStructure
 	 * @param meshStructure
 	 *            the mesh structure object
 	 *            the mesh structure object
 	 * @param vertexListSize
 	 * @param vertexListSize
 	 *            a number of vertices in the model
 	 *            a number of vertices in the model
 	 * @param bonesGroups
 	 * @param bonesGroups
-	 *            this is an output parameter, it should be a one-sized array; the maximum amount of weights per vertex (up to
+	 *            this is an output parameter, it should be a one-sized array;
+	 *            the maximum amount of weights per vertex (up to
 	 *            MAXIMUM_WEIGHTS_PER_VERTEX) is stored there
 	 *            MAXIMUM_WEIGHTS_PER_VERTEX) is stored there
 	 * @param vertexReferenceMap
 	 * @param vertexReferenceMap
-	 *            this reference map allows to map the original vertices read from blender to vertices that are really in the model; one
+	 *            this reference map allows to map the original vertices read
+	 *            from blender to vertices that are really in the model; one
 	 *            vertex may appear several times in the result model
 	 *            vertex may appear several times in the result model
 	 * @param groupToBoneIndexMap
 	 * @param groupToBoneIndexMap
-	 *            this object maps the group index (to which a vertices in blender belong) to bone index of the model
+	 *            this object maps the group index (to which a vertices in
+	 *            blender belong) to bone index of the model
 	 * @param blenderContext
 	 * @param blenderContext
 	 *            the blender context
 	 *            the blender context
-	 * @return arrays of vertices weights and their bone indices and (as an output parameter) the maximum amount of weights for a vertex
+	 * @return arrays of vertices weights and their bone indices and (as an
+	 *         output parameter) the maximum amount of weights for a vertex
 	 * @throws BlenderFileException
 	 * @throws BlenderFileException
-	 *             this exception is thrown when the blend file structure is somehow invalid or corrupted
+	 *             this exception is thrown when the blend file structure is
+	 *             somehow invalid or corrupted
 	 */
 	 */
-	private VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups,
-			Map<Integer, List<Integer>> vertexReferenceMap, Map<Integer, Integer> groupToBoneIndexMap, BlenderContext blenderContext)
+	private VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups, Map<Integer, List<Integer>> vertexReferenceMap, Map<Integer, Integer> groupToBoneIndexMap, BlenderContext blenderContext)
 			throws BlenderFileException {
 			throws BlenderFileException {
 		Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
 		Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
 		FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
 		FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
@@ -253,27 +298,28 @@ import java.util.logging.Logger;
 					int weightIndex = 0;
 					int weightIndex = 0;
 					List<Structure> dw = pDW.fetchData(blenderContext.getInputStream());
 					List<Structure> dw = pDW.fetchData(blenderContext.getInputStream());
 					for (Structure deformWeight : dw) {
 					for (Structure deformWeight : dw) {
-                                              Integer boneIndex = groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());
-                                              
-                                               //Remove this code if 4 weights limitation is removed
-                                                if(weightIndex==4){
-                                                    LOGGER.log(Level.WARNING,"{0} has more than 4 weight on bone index {1}",new Object[]{meshStructure.getName(),boneIndex});
-                                                    break;
-                                                }
-						
-						if (boneIndex != null) {// null here means that we came accross group that has no bone attached to
+						Integer boneIndex = groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());
+
+						// Remove this code if 4 weights limitation is removed
+						if (weightIndex == 4) {
+							LOGGER.log(Level.WARNING, "{0} has more than 4 weight on bone index {1}", new Object[] { meshStructure.getName(), boneIndex });
+							break;
+						}
+
+						// null here means that we came accross group that has no bone attached to
+						if (boneIndex != null) {
 							float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
 							float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
 							if (weight == 0.0f) {
 							if (weight == 0.0f) {
 								weight = 1;
 								weight = 1;
 								boneIndex = Integer.valueOf(0);
 								boneIndex = Integer.valueOf(0);
 							}
 							}
 							// we apply the weight to all referenced vertices
 							// we apply the weight to all referenced vertices
-							for (Integer index : vertexIndices) {                                                            
+							for (Integer index : vertexIndices) {
 								weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, weight);
 								weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, weight);
 								indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, boneIndex.byteValue());
 								indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, boneIndex.byteValue());
 							}
 							}
 						}
 						}
-						++weightIndex;                                              
+						++weightIndex;
 					}
 					}
 				} else {
 				} else {
 					for (Integer index : vertexIndices) {
 					for (Integer index : vertexIndices) {
@@ -285,8 +331,10 @@ import java.util.logging.Logger;
 			}
 			}
 		} else {
 		} else {
 			// always bind all vertices to 0-indexed bone
 			// always bind all vertices to 0-indexed bone
-			// this bone makes the model look normally if vertices have no bone assigned
-			// and it is used in object animation, so if we come accross object animation
+			// this bone makes the model look normally if vertices have no bone
+			// assigned
+			// and it is used in object animation, so if we come accross object
+			// animation
 			// we can use the 0-indexed bone for this
 			// we can use the 0-indexed bone for this
 			for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {
 			for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {
 				// we apply the weight to all referenced vertices
 				// we apply the weight to all referenced vertices
@@ -305,11 +353,15 @@ import java.util.logging.Logger;
 		verticesWeightsIndices.setupData(Usage.CpuOnly, bonesGroups[0], Format.UnsignedByte, indicesData);
 		verticesWeightsIndices.setupData(Usage.CpuOnly, bonesGroups[0], Format.UnsignedByte, indicesData);
 		return new VertexBuffer[] { verticesWeights, verticesWeightsIndices };
 		return new VertexBuffer[] { verticesWeights, verticesWeightsIndices };
 	}
 	}
-	
+
 	/**
 	/**
-	 * Normalizes weights if needed and finds largest amount of weights used for all vertices in the buffer.
-	 * @param vertCount amount of vertices
-	 * @param weightsFloatData weights for vertices
+	 * Normalizes weights if needed and finds largest amount of weights used for
+	 * all vertices in the buffer.
+	 * 
+	 * @param vertCount
+	 *            amount of vertices
+	 * @param weightsFloatData
+	 *            weights for vertices
 	 */
 	 */
 	private int endBoneAssigns(int vertCount, FloatBuffer weightsFloatData) {
 	private int endBoneAssigns(int vertCount, FloatBuffer weightsFloatData) {
 		int maxWeightsPerVert = 0;
 		int maxWeightsPerVert = 0;
@@ -339,11 +391,9 @@ import java.util.logging.Logger;
 			}
 			}
 		}
 		}
 		weightsFloatData.rewind();
 		weightsFloatData.rewind();
-
-		// mesh.setMaxNumWeights(maxWeightsPerVert);
 		return maxWeightsPerVert;
 		return maxWeightsPerVert;
 	}
 	}
-	
+
 	@Override
 	@Override
 	public String getType() {
 	public String getType() {
 		return Modifier.ARMATURE_MODIFIER_DATA;
 		return Modifier.ARMATURE_MODIFIER_DATA;

+ 4 - 2
engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ModifierHelper.java

@@ -55,9 +55,11 @@ public class ModifierHelper extends AbstractBlenderHelper {
      * different blender versions.
      * different blender versions.
      * @param blenderVersion
      * @param blenderVersion
      *        the version read from the blend file
      *        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) {
-        super(blenderVersion);
+    public ModifierHelper(String blenderVersion, boolean fixUpAxis) {
+        super(blenderVersion, fixUpAxis);
     }
     }
 
 
     /**
     /**

+ 30 - 39
engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java

@@ -1,5 +1,11 @@
 package com.jme3.scene.plugins.blender.modifiers;
 package com.jme3.scene.plugins.blender.modifiers;
 
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
 import com.jme3.animation.AnimControl;
 import com.jme3.animation.AnimControl;
 import com.jme3.animation.Animation;
 import com.jme3.animation.Animation;
 import com.jme3.animation.SpatialTrack;
 import com.jme3.animation.SpatialTrack;
@@ -7,17 +13,11 @@ import com.jme3.scene.Node;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.Ipo;
 import com.jme3.scene.plugins.blender.animations.IpoHelper;
 import com.jme3.scene.plugins.blender.animations.IpoHelper;
-import com.jme3.scene.plugins.blender.constraints.Constraint;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.FileBlockHeader;
 import com.jme3.scene.plugins.blender.file.FileBlockHeader;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.ogre.AnimData;
 import com.jme3.scene.plugins.ogre.AnimData;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 
 
 /**
 /**
  * This modifier allows to add animation to the object.
  * This modifier allows to add animation to the object.
@@ -51,21 +51,22 @@ import java.util.logging.Logger;
 	 *             corrupted
 	 *             corrupted
 	 */
 	 */
 	public ObjectAnimationModifier(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
 	public ObjectAnimationModifier(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
-		LOGGER.warning("Object animation modifier not yet implemented!");
-		
+		objectOMA = objectStructure.getOldMemoryAddress();
 		Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
 		Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
 		if (pIpo.isNotNull()) {
 		if (pIpo.isNotNull()) {
 			// check if there is an action name connected with this ipo
 			// check if there is an action name connected with this ipo
 			String objectAnimationName = null;
 			String objectAnimationName = null;
 			List<FileBlockHeader> actionBlocks = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
 			List<FileBlockHeader> actionBlocks = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
-			for (FileBlockHeader actionBlock : actionBlocks) {
-				Structure action = actionBlock.getStructure(blenderContext);
-				List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext);
-				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;
+			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;
+						}
 					}
 					}
 				}
 				}
 			}
 			}
@@ -79,7 +80,7 @@ import java.util.logging.Logger;
 			Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0);
 			Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0);
 			Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
 			Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
 			int fps = blenderContext.getBlenderKey().getFps();
 			int fps = blenderContext.getBlenderKey().getFps();
-
+			
 			// calculating track for the only bone in this skeleton
 			// calculating track for the only bone in this skeleton
 			SpatialTrack track = (SpatialTrack) ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps);
 			SpatialTrack track = (SpatialTrack) ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps);
 			
 			
@@ -89,7 +90,7 @@ import java.util.logging.Logger;
 			animations.add(animation);
 			animations.add(animation);
 
 
 			animData = new AnimData(null, animations);
 			animData = new AnimData(null, animations);
-			objectOMA = objectStructure.getOldMemoryAddress();
+			blenderContext.setAnimData(objectOMA, animData);
 		}
 		}
 	}
 	}
 	
 	
@@ -98,30 +99,20 @@ import java.util.logging.Logger;
 		if(invalid) {
 		if(invalid) {
 			LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName());
 			LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName());
 		}//if invalid, animData will be null
 		}//if invalid, animData will be null
-		if(animData == null) {
-			return node;
-		}
-		
-		ArrayList<Animation> animList = animData.anims;
-		if (animList != null && animList.size() > 0) {
-			List<Constraint> constraints = blenderContext.getConstraints(this.objectOMA);
-			HashMap<String, Animation> anims = new HashMap<String, Animation>();
-			for (int i = 0; i < animList.size(); ++i) {
-				Animation animation = (Animation) animList.get(i).clone();
-
-				// baking constraints into animations
-				if (constraints != null && constraints.size() > 0) {
-					for (Constraint constraint : constraints) {
-						constraint.affectAnimation(animation, 0);
-					}
+		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>();
+				for (int i = 0; i < animList.size(); ++i) {
+					Animation animation = animList.get(i);
+					anims.put(animation.getName(), animation);
 				}
 				}
 
 
-				anims.put(animation.getName(), animation);
+				AnimControl control = new AnimControl(null);
+				control.setAnimations(anims);
+				node.addControl(control);
 			}
 			}
-
-			AnimControl control = new AnimControl(null);
-			control.setAnimations(anims);
-			node.addControl(control);
 		}
 		}
 		return node;
 		return node;
 	}
 	}

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

@@ -49,6 +49,7 @@ import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
 import com.jme3.scene.plugins.blender.cameras.CameraHelper;
 import com.jme3.scene.plugins.blender.cameras.CameraHelper;
+import com.jme3.scene.plugins.blender.constraints.Constraint;
 import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
 import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
 import com.jme3.scene.plugins.blender.curves.CurvesHelper;
 import com.jme3.scene.plugins.blender.curves.CurvesHelper;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
@@ -99,9 +100,11 @@ public class ObjectHelper extends AbstractBlenderHelper {
 	 * different blender versions.
 	 * different blender versions.
 	 * @param blenderVersion
 	 * @param blenderVersion
 	 *        the version read from the blend file
 	 *        the version read from the blend file
+	 * @param fixUpAxis
+     *        a variable that indicates if the Y asxis is the UP axis or not
 	 */
 	 */
-	public ObjectHelper(String blenderVersion) {
-		super(blenderVersion);
+	public ObjectHelper(String blenderVersion, boolean fixUpAxis) {
+		super(blenderVersion, fixUpAxis);
 	}
 	}
 
 
 	/**
 	/**
@@ -121,17 +124,12 @@ public class ObjectHelper extends AbstractBlenderHelper {
 		}
 		}
 
 
 		blenderContext.pushParent(objectStructure);
 		blenderContext.pushParent(objectStructure);
-		ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
 
 
 		//get object data
 		//get object data
 		int type = ((Number)objectStructure.getFieldValue("type")).intValue();
 		int type = ((Number)objectStructure.getFieldValue("type")).intValue();
 		String name = objectStructure.getName();
 		String name = objectStructure.getName();
 		LOGGER.log(Level.INFO, "Loading obejct: {0}", name);
 		LOGGER.log(Level.INFO, "Loading obejct: {0}", name);
 
 
-		//loading constraints connected with this object
-		ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
-		constraintHelper.loadConstraints(objectStructure, blenderContext);
-
 		int restrictflag = ((Number)objectStructure.getFieldValue("restrictflag")).intValue();
 		int restrictflag = ((Number)objectStructure.getFieldValue("restrictflag")).intValue();
 		boolean visible = (restrictflag & 0x01) != 0;
 		boolean visible = (restrictflag & 0x01) != 0;
 		Object result = null;
 		Object result = null;
@@ -143,7 +141,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
 			parent = this.toObject(parentStructure, blenderContext);
 			parent = this.toObject(parentStructure, blenderContext);
 		}
 		}
 
 
-		Transform t = objectHelper.getTransformation(objectStructure, blenderContext);
+		Transform t = this.getTransformation(objectStructure, blenderContext);
 		
 		
 		try {
 		try {
 			switch(type) {
 			switch(type) {
@@ -245,7 +243,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
 					}
 					}
 					break;
 					break;
 				case OBJECT_TYPE_ARMATURE:
 				case OBJECT_TYPE_ARMATURE:
-					//Do not do anything, the object with all needed data is loaded when armature modifier loads
+					//Do nothing, the object with all needed data is loaded when armature modifier loads
 					break;
 					break;
 				default:
 				default:
 					LOGGER.log(Level.WARNING, "Unknown object type: {0}", type);
 					LOGGER.log(Level.WARNING, "Unknown object type: {0}", type);
@@ -255,13 +253,25 @@ public class ObjectHelper extends AbstractBlenderHelper {
 		}
 		}
 		
 		
 		if(result != null) {
 		if(result != null) {
+			blenderContext.addLoadedFeatures(objectStructure.getOldMemoryAddress(), name, objectStructure, result);
+			
+			//loading constraints connected with this object
+			ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
+			constraintHelper.loadConstraints(objectStructure, blenderContext);
+			
+			//baking constraints
+			List<Constraint> objectConstraints = blenderContext.getConstraints(objectStructure.getOldMemoryAddress());
+			if(objectConstraints!=null) {
+				for(Constraint objectConstraint : objectConstraints) {
+					objectConstraint.bakeStatic();
+				}
+			}
+			
 			//reading custom properties
 			//reading custom properties
 			Properties properties = this.loadProperties(objectStructure, blenderContext);
 			Properties properties = this.loadProperties(objectStructure, blenderContext);
 			if(result instanceof Spatial && properties != null && properties.getValue() != null) {
 			if(result instanceof Spatial && properties != null && properties.getValue() != null) {
 				((Spatial)result).setUserData("properties", properties);
 				((Spatial)result).setUserData("properties", properties);
 			}
 			}
-			
-			blenderContext.addLoadedFeatures(objectStructure.getOldMemoryAddress(), name, objectStructure, result);
 		}
 		}
 		return result;
 		return result;
 	}
 	}
@@ -292,13 +302,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
 
 
 		Vector3f translation = localMatrix.toTranslationVector();
 		Vector3f translation = localMatrix.toTranslationVector();
 		Quaternion rotation = localMatrix.toRotationQuat();
 		Quaternion rotation = localMatrix.toRotationQuat();
-		//getting the scale
-		float scaleX = (float) Math.sqrt(parentInv.m00 * parentInv.m00 + parentInv.m10 * parentInv.m10 + parentInv.m20 * parentInv.m20);
-		float scaleY = (float) Math.sqrt(parentInv.m01 * parentInv.m01 + parentInv.m11 * parentInv.m11 + parentInv.m21 * parentInv.m21);
-		float scaleZ = (float) Math.sqrt(parentInv.m02 * parentInv.m02 + parentInv.m12 * parentInv.m12 + parentInv.m22 * parentInv.m22);
-		Vector3f scale = new Vector3f(size.get(0).floatValue() * scaleX, 
-									  size.get(1).floatValue() * scaleY, 
-									  size.get(2).floatValue() * scaleZ);
+		Vector3f scale = this.getScale(parentInv).multLocal(size.get(0).floatValue(), size.get(1).floatValue(), size.get(2).floatValue());
 		
 		
 		if(fixUpAxis) {
 		if(fixUpAxis) {
 			float y = translation.y;
 			float y = translation.y;
@@ -321,35 +325,76 @@ public class ObjectHelper extends AbstractBlenderHelper {
 	}
 	}
 
 
 	/**
 	/**
-	 * This method returns the transformation matrix of the given object structure.
-	 * @param objectStructure
-	 *        the structure with object's data
-	 * @return object's transformation matrix
+	 * This method returns the matrix of a given name for the given structure.
+	 * The matrix is NOT transformed if Y axis is up - the raw data is loaded from the blender file.
+	 * @param structure
+	 *        the structure with matrix data
+	 * @param matrixName
+	 * 		  the name of the matrix
+	 * @return the required matrix
 	 */
 	 */
-	public Matrix4f getTransformationMatrix(Structure objectStructure) {
-		return this.getMatrix(objectStructure, "obmat");
+	public Matrix4f getMatrix(Structure structure, String matrixName) {
+		return this.getMatrix(structure, matrixName, false);
 	}
 	}
-
+	
 	/**
 	/**
-	 * This method returns the matrix of a given name for the given object structure.
-	 * @param objectStructure
-	 *        the structure with object's data
+	 * This method returns the matrix of a given name for the given structure.
+	 * It takes up axis into consideration.
+	 * @param structure
+	 *        the structure with matrix data
 	 * @param matrixName
 	 * @param matrixName
-	 * 		  the name of the matrix structure
-	 * @return object's matrix
+	 * 		  the name of the matrix
+	 * @return the required matrix
 	 */
 	 */
 	@SuppressWarnings("unchecked")
 	@SuppressWarnings("unchecked")
-	protected Matrix4f getMatrix(Structure objectStructure, String matrixName) {
+	public Matrix4f getMatrix(Structure structure, String matrixName, boolean applyFixUpAxis) {
 		Matrix4f result = new Matrix4f();
 		Matrix4f result = new Matrix4f();
-		DynamicArray<Number> obmat = (DynamicArray<Number>)objectStructure.getFieldValue(matrixName);
-		for(int i = 0; i < 4; ++i) {
-			for(int j = 0; j < 4; ++j) {
+		DynamicArray<Number> obmat = (DynamicArray<Number>)structure.getFieldValue(matrixName);
+		int rowAndColumnSize = Math.abs((int)Math.sqrt(obmat.getTotalSize()));//the matrix must be square
+		for(int i = 0; i < rowAndColumnSize; ++i) {
+			for(int j = 0; j < rowAndColumnSize; ++j) {
 				result.set(i, j, obmat.get(j, i).floatValue());
 				result.set(i, j, obmat.get(j, i).floatValue());
 			}
 			}
 		}
 		}
+		if(applyFixUpAxis && fixUpAxis) {
+        	Vector3f translation = result.toTranslationVector();
+            Quaternion rotation = result.toRotationQuat();
+            Vector3f scale = this.getScale(result);
+            
+			float y = translation.y;
+			translation.y = translation.z;
+			translation.z = -y;
+			
+			y = rotation.getY();
+			float z = rotation.getZ();
+			rotation.set(rotation.getX(), z, -y, rotation.getW());
+			
+			y=scale.y;
+			scale.y = scale.z;
+			scale.z = y;
+			
+			result.loadIdentity();
+			result.setTranslation(translation);
+			result.setRotationQuaternion(rotation);
+			result.setScale(scale);
+        }
 		return result;
 		return result;
 	}
 	}
 
 
+	/**
+	 * This method returns the scale from the given matrix.
+	 * 
+	 * @param matrix
+	 *            the transformation matrix
+	 * @return the scale from the given matrix
+	 */
+	public Vector3f getScale(Matrix4f matrix) {
+		float scaleX = (float) Math.sqrt(matrix.m00 * matrix.m00 + matrix.m10 * matrix.m10 + matrix.m20 * matrix.m20);
+		float scaleY = (float) Math.sqrt(matrix.m01 * matrix.m01 + matrix.m11 * matrix.m11 + matrix.m21 * matrix.m21);
+		float scaleZ = (float) Math.sqrt(matrix.m02 * matrix.m02 + matrix.m12 * matrix.m12 + matrix.m22 * matrix.m22);
+		return new Vector3f(scaleX, scaleY, scaleZ);
+	}
+	
 	@Override
 	@Override
 	public void clearState() {
 	public void clearState() {
 		fixUpAxis = false;
 		fixUpAxis = false;

+ 4 - 2
engine/src/blender/com/jme3/scene/plugins/blender/particles/ParticlesHelper.java

@@ -86,9 +86,11 @@ public class ParticlesHelper extends AbstractBlenderHelper {
 	 * different blender versions.
 	 * different blender versions.
 	 * @param blenderVersion
 	 * @param blenderVersion
 	 *        the version read from the blend file
 	 *        the version read from the blend file
+	 * @param fixUpAxis
+     *        a variable that indicates if the Y asxis is the UP axis or not
 	 */
 	 */
-	public ParticlesHelper(String blenderVersion) {
-		super(blenderVersion);
+	public ParticlesHelper(String blenderVersion, boolean fixUpAxis) {
+		super(blenderVersion, fixUpAxis);
 	}
 	}
 
 
 	@SuppressWarnings("unchecked")
 	@SuppressWarnings("unchecked")

+ 1 - 1
engine/src/blender/com/jme3/scene/plugins/blender/textures/NoiseGenerator.java

@@ -96,7 +96,7 @@ import java.util.logging.Logger;
      *        the number of blender version
      *        the number of blender version
      */
      */
     public NoiseGenerator(String blenderVersion) {
     public NoiseGenerator(String blenderVersion) {
-        super(blenderVersion);
+        super(blenderVersion, false);
         this.loadConstants();
         this.loadConstants();
     }
     }
 
 

+ 4 - 2
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java

@@ -135,9 +135,11 @@ public class TextureHelper extends AbstractBlenderHelper {
 	 * 
 	 * 
 	 * @param blenderVersion
 	 * @param blenderVersion
 	 *        the version read from the blend file
 	 *        the version read from the blend file
+	 * @param fixUpAxis
+     *        a variable that indicates if the Y asxis is the UP axis or not
 	 */
 	 */
-	public TextureHelper(String blenderVersion) {
-		super(blenderVersion);
+	public TextureHelper(String blenderVersion, boolean fixUpAxis) {
+		super(blenderVersion, false);
 		noiseGenerator = new NoiseGenerator(blenderVersion);
 		noiseGenerator = new NoiseGenerator(blenderVersion);
 		textureGenerators.put(Integer.valueOf(TEX_BLEND), new TextureGeneratorBlend(noiseGenerator));
 		textureGenerators.put(Integer.valueOf(TEX_BLEND), new TextureGeneratorBlend(noiseGenerator));
 		textureGenerators.put(Integer.valueOf(TEX_CLOUDS), new TextureGeneratorClouds(noiseGenerator));
 		textureGenerators.put(Integer.valueOf(TEX_CLOUDS), new TextureGeneratorClouds(noiseGenerator));