From a1d73d159d351475aaea9d89565a709cad6604d0 Mon Sep 17 00:00:00 2001 From: "Kae..pl" Date: Tue, 6 Dec 2011 22:33:49 +0000 Subject: [PATCH] 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 --- .../blender/AbstractBlenderHelper.java | 12 +- .../scene/plugins/blender/BlenderContext.java | 918 ++++++++++-------- .../scene/plugins/blender/BlenderLoader.java | 34 +- .../blender/animations/ArmatureHelper.java | 366 +++---- .../scene/plugins/blender/animations/Ipo.java | 98 +- .../plugins/blender/animations/IpoHelper.java | 13 +- .../plugins/blender/cameras/CameraHelper.java | 6 +- .../blender/constraints/BlenderTrack.java | 147 +++ .../blender/constraints/Constraint.java | 217 ++--- .../blender/constraints/ConstraintAction.java | 16 +- .../constraints/ConstraintChildOf.java | 14 +- .../constraints/ConstraintClampTo.java | 16 +- .../constraints/ConstraintDampTrack.java | 49 + .../constraints/ConstraintDistLimit.java | 123 ++- .../constraints/ConstraintFactory.java | 78 -- .../constraints/ConstraintFollowPath.java | 14 +- .../blender/constraints/ConstraintHelper.java | 160 ++- .../ConstraintInverseKinematics.java | 77 +- .../constraints/ConstraintLocLike.java | 112 ++- .../constraints/ConstraintLocLimit.java | 143 ++- .../constraints/ConstraintLockTrack.java | 16 +- .../blender/constraints/ConstraintMinMax.java | 14 +- .../blender/constraints/ConstraintNull.java | 13 +- .../blender/constraints/ConstraintPivot.java | 50 + .../blender/constraints/ConstraintPython.java | 14 +- .../constraints/ConstraintRigidBodyJoint.java | 14 +- .../constraints/ConstraintRotLike.java | 107 +- .../constraints/ConstraintRotLimit.java | 140 ++- .../constraints/ConstraintShrinkWrap.java | 54 +- .../constraints/ConstraintSizeLike.java | 81 +- .../constraints/ConstraintSizeLimit.java | 134 ++- .../ConstraintSplineInverseKinematic.java | 50 + .../constraints/ConstraintStretchTo.java | 19 +- .../constraints/ConstraintTransform.java | 16 +- .../blender/constraints/ConstraintType.java | 145 --- .../plugins/blender/constraints/Feature.java | 274 ++++++ .../plugins/blender/curves/CurvesHelper.java | 8 +- .../plugins/blender/lights/LightHelper.java | 6 +- .../blender/materials/MaterialHelper.java | 8 +- .../plugins/blender/meshes/MeshHelper.java | 6 +- .../blender/modifiers/ArmatureModifier.java | 310 +++--- .../blender/modifiers/ModifierHelper.java | 6 +- .../modifiers/ObjectAnimationModifier.java | 69 +- .../plugins/blender/objects/ObjectHelper.java | 113 ++- .../blender/particles/ParticlesHelper.java | 6 +- .../blender/textures/NoiseGenerator.java | 2 +- .../blender/textures/TextureHelper.java | 6 +- 47 files changed, 2494 insertions(+), 1800 deletions(-) create mode 100644 engine/src/blender/com/jme3/scene/plugins/blender/constraints/BlenderTrack.java create mode 100644 engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDampTrack.java delete mode 100644 engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFactory.java create mode 100644 engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPivot.java create mode 100644 engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSplineInverseKinematic.java delete mode 100644 engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintType.java create mode 100644 engine/src/blender/com/jme3/scene/plugins/blender/constraints/Feature.java diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java index ba43384dc..8f8ba891b 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java @@ -60,17 +60,11 @@ public abstract class AbstractBlenderHelper { * versions. * @param blenderVersion * 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 - * 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; if(fixUpAxis) { upAxisRotationQuaternion = new Quaternion().fromAngles(-FastMath.HALF_PI, 0, 0); diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java b/engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java index 2971795b0..a59af46e5 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java @@ -31,6 +31,16 @@ */ 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.BlenderKey; 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.meshes.MeshContext; 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) */ 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 fileBlockHeadersByOma = new HashMap(); - /** A map containing the file block headers. The key is the block code. */ - private Map> fileBlockHeadersByCode = new HashMap>(); - /** - * 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 loadedFeatures = new HashMap(); - /** - * 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 loadedFeaturesByName = new HashMap(); - /** A stack that hold the parent structure of currently loaded feature. */ - private Stack parentStack = new Stack(); - /** A map storing loaded ipos. The key is the ipo's owner old memory address and the value is the ipo. */ - private Map loadedIpos = new HashMap(); - /** A list of modifiers for the specified object. */ - protected Map> modifiers = new HashMap>(); - /** A list of constraints for the specified object. */ - protected Map> constraints = new HashMap>(); - /** A map of mesh contexts. */ - protected Map meshContexts = new HashMap(); - /** A map of material contexts. */ - protected Map materialContexts = new HashMap(); - /** A map og helpers that perform loading. */ - private Map helpers = new HashMap(); - - /** - * 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 headers = fileBlockHeadersByCode.get(Integer.valueOf(fileBlockHeader.getCode())); - if (headers == null) { - headers = new ArrayList(); - 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 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 - * the type of the helper - * @param clazz - * helper's class definition - * @param helper - * the helper instance - */ - public void putHelper(Class clazz, AbstractBlenderHelper helper) { - helpers.put(clazz.getSimpleName(), helper); - } - - @SuppressWarnings("unchecked") - public 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 objectModifiers = this.modifiers.get(ownerOMA); - if (objectModifiers == null) { - objectModifiers = new ArrayList(); - 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 getModifiers(Long objectOMA, String type) { - List result = new ArrayList(); - List 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 constraints) { - List objectConstraints = this.constraints.get(ownerOMA); - if (objectConstraints == null) { - objectConstraints = new ArrayList(); - 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 - null is returned. - * @param objectOMA - * object's old memory address - * @return the list of object's modifiers or null - */ - public List 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 fileBlockHeadersByOma = new HashMap(); + /** A map containing the file block headers. The key is the block code. */ + private Map> fileBlockHeadersByCode = new HashMap>(); + /** + * 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 loadedFeatures = new HashMap(); + /** + * 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 loadedFeaturesByName = new HashMap(); + /** A stack that hold the parent structure of currently loaded feature. */ + private Stack parentStack = new Stack(); + /** + * A map storing loaded ipos. The key is the ipo's owner old memory address + * and the value is the ipo. + */ + private Map loadedIpos = new HashMap(); + /** A list of modifiers for the specified object. */ + protected Map> modifiers = new HashMap>(); + /** A list of constraints for the specified object. */ + protected Map> constraints = new HashMap>(); + /** Anim data loaded for features. */ + private Map animData = new HashMap(); + /** A map of mesh contexts. */ + protected Map meshContexts = new HashMap(); + /** A map of material contexts. */ + protected Map materialContexts = new HashMap(); + /** A map og helpers that perform loading. */ + private Map helpers = new HashMap(); + + /** + * 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 headers = fileBlockHeadersByCode.get(Integer.valueOf(fileBlockHeader.getCode())); + if (headers == null) { + headers = new ArrayList(); + 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 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 + * the type of the helper + * @param clazz + * helper's class definition + * @param helper + * the helper instance + */ + public void putHelper(Class clazz, AbstractBlenderHelper helper) { + helpers.put(clazz.getSimpleName(), helper); + } + + @SuppressWarnings("unchecked") + public 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 objectModifiers = this.modifiers.get(ownerOMA); + if (objectModifiers == null) { + objectModifiers = new ArrayList(); + 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 getModifiers(Long objectOMA, String type) { + List result = new ArrayList(); + List 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 constraints) { + List objectConstraints = this.constraints.get(ownerOMA); + if (objectConstraints == null) { + objectConstraints = new ArrayList(); + 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 - null is returned. + * + * @param objectOMA + * object's old memory address + * @return the list of object's modifiers or null + */ + public List 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. * If the context is already set it will be replaced. + * * @param meshOMA - * the mesh's old memory address + * the mesh's old memory address * @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 null 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 null is returned. + * * @param meshOMA - * the mesh's old memory address + * the mesh's old memory address * @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 - * the material + * the material * @param materialContext - * the material's context + * the material's context */ public void setMaterialContext(Material material, MaterialContext materialContext) { this.materialContexts.put(material, materialContext); } /** - * This method returns the material context for the given material. - * If no context exists then null is returned. + * This method returns the material context for the given material. If no + * context exists then null is returned. + * * @param material - * the material + * the material * @return material's context */ public MaterialContext getMaterialContext(Material 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(); } catch (IOException e) { LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e); } loadedFeatures.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; + } + } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java b/engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java index dd5011dfd..a89e668fa 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java @@ -189,30 +189,20 @@ public class BlenderLoader extends AbstractBlenderLoader { blenderContext.setBlenderKey(blenderKey); // 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 - 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.setFaceCullMode(blenderKey.getFaceCullMode()); diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java index 85c6c0f6e..c4c84f53e 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java @@ -31,50 +31,126 @@ */ 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.BoneTrack; +import com.jme3.animation.Skeleton; import com.jme3.math.Matrix4f; 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.BlenderContext; import com.jme3.scene.plugins.blender.curves.BezierCurve; 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. - * @author Marcin Roguski + * @author Marcin Roguski (Kaelthas) */ public class ArmatureHelper extends AbstractBlenderHelper { - private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName()); - + + /** A map of bones and their old memory addresses. */ + private Map bonesOMAs = new HashMap(); + /** Bone transforms need to be applied after the model is attached to the skeleton. Otherwise it will have no effect. */ + private Map boneBindTransforms = new HashMap(); + /** * This constructor parses the given blender version and stores the result. Some functionalities may differ in * different blender versions. * @param blenderVersion * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not */ - public ArmatureHelper(String blenderVersion) { - 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 bonesMap = new HashMap(); - /** A map of bones and their old memory addresses. */ - protected Map bonesOMAs = new HashMap(); - /** This list contains bones hierarchy and their matrices. It is later converted into jme bones. */ - protected List boneDataRoots = new ArrayList(); + * 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 result, Matrix4f arbt, + final Map 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 loc = (DynamicArray) poseChannel.getFieldValue("loc"); + DynamicArray size = (DynamicArray) poseChannel.getFieldValue("size"); + DynamicArray quat = (DynamicArray) 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 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 @@ -90,6 +166,16 @@ public class ArmatureHelper extends AbstractBlenderHelper { } 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 @@ -100,15 +186,15 @@ public class ArmatureHelper extends AbstractBlenderHelper { * @throws BlenderFileException * this exception is thrown when the blender file is somehow corrupted */ - public Map getGroupToBoneIndexMap(Structure defBaseStructure, BlenderContext blenderContext) throws BlenderFileException { + public Map getGroupToBoneIndexMap(Structure defBaseStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException { Map result = null; - if (bonesMap != null && bonesMap.size() != 0) { + if (skeleton.getBoneCount() != 0) { result = new HashMap(); List deformGroups = defBaseStructure.evaluateListBase(blenderContext);//bDeformGroup int groupIndex = 0; for (Structure deformGroup : deformGroups) { String deformGroupName = deformGroup.getFieldValue("name").toString(); - Integer boneIndex = bonesMap.get(deformGroupName); + Integer boneIndex = this.getBoneIndex(skeleton, deformGroupName); if (boneIndex != null) { result.put(Integer.valueOf(groupIndex), boneIndex); } @@ -118,191 +204,6 @@ public class ArmatureHelper extends AbstractBlenderHelper { 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 boneMat = (DynamicArray) 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 sizeArray = (DynamicArray) 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 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 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 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(); - 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 bones = new ArrayList(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 public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) { return true; @@ -320,11 +221,11 @@ public class ArmatureHelper extends AbstractBlenderHelper { * an exception is thrown when there are problems with the blend * file */ - public BoneTrack[] getTracks(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException { + public BoneTrack[] getTracks(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException { if (blenderVersion < 250) { - return this.getTracks249(actionStructure, blenderContext); + return this.getTracks249(actionStructure, skeleton, blenderContext); } 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 * 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!"); int fps = blenderContext.getBlenderKey().getFps(); Structure groups = (Structure) actionStructure.getFieldValue("groups"); List 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 tracks = new ArrayList(); for (Structure actionGroup : actionGroups) { String name = actionGroup.getFieldValue("name").toString(); - Integer boneIndex = bonesMap.get(name); + Integer boneIndex = this.getBoneIndex(skeleton, name); if (boneIndex != null) { List channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(blenderContext); BezierCurve[] bezierCurves = new BezierCurve[channels.size()]; @@ -374,8 +271,8 @@ public class ArmatureHelper extends AbstractBlenderHelper { 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()]); @@ -393,31 +290,44 @@ public class ArmatureHelper extends AbstractBlenderHelper { * an exception is thrown when there are problems with the blend * 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!"); IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class); int fps = blenderContext.getBlenderKey().getFps(); Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase"); List 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 tracks = new ArrayList(); for (Structure bActionChannel : actionChannels) { 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"); if (!p.isNull()) { Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0); Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext); - tracks.add( (BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps)); + tracks.add((BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps)); } } } 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= 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. * - * @author Marcin Roguski + * @author Marcin Roguski (Kaelthas) */ public static enum Space { @@ -227,16 +132,16 @@ public abstract class Constraint { */ public static Space valueOf(byte 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; } } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintAction.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintAction.java index 5f3219542..a198e441a 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintAction.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintAction.java @@ -1,6 +1,5 @@ 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.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -20,7 +19,7 @@ import java.util.logging.Logger; * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintAction(Structure constraintStructure, Long boneOMA, + public ConstraintAction(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { - super(constraintStructure, boneOMA, influenceIpo, blenderContext); + super(constraintStructure, ownerOMA, influenceIpo, blenderContext); } - + @Override - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { // TODO: implement 'Action' constraint LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!"); } @Override - public ConstraintType getType() { - return ConstraintType.CONSTRAINT_TYPE_ACTION; + public void bakeStatic() { + // TODO: implement 'Action' constraint + LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!"); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintChildOf.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintChildOf.java index c29c0db72..99fe8c5cc 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintChildOf.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintChildOf.java @@ -1,6 +1,5 @@ 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.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -20,7 +19,7 @@ import java.util.logging.Logger; * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintChildOf(Structure constraintStructure, Long boneOMA, + public ConstraintChildOf(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { - super(constraintStructure, boneOMA, influenceIpo, blenderContext); + super(constraintStructure, ownerOMA, influenceIpo, blenderContext); } @Override - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { // TODO: implement ChildOf constraint LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!"); } @Override - public ConstraintType getType() { - return ConstraintType.CONSTRAINT_TYPE_CHILDOF; + public void bakeStatic() { + // TODO: implement ChildOf constraint + LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!"); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintClampTo.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintClampTo.java index 09577f1db..48905e33e 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintClampTo.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintClampTo.java @@ -1,6 +1,5 @@ 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.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -20,7 +19,7 @@ import java.util.logging.Logger; * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintClampTo(Structure constraintStructure, Long boneOMA, + public ConstraintClampTo(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { - super(constraintStructure, boneOMA, influenceIpo, blenderContext); + super(constraintStructure, ownerOMA, influenceIpo, blenderContext); } @Override - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { //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 - 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); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDampTrack.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDampTrack.java new file mode 100644 index 000000000..4c2dc999c --- /dev/null +++ b/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!"); + } +} diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDistLimit.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDistLimit.java index c8725d44b..3d3778d52 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDistLimit.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDistLimit.java @@ -1,12 +1,15 @@ package com.jme3.scene.plugins.blender.constraints; 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.scene.Spatial; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; import com.jme3.scene.plugins.blender.file.Structure; +import com.jme3.scene.plugins.ogre.AnimData; /** * 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_ONSURFACE = 2; - /** + protected int mode; + protected float dist; + + /** * This constructor creates the constraint instance. * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintDistLimit(Structure constraintStructure, Long boneOMA, + public ConstraintDistLimit(Structure constraintStructure, Long ownerOMA, 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 - 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 - 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); + } } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFactory.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFactory.java deleted file mode 100644 index dd58b14fe..000000000 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFactory.java +++ /dev/null @@ -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); - } - } -} diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFollowPath.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFollowPath.java index 05d3db2ab..644ef320a 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFollowPath.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintFollowPath.java @@ -1,6 +1,5 @@ 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.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -20,7 +19,7 @@ import java.util.logging.Logger; * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintFollowPath(Structure constraintStructure, Long boneOMA, + public ConstraintFollowPath(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { - super(constraintStructure, boneOMA, influenceIpo, blenderContext); + super(constraintStructure, ownerOMA, influenceIpo, blenderContext); } @Override - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { //TODO: implement when curves are implemented LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!"); } @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!"); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java index 3e5a58f47..75478487f 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java @@ -1,5 +1,12 @@ 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.BlenderContext; 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.file.Pointer; 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. - * @author Marcin Roguski + * @author Marcin Roguski (Kaelthas) */ public class ConstraintHelper extends AbstractBlenderHelper { private static final Logger LOGGER = Logger.getLogger(ConstraintHelper.class.getName()); + private static final Map> constraintClasses = new HashMap>(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 * 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. * @param blenderVersion * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not */ - public 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 - * the structure we read constraint's for + * the structure we read constraint's for * @param blenderContext - * the blender context + * the blender context * @throws BlenderFileException */ - public Map> 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>(0); - } - + public void loadConstraints(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException { + LOGGER.fine("Loading constraints."); // reading influence ipos for the constraints IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class); Map> constraintsIpos = new HashMap>(); @@ -74,11 +102,9 @@ public class ConstraintHelper extends AbstractBlenderHelper { } } } - - Map> result = new HashMap>(); //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()) { List poseChannels = ((Structure) pPose.fetchData(blenderContext.getInputStream()).get(0).getFieldValue("chanbase")).evaluateListBase(blenderContext); for (Structure poseChannel : poseChannels) { @@ -96,40 +122,78 @@ public class ConstraintHelper extends AbstractBlenderHelper { float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue(); 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); } } - // TODO: reading constraints for objects (implement when object's animation will be available) - List 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 constraints = ((Structure)objectStructure.getFieldValue("constraints")).evaluateListBase(blenderContext); - List constraintsList = new ArrayList(constraints.size()); + //loading constraints connected with the object itself + List constraints = ((Structure)objectStructure.getFieldValue("constraints")).evaluateListBase(blenderContext); + List constraintsList = new ArrayList(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 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 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 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 diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintInverseKinematics.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintInverseKinematics.java index 744b8efa3..5e7ac3ede 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintInverseKinematics.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintInverseKinematics.java @@ -1,7 +1,9 @@ package com.jme3.scene.plugins.blender.constraints; import com.jme3.animation.Animation; +import com.jme3.animation.Skeleton; 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.exceptions.BlenderFileException; import com.jme3.scene.plugins.blender.file.Structure; @@ -20,7 +22,7 @@ import java.util.logging.Logger; * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * the ipo curve of the influence factor @@ -31,23 +33,30 @@ import java.util.logging.Logger; * corrupted */ 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 - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { // try { // 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); // Vector3f pt = null;// Point Target // if (targetObject instanceof Bone) { // 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) { // Structure armatureNodeStructure = (Structure) this.getTarget(LoadedFeatureDataType.LOADED_STRUCTURE); // ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); @@ -106,7 +115,7 @@ import java.util.logging.Logger; // for (CalculationBone bone : bones) { // bone.applyCalculatedTracks(); // } - +// // System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); // for (int i = 0; i < bones.length; ++i) { // 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 bonesList = new ArrayList(); -// Bone currentBone = bone; // 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) { -// 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; // } // } -// currentBone = currentBone.getParent(); -// } while (currentBone != null); +// ownerBone = ownerBone.getParent(); +// } while (ownerBone != null); // //attaching children // CalculationBone[] result = bonesList.toArray(new CalculationBone[bonesList.size()]); // for (int i = result.length - 1; i > 0; --i) { // result[i].attachChild(result[i - 1]); // } // return result; -// } - - @Override - public ConstraintType getType() { - return ConstraintType.CONSTRAINT_TYPE_KINEMATIC; + return null; } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLike.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLike.java index 3561de528..495c67a03 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLike.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLike.java @@ -1,12 +1,13 @@ package com.jme3.scene.plugins.blender.constraints; import com.jme3.animation.Animation; -import com.jme3.animation.BoneTrack; +import com.jme3.math.Transform; import com.jme3.math.Vector3f; 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; +import com.jme3.scene.plugins.ogre.AnimData; /** * 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_Y = 0x02; 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_Y_INVERT = 0x20; private static final int LOCLIKE_Z_INVERT = 0x40; private static final int LOCLIKE_OFFSET = 0x80; + protected int flag; + /** * This constructor creates the constraint instance. * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintLocLike(Structure constraintStructure, Long boneOMA, + public ConstraintLocLike(Structure constraintStructure, Long ownerOMA, 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 - 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 - 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); + } } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLimit.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLimit.java index 0352354be..b248ce0bb 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLimit.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLocLimit.java @@ -1,12 +1,14 @@ package com.jme3.scene.plugins.blender.constraints; 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.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; +import com.jme3.scene.plugins.ogre.AnimData; /** * 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_ZMAX = 0x20; + protected float[][] limits = new float[3][2]; + protected int flag; + /** * This constructor creates the constraint instance. * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintLocLimit(Structure constraintStructure, Long boneOMA, + public ConstraintLocLimit(Structure constraintStructure, Long ownerOMA, 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 - 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 - 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; + } + } } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLockTrack.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLockTrack.java index b0d8bcadc..cd435ec46 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLockTrack.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintLockTrack.java @@ -1,6 +1,5 @@ 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.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -20,7 +19,7 @@ import java.util.logging.Logger; * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintLockTrack(Structure constraintStructure, Long boneOMA, + public ConstraintLockTrack(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { - super(constraintStructure, boneOMA, influenceIpo, blenderContext); + super(constraintStructure, ownerOMA, influenceIpo, blenderContext); } @Override - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { // TODO: implement 'Lock track' constraint LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!"); } - + @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!"); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintMinMax.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintMinMax.java index 9c331fa4d..5749ccbd7 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintMinMax.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintMinMax.java @@ -1,6 +1,5 @@ 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.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -20,7 +19,7 @@ import java.util.logging.Logger; * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintMinMax(Structure constraintStructure, Long boneOMA, + public ConstraintMinMax(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { - super(constraintStructure, boneOMA, influenceIpo, blenderContext); + super(constraintStructure, ownerOMA, influenceIpo, blenderContext); } @Override - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { // TODO: implement 'Min max' constraint LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!"); } @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!"); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintNull.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintNull.java index 62459cd87..3ff3b8694 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintNull.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintNull.java @@ -1,6 +1,5 @@ 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.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -17,7 +16,7 @@ import com.jme3.scene.plugins.blender.file.Structure; * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintNull(Structure constraintStructure, Long boneOMA, + public ConstraintNull(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { - super(constraintStructure, boneOMA, influenceIpo, blenderContext); + super(constraintStructure, ownerOMA, influenceIpo, blenderContext); } @Override - public void affectAnimation(Animation animation, int targetIndex) {} + public void bakeDynamic() {} @Override - public ConstraintType getType() { - return ConstraintType.CONSTRAINT_TYPE_NULL; - } + public void bakeStatic() {} } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPivot.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPivot.java new file mode 100644 index 000000000..d24a3642d --- /dev/null +++ b/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!"); + } +} diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPython.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPython.java index d8a6ba15f..8d2bdd106 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPython.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPython.java @@ -1,6 +1,5 @@ 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.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -20,7 +19,7 @@ import java.util.logging.Logger; * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintPython(Structure constraintStructure, Long boneOMA, + public ConstraintPython(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { - super(constraintStructure, boneOMA, influenceIpo, blenderContext); + super(constraintStructure, ownerOMA, influenceIpo, blenderContext); } @Override - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { // TODO: implement 'Python' constraint LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!"); } @Override - public ConstraintType getType() { - return ConstraintType.CONSTRAINT_TYPE_PYTHON; + public void bakeStatic() { + // TODO: implement 'Python' constraint + LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!"); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRigidBodyJoint.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRigidBodyJoint.java index 0fe2795ef..62f3999cc 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRigidBodyJoint.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRigidBodyJoint.java @@ -1,6 +1,5 @@ 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.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -20,7 +19,7 @@ import java.util.logging.Logger; * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * the ipo curve of the influence factor @@ -31,18 +30,19 @@ import java.util.logging.Logger; * corrupted */ 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 - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { // TODO: implement 'Rigid body joint' constraint LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!"); } @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!"); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLike.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLike.java index ba652d9dd..7be3d7f54 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLike.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLike.java @@ -1,12 +1,13 @@ package com.jme3.scene.plugins.blender.constraints; import com.jme3.animation.Animation; -import com.jme3.animation.BoneTrack; import com.jme3.math.Quaternion; +import com.jme3.math.Transform; 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; +import com.jme3.scene.plugins.ogre.AnimData; /** * 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_OFFSET = 0x80; - /** + protected int flag; + + /** * This constructor creates the constraint instance. * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintRotLike(Structure constraintStructure, Long boneOMA, + public ConstraintRotLike(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { - super(constraintStructure, boneOMA, influenceIpo, blenderContext); + super(constraintStructure, ownerOMA, influenceIpo, blenderContext); + + flag = ((Number) data.getFieldValue("flag")).intValue(); } @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 - 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 + } } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLimit.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLimit.java index 90749ed5d..7a53926c0 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLimit.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintRotLimit.java @@ -1,13 +1,14 @@ package com.jme3.scene.plugins.blender.constraints; import com.jme3.animation.Animation; -import com.jme3.animation.BoneTrack; import com.jme3.math.FastMath; import com.jme3.math.Quaternion; +import com.jme3.math.Transform; 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; +import com.jme3.scene.plugins.ogre.AnimData; /** * 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_ZROT = 0x04; + protected float[][] limits = new float[3][2]; + protected int flag; + /** * This constructor creates the constraint instance. * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintRotLimit(Structure constraintStructure, Long boneOMA, + public ConstraintRotLimit(Structure constraintStructure, Long ownerOMA, 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 - 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 - 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; + } } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintShrinkWrap.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintShrinkWrap.java index 770903b13..e37759387 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintShrinkWrap.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintShrinkWrap.java @@ -1,7 +1,10 @@ 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.BoneTrack; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; @@ -10,28 +13,23 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.VertexBuffer.Type; 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.exceptions.BlenderFileException; 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. * @author Marcin Roguski (Kaelthas) */ /*package*/ class ConstraintShrinkWrap extends Constraint { - private static final Logger LOGGER = Logger.getLogger(ConstraintShrinkWrap.class.getName()); /** * This constructor creates the constraint instance. * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintShrinkWrap(Structure constraintStructure, Long boneOMA, + public ConstraintShrinkWrap(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { - super(constraintStructure, boneOMA, influenceIpo, blenderContext); + super(constraintStructure, ownerOMA, influenceIpo, blenderContext); } @Override - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { //loading mesh points (blender ensures that the target is a mesh-object) List pts = new ArrayList(); - 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> 1; + } } @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 - 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); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLimit.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLimit.java index b8bf6a4d1..80ec46122 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLimit.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLimit.java @@ -1,12 +1,13 @@ package com.jme3.scene.plugins.blender.constraints; import com.jme3.animation.Animation; -import com.jme3.animation.BoneTrack; +import com.jme3.math.Transform; import com.jme3.math.Vector3f; 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; +import com.jme3.scene.plugins.ogre.AnimData; /** * 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_ZMAX = 0x20; + protected float[][] limits = new float[3][2]; + protected int flag; + /** * This constructor creates the constraint instance. * * @param constraintStructure * the constraint's structure (bConstraint clss in blender 2.49). - * @param boneOMA + * @param ownerOMA * the old memory address of the constraint owner * @param influenceIpo * 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 * corrupted */ - public ConstraintSizeLimit(Structure constraintStructure, Long boneOMA, + public ConstraintSizeLimit(Structure constraintStructure, Long ownerOMA, 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 - 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 - 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; + } + } } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSplineInverseKinematic.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSplineInverseKinematic.java new file mode 100644 index 000000000..753ebf87b --- /dev/null +++ b/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!"); + } +} diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintStretchTo.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintStretchTo.java index ecbe4c758..7c56d346b 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintStretchTo.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintStretchTo.java @@ -1,6 +1,5 @@ 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.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -19,8 +18,8 @@ import java.util.logging.Logger; * This constructor creates the constraint instance. * * @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 * @param influenceIpo * 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 * 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 - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { // TODO: implement 'Stretch to' constraint LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!"); } @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!"); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintTransform.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintTransform.java index 7839fbc79..b5ac5fa30 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintTransform.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintTransform.java @@ -1,6 +1,5 @@ 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.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -19,8 +18,8 @@ import java.util.logging.Logger; * This constructor creates the constraint instance. * * @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 * @param influenceIpo * 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 * corrupted */ - public ConstraintTransform(Structure constraintStructure, Long boneOMA, + public ConstraintTransform(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { - super(constraintStructure, boneOMA, influenceIpo, blenderContext); + super(constraintStructure, ownerOMA, influenceIpo, blenderContext); } @Override - public void affectAnimation(Animation animation, int targetIndex) { + public void bakeDynamic() { // TODO: implement 'Transform' constraint LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!"); } @Override - public ConstraintType getType() { - return ConstraintType.CONSTRAINT_TYPE_TRANSFORM; + public void bakeStatic() { + // TODO: implement 'Transform' constraint + LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!"); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintType.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintType.java deleted file mode 100644 index 35c161bb6..000000000 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintType.java +++ /dev/null @@ -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 typesMap = new HashMap(ConstraintType.values().length); - /** The map containing class names and types of constraints. */ - private static final Map idsMap = new HashMap(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(); - } -} diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Feature.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Feature.java new file mode 100644 index 000000000..9d2158c2b --- /dev/null +++ b/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 locArray = ((DynamicArray) targetStructure.getFieldValue("loc")); + Vector3f loc = new Vector3f(locArray.get(0).floatValue(), locArray.get(1).floatValue(), locArray.get(2).floatValue()); + DynamicArray rotArray = ((DynamicArray) targetStructure.getFieldValue("rot")); + Quaternion rot = new Quaternion(new float[] { rotArray.get(0).floatValue(), rotArray.get(1).floatValue(), rotArray.get(2).floatValue() }); + DynamicArray sizeArray = ((DynamicArray) 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; + } +} diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/curves/CurvesHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/curves/CurvesHelper.java index d867136f0..af30f3bb3 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/curves/CurvesHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/curves/CurvesHelper.java @@ -43,9 +43,11 @@ public class CurvesHelper extends AbstractBlenderHelper { * different blender versions. * @param blenderVersion * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not */ - public 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[2] = 0; 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]); } else { verts[j] = new Vector3f(temp[0], temp[2], -temp[1]); diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/lights/LightHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/lights/LightHelper.java index 341602af4..1910ca197 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/lights/LightHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/lights/LightHelper.java @@ -59,9 +59,11 @@ public class LightHelper extends AbstractBlenderHelper { * different blender versions. * @param blenderVersion * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not */ - public LightHelper(String blenderVersion) { - super(blenderVersion); + public LightHelper(String blenderVersion, boolean fixUpAxis) { + super(blenderVersion, fixUpAxis); } public Light toLight(Structure structure, BlenderContext blenderContext) throws BlenderFileException { diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialHelper.java index 6b7a6288e..d054a3520 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialHelper.java +++ b/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.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; -import com.jme3.scene.plugins.blender.textures.TextureHelper; import com.jme3.shader.VarType; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; @@ -101,9 +100,11 @@ public class MaterialHelper extends AbstractBlenderHelper { * * @param blenderVersion * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not */ - public MaterialHelper(String blenderVersion) { - super(blenderVersion); + public MaterialHelper(String blenderVersion, boolean fixUpAxis) { + super(blenderVersion, false); // setting alpha masks alphaMasks.put(ALPHA_MASK_NONE, new IAlphaMask() { @Override @@ -204,7 +205,6 @@ public class MaterialHelper extends AbstractBlenderHelper { // texture Type colorTextureType = null; Map texturesMap = new HashMap(); - TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class); for(Entry textureEntry : materialContext.loadedTextures.entrySet()) { int mapto = textureEntry.getKey().intValue(); Texture texture = textureEntry.getValue(); diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java index 0c8433432..4c7d0b1cf 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java @@ -74,9 +74,11 @@ public class MeshHelper extends AbstractBlenderHelper { * * @param blenderVersion * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not */ - public MeshHelper(String blenderVersion) { - super(blenderVersion); + public MeshHelper(String blenderVersion, boolean fixUpAxis) { + super(blenderVersion,fixUpAxis); } /** diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java index 1ac1144ed..fb45b29e1 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java @@ -1,6 +1,20 @@ 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.scene.Geometry; 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.LoadedFeatureDataType; 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.ConstraintHelper; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; import com.jme3.scene.plugins.blender.file.FileBlockHeader; 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.ogre.AnimData; 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. @@ -37,34 +43,30 @@ import java.util.logging.Logger; * @author Marcin Roguski (Kaelthas) */ /* package */class ArmatureModifier extends Modifier { - private static final Logger LOGGER = Logger.getLogger(ArmatureModifier.class.getName()); - private static final int MAXIMUM_WEIGHTS_PER_VERTEX = 4; // 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. */ - 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. */ - 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 @@ -81,75 +83,94 @@ import java.util.logging.Logger; * corrupted */ 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"); if (pArmatureObject.isNotNull()) { - ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class); - + 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 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 chanbase = ((Structure) pose.getFieldValue("chanbase")).evaluateListBase(blenderContext); + + Map bonesPoseChannels = new HashMap(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 bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase(blenderContext); + List bonesList = new ArrayList(); + 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 animations = new ArrayList(); List 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) { Structure actionStructure = header.getStructure(blenderContext); 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; - for(BoneTrack track : tracks) { + for (BoneTrack track : tracks) { float length = track.getLength(); - if(length > maximumTrackLength) { + if (length > maximumTrackLength) { maximumTrackLength = length; } } - + Animation boneAnimation = new Animation(actionName, maximumTrackLength); boneAnimation.setTracks(tracks); 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 @SuppressWarnings("unchecked") public Node apply(Node node, BlenderContext blenderContext) { - if(invalid) { + if (invalid) { LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName()); - }//if invalid, animData will be null - if(animData == null) { + }// if invalid, animData will be null + if (animData == null) { return node; } - + // setting weights for bones List geomList = (List) blenderContext.getLoadedFeature(this.meshOMA, LoadedFeatureDataType.LOADED_FEATURE); - for(Geometry geom : geomList) { + for (Geometry geom : geomList) { Mesh mesh = geom.getMesh(); if (this.verticesWeights != null) { mesh.setMaxNumWeights(this.boneGroups); @@ -157,85 +178,109 @@ import java.util.logging.Logger; 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 constraints = blenderContext.getConstraints(boneOMA); + if (constraints != null && constraints.size() > 0) { + for (Constraint constraint : constraints) { + constraint.bakeDynamic(); + constraint.bakeStatic(); + } + } + } + + // applying animations ArrayList animList = animData.anims; if (animList != null && animList.size() > 0) { - List constraints = blenderContext.getConstraints(this.armatureObjectOMA); - HashMap anims = new HashMap(); + HashMap anims = new HashMap(animList.size()); 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); } - // applying the control to the node - SkeletonControl skeletonControl = new SkeletonControl(animData.skeleton); AnimControl control = new AnimControl(animData.skeleton); - control.setAnimations(anims); node.addControl(control); - node.addControl(skeletonControl); + node.addControl(new SkeletonControl(animData.skeleton)); } + return node; } - + /** * 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 - * 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); Structure defBase = (Structure) objectStructure.getFieldValue("defbase"); - Map groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, blenderContext); + Map groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, skeleton, blenderContext); int[] bonesGroups = new int[] { 0 }; 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.verticesWeightsIndices = boneWeightsAndIndex[1]; 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 * the mesh structure object * @param vertexListSize * a number of vertices in the model * @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 * @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 * @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 * 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 - * 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> vertexReferenceMap, Map groupToBoneIndexMap, BlenderContext blenderContext) + private VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups, Map> vertexReferenceMap, Map groupToBoneIndexMap, BlenderContext blenderContext) throws BlenderFileException { Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX); @@ -253,27 +298,28 @@ import java.util.logging.Logger; int weightIndex = 0; List dw = pDW.fetchData(blenderContext.getInputStream()); 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(); if (weight == 0.0f) { weight = 1; boneIndex = Integer.valueOf(0); } // 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); indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, boneIndex.byteValue()); } } - ++weightIndex; + ++weightIndex; } } else { for (Integer index : vertexIndices) { @@ -285,8 +331,10 @@ import java.util.logging.Logger; } } else { // 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 for (List vertexIndexList : vertexReferenceMap.values()) { // 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); 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) { int maxWeightsPerVert = 0; @@ -339,11 +391,9 @@ import java.util.logging.Logger; } } weightsFloatData.rewind(); - - // mesh.setMaxNumWeights(maxWeightsPerVert); return maxWeightsPerVert; } - + @Override public String getType() { return Modifier.ARMATURE_MODIFIER_DATA; diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ModifierHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ModifierHelper.java index b089bacf1..39cb82ee7 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ModifierHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ModifierHelper.java @@ -55,9 +55,11 @@ public class ModifierHelper extends AbstractBlenderHelper { * different blender versions. * @param blenderVersion * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not */ - public ModifierHelper(String blenderVersion) { - super(blenderVersion); + public ModifierHelper(String blenderVersion, boolean fixUpAxis) { + super(blenderVersion, fixUpAxis); } /** diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java index b66b0aa26..2ee31d68a 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java @@ -1,5 +1,11 @@ package com.jme3.scene.plugins.blender.modifiers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + import com.jme3.animation.AnimControl; import com.jme3.animation.Animation; import com.jme3.animation.SpatialTrack; @@ -7,17 +13,11 @@ import com.jme3.scene.Node; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.animations.Ipo; import com.jme3.scene.plugins.blender.animations.IpoHelper; -import com.jme3.scene.plugins.blender.constraints.Constraint; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; import com.jme3.scene.plugins.blender.file.FileBlockHeader; import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.ogre.AnimData; -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. @@ -51,21 +51,22 @@ import java.util.logging.Logger; * corrupted */ 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"); if (pIpo.isNotNull()) { // check if there is an action name connected with this ipo String objectAnimationName = null; List actionBlocks = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00)); - for (FileBlockHeader actionBlock : actionBlocks) { - Structure action = actionBlock.getStructure(blenderContext); - List 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 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); Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext); int fps = blenderContext.getBlenderKey().getFps(); - + // calculating track for the only bone in this skeleton SpatialTrack track = (SpatialTrack) ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps); @@ -89,7 +90,7 @@ import java.util.logging.Logger; animations.add(animation); animData = new AnimData(null, animations); - objectOMA = objectStructure.getOldMemoryAddress(); + blenderContext.setAnimData(objectOMA, animData); } } @@ -98,30 +99,20 @@ import java.util.logging.Logger; if(invalid) { LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName()); }//if invalid, animData will be null - if(animData == null) { - return node; - } - - ArrayList animList = animData.anims; - if (animList != null && animList.size() > 0) { - List constraints = blenderContext.getConstraints(this.objectOMA); - HashMap anims = new HashMap(); - 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 animList = animData.anims; + if (animList != null && animList.size() > 0) { + HashMap anims = new HashMap(); + 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; } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/objects/ObjectHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/objects/ObjectHelper.java index 7ddfc353f..37f29d7a8 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/objects/ObjectHelper.java +++ b/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.LoadedFeatureDataType; 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.curves.CurvesHelper; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -99,9 +100,11 @@ public class ObjectHelper extends AbstractBlenderHelper { * different blender versions. * @param blenderVersion * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not */ - public 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); - ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); //get object data int type = ((Number)objectStructure.getFieldValue("type")).intValue(); String name = objectStructure.getName(); 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(); boolean visible = (restrictflag & 0x01) != 0; Object result = null; @@ -143,7 +141,7 @@ public class ObjectHelper extends AbstractBlenderHelper { parent = this.toObject(parentStructure, blenderContext); } - Transform t = objectHelper.getTransformation(objectStructure, blenderContext); + Transform t = this.getTransformation(objectStructure, blenderContext); try { switch(type) { @@ -245,7 +243,7 @@ public class ObjectHelper extends AbstractBlenderHelper { } break; 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; default: LOGGER.log(Level.WARNING, "Unknown object type: {0}", type); @@ -255,13 +253,25 @@ public class ObjectHelper extends AbstractBlenderHelper { } 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 objectConstraints = blenderContext.getConstraints(objectStructure.getOldMemoryAddress()); + if(objectConstraints!=null) { + for(Constraint objectConstraint : objectConstraints) { + objectConstraint.bakeStatic(); + } + } + //reading custom properties Properties properties = this.loadProperties(objectStructure, blenderContext); if(result instanceof Spatial && properties != null && properties.getValue() != null) { ((Spatial)result).setUserData("properties", properties); } - - blenderContext.addLoadedFeatures(objectStructure.getOldMemoryAddress(), name, objectStructure, result); } return result; } @@ -292,13 +302,7 @@ public class ObjectHelper extends AbstractBlenderHelper { Vector3f translation = localMatrix.toTranslationVector(); 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) { 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 - * the name of the matrix structure - * @return object's matrix + * the name of the matrix + * @return the required matrix */ @SuppressWarnings("unchecked") - protected Matrix4f getMatrix(Structure objectStructure, String matrixName) { + public Matrix4f getMatrix(Structure structure, String matrixName, boolean applyFixUpAxis) { Matrix4f result = new Matrix4f(); - DynamicArray obmat = (DynamicArray)objectStructure.getFieldValue(matrixName); - for(int i = 0; i < 4; ++i) { - for(int j = 0; j < 4; ++j) { + DynamicArray obmat = (DynamicArray)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()); } } + 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; } + /** + * 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 public void clearState() { fixUpAxis = false; diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/particles/ParticlesHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/particles/ParticlesHelper.java index 8ae84ac6a..de1252a34 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/particles/ParticlesHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/particles/ParticlesHelper.java @@ -86,9 +86,11 @@ public class ParticlesHelper extends AbstractBlenderHelper { * different blender versions. * @param blenderVersion * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not */ - public ParticlesHelper(String blenderVersion) { - super(blenderVersion); + public ParticlesHelper(String blenderVersion, boolean fixUpAxis) { + super(blenderVersion, fixUpAxis); } @SuppressWarnings("unchecked") diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/NoiseGenerator.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/NoiseGenerator.java index c129662a7..a8bd890ce 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/NoiseGenerator.java +++ b/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 */ public NoiseGenerator(String blenderVersion) { - super(blenderVersion); + super(blenderVersion, false); this.loadConstants(); } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java index 0b6ba6bf7..2248efdd3 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java @@ -135,9 +135,11 @@ public class TextureHelper extends AbstractBlenderHelper { * * @param blenderVersion * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not */ - public TextureHelper(String blenderVersion) { - super(blenderVersion); + public TextureHelper(String blenderVersion, boolean fixUpAxis) { + super(blenderVersion, false); noiseGenerator = new NoiseGenerator(blenderVersion); textureGenerators.put(Integer.valueOf(TEX_BLEND), new TextureGeneratorBlend(noiseGenerator)); textureGenerators.put(Integer.valueOf(TEX_CLOUDS), new TextureGeneratorClouds(noiseGenerator));