diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java index 823b34207..921e5cb5c 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java @@ -56,6 +56,7 @@ import com.jme3.effect.shapes.EmitterMeshVertexShape; import com.jme3.effect.shapes.EmitterShape; import com.jme3.material.Material; import com.jme3.math.Matrix4f; +import com.jme3.math.Transform; import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; @@ -67,6 +68,7 @@ import com.jme3.scene.plugins.blender.data.Structure; import com.jme3.scene.plugins.blender.exception.BlenderFileException; import com.jme3.scene.plugins.blender.helpers.ParticlesHelper; import com.jme3.scene.plugins.blender.structures.Constraint; +import com.jme3.scene.plugins.blender.structures.Ipo; import com.jme3.scene.plugins.blender.structures.Modifier; import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper; import com.jme3.scene.plugins.blender.utils.DataRepository; @@ -107,6 +109,8 @@ public class ModifierHelper extends AbstractBlenderHelper { public Node applyModifier(Node node, Modifier modifier, DataRepository dataRepository) { if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifier.getType())) { return this.applyArmatureModifierData(node, modifier, dataRepository); + } else if (Modifier.OBJECT_ANIMATION_MODIFIER_DATA.equals(modifier.getType())) { + return this.applyObjectAnimationModifier(node, modifier, dataRepository); } else if (Modifier.ARRAY_MODIFIER_DATA.equals(modifier.getType())) { return this.applyArrayModifierData(node, modifier, dataRepository); } else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifier.getType())) { @@ -227,17 +231,20 @@ public class ModifierHelper extends AbstractBlenderHelper { Structure armatureObject = (Structure) dataRepository.getLoadedFeature(pArmatureObject.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_STRUCTURE); if (armatureObject == null) {// we check this first not to fetch the structure unnecessary armatureObject = pArmatureObject.fetchData(dataRepository.getInputStream()).get(0); - objectHelper.toObject(armatureObject, dataRepository); } modifierAdditionalData = armatureObject.getOldMemoryAddress(); ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class); - // changing bones matrices so that they fit the current object (taht is why we need a copy of a skeleton) + // changing bones matrices so that they fit the current object (that is why we need a copy of a skeleton) Matrix4f armatureObjectMatrix = objectHelper.getTransformationMatrix(armatureObject); Matrix4f inverseMeshObjectMatrix = objectHelper.getTransformationMatrix(objectStructure).invert(); Matrix4f additionalRootBoneTransformation = inverseMeshObjectMatrix.multLocal(armatureObjectMatrix); Bone[] bones = armatureHelper.buildBonesStructure(Long.valueOf(0L), additionalRootBoneTransformation); + //setting the bones structure inside the skeleton (thus completing its loading) + Skeleton skeleton = new Skeleton(bones); + dataRepository.addLoadedFeatures(armatureObject.getOldMemoryAddress(), armatureObject.getName(), armatureObject, skeleton); + String objectName = objectStructure.getName(); Set animationNames = dataRepository.getBlenderKey().getAnimationNames(objectName); if (animationNames != null && animationNames.size() > 0) { @@ -275,6 +282,81 @@ public class ModifierHelper extends AbstractBlenderHelper { modifierAdditionalData = null; } } + + //at the end read object's animation modifier + Modifier objectAnimationModifier = this.readObjectAnimation(objectStructure, dataRepository); + if(objectAnimationModifier != null) { + dataRepository.addModifier(objectStructure.getOldMemoryAddress(), + objectAnimationModifier.getType(), + objectAnimationModifier.getJmeModifierRepresentation(), + objectAnimationModifier.getAdditionalData()); + } + } + + /** + * This method reads animation of the object itself (without bones) and stores it as an ArmatureModifierData + * modifier. The animation is returned as a modifier. It should be later applied regardless other modifiers. The + * reason for this is that object may not have modifiers added but it's animation should be working. + * @param objectStructure + * the structure of the object + * @param dataRepository + * the data repository + * @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 + */ + protected Modifier readObjectAnimation(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException { + 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 = dataRepository.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00)); + for(FileBlockHeader actionBlock : actionBlocks) { + Structure action = actionBlock.getStructure(dataRepository); + List actionChannels = ((Structure)action.getFieldValue("chanbase")).evaluateListBase(dataRepository); + 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; + } + } + } + + String objectName = objectStructure.getName(); + if(objectAnimationName == null) {//set the object's animation name to object's name + objectAnimationName = objectName; + } + + IpoHelper ipoHelper = dataRepository.getHelper(IpoHelper.class); + Structure ipoStructure = pIpo.fetchData(dataRepository.getInputStream()).get(0); + Ipo ipo = ipoHelper.createIpo(ipoStructure, dataRepository); + int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, objectAnimationName); + if(animationFrames == null) {//if the name was created here there are no frames set for the animation + animationFrames = new int[] {1, ipo.getLastFrame()}; + } + int fps = dataRepository.getBlenderKey().getFps(); + float start = (float)animationFrames[0] / (float)fps; + float stop = (float)animationFrames[1] / (float)fps; + + //calculating track for the only bone in this skeleton + BoneTrack[] tracks = new BoneTrack[1]; + tracks[0] = ipo.calculateTrack(0, animationFrames[0], animationFrames[1], fps); + + BoneAnimation boneAnimation = new BoneAnimation(objectAnimationName, stop - start); + boneAnimation.setTracks(tracks); + ArrayList animations = new ArrayList(1); + animations.add(boneAnimation); + + //preparing the object's bone + ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class); + Transform t = objectHelper.getTransformation(objectStructure); + Bone bone = new Bone(null); + bone.setBindTransforms(t.getTranslation(), t.getRotation(), t.getScale()); + + return new Modifier(Modifier.OBJECT_ANIMATION_MODIFIER_DATA, new AnimData(new Skeleton(new Bone[] {bone}), animations), objectStructure.getOldMemoryAddress()); + } + return null; } /** @@ -404,6 +486,12 @@ public class ModifierHelper extends AbstractBlenderHelper { return node; } + protected Node applyObjectAnimationModifier(Node node, Modifier modifier, DataRepository dataRepository) { + AnimData ad = (AnimData) modifier.getJmeModifierRepresentation(); + ad.skeleton.getBone(0).setAttachNode(node); + return this.applyArmatureModifierData(node, modifier, dataRepository); + } + /** * This method applies the array modifier to the node. * @param node diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ObjectHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ObjectHelper.java index 917f158e1..4b2e72043 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ObjectHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ObjectHelper.java @@ -31,15 +31,10 @@ */ package com.jme3.scene.plugins.blender.helpers.v249; -import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import com.jme3.animation.Bone; -import com.jme3.animation.BoneAnimation; -import com.jme3.animation.BoneTrack; -import com.jme3.animation.Skeleton; import com.jme3.light.DirectionalLight; import com.jme3.light.Light; import com.jme3.light.PointLight; @@ -53,10 +48,8 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.Spatial.CullHint; -import com.jme3.scene.plugins.blender.data.FileBlockHeader; import com.jme3.scene.plugins.blender.data.Structure; import com.jme3.scene.plugins.blender.exception.BlenderFileException; -import com.jme3.scene.plugins.blender.structures.Ipo; import com.jme3.scene.plugins.blender.structures.Modifier; import com.jme3.scene.plugins.blender.structures.Properties; import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper; @@ -64,7 +57,6 @@ import com.jme3.scene.plugins.blender.utils.DataRepository; import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType; import com.jme3.scene.plugins.blender.utils.DynamicArray; import com.jme3.scene.plugins.blender.utils.Pointer; -import com.jme3.scene.plugins.ogre.AnimData; /** * A class that is used in object calculations. @@ -142,7 +134,6 @@ public class ObjectHelper extends AbstractBlenderHelper { //reading modifiers modifierHelper.readModifiers(objectStructure, dataRepository); - Modifier objectAnimationModifier = objectHelper.readObjectAnimation(objectStructure, dataRepository); //loading constraints connected with this object constraintHelper.loadConstraints(objectStructure, dataRepository); @@ -188,10 +179,6 @@ public class ObjectHelper extends AbstractBlenderHelper { for(Modifier modifier : modifiers) { modifierHelper.applyModifier(node, modifier, dataRepository); } - //adding object animation modifier - if(objectAnimationModifier != null) { - node = modifierHelper.applyModifier(node, objectAnimationModifier, dataRepository); - } //setting the parent if(parent instanceof Node) { @@ -352,71 +339,6 @@ public class ObjectHelper extends AbstractBlenderHelper { return result; } - /** - * This method reads animation of the object itself (without bones) and stores it as an ArmatureModifierData - * modifier. The animation is returned as a modifier. It should be later applied regardless other modifiers. The - * reason for this is that object may not have modifiers added but it's animation should be working. - * @param objectStructure - * the structure of the object - * @param dataRepository - * the data repository - * @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 Modifier readObjectAnimation(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException { - 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 = dataRepository.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00)); - for(FileBlockHeader actionBlock : actionBlocks) { - Structure action = actionBlock.getStructure(dataRepository); - List actionChannels = ((Structure)action.getFieldValue("chanbase")).evaluateListBase(dataRepository); - 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; - } - } - } - - String objectName = objectStructure.getName(); - if(objectAnimationName == null) {//set the object's animation name to object's name - objectAnimationName = objectName; - } - - IpoHelper ipoHelper = dataRepository.getHelper(IpoHelper.class); - Structure ipoStructure = pIpo.fetchData(dataRepository.getInputStream()).get(0); - Ipo ipo = ipoHelper.createIpo(ipoStructure, dataRepository); - int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, objectAnimationName); - if(animationFrames == null) {//if the name was created here there are no frames set for the animation - animationFrames = new int[] {1, ipo.getLastFrame()}; - } - int fps = dataRepository.getBlenderKey().getFps(); - float start = (float)animationFrames[0] / (float)fps; - float stop = (float)animationFrames[1] / (float)fps; - - //calculating track for the only bone in this skeleton - BoneTrack[] tracks = new BoneTrack[1]; - tracks[0] = ipo.calculateTrack(0, animationFrames[0], animationFrames[1], fps); - - BoneAnimation boneAnimation = new BoneAnimation(objectAnimationName, stop - start); - boneAnimation.setTracks(tracks); - ArrayList animations = new ArrayList(1); - animations.add(boneAnimation); - - //preparing the object's bone - Transform t = this.getTransformation(objectStructure); - Bone bone = new Bone(null); - bone.setBindTransforms(t.getTranslation(), t.getRotation(), t.getScale()); - - return new Modifier(Modifier.ARMATURE_MODIFIER_DATA, new AnimData(new Skeleton(new Bone[] {bone}), animations), objectStructure.getOldMemoryAddress()); - } - return null; - } - @Override public void clearState() { fixUpAxis = false;