diff --git a/engine/src/blender/com/jme3/asset/BlenderKey.java b/engine/src/blender/com/jme3/asset/BlenderKey.java index b45b15278..d37910bb5 100644 --- a/engine/src/blender/com/jme3/asset/BlenderKey.java +++ b/engine/src/blender/com/jme3/asset/BlenderKey.java @@ -33,12 +33,8 @@ package com.jme3.asset; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; import java.util.Queue; -import java.util.Set; import com.jme3.bounding.BoundingVolume; import com.jme3.collision.Collidable; @@ -66,13 +62,6 @@ import com.jme3.texture.Texture; public class BlenderKey extends ModelKey { protected static final int DEFAULT_FPS = 25; - /** - * Animation definitions. The key is the object name that owns the animation. The value is a map between animation - * name and its start and stop frames. Blender stores a pointer for animation within object. Therefore one object - * can only have one animation at the time. We want to be able to switch between animations for one object so we - * need to map the object name to animation names the object will use. - */ - protected Map> animations; /** * FramesPerSecond parameter describe how many frames there are in each second. It allows to calculate the time * between the frames. @@ -126,76 +115,6 @@ public class BlenderKey extends ModelKey { super(name); } - /** - * This method adds an animation definition. If a definition already eixists in the key then it is replaced. - * @param objectName - * the name of animation's owner - * @param name - * the name of the animation - * @param start - * the start frame of the animation - * @param stop - * the stop frame of the animation - */ - public synchronized void addAnimation(String objectName, String name, int start, int stop) { - if (objectName == null) { - throw new IllegalArgumentException("Object name cannot be null!"); - } - if (name == null) { - throw new IllegalArgumentException("Animation name cannot be null!"); - } - if (start > stop) { - throw new IllegalArgumentException("Start frame cannot be greater than stop frame!"); - } - if (animations == null) { - animations = new HashMap>(); - animations.put(objectName, new HashMap()); - } - Map objectAnimations = animations.get(objectName); - if (objectAnimations == null) { - objectAnimations = new HashMap(); - animations.put(objectName, objectAnimations); - } - objectAnimations.put(name, new int[] { start, stop }); - } - - /** - * This method returns the animation frames boundaries. - * @param objectName - * the name of animation's owner - * @param name - * animation name - * @return animation frame boundaries in a table [start, stop] or null if animation of the given name does not - * exists - */ - public int[] getAnimationFrames(String objectName, String name) { - Map objectAnimations = animations == null ? null : animations.get(objectName); - int[] frames = objectAnimations == null ? null : objectAnimations.get(name); - return frames == null ? null : frames.clone(); - } - - /** - * This method returns the animation names for the given object name. - * @param objectName - * the name of the object - * @return an array of animations for this object - */ - public Set getAnimationNames(String objectName) { - Map objectAnimations = animations == null ? null : animations.get(objectName); - return objectAnimations == null ? null : objectAnimations.keySet(); - } - - /** - * This method returns the animations map. - * The key is the animated spatial name. The value is a map where the key - * is the animation name and the value is 2-element array of int that has - * start and stop frame of the animation. - * @return the animations map - */ - public Map> getAnimations() { - return animations; - } - /** * This method returns frames per second amount. The default value is BlenderKey.DEFAULT_FPS = 25. * @return the frames per second amount @@ -424,22 +343,6 @@ public class BlenderKey extends ModelKey { public void write(JmeExporter e) throws IOException { super.write(e); OutputCapsule oc = e.getCapsule(this); - // saving animations - oc.write(animations == null ? 0 : animations.size(), "anim-size", 0); - if (animations != null) { - int objectCounter = 0; - for (Entry> animEntry : animations.entrySet()) { - oc.write(animEntry.getKey(), "animated-object-" + objectCounter, null); - int animsAmount = animEntry.getValue().size(); - oc.write(animsAmount, "anims-amount-" + objectCounter, 0); - for (Entry animsEntry : animEntry.getValue().entrySet()) { - oc.write(animsEntry.getKey(), "anim-name-" + objectCounter, null); - oc.write(animsEntry.getValue(), "anim-frames-" + objectCounter, null); - } - ++objectCounter; - } - } - // saving the rest of the data oc.write(fps, "fps", DEFAULT_FPS); oc.write(generatedTextureWidth, "generated-texture-width", 20); oc.write(generatedTextureHeight, "generated-texture-height", 20); @@ -458,28 +361,6 @@ public class BlenderKey extends ModelKey { public void read(JmeImporter e) throws IOException { super.read(e); InputCapsule ic = e.getCapsule(this); - // reading animations - int animSize = ic.readInt("anim-size", 0); - if (animSize > 0) { - if (animations == null) { - animations = new HashMap>(animSize); - } else { - animations.clear(); - } - for (int i = 0; i < animSize; ++i) { - String objectName = ic.readString("animated-object-" + i, null); - int animationsAmount = ic.readInt("anims-amount-" + i, 0); - Map objectAnimations = new HashMap(animationsAmount); - for (int j = 0; j < animationsAmount; ++j) { - String animName = ic.readString("anim-name-" + i, null); - int[] animFrames = ic.readIntArray("anim-frames-" + i, null); - objectAnimations.put(animName, animFrames); - } - animations.put(objectName, objectAnimations); - } - } - - // reading the rest of the data fps = ic.readInt("fps", DEFAULT_FPS); generatedTextureWidth = ic.readInt("generated-texture-width", 20); generatedTextureHeight = ic.readInt("generated-texture-height", 20); @@ -498,7 +379,6 @@ public class BlenderKey extends ModelKey { public int hashCode() { final int prime = 31; int result = super.hashCode(); - result = prime * result + (animations == null ? 0 : animations.hashCode()); result = prime * result + (assetRootPath == null ? 0 : assetRootPath.hashCode()); result = prime * result + (defaultMaterial == null ? 0 : defaultMaterial.hashCode()); result = prime * result + (faceCullMode == null ? 0 : faceCullMode.hashCode()); @@ -526,13 +406,6 @@ public class BlenderKey extends ModelKey { return false; } BlenderKey other = (BlenderKey) obj; - if (animations == null) { - if (other.animations != null) { - return false; - } - } else if (!animations.equals(other.animations)) { - return false; - } if (assetRootPath == null) { if (other.assetRootPath != null) { return false; 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 d760732f1..fc56a9d88 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 @@ -39,7 +39,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.jme3.animation.Bone; -import com.jme3.animation.BoneTrack; +import com.jme3.animation.Track; import com.jme3.math.Matrix4f; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; @@ -320,20 +320,16 @@ public class ArmatureHelper extends AbstractBlenderHelper { * the structure containing the tracks * @param blenderContext * the blender context - * @param objectName - * the name of the object that will use these tracks - * @param animationName - * the animation name * @return a list of tracks for the specified animation * @throws BlenderFileException * an exception is thrown when there are problems with the blend * file */ - public BoneTrack[] getTracks(Structure actionStructure, BlenderContext blenderContext, String objectName, String animationName) throws BlenderFileException { + public Track[] getTracks(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException { if (blenderVersion < 250) { - return this.getTracks249(actionStructure, blenderContext, objectName, animationName); + return this.getTracks249(actionStructure, blenderContext); } else { - return this.getTracks250(actionStructure, blenderContext, objectName, animationName); + return this.getTracks250(actionStructure, blenderContext); } } @@ -344,26 +340,21 @@ public class ArmatureHelper extends AbstractBlenderHelper { * the structure containing the tracks * @param blenderContext * the blender context - * @param objectName - * the name of the object that will use these tracks - * @param animationName - * the animation name * @return a list of tracks for the specified animation * @throws BlenderFileException * an exception is thrown when there are problems with the blend * file */ - private BoneTrack[] getTracks250(Structure actionStructure, BlenderContext blenderContext, String objectName, String animationName) throws BlenderFileException { + private Track[] getTracks250(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException { LOGGER.log(Level.INFO, "Getting tracks!"); int fps = blenderContext.getBlenderKey().getFps(); - int[] animationFrames = blenderContext.getBlenderKey().getAnimationFrames(objectName, animationName); Structure groups = (Structure) actionStructure.getFieldValue("groups"); List actionGroups = groups.evaluateListBase(blenderContext);//bActionGroup if (actionGroups != null && actionGroups.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) { throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!"); } - List tracks = new ArrayList(); + List> tracks = new ArrayList>(); for (Structure actionGroup : actionGroups) { String name = actionGroup.getFieldValue("name").toString(); Integer boneIndex = bonesMap.get(name); @@ -389,10 +380,10 @@ public class ArmatureHelper extends AbstractBlenderHelper { } Ipo ipo = new Ipo(bezierCurves); - tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps)); + tracks.add(ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps)); } } - return tracks.toArray(new BoneTrack[tracks.size()]); + return tracks.toArray(new Track[tracks.size()]); } /** @@ -402,26 +393,21 @@ public class ArmatureHelper extends AbstractBlenderHelper { * the structure containing the tracks * @param blenderContext * the blender context - * @param objectName - * the name of the object that will use these tracks - * @param animationName - * the animation name * @return a list of tracks for the specified animation * @throws BlenderFileException * an exception is thrown when there are problems with the blend * file */ - private BoneTrack[] getTracks249(Structure actionStructure, BlenderContext blenderContext, String objectName, String animationName) throws BlenderFileException { + private Track[] getTracks249(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException { LOGGER.log(Level.INFO, "Getting tracks!"); IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class); int fps = blenderContext.getBlenderKey().getFps(); - int[] animationFrames = blenderContext.getBlenderKey().getAnimationFrames(objectName, animationName); Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase"); List actionChannels = chanbase.evaluateListBase(blenderContext);//bActionChannel if (actionChannels != null && actionChannels.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) { throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!"); } - List tracks = new ArrayList(); + List> tracks = new ArrayList>(); for (Structure bActionChannel : actionChannels) { String name = bActionChannel.getFieldValue("name").toString(); Integer boneIndex = bonesMap.get(name); @@ -430,11 +416,11 @@ public class ArmatureHelper extends AbstractBlenderHelper { if (!p.isNull()) { Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0); Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext); - tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps)); + tracks.add(ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps)); } } } - return tracks.toArray(new BoneTrack[tracks.size()]); + return tracks.toArray(new Track[tracks.size()]); } /** 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 8c9360d1e..cb5e330cc 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 @@ -1,6 +1,8 @@ package com.jme3.scene.plugins.blender.animations; import com.jme3.animation.BoneTrack; +import com.jme3.animation.SpatialTrack; +import com.jme3.animation.Track; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.scene.plugins.blender.curves.BezierCurve; @@ -28,7 +30,7 @@ public class Ipo { /** A list of bezier curves for this interpolation object. */ private BezierCurve[] bezierCurves; /** Each ipo contains one bone track. */ - private BoneTrack calculatedTrack; + private Track calculatedTrack; /** * Constructor. Stores the bezier curves. @@ -105,8 +107,9 @@ public class Ipo { /** * This method calculates the value of the curves as a bone track between the specified frames. - * @param boneIndex - * the index of the bone for which the method calculates the tracks + * @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 @@ -115,63 +118,68 @@ public class Ipo { * frame rate (frames per second) * @return bone track for the specified bone */ - public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps) { - //preparing data for track - int framesAmount = stopFrame - startFrame; - float start = (startFrame - 1.0f) / fps; - float timeBetweenFrames = 1.0f / fps; + 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; - 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 bObjectRotation = false; - Vector3f[] scales = new Vector3f[framesAmount + 1]; - float[] scale = new float[3]; + 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[3]; - //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()) { - case AC_LOC_X: - case AC_LOC_Y: - case AC_LOC_Z: - translation[bezierCurves[j].getType() - 1] = (float) value; - break; - case OB_ROT_X: - case OB_ROT_Y: - case OB_ROT_Z: - objectRotation[bezierCurves[j].getType() - 7] = (float) value; - bObjectRotation = true; - break; - case AC_SIZE_X: - case AC_SIZE_Y: - case AC_SIZE_Z: - scale[bezierCurves[j].getType() - 13] = (float) value; - break; - case AC_QUAT_W: - quaternionRotation[3] = (float) value; - break; - case AC_QUAT_X: - case AC_QUAT_Y: - case AC_QUAT_Z: - quaternionRotation[bezierCurves[j].getType() - 26] = (float) value; - break; - default: - //TODO: error? info? warning? + //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()) { + case AC_LOC_X: + case AC_LOC_Y: + case AC_LOC_Z: + translation[bezierCurves[j].getType() - 1] = (float) value; + break; + case OB_ROT_X: + case OB_ROT_Y: + case OB_ROT_Z: + objectRotation[bezierCurves[j].getType() - 7] = (float) value; + break; + case AC_SIZE_X: + case AC_SIZE_Y: + case AC_SIZE_Z: + scale[bezierCurves[j].getType() - 13] = (float) value; + break; + case AC_QUAT_W: + quaternionRotation[3] = (float) value; + break; + case AC_QUAT_X: + case AC_QUAT_Y: + case AC_QUAT_Z: + quaternionRotation[bezierCurves[j].getType() - 26] = (float) value; + break; + default: + //TODO: error? info? warning? + } } + 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]); } - translations[index] = new Vector3f(translation[0], translation[1], translation[2]); - rotations[index] = bObjectRotation ? new Quaternion().fromAngles(objectRotation) - : new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]); - scales[index] = new Vector3f(scale[0], scale[1], scale[2]); - } - calculatedTrack = new BoneTrack(boneIndex, times, translations, rotations, scales); + if(bSpatialTrack) { + 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/modifiers/ArmatureModifier.java b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java index 241e9b62c..dc4be4945 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 @@ -6,7 +6,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -15,6 +14,7 @@ import com.jme3.animation.Animation; import com.jme3.animation.Bone; import com.jme3.animation.Skeleton; import com.jme3.animation.SkeletonControl; +import com.jme3.animation.Track; import com.jme3.math.Matrix4f; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; @@ -116,28 +116,27 @@ import com.jme3.util.BufferUtils; this.readVerticesWeightsData(objectStructure, meshStructure, blenderContext); //read animations - String objectName = objectStructure.getName(); - Set animationNames = blenderContext.getBlenderKey().getAnimationNames(objectName); - System.out.println("Loaded animation " + objectName); - if (animationNames != null && animationNames.size() > 0) { - ArrayList animations = new ArrayList(); - List actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00)); - for (FileBlockHeader header : actionHeaders) { - Structure actionStructure = header.getStructure(blenderContext); - String actionName = actionStructure.getName(); - if (animationNames.contains(actionName)) { - int[] animationFrames = blenderContext.getBlenderKey().getAnimationFrames(objectName, actionName); - int fps = blenderContext.getBlenderKey().getFps(); - float start = (float) animationFrames[0] / (float) fps; - float stop = (float) animationFrames[1] / (float) fps; - Animation boneAnimation = new Animation(actionName, stop - start); - boneAnimation.setTracks(armatureHelper.getTracks(actionStructure, blenderContext, objectName, actionName)); - animations.add(boneAnimation); - + ArrayList animations = new ArrayList(); + List actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00)); + for (FileBlockHeader header : actionHeaders) { + Structure actionStructure = header.getStructure(blenderContext); + String actionName = actionStructure.getName(); + + Track[] tracks = armatureHelper.getTracks(actionStructure, blenderContext); + //determining the animation time + float maximumTrackLength = 0; + for(Track track : tracks) { + float length = track.getLength(); + if(length > maximumTrackLength) { + maximumTrackLength = length; } } - animData = new AnimData(new Skeleton(bones), animations); + + Animation boneAnimation = new Animation(actionName, maximumTrackLength); + boneAnimation.setTracks(tracks); + animations.add(boneAnimation); } + animData = new AnimData(new Skeleton(bones), animations); } } } 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 22ab79f89..dd6e92e7c 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java @@ -1,10 +1,22 @@ package com.jme3.scene.plugins.blender.modifiers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.logging.Level; import java.util.logging.Logger; +import com.jme3.animation.AnimControl; +import com.jme3.animation.Animation; +import com.jme3.animation.Track; import com.jme3.scene.Node; import com.jme3.scene.plugins.blender.BlenderContext; +import com.jme3.scene.plugins.blender.animations.Ipo; +import com.jme3.scene.plugins.blender.animations.IpoHelper; +import com.jme3.scene.plugins.blender.constraints.Constraint; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; +import com.jme3.scene.plugins.blender.file.FileBlockHeader; +import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.ogre.AnimData; @@ -41,13 +53,12 @@ import com.jme3.scene.plugins.ogre.AnimData; */ public ObjectAnimationModifier(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException { LOGGER.warning("Object animation modifier not yet implemented!"); - /* + 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)); + List actionBlocks = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00)); for (FileBlockHeader actionBlock : actionBlocks) { Structure action = actionBlock.getStructure(blenderContext); List actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext); @@ -68,38 +79,51 @@ import com.jme3.scene.plugins.ogre.AnimData; IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class); Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0); Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext); - int[] animationFrames = blenderContext.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 = blenderContext.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); + Track track = ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps); + + Animation animation = new Animation(objectAnimationName, ipo.getLastFrame() / fps); + animation.setTracks(new Track[] { track }); ArrayList animations = new ArrayList(1); - animations.add(boneAnimation); - - // preparing the object's bone - ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); - Transform t = objectHelper.getTransformation(objectStructure, blenderContext); - Bone bone = new Bone(null); - bone.setBindTransforms(t.getTranslation(), t.getRotation(), t.getScale()); + animations.add(animation); - animData = new AnimData(new Skeleton(new Bone[] { bone }), animations); + animData = new AnimData(null, animations); objectOMA = objectStructure.getOldMemoryAddress(); } - */ } @Override public Node apply(Node node, BlenderContext blenderContext) { - LOGGER.warning("Object animation modifier not yet implemented!"); + if(invalid) { + LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName()); + }//if invalid, animData will be null + if(animData == null) { + return node; + } + + ArrayList animList = animData.anims; + if (animList != null && animList.size() > 0) { + List constraints = blenderContext.getConstraints(this.objectOMA); + HashMap anims = new HashMap(); + for (int i = 0; i < animList.size(); ++i) { + Animation animation = (Animation) animList.get(i).clone(); + + // baking constraints into animations + if (constraints != null && constraints.size() > 0) { + for (Constraint constraint : constraints) { + constraint.affectAnimation(animation, 0); + } + } + + anims.put(animation.getName(), animation); + } + + AnimControl control = new AnimControl(null); + control.setAnimations(anims); + node.addControl(control); + } return node; }