From 8b1ddbe60fadb8955efbcd8cef38090d20b1bdea Mon Sep 17 00:00:00 2001 From: Paul Speed Date: Sun, 20 Mar 2016 02:47:16 -0400 Subject: [PATCH] First round of getting JmeCloneable implemented... added support for Cloner to the controls that implemented cloneForSpatial(). Unused until spatial cloning is implemented. --- .../control/AbstractPhysicsControl.java | 10 ++- .../control/BetterCharacterControl.java | 12 +++- .../jme3/bullet/control/CharacterControl.java | 27 +++++++- .../com/jme3/bullet/control/GhostControl.java | 23 ++++++- .../control/KinematicRagdollControl.java | 15 ++++- .../jme3/bullet/control/RigidBodyControl.java | 37 ++++++++++- .../jme3/bullet/control/VehicleControl.java | 61 ++++++++++++++++++- .../java/com/jme3/animation/AnimControl.java | 31 +++++++++- .../java/com/jme3/animation/Animation.java | 31 +++++++++- .../java/com/jme3/animation/AudioTrack.java | 24 +++++++- .../com/jme3/animation/ClonableTrack.java | 3 +- .../java/com/jme3/animation/EffectTrack.java | 33 ++++++++++ .../java/com/jme3/animation/Skeleton.java | 13 +++- .../com/jme3/animation/SkeletonControl.java | 27 +++++++- .../java/com/jme3/animation/TrackInfo.java | 18 +++++- .../src/main/java/com/jme3/app/StatsView.java | 14 ++++- .../jme3/cinematic/events/MotionEvent.java | 29 ++++++++- .../java/com/jme3/effect/ParticleEmitter.java | 18 +++++- .../main/java/com/jme3/input/ChaseCamera.java | 21 ++++++- .../jme3/scene/control/AbstractControl.java | 18 +++++- .../com/jme3/scene/control/LodControl.java | 15 ++++- .../com/jme3/scene/control/UpdateControl.java | 13 ++++ .../jme3/scene/instancing/InstancedNode.java | 18 +++++- .../jme3test/bullet/PhysicsHoverControl.java | 14 ++++- .../java/jme3test/light/TestPssmShadow.java | 11 ++++ .../geomipmap/NormalRecalcControl.java | 9 +++ .../terrain/geomipmap/TerrainLodControl.java | 26 +++++++- 27 files changed, 547 insertions(+), 24 deletions(-) diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/AbstractPhysicsControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/AbstractPhysicsControl.java index 7c69fdf51..d4f3658c0 100644 --- a/jme3-bullet/src/common/java/com/jme3/bullet/control/AbstractPhysicsControl.java +++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/AbstractPhysicsControl.java @@ -41,6 +41,8 @@ import com.jme3.math.Vector3f; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.scene.Spatial; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** @@ -49,7 +51,7 @@ import java.io.IOException; * * @author normenhansen */ -public abstract class AbstractPhysicsControl implements PhysicsControl { +public abstract class AbstractPhysicsControl implements PhysicsControl, JmeCloneable { private final Quaternion tmp_inverseWorldRotation = new Quaternion(); protected Spatial spatial; @@ -161,6 +163,12 @@ public abstract class AbstractPhysicsControl implements PhysicsControl { } + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.spatial = cloner.clone(spatial); + createSpatialData(this.spatial); + } + public void setSpatial(Spatial spatial) { if (this.spatial != null && this.spatial != spatial) { removeSpatialData(this.spatial); diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java index d88e57a26..30190f1f1 100644 --- a/jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java +++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java @@ -50,6 +50,8 @@ import com.jme3.renderer.ViewPort; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; import com.jme3.util.TempVars; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; import java.util.List; import java.util.logging.Level; @@ -68,7 +70,7 @@ import java.util.logging.Logger; * * @author normenhansen */ -public class BetterCharacterControl extends AbstractPhysicsControl implements PhysicsTickListener { +public class BetterCharacterControl extends AbstractPhysicsControl implements PhysicsTickListener, JmeCloneable { protected static final Logger logger = Logger.getLogger(BetterCharacterControl.class.getName()); protected PhysicsRigidBody rigidBody; @@ -670,6 +672,14 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph return control; } + @Override + public Object jmeClone() { + BetterCharacterControl control = new BetterCharacterControl(radius, height, mass); + control.setJumpForce(jumpForce); + control.spatial = this.spatial; + return control; + } + @Override public void write(JmeExporter ex) throws IOException { super.write(ex); diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/CharacterControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/CharacterControl.java index f455043eb..7ef80778c 100644 --- a/jme3-bullet/src/common/java/com/jme3/bullet/control/CharacterControl.java +++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/CharacterControl.java @@ -44,13 +44,15 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** * You might want to try BetterCharacterControl as well. * @author normenhansen */ -public class CharacterControl extends PhysicsCharacter implements PhysicsControl { +public class CharacterControl extends PhysicsCharacter implements PhysicsControl, JmeCloneable { protected Spatial spatial; protected boolean enabled = true; @@ -104,6 +106,29 @@ public class CharacterControl extends PhysicsCharacter implements PhysicsControl return control; } + @Override + public Object jmeClone() { + CharacterControl control = new CharacterControl(collisionShape, stepHeight); + control.setCcdMotionThreshold(getCcdMotionThreshold()); + control.setCcdSweptSphereRadius(getCcdSweptSphereRadius()); + control.setCollideWithGroups(getCollideWithGroups()); + control.setCollisionGroup(getCollisionGroup()); + control.setFallSpeed(getFallSpeed()); + control.setGravity(getGravity()); + control.setJumpSpeed(getJumpSpeed()); + control.setMaxSlope(getMaxSlope()); + control.setPhysicsLocation(getPhysicsLocation()); + control.setUpAxis(getUpAxis()); + control.setApplyPhysicsLocal(isApplyPhysicsLocal()); + control.spatial = this.spatial; + return control; + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.spatial = cloner.clone(spatial); + } + public void setSpatial(Spatial spatial) { this.spatial = spatial; setUserObject(spatial); diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/GhostControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/GhostControl.java index 55fdfdcc3..70c636507 100644 --- a/jme3-bullet/src/common/java/com/jme3/bullet/control/GhostControl.java +++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/GhostControl.java @@ -44,6 +44,8 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** @@ -51,7 +53,7 @@ import java.io.IOException; * overlaps with other physics objects (e.g. aggro radius). * @author normenhansen */ -public class GhostControl extends PhysicsGhostObject implements PhysicsControl { +public class GhostControl extends PhysicsGhostObject implements PhysicsControl, JmeCloneable { protected Spatial spatial; protected boolean enabled = true; @@ -106,6 +108,25 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl { return control; } + @Override + public Object jmeClone() { + GhostControl control = new GhostControl(collisionShape); + control.setCcdMotionThreshold(getCcdMotionThreshold()); + control.setCcdSweptSphereRadius(getCcdSweptSphereRadius()); + control.setCollideWithGroups(getCollideWithGroups()); + control.setCollisionGroup(getCollisionGroup()); + control.setPhysicsLocation(getPhysicsLocation()); + control.setPhysicsRotation(getPhysicsRotationMatrix()); + control.setApplyPhysicsLocal(isApplyPhysicsLocal()); + control.spatial = this.spatial; + return control; + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.spatial = cloner.clone(spatial); + } + public void setSpatial(Spatial spatial) { this.spatial = spatial; setUserObject(spatial); diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java index 78cc4ca0a..6c25b6662 100644 --- a/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java +++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java @@ -61,6 +61,8 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; import com.jme3.util.TempVars; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; import java.util.*; import java.util.logging.Level; @@ -92,7 +94,7 @@ import java.util.logging.Logger; * * @author Normen Hansen and Rémy Bouquet (Nehon) */ -public class KinematicRagdollControl extends AbstractPhysicsControl implements PhysicsCollisionListener { +public class KinematicRagdollControl extends AbstractPhysicsControl implements PhysicsCollisionListener, JmeCloneable { protected static final Logger logger = Logger.getLogger(KinematicRagdollControl.class.getName()); protected List listeners; @@ -920,6 +922,17 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P return control; } + @Override + public Object jmeClone() { + KinematicRagdollControl control = new KinematicRagdollControl(preset, weightThreshold); + control.setMode(mode); + control.setRootMass(rootMass); + control.setWeightThreshold(weightThreshold); + control.setApplyPhysicsLocal(applyLocal); + control.spatial = this.spatial; + return control; + } + public Vector3f setIKTarget(Bone bone, Vector3f worldPos, int chainLength) { Vector3f target = worldPos.subtract(targetModel.getWorldTranslation()); ikTargets.put(bone.getName(), target); diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/RigidBodyControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/RigidBodyControl.java index 0e1f1c019..25a23cc7c 100644 --- a/jme3-bullet/src/common/java/com/jme3/bullet/control/RigidBodyControl.java +++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/RigidBodyControl.java @@ -51,13 +51,15 @@ import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Sphere; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** * * @author normenhansen */ -public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl { +public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl, JmeCloneable { protected Spatial spatial; protected boolean enabled = true; @@ -116,6 +118,39 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl return control; } + @Override + public Object jmeClone() { + RigidBodyControl control = new RigidBodyControl(collisionShape, mass); + control.setAngularFactor(getAngularFactor()); + control.setAngularSleepingThreshold(getAngularSleepingThreshold()); + control.setCcdMotionThreshold(getCcdMotionThreshold()); + control.setCcdSweptSphereRadius(getCcdSweptSphereRadius()); + control.setCollideWithGroups(getCollideWithGroups()); + control.setCollisionGroup(getCollisionGroup()); + control.setDamping(getLinearDamping(), getAngularDamping()); + control.setFriction(getFriction()); + control.setGravity(getGravity()); + control.setKinematic(isKinematic()); + control.setKinematicSpatial(isKinematicSpatial()); + control.setLinearSleepingThreshold(getLinearSleepingThreshold()); + control.setPhysicsLocation(getPhysicsLocation(null)); + control.setPhysicsRotation(getPhysicsRotationMatrix(null)); + control.setRestitution(getRestitution()); + + if (mass > 0) { + control.setAngularVelocity(getAngularVelocity()); + control.setLinearVelocity(getLinearVelocity()); + } + control.setApplyPhysicsLocal(isApplyPhysicsLocal()); + control.spatial = this.spatial; + return control; + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.spatial = cloner.clone(spatial); + } + public void setSpatial(Spatial spatial) { this.spatial = spatial; setUserObject(spatial); diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/VehicleControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/VehicleControl.java index 0600da9bc..7ad36b3ae 100644 --- a/jme3-bullet/src/common/java/com/jme3/bullet/control/VehicleControl.java +++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/VehicleControl.java @@ -46,6 +46,8 @@ import com.jme3.renderer.ViewPort; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; import java.util.Iterator; @@ -53,7 +55,7 @@ import java.util.Iterator; * * @author normenhansen */ -public class VehicleControl extends PhysicsVehicle implements PhysicsControl { +public class VehicleControl extends PhysicsVehicle implements PhysicsControl, JmeCloneable { protected Spatial spatial; protected boolean enabled = true; @@ -156,6 +158,63 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl { return control; } + @Override + public Object jmeClone() { + VehicleControl control = new VehicleControl(collisionShape, mass); + control.setAngularFactor(getAngularFactor()); + control.setAngularSleepingThreshold(getAngularSleepingThreshold()); + control.setAngularVelocity(getAngularVelocity()); + control.setCcdMotionThreshold(getCcdMotionThreshold()); + control.setCcdSweptSphereRadius(getCcdSweptSphereRadius()); + control.setCollideWithGroups(getCollideWithGroups()); + control.setCollisionGroup(getCollisionGroup()); + control.setDamping(getLinearDamping(), getAngularDamping()); + control.setFriction(getFriction()); + control.setGravity(getGravity()); + control.setKinematic(isKinematic()); + control.setLinearSleepingThreshold(getLinearSleepingThreshold()); + control.setLinearVelocity(getLinearVelocity()); + control.setPhysicsLocation(getPhysicsLocation()); + control.setPhysicsRotation(getPhysicsRotationMatrix()); + control.setRestitution(getRestitution()); + + control.setFrictionSlip(getFrictionSlip()); + control.setMaxSuspensionTravelCm(getMaxSuspensionTravelCm()); + control.setSuspensionStiffness(getSuspensionStiffness()); + control.setSuspensionCompression(tuning.suspensionCompression); + control.setSuspensionDamping(tuning.suspensionDamping); + control.setMaxSuspensionForce(getMaxSuspensionForce()); + + for (Iterator it = wheels.iterator(); it.hasNext();) { + VehicleWheel wheel = it.next(); + VehicleWheel newWheel = control.addWheel(wheel.getLocation(), wheel.getDirection(), wheel.getAxle(), wheel.getRestLength(), wheel.getRadius(), wheel.isFrontWheel()); + newWheel.setFrictionSlip(wheel.getFrictionSlip()); + newWheel.setMaxSuspensionTravelCm(wheel.getMaxSuspensionTravelCm()); + newWheel.setSuspensionStiffness(wheel.getSuspensionStiffness()); + newWheel.setWheelsDampingCompression(wheel.getWheelsDampingCompression()); + newWheel.setWheelsDampingRelaxation(wheel.getWheelsDampingRelaxation()); + newWheel.setMaxSuspensionForce(wheel.getMaxSuspensionForce()); + + // Copy the wheel spatial reference directly for now. They'll + // get fixed up in the cloneFields() method + newWheel.setWheelSpatial(wheel.getWheelSpatial()); + } + control.setApplyPhysicsLocal(isApplyPhysicsLocal()); + + control.spatial = spatial; + return control; + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.spatial = cloner.clone(spatial); + + for( VehicleWheel wheel : wheels ) { + Spatial spatial = cloner.clone(wheel.getWheelSpatial()); + wheel.setWheelSpatial(spatial); + } + } + public void setSpatial(Spatial spatial) { this.spatial = spatial; setUserObject(spatial); diff --git a/jme3-core/src/main/java/com/jme3/animation/AnimControl.java b/jme3-core/src/main/java/com/jme3/animation/AnimControl.java index 9c3013f5e..36dbb6be5 100644 --- a/jme3-core/src/main/java/com/jme3/animation/AnimControl.java +++ b/jme3-core/src/main/java/com/jme3/animation/AnimControl.java @@ -38,11 +38,14 @@ import com.jme3.scene.Mesh; import com.jme3.scene.Spatial; import com.jme3.scene.control.AbstractControl; import com.jme3.scene.control.Control; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import com.jme3.util.TempVars; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.Map; import java.util.Map.Entry; /** @@ -65,7 +68,7 @@ import java.util.Map.Entry; * * @author Kirill Vainer */ -public final class AnimControl extends AbstractControl implements Cloneable { +public final class AnimControl extends AbstractControl implements Cloneable, JmeCloneable { /** * Skeleton object must contain corresponding data for the targets' weight buffers. @@ -131,6 +134,32 @@ public final class AnimControl extends AbstractControl implements Cloneable { } } + @Override + public Object jmeClone() { + AnimControl clone = (AnimControl) super.jmeClone(); + clone.channels = new ArrayList(); + clone.listeners = new ArrayList(); + + return clone; + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + super.cloneFields(cloner, original); + + this.skeleton = cloner.clone(skeleton); + + // Note cloneForSpatial() never actually cloned the animation map... just its reference + HashMap newMap = new HashMap<>(); + + // animationMap is cloned, but only ClonableTracks will be cloned as they need a reference to a cloned spatial + for( Map.Entry e : animationMap.entrySet() ) { + newMap.put(e.getKey(), cloner.clone(e.getValue())); + } + + this.animationMap = newMap; + } + /** * @param animations Set the animations that this AnimControl * will be capable of playing. The animations should be compatible diff --git a/jme3-core/src/main/java/com/jme3/animation/Animation.java b/jme3-core/src/main/java/com/jme3/animation/Animation.java index 5ae34628e..9fe47db9f 100644 --- a/jme3-core/src/main/java/com/jme3/animation/Animation.java +++ b/jme3-core/src/main/java/com/jme3/animation/Animation.java @@ -35,6 +35,8 @@ import com.jme3.export.*; import com.jme3.scene.Spatial; import com.jme3.util.SafeArrayList; import com.jme3.util.TempVars; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** @@ -42,7 +44,7 @@ import java.io.IOException; * * @author Kirill Vainer, Marcin Roguski (Kaelthas) */ -public class Animation implements Savable, Cloneable { +public class Animation implements Savable, Cloneable, JmeCloneable { /** * The name of the animation. @@ -190,6 +192,33 @@ public class Animation implements Savable, Cloneable { } } + @Override + public Object jmeClone() { + try { + return super.clone(); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException("Error cloning", e); + } + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + + // There is some logic here that I'm copying but I'm not sure if + // it's a mistake or not. If a track is not a CloneableTrack then it + // isn't cloned at all... even though they all implement clone() methods. -pspeed + SafeArrayList newTracks = new SafeArrayList<>(Track.class); + for( Track track : tracks ) { + if( track instanceof ClonableTrack ) { + newTracks.add(cloner.clone(track)); + } else { + // this is the part that seems fishy + newTracks.add(track); + } + } + this.tracks = newTracks; + } + @Override public String toString() { return getClass().getSimpleName() + "[name=" + name + ", length=" + length + ']'; diff --git a/jme3-core/src/main/java/com/jme3/animation/AudioTrack.java b/jme3-core/src/main/java/com/jme3/animation/AudioTrack.java index 58f8e2489..fc67686d2 100644 --- a/jme3-core/src/main/java/com/jme3/animation/AudioTrack.java +++ b/jme3-core/src/main/java/com/jme3/animation/AudioTrack.java @@ -39,6 +39,8 @@ import com.jme3.export.OutputCapsule; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.util.TempVars; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -193,7 +195,27 @@ public class AudioTrack implements ClonableTrack { return audioTrack; } - /** + @Override + public Object jmeClone() { + try { + return super.clone(); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException("Error cloning", e); + } + } + + + @Override + public void cloneFields( Cloner cloner, Object original ) { + // Duplicating the old cloned state from cloneForSpatial() + this.initialized = false; + this.started = false; + this.played = false; + this.audio = cloner.clone(audio); + } + + + /** * recursive function responsible for finding the newly cloned AudioNode * * @param spat diff --git a/jme3-core/src/main/java/com/jme3/animation/ClonableTrack.java b/jme3-core/src/main/java/com/jme3/animation/ClonableTrack.java index ae7ae6703..bfdd87abd 100644 --- a/jme3-core/src/main/java/com/jme3/animation/ClonableTrack.java +++ b/jme3-core/src/main/java/com/jme3/animation/ClonableTrack.java @@ -32,6 +32,7 @@ package com.jme3.animation; import com.jme3.scene.Spatial; +import com.jme3.util.clone.JmeCloneable; /** * An interface that allow to clone a Track for a given Spatial. @@ -43,7 +44,7 @@ import com.jme3.scene.Spatial; * * @author Nehon */ -public interface ClonableTrack extends Track { +public interface ClonableTrack extends Track, JmeCloneable { /** * Allows to clone the track for a given Spatial. diff --git a/jme3-core/src/main/java/com/jme3/animation/EffectTrack.java b/jme3-core/src/main/java/com/jme3/animation/EffectTrack.java index 42c4c007e..82af6e135 100644 --- a/jme3-core/src/main/java/com/jme3/animation/EffectTrack.java +++ b/jme3-core/src/main/java/com/jme3/animation/EffectTrack.java @@ -44,6 +44,8 @@ import com.jme3.scene.Spatial.CullHint; import com.jme3.scene.control.AbstractControl; import com.jme3.scene.control.Control; import com.jme3.util.TempVars; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -116,6 +118,22 @@ public class EffectTrack implements ClonableTrack { } } + @Override + public Object jmeClone() { + KillParticleControl c = new KillParticleControl(); + //this control should be removed as it shouldn't have been persisted in the first place + //In the quest to find the less hackish solution to achieve this, + //making it remove itself from the spatial in the first update loop when loaded was the less bad. + c.remove = true; + c.spatial = spatial; + return c; + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.spatial = cloner.clone(spatial); + } + @Override protected void controlRender(RenderManager rm, ViewPort vp) { } @@ -284,6 +302,21 @@ public class EffectTrack implements ClonableTrack { return effectTrack; } + @Override + public Object jmeClone() { + try { + return super.clone(); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException("Error cloning", e); + } + } + + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.emitter = cloner.clone(emitter); + } + /** * recursive function responsible for finding the newly cloned Emitter * diff --git a/jme3-core/src/main/java/com/jme3/animation/Skeleton.java b/jme3-core/src/main/java/com/jme3/animation/Skeleton.java index b0d3419d8..8ae3ca507 100644 --- a/jme3-core/src/main/java/com/jme3/animation/Skeleton.java +++ b/jme3-core/src/main/java/com/jme3/animation/Skeleton.java @@ -34,6 +34,8 @@ package com.jme3.animation; import com.jme3.export.*; import com.jme3.math.Matrix4f; import com.jme3.util.TempVars; +import com.jme3.util.clone.JmeCloneable; +import com.jme3.util.clone.Cloner; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -45,7 +47,7 @@ import java.util.List; * * @author Kirill Vainer */ -public final class Skeleton implements Savable { +public final class Skeleton implements Savable, JmeCloneable { private Bone[] rootBones; private Bone[] boneList; @@ -118,6 +120,15 @@ public final class Skeleton implements Savable { public Skeleton() { } + @Override + public Object jmeClone() { + return new Skeleton(this); + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + } + private void createSkinningMatrices() { skinningMatrixes = new Matrix4f[boneList.length]; for (int i = 0; i < skinningMatrixes.length; i++) { diff --git a/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java b/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java index dedb2cb81..2e0b17c3b 100644 --- a/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java +++ b/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java @@ -46,6 +46,8 @@ import com.jme3.scene.control.Control; import com.jme3.shader.VarType; import com.jme3.util.SafeArrayList; import com.jme3.util.TempVars; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; import java.nio.Buffer; import java.nio.ByteBuffer; @@ -63,7 +65,7 @@ import java.util.logging.Logger; * * @author Rémy Bouquet Based on AnimControl by Kirill Vainer */ -public class SkeletonControl extends AbstractControl implements Cloneable { +public class SkeletonControl extends AbstractControl implements Cloneable, JmeCloneable { /** * The skeleton of the model. @@ -386,6 +388,29 @@ public class SkeletonControl extends AbstractControl implements Cloneable { return clone; } + @Override + public Object jmeClone() { + return super.jmeClone(); + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + super.cloneFields(cloner, original); + + this.skeleton = cloner.clone(skeleton); + + // If the targets were cloned then this will clone them. If the targets + // were shared then this will share them. + this.targets = cloner.clone(targets); + + // Not automatic set cloning yet + Set newMaterials = new HashSet(); + for( Material m : this.materials ) { + newMaterials.add(cloner.clone(m)); + } + this.materials = newMaterials; + } + /** * * @param boneName the name of the bone diff --git a/jme3-core/src/main/java/com/jme3/animation/TrackInfo.java b/jme3-core/src/main/java/com/jme3/animation/TrackInfo.java index b6bff101a..7ee927cd3 100644 --- a/jme3-core/src/main/java/com/jme3/animation/TrackInfo.java +++ b/jme3-core/src/main/java/com/jme3/animation/TrackInfo.java @@ -36,6 +36,8 @@ 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; import java.util.ArrayList; @@ -48,7 +50,7 @@ import java.util.ArrayList; * * @author Nehon */ -public class TrackInfo implements Savable { +public class TrackInfo implements Savable, JmeCloneable { ArrayList tracks = new ArrayList(); @@ -72,4 +74,18 @@ public class TrackInfo implements Savable { public void addTrack(Track track) { tracks.add(track); } + + @Override + public Object jmeClone() { + try { + return super.clone(); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException("Error cloning", e); + } + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.tracks = cloner.clone(tracks); + } } diff --git a/jme3-core/src/main/java/com/jme3/app/StatsView.java b/jme3-core/src/main/java/com/jme3/app/StatsView.java index 583e1acc5..9fb7670fe 100644 --- a/jme3-core/src/main/java/com/jme3/app/StatsView.java +++ b/jme3-core/src/main/java/com/jme3/app/StatsView.java @@ -41,6 +41,8 @@ import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; /** * The StatsView provides a heads-up display (HUD) of various @@ -58,7 +60,7 @@ import com.jme3.scene.control.Control; * rootNode.attachChild(statsView);
* */ -public class StatsView extends Node implements Control { +public class StatsView extends Node implements Control, JmeCloneable { private BitmapText statText; private Statistics statistics; @@ -120,6 +122,16 @@ public class StatsView extends Node implements Control { return (Control) spatial; } + @Override + public Object jmeClone() { + throw new UnsupportedOperationException("Not yet implemented."); + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + throw new UnsupportedOperationException("Not yet implemented."); + } + public void setSpatial(Spatial spatial) { } diff --git a/jme3-core/src/main/java/com/jme3/cinematic/events/MotionEvent.java b/jme3-core/src/main/java/com/jme3/cinematic/events/MotionEvent.java index 2fcbd016f..dbb9b494c 100644 --- a/jme3-core/src/main/java/com/jme3/cinematic/events/MotionEvent.java +++ b/jme3-core/src/main/java/com/jme3/cinematic/events/MotionEvent.java @@ -47,6 +47,8 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** @@ -56,7 +58,7 @@ import java.io.IOException; * * @author Nehon */ -public class MotionEvent extends AbstractCinematicEvent implements Control { +public class MotionEvent extends AbstractCinematicEvent implements Control, JmeCloneable { protected Spatial spatial; protected int currentWayPoint; @@ -292,6 +294,31 @@ public class MotionEvent extends AbstractCinematicEvent implements Control { return control; } + @Override + public Object jmeClone() { + MotionEvent control = new MotionEvent(); + control.path = path; + control.playState = playState; + control.currentWayPoint = currentWayPoint; + control.currentValue = currentValue; + control.direction = direction.clone(); + control.lookAt = lookAt.clone(); + control.upVector = upVector.clone(); + control.rotation = rotation.clone(); + control.initialDuration = initialDuration; + control.speed = speed; + control.loopMode = loopMode; + control.directionType = directionType; + control.spatial = spatial; + + return control; + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.spatial = cloner.clone(spatial); + } + @Override public void onPlay() { traveledDistance = 0; diff --git a/jme3-core/src/main/java/com/jme3/effect/ParticleEmitter.java b/jme3-core/src/main/java/com/jme3/effect/ParticleEmitter.java index b4f8bb270..d53273c4e 100644 --- a/jme3-core/src/main/java/com/jme3/effect/ParticleEmitter.java +++ b/jme3-core/src/main/java/com/jme3/effect/ParticleEmitter.java @@ -54,6 +54,8 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; import com.jme3.util.TempVars; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** @@ -108,7 +110,7 @@ public class ParticleEmitter extends Geometry { private transient Vector3f temp = new Vector3f(); private transient Vector3f lastPos; - public static class ParticleEmitterControl implements Control { + public static class ParticleEmitterControl implements Control, JmeCloneable { ParticleEmitter parentEmitter; @@ -125,6 +127,20 @@ public class ParticleEmitter extends Geometry { // fixed automatically by ParticleEmitter.clone() method. } + @Override + public Object jmeClone() { + try { + return super.clone(); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException("Error cloning", e); + } + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.parentEmitter = cloner.clone(parentEmitter); + } + public void setSpatial(Spatial spatial) { } diff --git a/jme3-core/src/main/java/com/jme3/input/ChaseCamera.java b/jme3-core/src/main/java/com/jme3/input/ChaseCamera.java index 427670980..de2c6e8ae 100644 --- a/jme3-core/src/main/java/com/jme3/input/ChaseCamera.java +++ b/jme3-core/src/main/java/com/jme3/input/ChaseCamera.java @@ -43,13 +43,15 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** * A camera that follows a spatial and can turn around it by dragging the mouse * @author nehon */ -public class ChaseCamera implements ActionListener, AnalogListener, Control { +public class ChaseCamera implements ActionListener, AnalogListener, Control, JmeCloneable { protected Spatial target = null; protected float minVerticalRotation = 0.00f; @@ -575,6 +577,23 @@ public class ChaseCamera implements ActionListener, AnalogListener, Control { return cc; } + @Override + public Object jmeClone() { + ChaseCamera cc = new ChaseCamera(cam, inputManager); + cc.target = target; + cc.setMaxDistance(getMaxDistance()); + cc.setMinDistance(getMinDistance()); + return cc; + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.target = cloner.clone(target); + computePosition(); + prevPos = new Vector3f(target.getWorldTranslation()); + cam.setLocation(pos); + } + /** * Sets the spacial for the camera control, should only be used internally * @param spatial diff --git a/jme3-core/src/main/java/com/jme3/scene/control/AbstractControl.java b/jme3-core/src/main/java/com/jme3/scene/control/AbstractControl.java index 387a679b9..05da60f0f 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/AbstractControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/AbstractControl.java @@ -38,6 +38,8 @@ import com.jme3.export.OutputCapsule; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.scene.Spatial; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** @@ -45,7 +47,7 @@ import java.io.IOException; * * @author Kirill Vainer */ -public abstract class AbstractControl implements Control, Cloneable { +public abstract class AbstractControl implements Control, JmeCloneable { protected boolean enabled = true; protected Spatial spatial; @@ -105,6 +107,20 @@ public abstract class AbstractControl implements Control, Cloneable { } } + @Override + public Object jmeClone() { + try { + return super.clone(); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException( "Can't clone control for spatial", e ); + } + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.spatial = cloner.clone(spatial); + } + public void update(float tpf) { if (!enabled) return; diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LodControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LodControl.java index 030ccbb3a..f6b657842 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/LodControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/LodControl.java @@ -43,6 +43,8 @@ import com.jme3.renderer.ViewPort; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; import com.jme3.scene.Spatial; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** @@ -56,7 +58,7 @@ import java.io.IOException; * and will update the spatial's LOD if the camera has moved by a specified * amount. */ -public class LodControl extends AbstractControl implements Cloneable { +public class LodControl extends AbstractControl implements Cloneable, JmeCloneable { private float trisPerPixel = 1f; private float distTolerance = 1f; @@ -140,7 +142,16 @@ public class LodControl extends AbstractControl implements Cloneable { clone.lastLevel = 0; clone.numTris = numTris != null ? numTris.clone() : null; return clone; - } + } + + @Override + public Object jmeClone() { + LodControl clone = (LodControl)super.jmeClone(); + clone.lastDistance = 0; + clone.lastLevel = 0; + clone.numTris = numTris != null ? numTris.clone() : null; + return clone; + } @Override protected void controlUpdate(float tpf) { diff --git a/jme3-core/src/main/java/com/jme3/scene/control/UpdateControl.java b/jme3-core/src/main/java/com/jme3/scene/control/UpdateControl.java index 7688cde2f..9c101c73e 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/UpdateControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/UpdateControl.java @@ -35,6 +35,8 @@ import com.jme3.app.AppTask; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.scene.Spatial; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Future; @@ -94,4 +96,15 @@ public class UpdateControl extends AbstractControl { return control; } + @Override + public Object jmeClone() { + UpdateControl clone = (UpdateControl)super.jmeClone(); + + // This is kind of questionable since the tasks aren't cloned and have + // no reference to the new spatial or anything. They'll get run again + // but it's not clear to me why that would be desired. I'm doing it + // because the old cloneForSpatial() code does. FIXME? -pspeed + clone.taskQueue.addAll(taskQueue); + return clone; + } } diff --git a/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedNode.java b/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedNode.java index 61ec61956..45dd85417 100644 --- a/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedNode.java +++ b/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedNode.java @@ -44,6 +44,8 @@ import com.jme3.scene.control.Control; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.material.MatParam; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; import java.util.HashMap; @@ -106,7 +108,7 @@ public class InstancedNode extends GeometryGroupNode { } } - private static class InstancedNodeControl implements Control { + private static class InstancedNodeControl implements Control, JmeCloneable { private InstancedNode node; @@ -124,6 +126,20 @@ public class InstancedNode extends GeometryGroupNode { // fixed automatically by InstancedNode.clone() method. } + @Override + public Object jmeClone() { + try { + return super.clone(); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException("Error cloning control", e); + } + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.node = cloner.clone(node); + } + public void setSpatial(Spatial spatial){ } diff --git a/jme3-examples/src/main/java/jme3test/bullet/PhysicsHoverControl.java b/jme3-examples/src/main/java/jme3test/bullet/PhysicsHoverControl.java index 922a7217d..b1f3a1fe9 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/PhysicsHoverControl.java +++ b/jme3-examples/src/main/java/jme3test/bullet/PhysicsHoverControl.java @@ -46,13 +46,15 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; /** * PhysicsHoverControl uses a RayCast Vehicle with "slippery wheels" to simulate a hovering tank * @author normenhansen */ -public class PhysicsHoverControl extends PhysicsVehicle implements PhysicsControl, PhysicsTickListener { +public class PhysicsHoverControl extends PhysicsVehicle implements PhysicsControl, PhysicsTickListener, JmeCloneable { protected Spatial spatial; protected boolean enabled = true; @@ -99,6 +101,16 @@ public class PhysicsHoverControl extends PhysicsVehicle implements PhysicsContro throw new UnsupportedOperationException("Not supported yet."); } + @Override + public Object jmeClone() { + throw new UnsupportedOperationException("Not yet implemented."); + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + throw new UnsupportedOperationException("Not yet implemented."); + } + public void setSpatial(Spatial spatial) { this.spatial = spatial; setUserObject(spatial); diff --git a/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java b/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java index 3f446c49d..55d5a3f87 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java +++ b/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java @@ -67,6 +67,8 @@ import com.jme3.texture.Texture; import com.jme3.texture.Texture.WrapMode; import com.jme3.util.SkyFactory; import com.jme3.util.TangentBinormalGenerator; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; public class TestPssmShadow extends SimpleApplication implements ActionListener { @@ -249,6 +251,15 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener time = 0; } + @Override + public Object jmeClone() { + return null; + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + } + @Override protected void controlRender(RenderManager rm, ViewPort vp) { } diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/NormalRecalcControl.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/NormalRecalcControl.java index 2f4d7d980..c43c491ec 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/NormalRecalcControl.java +++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/NormalRecalcControl.java @@ -40,6 +40,8 @@ import com.jme3.renderer.ViewPort; import com.jme3.scene.Spatial; import com.jme3.scene.control.AbstractControl; import com.jme3.scene.control.Control; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; @@ -67,6 +69,13 @@ public class NormalRecalcControl extends AbstractControl { } + @Override + public Object jmeClone() { + NormalRecalcControl control = (NormalRecalcControl)super.jmeClone(); + control.setEnabled(true); + return control; + } + @Override public Control cloneForSpatial(Spatial spatial) { NormalRecalcControl control = new NormalRecalcControl(terrain); diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainLodControl.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainLodControl.java index 7d2f43305..f52b1ca89 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainLodControl.java +++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainLodControl.java @@ -46,6 +46,8 @@ import com.jme3.scene.control.Control; import com.jme3.terrain.Terrain; import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.geomipmap.lodcalc.LodCalculator; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -298,7 +300,29 @@ public class TerrainLodControl extends AbstractControl { - + + @Override + public Object jmeClone() { + if (spatial instanceof Terrain) { + TerrainLodControl cloned = new TerrainLodControl((Terrain) spatial, cameras); + cloned.setLodCalculator(lodCalculator.clone()); + cloned.spatial = spatial; + return cloned; + } + return null; + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + this.lodCalculator = cloner.clone(lodCalculator); + + try { + // Not deep clone of the cameras themselves + this.cameras = cloner.javaClone(cameras); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException("Error cloning", e); + } + } @Override