浏览代码

Merge pull request #2307 from neph1/animation_refactor

Minor refactor to allow for saving AnimLayers
Rickard Edén 1 年之前
父节点
当前提交
db6353046c

+ 5 - 3
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 class AnimComposer extends AbstractControl {
      * @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 class AnimComposer extends AbstractControl {
     @Override
     protected void controlUpdate(float tpf) {
         for (AnimLayer layer : layers.values()) {
-            layer.update(tpf);
+            layer.update(tpf, globalSpeed);
         }
     }
 
@@ -542,6 +542,7 @@ public class AnimComposer extends AbstractControl {
         InputCapsule ic = im.getCapsule(this);
         animClipMap = (Map<String, AnimClip>) ic.readStringSavableMap("animClipMap", new HashMap<String, AnimClip>());
         globalSpeed = ic.readFloat("globalSpeed", 1f);
+        layers = (Map<String, AnimLayer>) ic.readStringSavableMap("layers", new HashMap<String, AnimLayer>());
     }
 
     /**
@@ -557,5 +558,6 @@ public class AnimComposer extends AbstractControl {
         OutputCapsule oc = ex.getCapsule(this);
         oc.writeStringSavableMap(animClipMap, "animClipMap", new HashMap<String, AnimClip>());
         oc.write(globalSpeed, "globalSpeed", 1f);
+        oc.writeStringSavableMap(layers, "layers", new HashMap<String, AnimLayer>());
     }
 }

+ 37 - 16
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 @@ import com.jme3.util.clone.JmeCloneable;
  * <p>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 class AnimLayer implements JmeCloneable {
      *
      * @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 @@ public class AnimLayer implements JmeCloneable {
      */
     @Override
     public void cloneFields(Cloner cloner, Object original) {
-        composer = cloner.clone(composer);
         currentAction = null;
         currentActionName = null;
     }
@@ -306,4 +311,20 @@ public class AnimLayer implements JmeCloneable {
             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);
+    }
 }

+ 20 - 2
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 class ArmatureMask implements AnimationMask {
 
         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);
+    }
 }

+ 33 - 0
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 class AnimComposerTest {
         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<String> 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() {