Skip to content

Commit

Permalink
Converted spatial over to use Cloner to do its various
Browse files Browse the repository at this point in the history
deep and semi-shallow cloning.  I'd be very surprised if nothing
is broken as there is only so much testing I can easily do.
Also various fixes for places I forgot to call super.cloneFields().
  • Loading branch information
pspeed42 committed Mar 27, 2016
1 parent 0a876b0 commit ab6fb03
Show file tree
Hide file tree
Showing 19 changed files with 211 additions and 76 deletions.
29 changes: 12 additions & 17 deletions jme3-core/src/main/java/com/jme3/animation/EffectTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,22 +118,17 @@ protected void controlUpdate(float tpf) {
}
}

@Override
@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.
//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) {
}
Expand All @@ -143,8 +138,8 @@ public Control cloneForSpatial(Spatial spatial) {

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.
//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.setSpatial(spatial);
return c;
Expand Down Expand Up @@ -261,7 +256,7 @@ public float getLength() {
public float[] getKeyFrameTimes() {
return new float[] { startOffset };
}

/**
* Clone this track
*
Expand Down Expand Up @@ -302,21 +297,21 @@ public Track cloneForSpatial(Spatial spatial) {
return effectTrack;
}

@Override
@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 ) {
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.emitter = cloner.clone(emitter);
}

/**
* recursive function responsible for finding the newly cloned Emitter
*
Expand Down
2 changes: 2 additions & 0 deletions jme3-core/src/main/java/com/jme3/audio/AudioNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,8 @@ public AudioNode clone(){
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);

this.direction = cloner.clone(direction);
this.velocity = cloner.clone(velocity);

Expand Down
9 changes: 9 additions & 0 deletions jme3-core/src/main/java/com/jme3/effect/ParticleEmitter.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,13 @@ public ParticleEmitter clone() {

@Override
public ParticleEmitter clone(boolean cloneMaterial) {
return (ParticleEmitter)super.clone(cloneMaterial);
}

/**
* The old clone() method that did not use the new Cloner utility.
*/
public ParticleEmitter oldClone(boolean cloneMaterial) {
ParticleEmitter clone = (ParticleEmitter) super.clone(cloneMaterial);
clone.shape = shape.deepClone();

Expand Down Expand Up @@ -216,6 +223,8 @@ public ParticleEmitter clone(boolean cloneMaterial) {
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);

this.shape = cloner.clone(shape);
this.control = cloner.clone(control);
this.faceNormal = cloner.clone(faceNormal);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ public void setHorizontal(boolean horizontal) {
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);

// Change in behavior: the old origin was not cloned -pspeed
this.origin = cloner.clone(origin);
}
Expand Down
2 changes: 2 additions & 0 deletions jme3-core/src/main/java/com/jme3/font/BitmapText.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ public BitmapText clone() {
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);

for( int i = 0; i < textPages.length; i++ ) {
textPages[i] = cloner.clone(textPages[i]);
}
Expand Down
2 changes: 2 additions & 0 deletions jme3-core/src/main/java/com/jme3/scene/AssetLinkNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public AssetLinkNode(String name, ModelKey key) {
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);

// This is a change in behavior because the old version did not clone
// this list... changes to one clone would be reflected in all.
// I think that's probably undesirable. -pspeed
Expand Down
2 changes: 2 additions & 0 deletions jme3-core/src/main/java/com/jme3/scene/BatchNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,8 @@ public Node clone(boolean cloneMaterials) {
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);

this.batches = cloner.clone(batches);
this.tmpFloat = cloner.clone(tmpFloat);
this.tmpFloatN = cloner.clone(tmpFloatN);
Expand Down
2 changes: 2 additions & 0 deletions jme3-core/src/main/java/com/jme3/scene/CameraNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ public Camera getCamera() {
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);

// A change in behavior... I think previously CameraNode was probably
// not really cloneable... or at least its camControl would be pointing
// to the wrong control. -pspeed
Expand Down
49 changes: 47 additions & 2 deletions jme3-core/src/main/java/com/jme3/scene/Geometry.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import com.jme3.renderer.Camera;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.IdentityCloneFunction;
import com.jme3.util.TempVars;
import java.io.IOException;
import java.util.Queue;
Expand Down Expand Up @@ -492,6 +493,13 @@ public boolean isBatched() {
*/
@Override
public Geometry clone(boolean cloneMaterial) {
return (Geometry)super.clone(cloneMaterial);
}

/**
* The old clone() method that did not use the new Cloner utility.
*/
public Geometry oldClone(boolean cloneMaterial) {
Geometry geomClone = (Geometry) super.clone(cloneMaterial);

// This geometry is managed,
Expand Down Expand Up @@ -535,6 +543,10 @@ public Geometry clone() {
*/
@Override
public Spatial deepClone() {
return super.deepClone();
}

public Spatial oldDeepClone() {
Geometry geomClone = clone(true);
geomClone.mesh = mesh.deepClone();
return geomClone;
Expand All @@ -545,9 +557,42 @@ public Spatial deepClone() {
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.mesh = cloner.clone(mesh);
super.cloneFields(cloner, original);

// If this is a grouped node and if our group node is
// also cloned then we'll grab it's reference.
if( groupNode != null ) {
if( cloner.isCloned(groupNode) ) {
// Then resolve the reference
this.groupNode = cloner.clone(groupNode);
} else {
// We are on our own now
this.groupNode = null;
this.startIndex = -1;
}

// The above is based on the fact that if we were
// cloning the hierarchy that contained the parent
// group then it would have been shallow cloned before
// this child. Can't really be otherwise.
}

this.cachedWorldMat = cloner.clone(cachedWorldMat);

// See if we are doing a shallow clone or a deep mesh clone
boolean shallowClone = (cloner.getCloneFunction(Mesh.class) instanceof IdentityCloneFunction);

// See if we clone the mesh using the special animation
// semi-deep cloning
if( shallowClone && mesh != null && mesh.getBuffer(Type.BindPosePosition) != null ) {
// Then we need to clone the mesh a little deeper
this.mesh = mesh.cloneForAnim();
} else {
// Do whatever the cloner wants to do about it
this.mesh = cloner.clone(mesh);
}

this.material = cloner.clone(material);
this.groupNode = cloner.clone(groupNode);
}

@Override
Expand Down
2 changes: 2 additions & 0 deletions jme3-core/src/main/java/com/jme3/scene/LightNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ public Light getLight() {
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);

// A change in behavior... I think previously LightNode was probably
// not really cloneable... or at least its lightControl would be pointing
// to the wrong control. -pspeed
Expand Down
4 changes: 3 additions & 1 deletion jme3-core/src/main/java/com/jme3/scene/Mesh.java
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,9 @@ public Mesh cloneForAnim(){
@Override
public Mesh jmeClone() {
try {
return (Mesh)super.clone();
Mesh clone = (Mesh)super.clone();
clone.vertexArrayID = -1;
return clone;
} catch (CloneNotSupportedException ex) {
throw new AssertionError();
}
Expand Down
14 changes: 13 additions & 1 deletion jme3-core/src/main/java/com/jme3/scene/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,17 @@ public Node clone(boolean cloneMaterials){
}

@Override
public Spatial deepClone(){
public Spatial deepClone() {
Node nodeClone = (Node)super.deepClone();

// Reset the fields of the clone that should be in a 'new' state.
nodeClone.updateList = null;
nodeClone.updateListValid = false; // safe because parent is nulled out in super.clone()

return nodeClone;
}

public Spatial oldDeepClone(){
Node nodeClone = (Node) super.clone();
nodeClone.children = new SafeArrayList<Spatial>(Spatial.class);
for (Spatial child : children){
Expand All @@ -713,6 +723,8 @@ public Spatial deepClone(){
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);

this.children = cloner.clone(children);

// Only the outer cloning thing knows whether this should be nulled
Expand Down
72 changes: 60 additions & 12 deletions jme3-core/src/main/java/com/jme3/scene/Spatial.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.control.Control;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.IdentityCloneFunction;
import com.jme3.util.clone.JmeCloneable;
import com.jme3.util.SafeArrayList;
import com.jme3.util.TempVars;
Expand Down Expand Up @@ -1263,12 +1264,42 @@ public void setLodLevel(int lod) {
* Note that meshes of geometries are not cloned explicitly, they
* are shared if static, or specially cloned if animated.
*
* All controls will be cloned using the Control.cloneForSpatial method
* on the clone.
*
* @see Mesh#cloneForAnim()
*/
public Spatial clone(boolean cloneMaterial) {
public Spatial clone( boolean cloneMaterial ) {

// Setup the cloner for the type of cloning we want to do.
Cloner cloner = new Cloner();

// First, we definitely do not want to clone our own parent
cloner.setClonedValue(parent, null);

// If we aren't cloning materials then we will make sure those
// aren't cloned also
if( !cloneMaterial ) {
cloner.setCloneFunction(Material.class, new IdentityCloneFunction<Material>());
}

// By default the meshes are not cloned. The geometry
// may choose to selectively force them to be cloned but
// normally they will be shared
cloner.setCloneFunction(Mesh.class, new IdentityCloneFunction<Mesh>());

// Clone it!
Spatial clone = cloner.clone(this);

// Because we've nulled the parent out we need to make sure
// the transforms and stuff get refreshed.
clone.setTransformRefresh();
clone.setLightListRefresh();

return clone;
}

/**
* The old clone() method that did not use the new Cloner utility.
*/
public Spatial oldClone(boolean cloneMaterial) {
try {
Spatial clone = (Spatial) super.clone();
if (worldBound != null) {
Expand Down Expand Up @@ -1344,7 +1375,22 @@ public Spatial clone() {
*
* @see Spatial#clone()
*/
public abstract Spatial deepClone();
public Spatial deepClone() {
// Setup the cloner for the type of cloning we want to do.
Cloner cloner = new Cloner();

// First, we definitely do not want to clone our own parent
cloner.setClonedValue(parent, null);

Spatial clone = cloner.clone(this);

// Because we've nulled the parent out we need to make sure
// the transforms and stuff get refreshed.
clone.setTransformRefresh();
clone.setLightListRefresh();

return clone;
}

/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
Expand Down Expand Up @@ -1381,13 +1427,15 @@ public void cloneFields( Cloner cloner, Object original ) {
// to avoid all of the nasty cloneForSpatial() fixup style code that
// used to inject stuff into the clone's user data. By using cloner
// to clone the user data we get this automatically.
userData = (HashMap<String, Savable>)userData.clone();
for( Map.Entry<String, Savable> e : userData.entrySet() ) {
Savable value = e.getValue();
if( value instanceof Cloneable ) {
// Note: all JmeCloneable objects are also Cloneable so this
// catches both cases.
e.setValue(cloner.clone(value));
if( userData != null ) {
userData = (HashMap<String, Savable>)userData.clone();
for( Map.Entry<String, Savable> e : userData.entrySet() ) {
Savable value = e.getValue();
if( value instanceof Cloneable ) {
// Note: all JmeCloneable objects are also Cloneable so this
// catches both cases.
e.setValue(cloner.clone(value));
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ public VertexBuffer[] getAllInstanceData() {
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);

this.globalInstanceData = cloner.clone(globalInstanceData);
this.transformInstanceData = cloner.clone(transformInstanceData);
this.geometries = cloner.clone(geometries);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,8 @@ public Node clone(boolean cloneMaterials) {
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);

this.control = cloner.clone(control);
this.lookUp = cloner.clone(lookUp);

Expand Down
Loading

0 comments on commit ab6fb03

Please sign in to comment.