From 3a84693f686b484869adffd0da20e1302dc176d9 Mon Sep 17 00:00:00 2001 From: "Kae..pl" Date: Fri, 27 Jan 2012 21:22:11 +0000 Subject: [PATCH] Many changes: - simplified implementation for bones loading - static bones poses discarded - loading of object animation for blender 2.50+ added (didn't work for these versions before) - several small bugfixes git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9115 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../scene/plugins/blender/BlenderContext.java | 28 ++ .../blender/animations/ArmatureHelper.java | 385 +++++++---------- .../blender/animations/BoneContext.java | 204 +++++++++ .../scene/plugins/blender/animations/Ipo.java | 409 +++++++++--------- .../plugins/blender/animations/IpoHelper.java | 281 +++++++----- .../blender/constraints/Constraint.java | 22 +- .../blender/constraints/ConstraintAction.java | 8 +- .../constraints/ConstraintChildOf.java | 8 +- .../constraints/ConstraintClampTo.java | 8 +- .../constraints/ConstraintDampTrack.java | 8 +- .../constraints/ConstraintDistLimit.java | 28 +- .../constraints/ConstraintFollowPath.java | 8 +- .../blender/constraints/ConstraintHelper.java | 6 +- .../ConstraintInverseKinematics.java | 8 +- .../constraints/ConstraintLocLike.java | 24 +- .../constraints/ConstraintLocLimit.java | 22 +- .../constraints/ConstraintLockTrack.java | 8 +- .../blender/constraints/ConstraintMinMax.java | 8 +- .../blender/constraints/ConstraintNull.java | 5 +- .../blender/constraints/ConstraintPivot.java | 8 +- .../blender/constraints/ConstraintPython.java | 8 +- .../constraints/ConstraintRigidBodyJoint.java | 8 +- .../constraints/ConstraintRotLike.java | 22 +- .../constraints/ConstraintRotLimit.java | 34 +- .../constraints/ConstraintShrinkWrap.java | 8 +- .../constraints/ConstraintSizeLike.java | 20 +- .../constraints/ConstraintSizeLimit.java | 18 +- .../ConstraintSplineInverseKinematic.java | 8 +- .../constraints/ConstraintStretchTo.java | 8 +- .../constraints/ConstraintTransform.java | 8 +- .../plugins/blender/constraints/Feature.java | 16 +- .../blender/modifiers/ArmatureModifier.java | 80 ++-- .../blender/modifiers/ModifierHelper.java | 207 ++++++--- .../modifiers/ObjectAnimationModifier.java | 83 ++-- .../plugins/blender/objects/ObjectHelper.java | 2 +- 35 files changed, 1104 insertions(+), 912 deletions(-) create mode 100644 engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java 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 5311a23db..8884c321e 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java @@ -46,6 +46,7 @@ import com.jme3.asset.AssetManager; import com.jme3.asset.BlenderKey; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; +import com.jme3.scene.plugins.blender.animations.BoneContext; import com.jme3.scene.plugins.blender.animations.Ipo; import com.jme3.scene.plugins.blender.constraints.Constraint; import com.jme3.scene.plugins.blender.file.BlenderInputStream; @@ -112,6 +113,8 @@ public class BlenderContext { private Map skeletons = new HashMap(); /** A map of mesh contexts. */ protected Map meshContexts = new HashMap(); + /** A map of bone contexts. */ + protected Map boneContexts = new HashMap(); /** A map of material contexts. */ protected Map materialContexts = new HashMap(); /** A map og helpers that perform loading. */ @@ -541,7 +544,32 @@ public class BlenderContext { public MeshContext getMeshContext(Long meshOMA) { return this.meshContexts.get(meshOMA); } + + /** + * This method sets the bone context for the given bone old memory address. + * If the context is already set it will be replaced. + * + * @param boneOMA + * the bone's old memory address + * @param boneContext + * the bones's context + */ + public void setBoneContext(Long boneOMA, BoneContext boneContext) { + this.boneContexts.put(boneOMA, boneContext); + } + /** + * This method returns the bone context for the given bone old memory + * address. If no context exists then null is returned. + * + * @param boneOMA + * the bone's old memory address + * @return bone's context + */ + public BoneContext getBoneContext(Long boneOMA) { + return boneContexts.get(boneOMA); + } + /** * This method sets the material context for the given material. If the * context is already set it will be replaced. 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 a06cdb70e..120e556ac 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 @@ -42,44 +42,39 @@ import com.jme3.animation.Bone; import com.jme3.animation.BoneTrack; import com.jme3.animation.Skeleton; import com.jme3.math.Matrix4f; -import com.jme3.math.Quaternion; -import com.jme3.math.Transform; import com.jme3.scene.plugins.blender.AbstractBlenderHelper; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.curves.BezierCurve; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; -import com.jme3.scene.plugins.blender.file.BlenderInputStream; -import com.jme3.scene.plugins.blender.file.DynamicArray; -import com.jme3.scene.plugins.blender.file.FileBlockHeader; import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; -import com.jme3.scene.plugins.blender.objects.ObjectHelper; /** - * This class defines the methods to calculate certain aspects of animation and armature functionalities. + * This class defines the methods to calculate certain aspects of animation and + * armature functionalities. + * * @author Marcin Roguski (Kaelthas) */ public class ArmatureHelper extends AbstractBlenderHelper { - private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName()); - - /** A map of bones and their old memory addresses. */ - private Map 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, boolean fixUpAxis) { - super(blenderVersion, fixUpAxis); - } - - /** + private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName()); + + /** A map of bones and their old memory addresses. */ + private Map bonesOMAs = 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, boolean fixUpAxis) { + super(blenderVersion, fixUpAxis); + } + + /** * This method builds the object's bones structure. * * @param boneStructure @@ -96,119 +91,61 @@ public class ArmatureHelper extends AbstractBlenderHelper { * an exception is thrown when there is problem with the blender * file */ - @SuppressWarnings("unchecked") - public void buildBones(Structure boneStructure, Bone parent, List 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; + public void buildBones(Structure boneStructure, Bone parent, List result, Matrix4f arbt, final Map bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { + BoneContext bc = new BoneContext(boneStructure, arbt, bonesPoseChannels, blenderContext); + bc.buildBone(result, bonesOMAs, blenderContext); } - /** - * This method returns the old memory address of a bone. If the bone does not exist in the blend file - zero is - * returned. - * @param bone - * the bone whose old memory address we seek - * @return the old memory address of the given bone - */ - public Long getBoneOMA(Bone bone) { - Long result = bonesOMAs.get(bone); - if (result == null) { - result = Long.valueOf(0); - } - return result; - } - /** - * This method returns the bind transform for the specified bone. + * This method returns the old memory address of a bone. If the bone does + * not exist in the blend file - zero is returned. + * * @param bone - * the bone - * @return bone's bind transform + * the bone whose old memory address we seek + * @return the old memory address of the given bone + */ + public Long getBoneOMA(Bone bone) { + Long result = bonesOMAs.get(bone); + if (result == null) { + result = Long.valueOf(0); + } + return result; + } + + /** + * This method returns a map where the key is the object's group index that + * is used by a bone and the key is the bone index in the armature. + * + * @param defBaseStructure + * a bPose structure of the object + * @return bone group-to-index map + * @throws BlenderFileException + * this exception is thrown when the blender file is somehow + * corrupted */ - public Transform getBoneBindTransform(Bone bone) { - return boneBindTransforms.get(bone); - } + public Map getGroupToBoneIndexMap(Structure defBaseStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException { + Map result = null; + 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 = this.getBoneIndex(skeleton, deformGroupName); + if (boneIndex != null) { + result.put(Integer.valueOf(groupIndex), boneIndex); + } + ++groupIndex; + } + } + return result; + } - /** - * This method returns a map where the key is the object's group index that is used by a bone and the key is the - * bone index in the armature. - * @param defBaseStructure - * a bPose structure of the object - * @return bone group-to-index map - * @throws BlenderFileException - * this exception is thrown when the blender file is somehow corrupted - */ - public Map getGroupToBoneIndexMap(Structure defBaseStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException { - Map result = null; - 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 = this.getBoneIndex(skeleton, deformGroupName); - if (boneIndex != null) { - result.put(Integer.valueOf(groupIndex), boneIndex); - } - ++groupIndex; - } - } - return result; - } + @Override + public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) { + return true; + } - @Override - public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) { - return true; - } - /** * This method retuns the bone tracks for animation. * @@ -221,16 +158,17 @@ public class ArmatureHelper extends AbstractBlenderHelper { * an exception is thrown when there are problems with the blend * file */ - public BoneTrack[] getTracks(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException { - if (blenderVersion < 250) { - return this.getTracks249(actionStructure, skeleton, blenderContext); - } else { - return this.getTracks250(actionStructure, skeleton, blenderContext); - } - } - - /** - * This method retuns the bone tracks for animation for blender version 2.50 and higher. + public BoneTrack[] getTracks(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException { + if (blenderVersion < 250) { + return this.getTracks249(actionStructure, skeleton, blenderContext); + } else { + return this.getTracks250(actionStructure, skeleton, blenderContext); + } + } + + /** + * This method retuns the bone tracks for animation for blender version 2.50 + * and higher. * * @param actionStructure * the structure containing the tracks @@ -241,45 +179,37 @@ public class ArmatureHelper extends AbstractBlenderHelper { * an exception is thrown when there are problems with the blend * file */ - private BoneTrack[] getTracks250(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException { - LOGGER.log(Level.INFO, "Getting tracks!"); - int fps = blenderContext.getBlenderKey().getFps(); - Structure groups = (Structure) actionStructure.getFieldValue("groups"); - List actionGroups = groups.evaluateListBase(blenderContext);//bActionGroup - List tracks = new ArrayList(); - for (Structure actionGroup : actionGroups) { - String name = actionGroup.getFieldValue("name").toString(); - Integer boneIndex = this.getBoneIndex(skeleton, name); - if (boneIndex != null) { - List channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(blenderContext); - BezierCurve[] bezierCurves = new BezierCurve[channels.size()]; - int channelCounter = 0; - for (Structure c : channels) { - //reading rna path first - BlenderInputStream bis = blenderContext.getInputStream(); - int currentPosition = bis.getPosition(); - Pointer pRnaPath = (Pointer) c.getFieldValue("rna_path"); - FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pRnaPath.getOldMemoryAddress()); - bis.setPosition(dataFileBlock.getBlockPosition()); - String rnaPath = bis.readString(); - bis.setPosition(currentPosition); - int arrayIndex = ((Number) c.getFieldValue("array_index")).intValue(); - int type = this.getCurveType(rnaPath, arrayIndex); + private BoneTrack[] getTracks250(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException { + LOGGER.log(Level.INFO, "Getting tracks!"); + IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class); + int fps = blenderContext.getBlenderKey().getFps(); + Structure groups = (Structure) actionStructure.getFieldValue("groups"); + List actionGroups = groups.evaluateListBase(blenderContext);// bActionGroup + List tracks = new ArrayList(); + for (Structure actionGroup : actionGroups) { + String name = actionGroup.getFieldValue("name").toString(); + int boneIndex = this.getBoneIndex(skeleton, name); + if (boneIndex >= 0) { + List channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(blenderContext); + BezierCurve[] bezierCurves = new BezierCurve[channels.size()]; + int channelCounter = 0; + for (Structure c : channels) { + int type = ipoHelper.getCurveType(c, blenderContext); + Pointer pBezTriple = (Pointer) c.getFieldValue("bezt"); + List bezTriples = pBezTriple.fetchData(blenderContext.getInputStream()); + bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2); + } - Pointer pBezTriple = (Pointer) c.getFieldValue("bezt"); - List bezTriples = pBezTriple.fetchData(blenderContext.getInputStream()); - bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2); - } + Ipo ipo = new Ipo(bezierCurves, fixUpAxis); + tracks.add((BoneTrack) ipo.calculateTrack(boneIndex, 0, ipo.getLastFrame(), fps, false)); + } + } + return tracks.toArray(new BoneTrack[tracks.size()]); + } - Ipo ipo = new Ipo(bezierCurves, fixUpAxis); - tracks.add((BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps)); - } - } - return tracks.toArray(new BoneTrack[tracks.size()]); - } - - /** - * This method retuns the bone tracks for animation for blender version 2.49 (and probably several lower versions too). + /** + * This method retuns the bone tracks for animation for blender version 2.49 + * (and probably several lower versions too). * * @param actionStructure * the structure containing the tracks @@ -290,61 +220,44 @@ public class ArmatureHelper extends AbstractBlenderHelper { * an exception is thrown when there are problems with the blend * file */ - private BoneTrack[] getTracks249(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException { - LOGGER.log(Level.INFO, "Getting tracks!"); - IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class); - int fps = blenderContext.getBlenderKey().getFps(); - Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase"); - List actionChannels = chanbase.evaluateListBase(blenderContext);//bActionChannel - List tracks = new ArrayList(); - for (Structure bActionChannel : actionChannels) { - String name = bActionChannel.getFieldValue("name").toString(); - Integer boneIndex = this.getBoneIndex(skeleton, name); - if (boneIndex != null && boneIndex.intValue() >= 0) { - Pointer p = (Pointer) bActionChannel.getFieldValue("ipo"); - if (!p.isNull()) { - Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0); - Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext); - tracks.add((BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps)); - } - } - } - return tracks.toArray(new BoneTrack[tracks.size()]); - } + private BoneTrack[] getTracks249(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException { + LOGGER.log(Level.INFO, "Getting tracks!"); + IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class); + int fps = blenderContext.getBlenderKey().getFps(); + Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase"); + List actionChannels = chanbase.evaluateListBase(blenderContext);// bActionChannel + List tracks = new ArrayList(); + for (Structure bActionChannel : actionChannels) { + String name = bActionChannel.getFieldValue("name").toString(); + int boneIndex = this.getBoneIndex(skeleton, name); + if (boneIndex >= 0) { + Pointer p = (Pointer) bActionChannel.getFieldValue("ipo"); + if (!p.isNull()) { + Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0); + Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext); + tracks.add((BoneTrack) ipo.calculateTrack(boneIndex, 0, ipo.getLastFrame(), fps, false)); + } + } + } + return tracks.toArray(new BoneTrack[tracks.size()]); + } - /** - * This method returns the index of the bone in the given skeleton. - * @param skeleton the skeleton - * @param boneName the name of the bone - * @return the index of the bone - */ - private int getBoneIndex(Skeleton skeleton, String boneName) { - int result = -1; - for(int i=0;i children = new ArrayList(); + /** Created bone (available after calling 'buildBone' method). */ + private Bone bone; + /** Bone's pose transform (available after calling 'buildBone' method). */ + private Transform poseTransform = new Transform(); + /** The bone's rest matrix. */ + private Matrix4f restMatrix; + /** Bone's total inverse transformation. */ + private Matrix4f inverseTotalTransformation; + /** Bone's parent inverse matrix. */ + private Matrix4f inverseParentMatrix; + + /** + * Constructor. Creates the basic set of bone's data. + * + * @param boneStructure + * the bone's structure + * @param objectToArmatureMatrix + * object-to-armature transformation matrix + * @param bonesPoseChannels + * a map of pose channels for each bone OMA + * @param blenderContext + * the blender context + * @throws BlenderFileException + * an exception is thrown when problem with blender data reading + * occurs + */ + public BoneContext(Structure boneStructure, Matrix4f objectToArmatureMatrix, final Map bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { + this(boneStructure, null, objectToArmatureMatrix, bonesPoseChannels, blenderContext); + } + + /** + * Constructor. Creates the basic set of bone's data. + * + * @param boneStructure + * the bone's structure + * @param parent + * bone's parent (null if the bone is the root bone) + * @param objectToArmatureMatrix + * object-to-armature transformation matrix + * @param bonesPoseChannels + * a map of pose channels for each bone OMA + * @param blenderContext + * the blender context + * @throws BlenderFileException + * an exception is thrown when problem with blender data reading + * occurs + */ + private BoneContext(Structure boneStructure, BoneContext parent, Matrix4f objectToArmatureMatrix, final Map bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { + this.parent = parent; + this.boneStructure = boneStructure; + boneName = boneStructure.getFieldValue("name").toString(); + ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); + armatureMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", true); + + fixUpAxis = blenderContext.getBlenderKey().isFixUpAxis(); + this.computeRestMatrix(objectToArmatureMatrix); + List childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext); + for (Structure child : childbase) { + this.children.add(new BoneContext(child, this, objectToArmatureMatrix, bonesPoseChannels, blenderContext)); + } + + poseChannel = bonesPoseChannels.get(boneStructure.getOldMemoryAddress()); + + blenderContext.setBoneContext(boneStructure.getOldMemoryAddress(), this); + } + + /** + * This method computes the rest matrix for the bone. + * + * @param objectToArmatureMatrix + * object-to-armature transformation matrix + */ + private void computeRestMatrix(Matrix4f objectToArmatureMatrix) { + if (parent != null) { + inverseParentMatrix = parent.inverseTotalTransformation.clone(); + } else if (fixUpAxis) { + inverseParentMatrix = objectToArmatureMatrix.clone(); + } else { + inverseParentMatrix = Matrix4f.IDENTITY.clone(); + } + + restMatrix = armatureMatrix.clone(); + inverseTotalTransformation = restMatrix.invert(); + + restMatrix = inverseParentMatrix.mult(restMatrix); + + for (BoneContext child : this.children) { + child.computeRestMatrix(objectToArmatureMatrix); + } + } + + /** + * This method computes the pose transform for the bone. + */ + @SuppressWarnings("unchecked") + private void computePoseTransform() { + DynamicArray loc = (DynamicArray) poseChannel.getFieldValue("loc"); + DynamicArray size = (DynamicArray) poseChannel.getFieldValue("size"); + DynamicArray quat = (DynamicArray) poseChannel.getFieldValue("quat"); + if (fixUpAxis) { + poseTransform.setTranslation(loc.get(0).floatValue(), -loc.get(2).floatValue(), loc.get(1).floatValue()); + poseTransform.setRotation(new Quaternion(quat.get(1).floatValue(), quat.get(3).floatValue(), -quat.get(2).floatValue(), quat.get(0).floatValue())); + poseTransform.setScale(size.get(0).floatValue(), size.get(2).floatValue(), size.get(1).floatValue()); + } else { + poseTransform.setTranslation(loc.get(0).floatValue(), loc.get(1).floatValue(), loc.get(2).floatValue()); + poseTransform.setRotation(new Quaternion(quat.get(0).floatValue(), quat.get(1).floatValue(), quat.get(2).floatValue(), quat.get(3).floatValue())); + poseTransform.setScale(size.get(0).floatValue(), size.get(1).floatValue(), size.get(2).floatValue()); + } + + Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation()); + localTransform.setScale(bone.getLocalScale()); + localTransform.getTranslation().addLocal(poseTransform.getTranslation()); + localTransform.getRotation().multLocal(poseTransform.getRotation()); + localTransform.getScale().multLocal(poseTransform.getScale()); + + poseTransform.set(localTransform); + } + + /** + * This method builds the bone. It recursively builds the bone's children. + * + * @param bones + * a list of bones where the newly created bone will be added + * @param boneOMAs + * the map between bone and its old memory address + * @param blenderContext + * the blender context + * @return newly created bone + */ + public Bone buildBone(List bones, Map boneOMAs, BlenderContext blenderContext) { + Long boneOMA = boneStructure.getOldMemoryAddress(); + bone = new Bone(boneName); + bones.add(bone); + boneOMAs.put(bone, boneOMA); + blenderContext.addLoadedFeatures(boneOMA, boneName, boneStructure, bone); + + Matrix4f pose = this.restMatrix.clone(); + ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); + + Vector3f poseLocation = pose.toTranslationVector(); + Quaternion rotation = pose.toRotationQuat(); + Vector3f scale = objectHelper.getScale(pose); + + bone.setBindTransforms(poseLocation, rotation, scale); + for (BoneContext child : children) { + bone.addChild(child.buildBone(bones, boneOMAs, blenderContext)); + } + + this.computePoseTransform(); + + return bone; + } + + /** + * @return bone's pose transformation + */ + public Transform getPoseTransform() { + return poseTransform; + } + + /** + * @return built bone (available after calling 'buildBone' method) + */ + public Bone getBone() { + return bone; + } +} diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java b/engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java index 1d243a620..58ce48cf9 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java @@ -9,209 +9,228 @@ import com.jme3.math.Vector3f; import com.jme3.scene.plugins.blender.curves.BezierCurve; /** - * This class is used to calculate bezier curves value for the given frames. The Ipo (interpolation object) consists - * of several b-spline curves (connected 3rd degree bezier curves) of a different type. + * This class is used to calculate bezier curves value for the given frames. The + * Ipo (interpolation object) consists of several b-spline curves (connected 3rd + * degree bezier curves) of a different type. + * * @author Marcin Roguski */ public class Ipo { - public static final int AC_LOC_X = 1; - public static final int AC_LOC_Y = 2; - public static final int AC_LOC_Z = 3; - public static final int OB_ROT_X = 7; - public static final int OB_ROT_Y = 8; - public static final int OB_ROT_Z = 9; - public static final int AC_SIZE_X = 13; - public static final int AC_SIZE_Y = 14; - public static final int AC_SIZE_Z = 15; - public static final int AC_QUAT_W = 25; - public static final int AC_QUAT_X = 26; - public static final int AC_QUAT_Y = 27; - public static final int AC_QUAT_Z = 28; - - /** A list of bezier curves for this interpolation object. */ - private BezierCurve[] bezierCurves; - /** Each ipo contains one bone track. */ - private Track calculatedTrack; - /** This variable indicates if the Y asxis is the UP axis or not. */ - protected boolean fixUpAxis; - - /** - * Constructor. Stores the bezier curves. - * @param bezierCurves - * a table of bezier curves - */ - public Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis) { - this.bezierCurves = bezierCurves; - this.fixUpAxis = fixUpAxis; - } + public static final int AC_LOC_X = 1; + public static final int AC_LOC_Y = 2; + public static final int AC_LOC_Z = 3; + public static final int OB_ROT_X = 7; + public static final int OB_ROT_Y = 8; + public static final int OB_ROT_Z = 9; + public static final int AC_SIZE_X = 13; + public static final int AC_SIZE_Y = 14; + public static final int AC_SIZE_Z = 15; + public static final int AC_QUAT_W = 25; + public static final int AC_QUAT_X = 26; + public static final int AC_QUAT_Y = 27; + public static final int AC_QUAT_Z = 28; - /** - * This method calculates the ipo value for the first curve. - * @param frame - * the frame for which the value is calculated - * @return calculated ipo value - */ - public float calculateValue(int frame) { - return this.calculateValue(frame, 0); - } + /** A list of bezier curves for this interpolation object. */ + private BezierCurve[] bezierCurves; + /** Each ipo contains one bone track. */ + private Track calculatedTrack; + /** This variable indicates if the Y asxis is the UP axis or not. */ + protected boolean fixUpAxis; - /** - * This method calculates the ipo value for the curve of the specified index. Make sure you do not exceed the - * curves amount. Alway chech the amount of curves before calling this method. - * @param frame - * the frame for which the value is calculated - * @param curveIndex - * the index of the curve - * @return calculated ipo value - */ - public float calculateValue(int frame, int curveIndex) { - return bezierCurves[curveIndex].evaluate(frame, BezierCurve.Y_VALUE); - } + /** + * Constructor. Stores the bezier curves. + * + * @param bezierCurves + * a table of bezier curves + */ + public Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis) { + this.bezierCurves = bezierCurves; + this.fixUpAxis = fixUpAxis; + } - /** - * This method returns the curves amount. - * @return the curves amount - */ - public int getCurvesAmount() { - return bezierCurves.length; - } + /** + * This method calculates the ipo value for the first curve. + * + * @param frame + * the frame for which the value is calculated + * @return calculated ipo value + */ + public float calculateValue(int frame) { + return this.calculateValue(frame, 0); + } - /** - * This method returns the frame where last bezier triple center point of the specified bezier curve is located. - * @return the frame number of the last defined bezier triple point for the specified ipo - */ - public int getLastFrame() { - int result = 1; - for (int i = 0; i < bezierCurves.length; ++i) { - int tempResult = bezierCurves[i].getLastFrame(); - if (tempResult > result) { - result = tempResult; - } - } - return result; - } + /** + * This method calculates the ipo value for the curve of the specified + * index. Make sure you do not exceed the curves amount. Alway chech the + * amount of curves before calling this method. + * + * @param frame + * the frame for which the value is calculated + * @param curveIndex + * the index of the curve + * @return calculated ipo value + */ + public float calculateValue(int frame, int curveIndex) { + return bezierCurves[curveIndex].evaluate(frame, BezierCurve.Y_VALUE); + } - /** - * This method calculates the value of the curves as a bone track between the specified frames. - * @param targetIndex - * the index of the target for which the method calculates the tracks - * IMPORTANT! Aet to -1 (or any negative number) if you want to load spatial animation. - * @param startFrame - * the firs frame of tracks (inclusive) - * @param stopFrame - * the last frame of the tracks (inclusive) - * @param fps - * frame rate (frames per second) - * @return bone track for the specified bone - */ - public Track calculateTrack(int targetIndex, int startFrame, int stopFrame, int fps) { - if(calculatedTrack == null) { - //preparing data for track - int framesAmount = stopFrame - startFrame; - float start = (startFrame - 1.0f) / fps; - float timeBetweenFrames = 1.0f / fps; + /** + * This method returns the curves amount. + * + * @return the curves amount + */ + public int getCurvesAmount() { + return bezierCurves.length; + } - float[] times = new float[framesAmount + 1]; - Vector3f[] translations = new Vector3f[framesAmount + 1]; - float[] translation = new float[3]; - Quaternion[] rotations = new Quaternion[framesAmount + 1]; - float[] quaternionRotation = new float[4]; - float[] objectRotation = new float[3]; - boolean bSpatialTrack = targetIndex < 0; - Vector3f[] scales = new Vector3f[framesAmount + 1]; - float[] scale = new float[] {1.0f, 1.0f, 1.0f}; - float degreeToRadiansFactor = FastMath.DEG_TO_RAD * 10;//the values in blender are divided by 10, so we need to mult it here - - //calculating track data - for (int frame = startFrame; frame <= stopFrame; ++frame) { - int index = frame - startFrame; - times[index] = start + (frame - 1) * timeBetweenFrames; - for (int j = 0; j < bezierCurves.length; ++j) { - double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE); - switch (bezierCurves[j].getType()) { - //LOCATION - case AC_LOC_X: - translation[0] = (float) value; - break; - case AC_LOC_Y: - if(fixUpAxis) { - translation[2] = (float) -value; - } else { - translation[1] = (float) value; - } - break; - case AC_LOC_Z: - translation[fixUpAxis ? 1 : 2] = (float) value; - break; - - //ROTATION (used with object animation) - //the value here is in degrees divided by 10 (so in example: 9 = PI/2) - case OB_ROT_X: - objectRotation[0] = (float) value * degreeToRadiansFactor; - break; - case OB_ROT_Y: - if(fixUpAxis) { - objectRotation[2] = (float) -value * degreeToRadiansFactor; - } else { - objectRotation[1] = (float) value * degreeToRadiansFactor; - } - break; - case OB_ROT_Z: - objectRotation[fixUpAxis ? 1 : 2] = (float) value * degreeToRadiansFactor; - break; - - //SIZE - case AC_SIZE_X: - scale[0] = (float) value; - break; - case AC_SIZE_Y: - if(fixUpAxis) { - scale[2] = (float) value; - } else { - scale[1] = (float) value; - } - break; - case AC_SIZE_Z: - scale[fixUpAxis ? 1 : 2] = (float) value; - break; - - //QUATERNION ROTATION (used with bone animation) - case AC_QUAT_W: - quaternionRotation[3] = (float) value; - break; - case AC_QUAT_X: - quaternionRotation[0] = (float) value; - break; - case AC_QUAT_Y: - if(fixUpAxis) { - quaternionRotation[2] = -(float) value; - } else { - quaternionRotation[1] = (float) value; - } - break; - case AC_QUAT_Z: - if(fixUpAxis) { - quaternionRotation[1] = (float) value; - } else { - quaternionRotation[2] = (float) value; - } - break; - default: - throw new IllegalStateException("Unknown ipo curve type: " + bezierCurves[j].getType()); - } - } - translations[index] = new Vector3f(translation[0], translation[1], translation[2]); - rotations[index] = bSpatialTrack ? new Quaternion().fromAngles(objectRotation) - : new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]); - scales[index] = new Vector3f(scale[0], scale[1], scale[2]); - } - if(bSpatialTrack) { - calculatedTrack = new SpatialTrack(times, translations, rotations, scales); - } else { - calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales); - } - } - return calculatedTrack; - } + /** + * This method returns the frame where last bezier triple center point of + * the specified bezier curve is located. + * + * @return the frame number of the last defined bezier triple point for the + * specified ipo + */ + public int getLastFrame() { + int result = 1; + for (int i = 0; i < bezierCurves.length; ++i) { + int tempResult = bezierCurves[i].getLastFrame(); + if (tempResult > result) { + result = tempResult; + } + } + return result; + } + + /** + * This method calculates the value of the curves as a bone track between + * the specified frames. + * + * @param targetIndex + * the index of the target for which the method calculates the + * tracks IMPORTANT! Aet to -1 (or any negative number) if you + * want to load spatial animation. + * @param startFrame + * the firs frame of tracks (inclusive) + * @param stopFrame + * the last frame of the tracks (inclusive) + * @param fps + * frame rate (frames per second) + * @param spatialTrack + * this flag indicates if the track belongs to a spatial or to a + * bone; the diference is important because it appears that bones + * in blender have the same type of coordinate system (Y as UP) + * as jme while other features have different one (Z is UP) + * @return bone track for the specified bone + */ + public Track calculateTrack(int targetIndex, int startFrame, int stopFrame, int fps, boolean spatialTrack) { + if (calculatedTrack == null) { + // preparing data for track + int framesAmount = stopFrame - startFrame; + float start = (startFrame - 1.0f) / fps; + float timeBetweenFrames = 1.0f / fps; + + float[] times = new float[framesAmount + 1]; + Vector3f[] translations = new Vector3f[framesAmount + 1]; + float[] translation = new float[3]; + Quaternion[] rotations = new Quaternion[framesAmount + 1]; + float[] quaternionRotation = new float[4]; + float[] objectRotation = new float[3]; + Vector3f[] scales = new Vector3f[framesAmount + 1]; + float[] scale = new float[] { 1.0f, 1.0f, 1.0f }; + float degreeToRadiansFactor = FastMath.DEG_TO_RAD * 10;// the values in blender are divided by 10, so we need to mult it here + + // calculating track data + for (int frame = startFrame; frame <= stopFrame; ++frame) { + int index = frame - startFrame; + times[index] = start + (frame - 1) * timeBetweenFrames; + for (int j = 0; j < bezierCurves.length; ++j) { + double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE); + switch (bezierCurves[j].getType()) { + // LOCATION + case AC_LOC_X: + translation[0] = (float) value; + break; + case AC_LOC_Y: + if (fixUpAxis && spatialTrack) { + translation[2] = (float) -value; + } else { + translation[1] = (float) value; + } + break; + case AC_LOC_Z: + translation[fixUpAxis && spatialTrack ? 1 : 2] = (float) value; + break; + + // ROTATION (used with object animation) + // the value here is in degrees divided by 10 (so in + // example: 9 = PI/2) + case OB_ROT_X: + objectRotation[0] = (float) value * degreeToRadiansFactor; + break; + case OB_ROT_Y: + if (fixUpAxis) { + objectRotation[2] = (float) -value * degreeToRadiansFactor; + } else { + objectRotation[1] = (float) value * degreeToRadiansFactor; + } + break; + case OB_ROT_Z: + objectRotation[fixUpAxis ? 1 : 2] = (float) value * degreeToRadiansFactor; + break; + + // SIZE + case AC_SIZE_X: + scale[0] = (float) value; + break; + case AC_SIZE_Y: + if (fixUpAxis && spatialTrack) { + scale[2] = (float) value; + } else { + scale[1] = (float) value; + } + break; + case AC_SIZE_Z: + scale[fixUpAxis && spatialTrack ? 1 : 2] = (float) value; + break; + + // QUATERNION ROTATION (used with bone animation), dunno + // why but here we shouldn't check the + // spatialTrack flag value + case AC_QUAT_W: + quaternionRotation[3] = (float) value; + break; + case AC_QUAT_X: + quaternionRotation[0] = (float) value; + break; + case AC_QUAT_Y: + if (fixUpAxis) { + quaternionRotation[2] = -(float) value; + } else { + quaternionRotation[1] = (float) value; + } + break; + case AC_QUAT_Z: + if (fixUpAxis) { + quaternionRotation[1] = (float) value; + } else { + quaternionRotation[2] = (float) value; + } + break; + default: + throw new IllegalStateException("Unknown ipo curve type: " + bezierCurves[j].getType()); + } + } + translations[index] = new Vector3f(translation[0], translation[1], translation[2]); + rotations[index] = spatialTrack ? new Quaternion().fromAngles(objectRotation) : new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]); + scales[index] = new Vector3f(scale[0], scale[1], scale[2]); + } + if (spatialTrack) { + calculatedTrack = new SpatialTrack(times, translations, rotations, scales); + } else { + calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales); + } + } + return calculatedTrack; + } } \ No newline at end of file diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java index 6b8d3c320..ea0a20791 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java @@ -7,114 +7,193 @@ import com.jme3.scene.plugins.blender.AbstractBlenderHelper; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.curves.BezierCurve; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; +import com.jme3.scene.plugins.blender.file.BlenderInputStream; +import com.jme3.scene.plugins.blender.file.FileBlockHeader; import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; /** - * This class helps to compute values from interpolation curves for features like animation or constraint influence. The - * curves are 3rd degree bezier curves. + * This class helps to compute values from interpolation curves for features + * like animation or constraint influence. The curves are 3rd degree bezier + * curves. + * * @author Marcin Roguski */ public class IpoHelper extends AbstractBlenderHelper { /** - * This constructor parses the given blender version and stores the result. Some functionalities may differ in - * different blender versions. - * @param blenderVersion - * the version read from the blend file - * @param fixUpAxis - * a variable that indicates if the Y asxis is the UP axis or not - */ - public IpoHelper(String blenderVersion, boolean fixUpAxis) { - super(blenderVersion, fixUpAxis); - } - - /** - * This method creates an ipo object used for interpolation calculations. - * @param ipoStructure - * the structure with ipo definition - * @param blenderContext - * the blender context - * @return the ipo object - * @throws BlenderFileException - * this exception is thrown when the blender file is somehow corrupted - */ - public Ipo createIpo(Structure ipoStructure, BlenderContext blenderContext) throws BlenderFileException { - Structure curvebase = (Structure) ipoStructure.getFieldValue("curve"); - - //preparing bezier curves - Ipo result = null; - List curves = curvebase.evaluateListBase(blenderContext);//IpoCurve - if (curves.size() > 0) { - BezierCurve[] bezierCurves = new BezierCurve[curves.size()]; - int frame = 0; - for (Structure curve : curves) { - Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt"); - List bezTriples = pBezTriple.fetchData(blenderContext.getInputStream()); - int type = ((Number) curve.getFieldValue("adrcode")).intValue(); - bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2); - } - curves.clear(); - result = new Ipo(bezierCurves, fixUpAxis); - blenderContext.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result); - } - return result; - } - - /** - * This method creates an ipo with only a single value. No track type is specified so do not use it for calculating - * tracks. - * @param constValue - * the value of this ipo - * @return constant ipo - */ - public Ipo createIpo(float constValue) { - return new ConstIpo(constValue); - } - - @Override - public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) { - return true; - } - - /** - * Ipo constant curve. This is a curve with only one value and no specified type. This type of ipo cannot be used to - * calculate tracks. It should only be used to calculate single value for a given frame. - * @author Marcin Roguski - */ - private class ConstIpo extends Ipo { - - /** The constant value of this ipo. */ - private float constValue; - - /** - * Constructor. Stores the constant value of this ipo. - * @param constValue - * the constant value of this ipo - */ - public ConstIpo(float constValue) { - super(null, false); - this.constValue = constValue; - } - - @Override - public float calculateValue(int frame) { - return constValue; - } - - @Override - public float calculateValue(int frame, int curveIndex) { - return constValue; - } - - @Override - public int getCurvesAmount() { - return 0; - } - - @Override - public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps) { - throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!"); - } - } + * This constructor parses the given blender version and stores the result. + * Some functionalities may differ in different blender versions. + * + * @param blenderVersion + * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not + */ + public IpoHelper(String blenderVersion, boolean fixUpAxis) { + super(blenderVersion, fixUpAxis); + } + + /** + * This method creates an ipo object used for interpolation calculations. + * + * @param ipoStructure + * the structure with ipo definition + * @param blenderContext + * the blender context + * @return the ipo object + * @throws BlenderFileException + * this exception is thrown when the blender file is somehow + * corrupted + */ + public Ipo fromIpoStructure(Structure ipoStructure, BlenderContext blenderContext) throws BlenderFileException { + Structure curvebase = (Structure) ipoStructure.getFieldValue("curve"); + + // preparing bezier curves + Ipo result = null; + List curves = curvebase.evaluateListBase(blenderContext);// IpoCurve + if (curves.size() > 0) { + BezierCurve[] bezierCurves = new BezierCurve[curves.size()]; + int frame = 0; + for (Structure curve : curves) { + Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt"); + List bezTriples = pBezTriple.fetchData(blenderContext.getInputStream()); + int type = ((Number) curve.getFieldValue("adrcode")).intValue(); + bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2); + } + curves.clear(); + result = new Ipo(bezierCurves, fixUpAxis); + blenderContext.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result); + } + return result; + } + + /** + * This method creates an ipo object used for interpolation calculations. It + * should be called for blender version 2.50 and higher. + * + * @param actionStructure + * the structure with action definition + * @param blenderContext + * the blender context + * @return the ipo object + * @throws BlenderFileException + * this exception is thrown when the blender file is somehow + * corrupted + */ + public Ipo fromAction(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException { + Ipo result = null; + List curves = ((Structure) actionStructure.getFieldValue("curves")).evaluateListBase(blenderContext);// FCurve + if (curves.size() > 0) { + BezierCurve[] bezierCurves = new BezierCurve[curves.size()]; + int frame = 0; + for (Structure curve : curves) { + Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt"); + List bezTriples = pBezTriple.fetchData(blenderContext.getInputStream()); + int type = this.getCurveType(curve, blenderContext); + bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2); + } + curves.clear(); + result = new Ipo(bezierCurves, fixUpAxis); + } + return result; + } + + /** + * This method returns the type of the ipo curve. + * + * @param structure + * the structure must contain the 'rna_path' field and + * 'array_index' field (the type is not important here) + * @param blenderContext + * the blender context + * @return the type of the curve + */ + public int getCurveType(Structure structure, BlenderContext blenderContext) { + // reading rna path first + BlenderInputStream bis = blenderContext.getInputStream(); + int currentPosition = bis.getPosition(); + Pointer pRnaPath = (Pointer) structure.getFieldValue("rna_path"); + FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pRnaPath.getOldMemoryAddress()); + bis.setPosition(dataFileBlock.getBlockPosition()); + String rnaPath = bis.readString(); + bis.setPosition(currentPosition); + int arrayIndex = ((Number) structure.getFieldValue("array_index")).intValue(); + + // determining the curve type + if (rnaPath.endsWith("location")) { + return Ipo.AC_LOC_X + arrayIndex; + } + if (rnaPath.endsWith("rotation_quaternion")) { + return Ipo.AC_QUAT_W + arrayIndex; + } + if (rnaPath.endsWith("scale")) { + return Ipo.AC_SIZE_X + arrayIndex; + } + if (rnaPath.endsWith("rotation")) { + return Ipo.OB_ROT_X + arrayIndex; + } + throw new IllegalStateException("Unknown curve rna path: " + rnaPath); + } + + /** + * This method creates an ipo with only a single value. No track type is + * specified so do not use it for calculating tracks. + * + * @param constValue + * the value of this ipo + * @return constant ipo + */ + public Ipo fromValue(float constValue) { + return new ConstIpo(constValue); + } + + @Override + public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) { + return true; + } + + /** + * Ipo constant curve. This is a curve with only one value and no specified + * type. This type of ipo cannot be used to calculate tracks. It should only + * be used to calculate single value for a given frame. + * + * @author Marcin Roguski + */ + private class ConstIpo extends Ipo { + + /** The constant value of this ipo. */ + private float constValue; + + /** + * Constructor. Stores the constant value of this ipo. + * + * @param constValue + * the constant value of this ipo + */ + public ConstIpo(float constValue) { + super(null, false); + this.constValue = constValue; + } + + @Override + public float calculateValue(int frame) { + return constValue; + } + + @Override + public float calculateValue(int frame, int curveIndex) { + return constValue; + } + + @Override + public int getCurvesAmount() { + return 0; + } + + @Override + public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps, boolean boneTrack) { + throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!"); + } + } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java index 729394433..6846d14bb 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java @@ -20,9 +20,6 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper; * @author Marcin Roguski (Kaelthas) */ public abstract class Constraint { - public static final int BAKE_DYNAMIC = 0x01; - public static final int BAKE_STATIC = 0x02; - /** The name of this constraint. */ protected final String name; /** The constraint's owner. */ @@ -79,32 +76,19 @@ public abstract class Constraint { /** * This method bakes the required sontraints into its owner. - * @param bakeFlag the bake type flag support the following values: - *
  • BAKE_DYNAMIC - bake animation's constraints - *
  • BAKE_STATIC - bake static constraints */ - public void bake(int bakeFlag) { + public void bake() { this.owner.update(); if(this.target != null) { this.target.update(); } - if((bakeFlag & BAKE_DYNAMIC) != 0) { - this.bakeDynamic(); - } - if((bakeFlag & BAKE_STATIC) != 0) { - this.bakeStatic(); - } + this.bakeConstraint(); } /** * Bake the animation's constraints into its owner. */ - protected abstract void bakeDynamic(); - - /** - * Bake the static constraints into its owner. - */ - protected abstract void bakeStatic(); + protected abstract void bakeConstraint(); /** * This method returns the bone traces for the bone that is affected by the given constraint. 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 fe81792da..6c58ac030 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 @@ -35,13 +35,7 @@ import java.util.logging.Logger; } @Override - protected void bakeDynamic() { - // TODO: implement 'Action' constraint - LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!"); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { // TODO: implement 'Action' constraint LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!"); } 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 aa6d7f785..592d74014 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 @@ -35,13 +35,7 @@ import java.util.logging.Logger; } @Override - protected void bakeDynamic() { - // TODO: implement ChildOf constraint - LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!"); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { // TODO: implement ChildOf constraint LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!"); } 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 c37f7ba0b..5c265c79d 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 @@ -36,13 +36,7 @@ import java.util.logging.Logger; } @Override - protected void bakeDynamic() { - //TODO: implement when curves are implemented - LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", name); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { //TODO: implement when curves are implemented LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", name); } 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 index c7b0e89c2..cf2784f89 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDampTrack.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDampTrack.java @@ -36,13 +36,7 @@ import com.jme3.scene.plugins.blender.file.Structure; } @Override - protected void bakeDynamic() { - // TODO Auto-generated method stub - LOGGER.log(Level.WARNING, "'Damp Track' constraint NOT implemented!"); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { // TODO Auto-generated method stub LOGGER.log(Level.WARNING, "'Damp Track' constraint NOT implemented!"); } 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 0fae66e9f..ff3b99a51 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,7 +1,6 @@ package com.jme3.scene.plugins.blender.constraints; import com.jme3.animation.Animation; -import com.jme3.animation.Bone; import com.jme3.math.Matrix4f; import com.jme3.math.Vector3f; import com.jme3.scene.Spatial; @@ -47,10 +46,10 @@ import com.jme3.scene.plugins.ogre.AnimData; } @Override - protected void bakeDynamic() { + protected void bakeConstraint() { + Object owner = this.owner.getObject(); AnimData animData = blenderContext.getAnimData(this.owner.getOma()); if(animData != null) { - Object owner = this.owner.getObject(); if(owner instanceof Spatial) { Vector3f targetLocation = ((Spatial) owner).getWorldTranslation(); for(Animation animation : animData.anims) { @@ -66,22 +65,17 @@ import com.jme3.scene.plugins.ogre.AnimData; } } } - } - - @Override - protected void bakeStatic() { - Matrix4f targetWorldMatrix = target.getWorldTransformMatrix(); - Vector3f targetLocation = targetWorldMatrix.toTranslationVector(); - Matrix4f m = owner.getParentWorldTransformMatrix(); - m.invertLocal(); - Matrix4f ownerWorldMatrix = owner.getWorldTransformMatrix(); - Vector3f ownerLocation = ownerWorldMatrix.toTranslationVector(); - this.distLimit(ownerLocation, targetLocation, ipo.calculateValue(0)); - Object owner = this.owner.getObject(); + + // apply static constraint only to spatials if(owner instanceof Spatial) { + Matrix4f targetWorldMatrix = target.getWorldTransformMatrix(); + Vector3f targetLocation = targetWorldMatrix.toTranslationVector(); + Matrix4f m = this.owner.getParentWorldTransformMatrix(); + m.invertLocal(); + Matrix4f ownerWorldMatrix = this.owner.getWorldTransformMatrix(); + Vector3f ownerLocation = ownerWorldMatrix.toTranslationVector(); + this.distLimit(ownerLocation, targetLocation, ipo.calculateValue(0)); ((Spatial) owner).setLocalTranslation(m.mult(ownerLocation)); - } else { - ((Bone) owner).setBindTransforms(m.mult(ownerLocation), ((Bone) owner).getLocalRotation(), ((Bone) owner).getLocalScale()); } } 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 056353741..5f8be2c22 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 @@ -35,13 +35,7 @@ import java.util.logging.Logger; } @Override - protected void bakeDynamic() { - //TODO: implement when curves are implemented - LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!"); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { //TODO: implement when curves are implemented LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!"); } 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 75478487f..d75728fee 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 @@ -93,7 +93,7 @@ public class ConstraintHelper extends AbstractBlenderHelper { Pointer pIpo = (Pointer) constraintChannel.getFieldValue("ipo"); if (pIpo.isNotNull()) { String constraintName = constraintChannel.getFieldValue("name").toString(); - Ipo ipo = ipoHelper.createIpo(pIpo.fetchData(blenderContext.getInputStream()).get(0), blenderContext); + Ipo ipo = ipoHelper.fromIpoStructure(pIpo.fetchData(blenderContext.getInputStream()).get(0), blenderContext); ipos.put(constraintName, ipo); } } @@ -120,7 +120,7 @@ public class ConstraintHelper extends AbstractBlenderHelper { Ipo ipo = ipoMap==null ? null : ipoMap.get(constraintName); if (ipo == null) { float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue(); - ipo = ipoHelper.createIpo(enforce); + ipo = ipoHelper.fromValue(enforce); } constraintsList.add(this.createConstraint(constraint, boneOMA, ipo, blenderContext)); } @@ -140,7 +140,7 @@ public class ConstraintHelper extends AbstractBlenderHelper { Ipo ipo = objectConstraintsIpos!=null ? objectConstraintsIpos.get(constraintName) : null; if (ipo == null) { float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue(); - ipo = ipoHelper.createIpo(enforce); + ipo = ipoHelper.fromValue(enforce); } constraintsList.add(this.createConstraint(constraint, objectStructure.getOldMemoryAddress(), ipo, blenderContext)); } 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 76b59a959..ef8544690 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 @@ -38,7 +38,7 @@ import java.util.logging.Logger; } @Override - protected void bakeDynamic() { + protected void bakeConstraint() { // try { // IK solver is only attached to bones // Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE); @@ -127,12 +127,6 @@ import java.util.logging.Logger; // } } - @Override - protected void bakeStatic() { - // TODO Auto-generated method stub - - } - /** * This method returns bones used for rotation calculations. * @param bone 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 83d876893..834dfb43a 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 @@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints; import com.jme3.animation.Animation; import com.jme3.math.Transform; import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -61,10 +62,10 @@ import com.jme3.scene.plugins.ogre.AnimData; } @Override - protected void bakeDynamic() { - AnimData animData = blenderContext.getAnimData(owner.getOma()); + protected void bakeConstraint() { + Object owner = this.owner.getObject(); + AnimData animData = blenderContext.getAnimData(this.owner.getOma()); if(animData != null) { - Object owner = this.owner.getObject(); Transform targetTransform = this.target.getTransform(); for(Animation animation : animData.anims) { BlenderTrack blenderTrack = this.getTrack(owner, animData.skeleton, animation); @@ -76,15 +77,14 @@ import com.jme3.scene.plugins.ogre.AnimData; blenderTrack.setKeyframes(blenderTrack.getTimes(), translations, blenderTrack.getRotations(), blenderTrack.getScales()); } } - } - - @Override - protected void bakeStatic() { - Transform targetTransform = this.target.getTransform(); - Transform ownerTransform = this.owner.getTransform(); - Vector3f ownerLocation = ownerTransform.getTranslation(); - this.locLike(ownerLocation, targetTransform.getTranslation(), ipo.calculateValue(0)); - this.owner.applyTransform(ownerTransform); + + if(owner instanceof Spatial) { + Transform targetTransform = this.target.getTransform(); + Transform ownerTransform = this.owner.getTransform(); + Vector3f ownerLocation = ownerTransform.getTranslation(); + this.locLike(ownerLocation, targetTransform.getTranslation(), ipo.calculateValue(0)); + this.owner.applyTransform(ownerTransform); + } } private void locLike(Vector3f ownerLocation, Vector3f targetLocation, float influence) { 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 fcc167383..bdadc98c2 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,8 +1,11 @@ package com.jme3.scene.plugins.blender.constraints; +import java.util.Arrays; + import com.jme3.animation.Animation; import com.jme3.math.Transform; import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -73,7 +76,7 @@ import com.jme3.scene.plugins.ogre.AnimData; } @Override - protected void bakeDynamic() { + protected void bakeConstraint() { Object owner = this.owner.getObject(); AnimData animData = blenderContext.getAnimData(this.owner.getOma()); if(animData != null) { @@ -82,19 +85,20 @@ import com.jme3.scene.plugins.ogre.AnimData; Vector3f[] translations = track.getTranslations(); int maxFrames = translations.length; for (int frame = 0; frame < maxFrames; ++frame) { + System.out.print(translations[frame] + "\t\t"); this.locLimit(translations[frame], ipo.calculateValue(frame)); + System.out.println(translations[frame]); } track.setKeyframes(track.getTimes(), translations, track.getRotations(), track.getScales()); } } - } - - @Override - protected void bakeStatic() { - Transform ownerTransform = this.owner.getTransform(); - Vector3f ownerLocation = ownerTransform.getTranslation(); - this.locLimit(ownerLocation, ipo.calculateValue(0)); - this.owner.applyTransform(ownerTransform); + + if(owner instanceof Spatial) { + Transform ownerTransform = this.owner.getTransform(); + Vector3f ownerLocation = ownerTransform.getTranslation(); + this.locLimit(ownerLocation, ipo.calculateValue(0)); + this.owner.applyTransform(ownerTransform); + } } /** 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 6f4a763dd..e54d70a45 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 @@ -36,13 +36,7 @@ import java.util.logging.Logger; } @Override - protected void bakeDynamic() { - // TODO: implement 'Lock track' constraint - LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!"); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { // TODO: implement 'Lock track' constraint LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!"); } 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 fcef6f5fd..f4a5456e8 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 @@ -35,13 +35,7 @@ import java.util.logging.Logger; } @Override - protected void bakeDynamic() { - // TODO: implement 'Min max' constraint - LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!"); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { // TODO: implement 'Min max' constraint LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!"); } 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 d011d7f64..4409969ee 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 @@ -33,8 +33,5 @@ import com.jme3.scene.plugins.blender.file.Structure; } @Override - protected void bakeDynamic() {} - - @Override - protected void bakeStatic() {} + protected void bakeConstraint() {} } 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 index 172a352e1..f0f3bae61 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPivot.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintPivot.java @@ -37,13 +37,7 @@ import com.jme3.scene.plugins.blender.file.Structure; } @Override - protected void bakeDynamic() { - // TODO Auto-generated method stub - LOGGER.log(Level.WARNING, "'Pivot' constraint NOT implemented!"); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { // TODO Auto-generated method stub LOGGER.log(Level.WARNING, "'Pivot' constraint NOT implemented!"); } 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 aef782021..a0beb7864 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 @@ -35,13 +35,7 @@ import java.util.logging.Logger; } @Override - protected void bakeDynamic() { - // TODO: implement 'Python' constraint - LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!"); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { // TODO: implement 'Python' constraint LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!"); } 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 345990225..b398ae612 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 @@ -35,13 +35,7 @@ import java.util.logging.Logger; } @Override - protected void bakeDynamic() { - // TODO: implement 'Rigid body joint' constraint - LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!"); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { // TODO: implement 'Rigid body joint' constraint LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!"); } 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 ef5a4883c..db0c93a6c 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 @@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints; import com.jme3.animation.Animation; import com.jme3.math.Quaternion; import com.jme3.math.Transform; +import com.jme3.scene.Spatial; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -47,10 +48,10 @@ import com.jme3.scene.plugins.ogre.AnimData; } @Override - protected void bakeDynamic() { + protected void bakeConstraint() { + Object owner = this.owner.getObject(); AnimData animData = blenderContext.getAnimData(this.owner.getOma()); if(animData != null) { - Object owner = this.owner.getObject(); Transform targetTransform = this.target.getTransform(); Quaternion targetRotation = targetTransform.getRotation(); for(Animation animation : animData.anims) { @@ -66,15 +67,14 @@ import com.jme3.scene.plugins.ogre.AnimData; track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales()); } } - } - - @Override - protected void bakeStatic() { - Transform targetTransform = this.target.getTransform(); - Transform ownerTransform = this.owner.getTransform(); - Quaternion ownerRotation = ownerTransform.getRotation(); - this.rotLike(ownerRotation, ownerRotation.toAngles(null), targetTransform.getRotation().toAngles(null), ipo.calculateValue(0)); - this.owner.applyTransform(ownerTransform); + + if(owner instanceof Spatial) { + Transform targetTransform = this.target.getTransform(); + Transform ownerTransform = this.owner.getTransform(); + Quaternion ownerRotation = ownerTransform.getRotation(); + this.rotLike(ownerRotation, ownerRotation.toAngles(null), targetTransform.getRotation().toAngles(null), ipo.calculateValue(0)); + this.owner.applyTransform(ownerTransform); + } } private void rotLike(Quaternion ownerRotation, float[] ownerAngles, float[] targetAngles, float influence) { 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 3e0907885..358b1e735 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,9 +1,12 @@ package com.jme3.scene.plugins.blender.constraints; +import java.util.Arrays; + import com.jme3.animation.Animation; import com.jme3.math.FastMath; import com.jme3.math.Quaternion; import com.jme3.math.Transform; +import com.jme3.scene.Spatial; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -68,10 +71,10 @@ import com.jme3.scene.plugins.ogre.AnimData; } @Override - protected void bakeDynamic() { - AnimData animData = blenderContext.getAnimData(owner.getOma()); + protected void bakeConstraint() { + Object owner = this.owner.getObject(); + AnimData animData = blenderContext.getAnimData(this.owner.getOma()); if(animData != null) { - Object owner = this.owner.getObject(); for(Animation animation : animData.anims) { BlenderTrack track = this.getTrack(owner, animData.skeleton, animation); Quaternion[] rotations = track.getRotations(); @@ -79,21 +82,22 @@ import com.jme3.scene.plugins.ogre.AnimData; int maxFrames = rotations.length; for (int frame = 0; frame < maxFrames; ++frame) { rotations[frame].toAngles(angles); + System.out.print(Arrays.toString(angles) + "\t\t"); this.rotLimit(angles, ipo.calculateValue(frame)); + System.out.println(Arrays.toString(angles)); rotations[frame].fromAngles(angles); } track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales()); } } - } - - @Override - protected void bakeStatic() { - Transform ownerTransform = this.owner.getTransform(); - float[] angles = ownerTransform.getRotation().toAngles(null); - this.rotLimit(angles, ipo.calculateValue(0)); - ownerTransform.getRotation().fromAngles(angles); - this.owner.applyTransform(ownerTransform); + + if(owner instanceof Spatial) { + Transform ownerTransform = this.owner.getTransform(); + float[] angles = ownerTransform.getRotation().toAngles(null); + this.rotLimit(angles, ipo.calculateValue(0)); + ownerTransform.getRotation().fromAngles(angles); + this.owner.applyTransform(ownerTransform); + } } /** @@ -114,7 +118,7 @@ import com.jme3.scene.plugins.ogre.AnimData; } angles[0] -= difference; } - if ((flag & LIMIT_YROT) != 0) { + if ((flag & LIMIT_ZROT) != 0) { float difference = 0.0f; if (angles[1] < limits[1][0]) { difference = (angles[1] - limits[1][0]) * influence; @@ -123,7 +127,7 @@ import com.jme3.scene.plugins.ogre.AnimData; } angles[1] -= difference; } - if ((flag & LIMIT_ZROT) != 0) { + /*if ((flag & LIMIT_ZROT) != 0) { float difference = 0.0f; if (angles[2] < limits[2][0]) { difference = (angles[2] - limits[2][0]) * influence; @@ -131,6 +135,6 @@ import com.jme3.scene.plugins.ogre.AnimData; difference = (angles[2] - limits[2][1]) * influence; } angles[2] -= difference; - } + }*/ } } 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 9b6f7bdd5..735203211 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 @@ -45,7 +45,7 @@ import com.jme3.scene.plugins.ogre.AnimData; } @Override - protected void bakeDynamic() { + protected void bakeConstraint() { //loading mesh points (blender ensures that the target is a mesh-object) List pts = new ArrayList(); Node target = (Node) this.target.getObject(); @@ -86,11 +86,7 @@ import com.jme3.scene.plugins.ogre.AnimData; track.setKeyframes(track.getTimes(), translations, rotations, track.getScales()); } } - } - - @Override - protected void bakeStatic() { - // TODO Auto-generated method stub + //TODO: static constraint for spatials } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLike.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLike.java index bd4068bee..8b697aa82 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLike.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSizeLike.java @@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints; import com.jme3.animation.Animation; import com.jme3.math.Transform; import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -52,10 +53,10 @@ import com.jme3.scene.plugins.ogre.AnimData; } @Override - protected void bakeDynamic() { + protected void bakeConstraint() { + Object owner = this.owner.getObject(); AnimData animData = blenderContext.getAnimData(this.owner.getOma()); if(animData != null) { - Object owner = this.owner.getObject(); Transform targetTransform = this.target.getTransform(); Vector3f targetScale = targetTransform.getScale(); for(Animation animation : animData.anims) { @@ -68,14 +69,13 @@ import com.jme3.scene.plugins.ogre.AnimData; track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales); } } - } - - @Override - protected void bakeStatic() { - Transform targetTransform = this.target.getTransform(); - Transform ownerTransform = this.owner.getTransform(); - this.sizeLike(ownerTransform.getScale(), targetTransform.getScale(), ipo.calculateValue(0)); - this.owner.applyTransform(ownerTransform); + + if(owner instanceof Spatial) { + Transform targetTransform = this.target.getTransform(); + Transform ownerTransform = this.owner.getTransform(); + this.sizeLike(ownerTransform.getScale(), targetTransform.getScale(), ipo.calculateValue(0)); + this.owner.applyTransform(ownerTransform); + } } private void sizeLike(Vector3f ownerScale, Vector3f targetScale, float influence) { 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 5c3dea041..5d5829958 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 @@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints; import com.jme3.animation.Animation; import com.jme3.math.Transform; import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.animations.Ipo; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; @@ -73,10 +74,10 @@ import com.jme3.scene.plugins.ogre.AnimData; } @Override - protected void bakeDynamic() { + protected void bakeConstraint() { + Object owner = this.owner.getObject(); AnimData animData = blenderContext.getAnimData(this.owner.getOma()); if(animData != null) { - Object owner = this.owner.getObject(); for(Animation animation : animData.anims) { BlenderTrack track = this.getTrack(owner, animData.skeleton, animation); Vector3f[] scales = track.getScales(); @@ -87,13 +88,12 @@ import com.jme3.scene.plugins.ogre.AnimData; track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales); } } - } - - @Override - protected void bakeStatic() { - Transform ownerTransform = this.owner.getTransform(); - this.sizeLimit(ownerTransform.getScale(), ipo.calculateValue(0)); - this.owner.applyTransform(ownerTransform); + + if(owner instanceof Spatial) { + Transform ownerTransform = this.owner.getTransform(); + this.sizeLimit(ownerTransform.getScale(), ipo.calculateValue(0)); + this.owner.applyTransform(ownerTransform); + } } private void sizeLimit(Vector3f scale, float influence) { 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 index f03db1dca..0d9f9ab45 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSplineInverseKinematic.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintSplineInverseKinematic.java @@ -37,14 +37,8 @@ import com.jme3.scene.plugins.blender.file.Structure; } @Override - protected void bakeDynamic() { + protected void bakeConstraint() { // TODO Auto-generated method stub LOGGER.log(Level.WARNING, "'Splie IK' constraint NOT implemented!"); } - - @Override - protected void bakeStatic() { - // TODO Auto-generated method stub - LOGGER.log(Level.WARNING, "'Spline IK' constraint NOT implemented!"); - } } 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 c25097fd6..a5a9f55aa 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 @@ -35,13 +35,7 @@ import java.util.logging.Logger; } @Override - protected void bakeDynamic() { - // TODO: implement 'Stretch to' constraint - LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!"); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { // TODO: implement 'Stretch to' constraint LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!"); } 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 6928fb821..5d111a318 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 @@ -35,13 +35,7 @@ import java.util.logging.Logger; } @Override - protected void bakeDynamic() { - // TODO: implement 'Transform' constraint - LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!"); - } - - @Override - protected void bakeStatic() { + protected void bakeConstraint() { // TODO: implement 'Transform' constraint LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!"); } 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 index 9f20ff7a2..ec51dfa34 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Feature.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Feature.java @@ -1,6 +1,7 @@ package com.jme3.scene.plugins.blender.constraints; import com.jme3.animation.Bone; +import com.jme3.math.FastMath; import com.jme3.math.Matrix4f; import com.jme3.math.Quaternion; import com.jme3.math.Transform; @@ -8,6 +9,7 @@ import com.jme3.math.Vector3f; import com.jme3.scene.Spatial; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType; +import com.jme3.scene.plugins.blender.animations.BoneContext; import com.jme3.scene.plugins.blender.constraints.Constraint.Space; import com.jme3.scene.plugins.blender.file.DynamicArray; import com.jme3.scene.plugins.blender.file.Structure; @@ -156,6 +158,7 @@ import com.jme3.scene.plugins.blender.file.Structure; } } // Bone + BoneContext boneContext = blenderContext.getBoneContext(oma); switch (space) { case CONSTRAINT_SPACE_LOCAL: Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation()); @@ -173,8 +176,9 @@ import com.jme3.scene.plugins.blender.file.Structure; worldTransform.setScale(bone.getWorldBindScale()); return worldTransform; case CONSTRAINT_SPACE_POSE: - // TODO - return null; + Transform poseTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation()); + poseTransform.setScale(bone.getLocalScale()); + return poseTransform; case CONSTRAINT_SPACE_PARLOCAL: Transform parentLocalTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation()); parentLocalTransform.setScale(bone.getLocalScale()); @@ -228,11 +232,15 @@ import com.jme3.scene.plugins.blender.file.Structure; break; case CONSTRAINT_SPACE_WORLD: Matrix4f m = this.getParentWorldTransformMatrix(); - m.invertLocal(); +// m.invertLocal(); transform.setTranslation(m.mult(transform.getTranslation())); transform.setRotation(m.mult(transform.getRotation(), null)); transform.setScale(transform.getScale()); bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale()); +// float x = FastMath.HALF_PI/2; +// float y = -FastMath.HALF_PI; +// float z = -FastMath.HALF_PI/2; +// bone.setBindTransforms(new Vector3f(0,0,0), new Quaternion().fromAngles(x, y, z), new Vector3f(1,1,1)); break; case CONSTRAINT_SPACE_PARLOCAL: Vector3f parentLocalTranslation = bone.getLocalPosition().add(transform.getTranslation()); @@ -240,7 +248,7 @@ import com.jme3.scene.plugins.blender.file.Structure; bone.setBindTransforms(parentLocalTranslation, parentLocalRotation, transform.getScale()); break; case CONSTRAINT_SPACE_POSE: - // TODO: + bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale()); break; default: throw new IllegalStateException("Invalid space type for target object: " + space.toString()); 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 40dee6ac2..c15e91f3b 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 @@ -42,8 +42,8 @@ import com.jme3.util.BufferUtils; * @author Marcin Roguski (Kaelthas) */ /* package */class ArmatureModifier extends Modifier { - private static final Logger LOGGER = Logger.getLogger(ArmatureModifier.class.getName()); - private static final int MAXIMUM_WEIGHTS_PER_VERTEX = 4; + private static final Logger LOGGER = Logger.getLogger(ArmatureModifier.class.getName()); + private static final int MAXIMUM_WEIGHTS_PER_VERTEX = 4; // @Marcin it was an Ogre limitation, but as long as we use a MaxNumWeight // variable in mesh, // i guess this limitation has no sense for the blender loader...so i guess @@ -55,17 +55,18 @@ import com.jme3.util.BufferUtils; // Rémy /** Loaded animation data. */ - private AnimData animData; + private AnimData animData; /** Old memory address of the mesh that will have the skeleton applied. */ - private Long meshOMA; + private Long meshOMA; /** - * The maxiumum amount of bone groups applied to a single vertex (max = MAXIMUM_WEIGHTS_PER_VERTEX). + * The maxiumum amount of bone groups applied to a single vertex (max = + * MAXIMUM_WEIGHTS_PER_VERTEX). */ - private int boneGroups; + private int boneGroups; /** The weights of vertices. */ - private VertexBuffer verticesWeights; + private VertexBuffer verticesWeights; /** The indexes of bones applied to vertices. */ - private VertexBuffer verticesWeightsIndices; + private VertexBuffer verticesWeightsIndices; /** * This constructor reads animation data from the object structore. The @@ -83,9 +84,12 @@ import com.jme3.util.BufferUtils; */ public ArmatureModifier(Structure objectStructure, Structure modifierStructure, BlenderContext blenderContext) throws BlenderFileException { Structure meshStructure = ((Pointer) objectStructure.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0); - Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices - - //if pDvert==null then there are not vertex groups and no need to load skeleton (untill bone envelopes are supported) + Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert + // = + // DeformVERTices + + // if pDvert==null then there are not vertex groups and no need to load + // skeleton (untill bone envelopes are supported) if (this.validate(modifierStructure, blenderContext) && pDvert.isNotNull()) { Pointer pArmatureObject = (Pointer) modifierStructure.getFieldValue("object"); if (pArmatureObject.isNotNull()) { @@ -109,15 +113,16 @@ import com.jme3.util.BufferUtils; Matrix4f armatureObjectMatrix = objectHelper.getMatrix(armatureObject, "obmat", true); Matrix4f inverseMeshObjectMatrix = objectHelper.getMatrix(objectStructure, "obmat", true).invertLocal(); Matrix4f objectToArmatureTransformation = armatureObjectMatrix.multLocal(inverseMeshObjectMatrix); - + List 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()])); - + Bone[] bones = bonesList.toArray(new Bone[bonesList.size()]); + Skeleton skeleton = new Skeleton(bones); + // read mesh indexes this.meshOMA = meshStructure.getOldMemoryAddress(); this.readVerticesWeightsData(objectStructure, meshStructure, skeleton, blenderContext); @@ -132,25 +137,30 @@ import com.jme3.util.BufferUtils; String actionName = actionStructure.getName(); BoneTrack[] tracks = armatureHelper.getTracks(actionStructure, skeleton, blenderContext); - // determining the animation time - float maximumTrackLength = 0; - for (BoneTrack track : tracks) { - float length = track.getLength(); - if (length > maximumTrackLength) { - maximumTrackLength = length; + if(tracks != null && tracks.length > 0) { + // determining the animation time + float maximumTrackLength = 0; + for (BoneTrack track : tracks) { + float length = track.getLength(); + if (length > maximumTrackLength) { + maximumTrackLength = length; + } } - } - Animation boneAnimation = new Animation(actionName, maximumTrackLength); - boneAnimation.setTracks(tracks); - animations.add(boneAnimation); + Animation boneAnimation = new Animation(actionName, maximumTrackLength); + boneAnimation.setTracks(tracks); + animations.add(boneAnimation); + } } } animData = new AnimData(skeleton, animations); // store the animation data for each bone - for (Structure boneStructure : bonebase) { - blenderContext.setAnimData(boneStructure.getOldMemoryAddress(), animData); + for (Bone bone : bones) { + Long boneOma = armatureHelper.getBoneOMA(bone); + if (boneOma != null) { + blenderContext.setAnimData(boneOma, animData); + } } } } @@ -177,28 +187,14 @@ import com.jme3.util.BufferUtils; } } - // applying bone transforms before constraints are baked + // applying constraints to Bones ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class); - //TODO: should we apply static bone poses ??? (this breaks the animation) -// for (int i = 0; i < animData.skeleton.getBoneCount(); ++i) { -// Bone bone = animData.skeleton.getBone(i); -// Transform transform = armatureHelper.getBoneBindTransform(bone); -// Transform boneTransform = armatureHelper.getLocalTransform(bone); -// if(transform!=null && boneTransform!=null) { -// bone.setBindTransforms(boneTransform.getTranslation().addLocal(transform.getTranslation()), -// boneTransform.getRotation().multLocal(transform.getRotation()), -// boneTransform.getScale().multLocal(transform.getScale())); -// } -// } - - // applying constraints to Bones (and only to bones, object constraints - // are applied in the ObjectHelper) for (int i = 0; i < animData.skeleton.getBoneCount(); ++i) { Long boneOMA = armatureHelper.getBoneOMA(animData.skeleton.getBone(i)); List constraints = blenderContext.getConstraints(boneOMA); if (constraints != null && constraints.size() > 0) { for (Constraint constraint : constraints) { - constraint.bake(Constraint.BAKE_DYNAMIC | Constraint.BAKE_STATIC); + constraint.bake(); } } } 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 4ed253e0a..652fd5735 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 @@ -31,82 +31,165 @@ */ package com.jme3.scene.plugins.blender.modifiers; -import com.jme3.scene.plugins.blender.AbstractBlenderHelper; -import com.jme3.scene.plugins.blender.BlenderContext; -import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; -import com.jme3.scene.plugins.blender.file.Pointer; -import com.jme3.scene.plugins.blender.file.Structure; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import com.jme3.scene.plugins.blender.AbstractBlenderHelper; +import com.jme3.scene.plugins.blender.BlenderContext; +import com.jme3.scene.plugins.blender.animations.Ipo; +import com.jme3.scene.plugins.blender.animations.IpoHelper; +import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; +import com.jme3.scene.plugins.blender.file.Pointer; +import com.jme3.scene.plugins.blender.file.Structure; + /** * A class that is used in modifiers calculations. + * * @author Marcin Roguski */ public class ModifierHelper extends AbstractBlenderHelper { - private static final Logger LOGGER = Logger.getLogger(ModifierHelper.class.getName()); + private static final Logger LOGGER = Logger.getLogger(ModifierHelper.class.getName()); + + /** + * This constructor parses the given blender version and stores the result. + * Some functionalities may differ in different blender versions. + * + * @param blenderVersion + * the version read from the blend file + * @param fixUpAxis + * a variable that indicates if the Y asxis is the UP axis or not + */ + public ModifierHelper(String blenderVersion, boolean fixUpAxis) { + super(blenderVersion, fixUpAxis); + } + + /** + * This method reads the given object's modifiers. + * + * @param objectStructure + * the object structure + * @param blenderContext + * the blender context + * @throws BlenderFileException + * this exception is thrown when the blender file is somehow + * corrupted + */ + public Collection readModifiers(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException { + Collection result = new ArrayList(); + Structure modifiersListBase = (Structure) objectStructure.getFieldValue("modifiers"); + List modifiers = modifiersListBase.evaluateListBase(blenderContext); + for (Structure modifierStructure : modifiers) { + Modifier modifier = null; + if (Modifier.ARRAY_MODIFIER_DATA.equals(modifierStructure.getType())) { + modifier = new ArrayModifier(modifierStructure, blenderContext); + } else if (Modifier.MIRROR_MODIFIER_DATA.equals(modifierStructure.getType())) { + modifier = new MirrorModifier(modifierStructure, blenderContext); + } else if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifierStructure.getType())) { + modifier = new ArmatureModifier(objectStructure, modifierStructure, blenderContext); + } else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifierStructure.getType())) { + modifier = new ParticlesModifier(modifierStructure, blenderContext); + } + + if (modifier != null) { + result.add(modifier); + blenderContext.addModifier(objectStructure.getOldMemoryAddress(), modifier); + } else { + LOGGER.log(Level.WARNING, "Unsupported modifier type: {0}", modifierStructure.getType()); + } + } - /** - * This constructor parses the given blender version and stores the result. Some functionalities may differ in - * different blender versions. - * @param blenderVersion - * the version read from the blend file - * @param fixUpAxis - * a variable that indicates if the Y asxis is the UP axis or not - */ - public ModifierHelper(String blenderVersion, boolean fixUpAxis) { - super(blenderVersion, fixUpAxis); - } + // at the end read object's animation modifier (object animation is + // either described by action or by ipo of the object) + Modifier modifier; + if (blenderVersion <= 249) { + modifier = this.readAnimationModifier249(objectStructure, blenderContext); + } else { + modifier = this.readAnimationModifier250(objectStructure, blenderContext); + } + if (modifier != null) { + result.add(modifier); + } + return result; + } - /** - * This method reads the given object's modifiers. - * @param objectStructure - * the object structure - * @param blenderContext - * the blender context - * @throws BlenderFileException - * this exception is thrown when the blender file is somehow corrupted - */ - public Collection readModifiers(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException { - Collection result = new ArrayList(); - Structure modifiersListBase = (Structure) objectStructure.getFieldValue("modifiers"); - List modifiers = modifiersListBase.evaluateListBase(blenderContext); - for (Structure modifierStructure : modifiers) { - Modifier modifier = null; - if (Modifier.ARRAY_MODIFIER_DATA.equals(modifierStructure.getType())) { - modifier = new ArrayModifier(modifierStructure, blenderContext); - } else if (Modifier.MIRROR_MODIFIER_DATA.equals(modifierStructure.getType())) { - modifier = new MirrorModifier(modifierStructure, blenderContext); - } else if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifierStructure.getType())) { - modifier = new ArmatureModifier(objectStructure, modifierStructure, blenderContext); - } else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifierStructure.getType())) { - modifier = new ParticlesModifier(modifierStructure, blenderContext); - } - - if(modifier != null) { - result.add(modifier); - blenderContext.addModifier(objectStructure.getOldMemoryAddress(), modifier); - } else { - LOGGER.log(Level.WARNING, "Unsupported modifier type: {0}", modifierStructure.getType()); - } - } + @Override + public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) { + return true; + } - //at the end read object's animation modifier - Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo"); - if (pIpo.isNotNull()) { - Modifier modifier = new ObjectAnimationModifier(objectStructure, blenderContext); - result.add(modifier); - blenderContext.addModifier(objectStructure.getOldMemoryAddress(), modifier); - } - return result; - } + /** + * This method reads the object's animation modifier for blender version + * 2.49 and lower. + * + * @param objectStructure + * the object's structure + * @param blenderContext + * the blender context + * @return loaded modifier + * @throws BlenderFileException + * this exception is thrown when the blender file is somehow + * corrupted + */ + private Modifier readAnimationModifier249(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException { + Modifier result = null; + Pointer pAction = (Pointer) objectStructure.getFieldValue("action"); + IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class); + if (pAction.isNotNull()) { + Structure action = pAction.fetchData(blenderContext.getInputStream()).get(0); + List actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext); + if (actionChannels.size() == 1) {// object's animtion action has + // only one channel + Pointer pChannelIpo = (Pointer) actionChannels.get(0).getFieldValue("ipo"); + Structure ipoStructure = pChannelIpo.fetchData(blenderContext.getInputStream()).get(0); + Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext); + result = new ObjectAnimationModifier(ipo, action.getName(), objectStructure.getOldMemoryAddress(), blenderContext); + blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result); + } else { + throw new IllegalStateException("Object's action cannot have more than one channel!"); + } + } else { + Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo"); + if (pIpo.isNotNull()) { + Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0); + Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext); + result = new ObjectAnimationModifier(ipo, objectStructure.getName(), objectStructure.getOldMemoryAddress(), blenderContext); + blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result); + } + } + return result; + } - @Override - public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) { - return true; - } + /** + * This method reads the object's animation modifier for blender version + * 2.50 and higher. + * + * @param objectStructure + * the object's structure + * @param blenderContext + * the blender context + * @return loaded modifier + * @throws BlenderFileException + * this exception is thrown when the blender file is somehow + * corrupted + */ + private Modifier readAnimationModifier250(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException { + Modifier result = null; + Pointer pAnimData = (Pointer) objectStructure.getFieldValue("adt"); + if (pAnimData.isNotNull()) { + Structure animData = pAnimData.fetchData(blenderContext.getInputStream()).get(0); + Pointer pAction = (Pointer) animData.getFieldValue("action"); + if (pAction.isNotNull()) { + Structure actionStructure = pAction.fetchData(blenderContext.getInputStream()).get(0); + IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class); + Ipo ipo = ipoHelper.fromAction(actionStructure, blenderContext); + result = new ObjectAnimationModifier(ipo, actionStructure.getName(), objectStructure.getOldMemoryAddress(), blenderContext); + blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result); + } + } + return result; + } } 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 2ee31d68a..a41395c47 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 @@ -2,7 +2,6 @@ package com.jme3.scene.plugins.blender.modifiers; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -12,11 +11,7 @@ import com.jme3.animation.SpatialTrack; import com.jme3.scene.Node; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.animations.Ipo; -import com.jme3.scene.plugins.blender.animations.IpoHelper; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; -import com.jme3.scene.plugins.blender.file.FileBlockHeader; -import com.jme3.scene.plugins.blender.file.Pointer; -import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.ogre.AnimData; /** @@ -25,13 +20,11 @@ import com.jme3.scene.plugins.ogre.AnimData; * @author Marcin Roguski (Kaelthas) */ /* package */class ObjectAnimationModifier extends Modifier { - private static final Logger LOGGER = Logger.getLogger(ObjectAnimationModifier.class.getName()); + private static final Logger LOGGER = Logger.getLogger(ObjectAnimationModifier.class.getName()); /** Loaded animation data. */ - private AnimData animData; - /** Old memory address of the object structure that will have the modifier applied. */ - private Long objectOMA; - + private AnimData animData; + /** * This constructor reads animation of the object itself (without bones) and * stores it as an ArmatureModifierData modifier. The animation is returned @@ -40,67 +33,41 @@ import com.jme3.scene.plugins.ogre.AnimData; * animation should be working. The stored modifier is an anim data and * additional data is given object's OMA. * - * @param objectStructure - * the structure of the object + * @param ipo + * the object's interpolation curves + * @param objectAnimationName + * the name of object's animation + * @param objectOMA + * the OMA of the object * @param blenderContext * the blender context - * @return animation modifier is returned, it should be separately applied - * when the object is loaded * @throws BlenderFileException * this exception is thrown when the blender file is somehow * corrupted */ - public ObjectAnimationModifier(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException { - objectOMA = objectStructure.getOldMemoryAddress(); - Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo"); - if (pIpo.isNotNull()) { - // check if there is an action name connected with this ipo - String objectAnimationName = null; - List actionBlocks = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00)); - 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; - } - } - } - } + public ObjectAnimationModifier(Ipo ipo, String objectAnimationName, Long objectOMA, BlenderContext blenderContext) throws BlenderFileException { + int fps = blenderContext.getBlenderKey().getFps(); - String objectName = objectStructure.getName(); - if (objectAnimationName == null) {// set the object's animation name to object's name - objectAnimationName = objectName; - } + // calculating track + SpatialTrack track = (SpatialTrack) ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps, true); - IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class); - Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0); - Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext); - int fps = blenderContext.getBlenderKey().getFps(); - - // calculating track for the only bone in this skeleton - SpatialTrack track = (SpatialTrack) ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps); - - Animation animation = new Animation(objectAnimationName, ipo.getLastFrame() / fps); - animation.setTracks(new SpatialTrack[] { track }); - ArrayList animations = new ArrayList(1); - animations.add(animation); + Animation animation = new Animation(objectAnimationName, ipo.getLastFrame() / fps); + animation.setTracks(new SpatialTrack[] { track }); + ArrayList animations = new ArrayList(1); + animations.add(animation); - animData = new AnimData(null, animations); - blenderContext.setAnimData(objectOMA, animData); - } + animData = new AnimData(null, animations); + blenderContext.setAnimData(objectOMA, animData); } - + @Override public Node apply(Node node, BlenderContext blenderContext) { - if(invalid) { + if (invalid) { LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName()); - }//if invalid, animData will be null - if(animData != null) { - //INFO: constraints for this modifier are applied in the ObjectHelper when the whole object is loaded + }// if invalid, animData will be null + if (animData != null) { + // INFO: constraints for this modifier are applied in the + // ObjectHelper when the whole object is loaded ArrayList animList = animData.anims; if (animList != null && animList.size() > 0) { HashMap anims = new HashMap(); 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 8d98a3c4a..172ac9742 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 @@ -261,7 +261,7 @@ public class ObjectHelper extends AbstractBlenderHelper { List objectConstraints = blenderContext.getConstraints(objectStructure.getOldMemoryAddress()); if(objectConstraints!=null) { for(Constraint objectConstraint : objectConstraints) { - objectConstraint.bake(Constraint.BAKE_STATIC); + objectConstraint.bake(); } }