From a4ee4044fcdc7f3f6441423c637c02c2efae1af5 Mon Sep 17 00:00:00 2001 From: Stephen Gold Date: Tue, 11 May 2021 08:59:41 -0700 Subject: [PATCH 1/2] TestMorph: test cloning and serialization --- .../main/java/jme3test/model/anim/TestMorph.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/jme3-examples/src/main/java/jme3test/model/anim/TestMorph.java b/jme3-examples/src/main/java/jme3test/model/anim/TestMorph.java index 52dffc1209..5e8d14eb51 100644 --- a/jme3-examples/src/main/java/jme3test/model/anim/TestMorph.java +++ b/jme3-examples/src/main/java/jme3test/model/anim/TestMorph.java @@ -3,6 +3,7 @@ import com.jme3.anim.MorphControl; import com.jme3.app.ChaseCameraAppState; import com.jme3.app.SimpleApplication; +import com.jme3.export.binary.BinaryExporter; import com.jme3.font.BitmapFont; import com.jme3.font.BitmapText; import com.jme3.input.KeyInput; @@ -16,7 +17,7 @@ import com.jme3.scene.mesh.MorphTarget; import com.jme3.scene.shape.Box; import com.jme3.util.BufferUtils; - +import com.jme3.util.clone.Cloner; import java.nio.FloatBuffer; public class TestMorph extends SimpleApplication { @@ -90,6 +91,19 @@ public void simpleInitApp() { g.setMorphState(weights); 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(); chase.setTarget(rootNode); From f386b588ad8203da442806c65aa6027102e5bd98 Mon Sep 17 00:00:00 2001 From: Stephen Gold Date: Tue, 11 May 2021 09:02:37 -0700 Subject: [PATCH 2/2] solve issue #1548 (MorphControl doesn't override methods) --- .../main/java/com/jme3/anim/MorphControl.java | 79 ++++++++++++++++++- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/anim/MorphControl.java b/jme3-core/src/main/java/com/jme3/anim/MorphControl.java index f6bda33e0b..85a23eb236 100644 --- a/jme3-core/src/main/java/com/jme3/anim/MorphControl.java +++ b/jme3-core/src/main/java/com/jme3/anim/MorphControl.java @@ -31,6 +31,10 @@ */ 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.material.*; import com.jme3.renderer.*; @@ -40,7 +44,8 @@ import com.jme3.shader.VarType; import com.jme3.util.BufferUtils; import com.jme3.util.SafeArrayList; - +import com.jme3.util.clone.Cloner; +import java.io.IOException; import java.nio.FloatBuffer; import java.util.logging.Level; 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 final static float MIN_WEIGHT = 0.005f; - final private SafeArrayList targets = new SafeArrayList<>(Geometry.class); - final private TargetLocator targetLocator = new TargetLocator(); + private static final String TAG_APPROXIMATE = "approximateTangents"; + + private SafeArrayList targets = new SafeArrayList<>(Geometry.class); + private TargetLocator targetLocator = new TargetLocator(); 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[] tmpNormArray; @@ -373,6 +380,70 @@ public boolean isApproximateTangents() { 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 { @Override public void visit(Geometry geom) {