فهرست منبع

test case and solution for issue #1548 (MorphControl doesn't override methods) (#1549)

* TestMorph: test cloning and serialization

* solve issue #1548 (MorphControl doesn't override methods)
Stephen Gold 4 سال پیش
والد
کامیت
01fbd16427

+ 75 - 4
jme3-core/src/main/java/com/jme3/anim/MorphControl.java

@@ -31,6 +31,10 @@
  */
  */
 package com.jme3.anim;
 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 com.jme3.export.Savable;
 import com.jme3.material.*;
 import com.jme3.material.*;
 import com.jme3.renderer.*;
 import com.jme3.renderer.*;
@@ -40,7 +44,8 @@ import com.jme3.scene.mesh.MorphTarget;
 import com.jme3.shader.VarType;
 import com.jme3.shader.VarType;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.SafeArrayList;
 import com.jme3.util.SafeArrayList;
-
+import com.jme3.util.clone.Cloner;
+import java.io.IOException;
 import java.nio.FloatBuffer;
 import java.nio.FloatBuffer;
 import java.util.logging.Level;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
@@ -59,11 +64,13 @@ public class MorphControl extends AbstractControl implements Savable {
     private static final int MAX_MORPH_BUFFERS = 14;
     private static final int MAX_MORPH_BUFFERS = 14;
     private final static float MIN_WEIGHT = 0.005f;
     private final static float MIN_WEIGHT = 0.005f;
 
 
-    final private SafeArrayList<Geometry> targets = new SafeArrayList<>(Geometry.class);
-    final private TargetLocator targetLocator = new TargetLocator();
+    private static final String TAG_APPROXIMATE = "approximateTangents";
+
+    private SafeArrayList<Geometry> targets = new SafeArrayList<>(Geometry.class);
+    private TargetLocator targetLocator = new TargetLocator();
 
 
     private boolean approximateTangents = true;
     private boolean approximateTangents = true;
-    final private MatParamOverride nullNumberOfBones = new MatParamOverride(VarType.Int, "NumberOfBones", null);
+    private MatParamOverride nullNumberOfBones = new MatParamOverride(VarType.Int, "NumberOfBones", null);
 
 
     private float[] tmpPosArray;
     private float[] tmpPosArray;
     private float[] tmpNormArray;
     private float[] tmpNormArray;
@@ -373,6 +380,70 @@ public class MorphControl extends AbstractControl implements Savable {
         return approximateTangents;
         return approximateTangents;
     }
     }
 
 
+    /**
+     * Callback from {@link com.jme3.util.clone.Cloner} to convert this
+     * shallow-cloned Control into a deep-cloned one, using the specified Cloner
+     * and original to resolve copied fields.
+     *
+     * @param cloner the Cloner that's cloning this Control (not null, modified)
+     * @param original the instance from which this Control was shallow-cloned
+     * (not null, unaffected)
+     */
+    @Override
+    public void cloneFields(Cloner cloner, Object original) {
+        super.cloneFields(cloner, original);
+
+        targets = cloner.clone(targets);
+        targetLocator = new TargetLocator();
+        nullNumberOfBones = cloner.clone(nullNumberOfBones);
+        tmpPosArray = null;
+        tmpNormArray = null;
+        tmpTanArray = null;
+    }
+
+    /**
+     * Create a shallow clone for the JME cloner.
+     *
+     * @return a new instance
+     */
+    @Override
+    public MorphControl jmeClone() {
+        try {
+            MorphControl clone = (MorphControl) super.clone();
+            return clone;
+        } catch (CloneNotSupportedException exception) {
+            throw new RuntimeException(exception);
+        }
+    }
+
+    /**
+     * De-serialize this Control from the specified importer, for example when
+     * loading from a J3O file.
+     *
+     * @param importer (not null)
+     * @throws IOException from the importer
+     */
+    @Override
+    public void read(JmeImporter importer) throws IOException {
+        super.read(importer);
+        InputCapsule capsule = importer.getCapsule(this);
+        approximateTangents = capsule.readBoolean(TAG_APPROXIMATE, true);
+    }
+
+    /**
+     * Serialize this Control to the specified exporter, for example when saving
+     * to a J3O file.
+     *
+     * @param exporter (not null)
+     * @throws IOException from the exporter
+     */
+    @Override
+    public void write(JmeExporter exporter) throws IOException {
+        super.write(exporter);
+        OutputCapsule capsule = exporter.getCapsule(this);
+        capsule.write(approximateTangents, TAG_APPROXIMATE, true);
+    }
+
     private class TargetLocator extends SceneGraphVisitorAdapter {
     private class TargetLocator extends SceneGraphVisitorAdapter {
         @Override
         @Override
         public void visit(Geometry geom) {
         public void visit(Geometry geom) {

+ 15 - 1
jme3-examples/src/main/java/jme3test/model/anim/TestMorph.java

@@ -3,6 +3,7 @@ package jme3test.model.anim;
 import com.jme3.anim.MorphControl;
 import com.jme3.anim.MorphControl;
 import com.jme3.app.ChaseCameraAppState;
 import com.jme3.app.ChaseCameraAppState;
 import com.jme3.app.SimpleApplication;
 import com.jme3.app.SimpleApplication;
+import com.jme3.export.binary.BinaryExporter;
 import com.jme3.font.BitmapFont;
 import com.jme3.font.BitmapFont;
 import com.jme3.font.BitmapText;
 import com.jme3.font.BitmapText;
 import com.jme3.input.KeyInput;
 import com.jme3.input.KeyInput;
@@ -16,7 +17,7 @@ import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.mesh.MorphTarget;
 import com.jme3.scene.mesh.MorphTarget;
 import com.jme3.scene.shape.Box;
 import com.jme3.scene.shape.Box;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.BufferUtils;
-
+import com.jme3.util.clone.Cloner;
 import java.nio.FloatBuffer;
 import java.nio.FloatBuffer;
 
 
 public class TestMorph extends SimpleApplication {
 public class TestMorph extends SimpleApplication {
@@ -90,6 +91,19 @@ public class TestMorph extends SimpleApplication {
 
 
         g.setMorphState(weights);
         g.setMorphState(weights);
         g.addControl(new MorphControl());
         g.addControl(new MorphControl());
+        /*
+         * Attach a clone of the morphing box model, in order to test cloning.
+         */
+        Geometry g2 = Cloner.deepClone(g);
+        g2.move(-4f, 0f, 0f);
+        rootNode.attachChild(g2);
+        /*
+         * Attach a saveAndLoad() copy of the morphing box model,
+         * in order to test serialization.
+         */
+        Geometry g3 = BinaryExporter.saveAndLoad(assetManager, g);
+        g3.move(-4f, 4f, 0f);
+        rootNode.attachChild(g3);
 
 
         ChaseCameraAppState chase = new ChaseCameraAppState();
         ChaseCameraAppState chase = new ChaseCameraAppState();
         chase.setTarget(rootNode);
         chase.setTarget(rootNode);