diff --git a/jme3-core/src/main/java/com/jme3/anim/AnimComposer.java b/jme3-core/src/main/java/com/jme3/anim/AnimComposer.java index d06b0816cc..f9cdf81167 100644 --- a/jme3-core/src/main/java/com/jme3/anim/AnimComposer.java +++ b/jme3-core/src/main/java/com/jme3/anim/AnimComposer.java @@ -66,7 +66,7 @@ public class AnimComposer extends AbstractControl { * Instantiate a composer with a single layer, no actions, and no clips. */ public AnimComposer() { - layers.put(DEFAULT_LAYER, new AnimLayer(this, DEFAULT_LAYER, null)); + layers.put(DEFAULT_LAYER, new AnimLayer(DEFAULT_LAYER, null)); } /** @@ -314,7 +314,7 @@ public Action removeAction(String name) { * @param mask the desired mask for the new layer (alias created) */ public void makeLayer(String name, AnimationMask mask) { - AnimLayer l = new AnimLayer(this, name, mask); + AnimLayer l = new AnimLayer(name, mask); layers.put(name, l); } @@ -399,7 +399,7 @@ public Set getAnimClipsNames() { @Override protected void controlUpdate(float tpf) { for (AnimLayer layer : layers.values()) { - layer.update(tpf); + layer.update(tpf, globalSpeed); } } @@ -542,6 +542,7 @@ public void read(JmeImporter im) throws IOException { InputCapsule ic = im.getCapsule(this); animClipMap = (Map) ic.readStringSavableMap("animClipMap", new HashMap()); globalSpeed = ic.readFloat("globalSpeed", 1f); + layers = (Map) ic.readStringSavableMap("layers", new HashMap()); } /** @@ -557,5 +558,6 @@ public void write(JmeExporter ex) throws IOException { OutputCapsule oc = ex.getCapsule(this); oc.writeStringSavableMap(animClipMap, "animClipMap", new HashMap()); oc.write(globalSpeed, "globalSpeed", 1f); + oc.writeStringSavableMap(layers, "layers", new HashMap()); } } diff --git a/jme3-core/src/main/java/com/jme3/anim/AnimLayer.java b/jme3-core/src/main/java/com/jme3/anim/AnimLayer.java index 0c3c97e998..6cd79e731d 100644 --- a/jme3-core/src/main/java/com/jme3/anim/AnimLayer.java +++ b/jme3-core/src/main/java/com/jme3/anim/AnimLayer.java @@ -32,8 +32,14 @@ package com.jme3.anim; import com.jme3.anim.tween.action.Action; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; import com.jme3.util.clone.Cloner; import com.jme3.util.clone.JmeCloneable; +import java.io.IOException; /** * A named portion of an AnimComposer that can run (at most) one Action at a @@ -48,7 +54,7 @@ *

Animation time may advance at a different rate from application time, * based on speedup factors in the composer and the current Action. */ -public class AnimLayer implements JmeCloneable { +public class AnimLayer implements JmeCloneable, Savable { /** * The Action currently running on this layer, or null if none. */ @@ -57,16 +63,12 @@ public class AnimLayer implements JmeCloneable { * The name of Action currently running on this layer, or null if none. */ private String currentActionName; - /** - * The composer that owns this layer. Were it not for cloning, this field - * would be final. - */ - private AnimComposer composer; + /** * Limits the portion of the model animated by this layer. If null, this * layer can animate the entire model. */ - private final AnimationMask mask; + private AnimationMask mask; /** * The current animation time, in scaled seconds. Always non-negative. */ @@ -79,23 +81,26 @@ public class AnimLayer implements JmeCloneable { /** * The name of this layer. */ - final private String name; + private String name; private boolean loop = true; + + /** + * For serialization only. Do not use. + */ + protected AnimLayer() { + + } /** * Instantiates a layer without a manager or a current Action, owned by the * specified composer. * - * @param composer the owner (not null, alias created) * @param name the layer name (not null) * @param mask the AnimationMask (alias created) or null to allow this layer * to animate the entire model */ - AnimLayer(AnimComposer composer, String name, AnimationMask mask) { - assert composer != null; - this.composer = composer; - + AnimLayer(String name, AnimationMask mask) { assert name != null; this.name = name; @@ -248,14 +253,15 @@ public void setLooping(boolean loop) { * * @param appDeltaTimeInSeconds the amount application time to advance the * current Action, in seconds + * @param globalSpeed the global speed applied to all layers. */ - void update(float appDeltaTimeInSeconds) { + void update(float appDeltaTimeInSeconds, float globalSpeed) { Action action = currentAction; if (action == null) { return; } - double speedup = action.getSpeed() * composer.getGlobalSpeed(); + double speedup = action.getSpeed() * globalSpeed; double scaledDeltaTime = speedup * appDeltaTimeInSeconds; time += scaledDeltaTime; @@ -292,7 +298,6 @@ void update(float appDeltaTimeInSeconds) { */ @Override public void cloneFields(Cloner cloner, Object original) { - composer = cloner.clone(composer); currentAction = null; currentActionName = null; } @@ -306,4 +311,20 @@ public Object jmeClone() { throw new AssertionError(); } } + + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule oc = ex.getCapsule(this); + oc.write(name, "name", null); + if (mask instanceof Savable) { + oc.write((Savable) mask, "mask", null); + } + } + + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule ic = im.getCapsule(this); + name = ic.readString("name", null); + mask = (AnimationMask) ic.readSavable("mask", null); + } } diff --git a/jme3-core/src/main/java/com/jme3/anim/ArmatureMask.java b/jme3-core/src/main/java/com/jme3/anim/ArmatureMask.java index 7f889fc042..bf8e10155d 100644 --- a/jme3-core/src/main/java/com/jme3/anim/ArmatureMask.java +++ b/jme3-core/src/main/java/com/jme3/anim/ArmatureMask.java @@ -31,14 +31,20 @@ */ package com.jme3.anim; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import java.io.IOException; import java.util.BitSet; /** * An AnimationMask to select joints from a single Armature. */ -public class ArmatureMask implements AnimationMask { +public class ArmatureMask implements AnimationMask, Savable { - final private BitSet affectedJoints = new BitSet(); + private BitSet affectedJoints = new BitSet(); /** * Instantiate a mask that affects no joints. @@ -206,4 +212,16 @@ public ArmatureMask removeAncestors(Joint start) { return this; } + + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule oc = ex.getCapsule(this); + oc.write(affectedJoints, "affectedJoints", null); + } + + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule ic = im.getCapsule(this); + affectedJoints = ic.readBitSet("affectedJoints", null); + } } diff --git a/jme3-core/src/test/java/com/jme3/anim/AnimComposerTest.java b/jme3-core/src/test/java/com/jme3/anim/AnimComposerTest.java index 331784352d..4cc5eb9080 100644 --- a/jme3-core/src/test/java/com/jme3/anim/AnimComposerTest.java +++ b/jme3-core/src/test/java/com/jme3/anim/AnimComposerTest.java @@ -31,6 +31,9 @@ */ package com.jme3.anim; +import com.jme3.anim.tween.action.Action; +import java.util.Set; +import java.util.TreeSet; import org.junit.Assert; import org.junit.Test; @@ -54,6 +57,36 @@ public void testGetAnimClipsNames() { Assert.assertNotNull(composer.getAnimClipsNames()); Assert.assertEquals(0, composer.getAnimClipsNames().size()); } + + @Test + public void testMakeLayer() { + AnimComposer composer = new AnimComposer(); + + final String layerName = "TestLayer"; + + composer.makeLayer(layerName, null); + + final Set layers = new TreeSet<>(); + layers.add("Default"); + layers.add(layerName); + + Assert.assertNotNull(composer.getLayer(layerName)); + Assert.assertEquals(layers, composer.getLayerNames()); + } + + @Test + public void testMakeAction() { + AnimComposer composer = new AnimComposer(); + + final String animName = "TestClip"; + + final AnimClip anim = new AnimClip(animName); + composer.addAnimClip(anim); + + final Action action = composer.makeAction(animName); + + Assert.assertNotNull(action); + } @Test(expected = UnsupportedOperationException.class) public void testGetAnimClipsIsNotModifiable() {