Skip to content

Commit ab6fb03

Browse files
committed
Converted spatial over to use Cloner to do its various
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().
1 parent 0a876b0 commit ab6fb03

19 files changed

+211
-76
lines changed

jme3-core/src/main/java/com/jme3/animation/EffectTrack.java

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,22 +118,17 @@ protected void controlUpdate(float tpf) {
118118
}
119119
}
120120

121-
@Override
121+
@Override
122122
public Object jmeClone() {
123123
KillParticleControl c = new KillParticleControl();
124124
//this control should be removed as it shouldn't have been persisted in the first place
125-
//In the quest to find the less hackish solution to achieve this,
126-
//making it remove itself from the spatial in the first update loop when loaded was the less bad.
125+
//In the quest to find the less hackish solution to achieve this,
126+
//making it remove itself from the spatial in the first update loop when loaded was the less bad.
127127
c.remove = true;
128128
c.spatial = spatial;
129129
return c;
130-
}
131-
132-
@Override
133-
public void cloneFields( Cloner cloner, Object original ) {
134-
this.spatial = cloner.clone(spatial);
135130
}
136-
131+
137132
@Override
138133
protected void controlRender(RenderManager rm, ViewPort vp) {
139134
}
@@ -143,8 +138,8 @@ public Control cloneForSpatial(Spatial spatial) {
143138

144139
KillParticleControl c = new KillParticleControl();
145140
//this control should be removed as it shouldn't have been persisted in the first place
146-
//In the quest to find the less hackish solution to achieve this,
147-
//making it remove itself from the spatial in the first update loop when loaded was the less bad.
141+
//In the quest to find the less hackish solution to achieve this,
142+
//making it remove itself from the spatial in the first update loop when loaded was the less bad.
148143
c.remove = true;
149144
c.setSpatial(spatial);
150145
return c;
@@ -261,7 +256,7 @@ public float getLength() {
261256
public float[] getKeyFrameTimes() {
262257
return new float[] { startOffset };
263258
}
264-
259+
265260
/**
266261
* Clone this track
267262
*
@@ -302,21 +297,21 @@ public Track cloneForSpatial(Spatial spatial) {
302297
return effectTrack;
303298
}
304299

305-
@Override
300+
@Override
306301
public Object jmeClone() {
307302
try {
308303
return super.clone();
309304
} catch( CloneNotSupportedException e ) {
310305
throw new RuntimeException("Error cloning", e);
311306
}
312-
}
307+
}
313308

314309

315-
@Override
316-
public void cloneFields( Cloner cloner, Object original ) {
310+
@Override
311+
public void cloneFields( Cloner cloner, Object original ) {
317312
this.emitter = cloner.clone(emitter);
318313
}
319-
314+
320315
/**
321316
* recursive function responsible for finding the newly cloned Emitter
322317
*

jme3-core/src/main/java/com/jme3/audio/AudioNode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,8 @@ public AudioNode clone(){
730730
*/
731731
@Override
732732
public void cloneFields( Cloner cloner, Object original ) {
733+
super.cloneFields(cloner, original);
734+
733735
this.direction = cloner.clone(direction);
734736
this.velocity = cloner.clone(velocity);
735737

jme3-core/src/main/java/com/jme3/effect/ParticleEmitter.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,13 @@ public ParticleEmitter clone() {
174174

175175
@Override
176176
public ParticleEmitter clone(boolean cloneMaterial) {
177+
return (ParticleEmitter)super.clone(cloneMaterial);
178+
}
179+
180+
/**
181+
* The old clone() method that did not use the new Cloner utility.
182+
*/
183+
public ParticleEmitter oldClone(boolean cloneMaterial) {
177184
ParticleEmitter clone = (ParticleEmitter) super.clone(cloneMaterial);
178185
clone.shape = shape.deepClone();
179186

@@ -216,6 +223,8 @@ public ParticleEmitter clone(boolean cloneMaterial) {
216223
*/
217224
@Override
218225
public void cloneFields( Cloner cloner, Object original ) {
226+
super.cloneFields(cloner, original);
227+
219228
this.shape = cloner.clone(shape);
220229
this.control = cloner.clone(control);
221230
this.faceNormal = cloner.clone(faceNormal);

jme3-core/src/main/java/com/jme3/effect/influencers/RadialParticleInfluencer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ public void setHorizontal(boolean horizontal) {
125125
*/
126126
@Override
127127
public void cloneFields( Cloner cloner, Object original ) {
128+
super.cloneFields(cloner, original);
129+
128130
// Change in behavior: the old origin was not cloned -pspeed
129131
this.origin = cloner.clone(origin);
130132
}

jme3-core/src/main/java/com/jme3/font/BitmapText.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ public BitmapText clone() {
9090
*/
9191
@Override
9292
public void cloneFields( Cloner cloner, Object original ) {
93+
super.cloneFields(cloner, original);
94+
9395
for( int i = 0; i < textPages.length; i++ ) {
9496
textPages[i] = cloner.clone(textPages[i]);
9597
}

jme3-core/src/main/java/com/jme3/scene/AssetLinkNode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ public AssetLinkNode(String name, ModelKey key) {
7676
*/
7777
@Override
7878
public void cloneFields( Cloner cloner, Object original ) {
79+
super.cloneFields(cloner, original);
80+
7981
// This is a change in behavior because the old version did not clone
8082
// this list... changes to one clone would be reflected in all.
8183
// I think that's probably undesirable. -pspeed

jme3-core/src/main/java/com/jme3/scene/BatchNode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,8 @@ public Node clone(boolean cloneMaterials) {
727727
*/
728728
@Override
729729
public void cloneFields( Cloner cloner, Object original ) {
730+
super.cloneFields(cloner, original);
731+
730732
this.batches = cloner.clone(batches);
731733
this.tmpFloat = cloner.clone(tmpFloat);
732734
this.tmpFloatN = cloner.clone(tmpFloatN);

jme3-core/src/main/java/com/jme3/scene/CameraNode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ public Camera getCamera() {
100100
*/
101101
@Override
102102
public void cloneFields( Cloner cloner, Object original ) {
103+
super.cloneFields(cloner, original);
104+
103105
// A change in behavior... I think previously CameraNode was probably
104106
// not really cloneable... or at least its camControl would be pointing
105107
// to the wrong control. -pspeed

jme3-core/src/main/java/com/jme3/scene/Geometry.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.jme3.renderer.Camera;
4545
import com.jme3.scene.VertexBuffer.Type;
4646
import com.jme3.util.clone.Cloner;
47+
import com.jme3.util.clone.IdentityCloneFunction;
4748
import com.jme3.util.TempVars;
4849
import java.io.IOException;
4950
import java.util.Queue;
@@ -492,6 +493,13 @@ public boolean isBatched() {
492493
*/
493494
@Override
494495
public Geometry clone(boolean cloneMaterial) {
496+
return (Geometry)super.clone(cloneMaterial);
497+
}
498+
499+
/**
500+
* The old clone() method that did not use the new Cloner utility.
501+
*/
502+
public Geometry oldClone(boolean cloneMaterial) {
495503
Geometry geomClone = (Geometry) super.clone(cloneMaterial);
496504

497505
// This geometry is managed,
@@ -535,6 +543,10 @@ public Geometry clone() {
535543
*/
536544
@Override
537545
public Spatial deepClone() {
546+
return super.deepClone();
547+
}
548+
549+
public Spatial oldDeepClone() {
538550
Geometry geomClone = clone(true);
539551
geomClone.mesh = mesh.deepClone();
540552
return geomClone;
@@ -545,9 +557,42 @@ public Spatial deepClone() {
545557
*/
546558
@Override
547559
public void cloneFields( Cloner cloner, Object original ) {
548-
this.mesh = cloner.clone(mesh);
560+
super.cloneFields(cloner, original);
561+
562+
// If this is a grouped node and if our group node is
563+
// also cloned then we'll grab it's reference.
564+
if( groupNode != null ) {
565+
if( cloner.isCloned(groupNode) ) {
566+
// Then resolve the reference
567+
this.groupNode = cloner.clone(groupNode);
568+
} else {
569+
// We are on our own now
570+
this.groupNode = null;
571+
this.startIndex = -1;
572+
}
573+
574+
// The above is based on the fact that if we were
575+
// cloning the hierarchy that contained the parent
576+
// group then it would have been shallow cloned before
577+
// this child. Can't really be otherwise.
578+
}
579+
580+
this.cachedWorldMat = cloner.clone(cachedWorldMat);
581+
582+
// See if we are doing a shallow clone or a deep mesh clone
583+
boolean shallowClone = (cloner.getCloneFunction(Mesh.class) instanceof IdentityCloneFunction);
584+
585+
// See if we clone the mesh using the special animation
586+
// semi-deep cloning
587+
if( shallowClone && mesh != null && mesh.getBuffer(Type.BindPosePosition) != null ) {
588+
// Then we need to clone the mesh a little deeper
589+
this.mesh = mesh.cloneForAnim();
590+
} else {
591+
// Do whatever the cloner wants to do about it
592+
this.mesh = cloner.clone(mesh);
593+
}
594+
549595
this.material = cloner.clone(material);
550-
this.groupNode = cloner.clone(groupNode);
551596
}
552597

553598
@Override

jme3-core/src/main/java/com/jme3/scene/LightNode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ public Light getLight() {
100100
*/
101101
@Override
102102
public void cloneFields( Cloner cloner, Object original ) {
103+
super.cloneFields(cloner, original);
104+
103105
// A change in behavior... I think previously LightNode was probably
104106
// not really cloneable... or at least its lightControl would be pointing
105107
// to the wrong control. -pspeed

jme3-core/src/main/java/com/jme3/scene/Mesh.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,9 @@ public Mesh cloneForAnim(){
307307
@Override
308308
public Mesh jmeClone() {
309309
try {
310-
return (Mesh)super.clone();
310+
Mesh clone = (Mesh)super.clone();
311+
clone.vertexArrayID = -1;
312+
return clone;
311313
} catch (CloneNotSupportedException ex) {
312314
throw new AssertionError();
313315
}

jme3-core/src/main/java/com/jme3/scene/Node.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,17 @@ public Node clone(boolean cloneMaterials){
697697
}
698698

699699
@Override
700-
public Spatial deepClone(){
700+
public Spatial deepClone() {
701+
Node nodeClone = (Node)super.deepClone();
702+
703+
// Reset the fields of the clone that should be in a 'new' state.
704+
nodeClone.updateList = null;
705+
nodeClone.updateListValid = false; // safe because parent is nulled out in super.clone()
706+
707+
return nodeClone;
708+
}
709+
710+
public Spatial oldDeepClone(){
701711
Node nodeClone = (Node) super.clone();
702712
nodeClone.children = new SafeArrayList<Spatial>(Spatial.class);
703713
for (Spatial child : children){
@@ -713,6 +723,8 @@ public Spatial deepClone(){
713723
*/
714724
@Override
715725
public void cloneFields( Cloner cloner, Object original ) {
726+
super.cloneFields(cloner, original);
727+
716728
this.children = cloner.clone(children);
717729

718730
// Only the outer cloning thing knows whether this should be nulled

jme3-core/src/main/java/com/jme3/scene/Spatial.java

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
4949
import com.jme3.scene.control.Control;
5050
import com.jme3.util.clone.Cloner;
51+
import com.jme3.util.clone.IdentityCloneFunction;
5152
import com.jme3.util.clone.JmeCloneable;
5253
import com.jme3.util.SafeArrayList;
5354
import com.jme3.util.TempVars;
@@ -1263,12 +1264,42 @@ public void setLodLevel(int lod) {
12631264
* Note that meshes of geometries are not cloned explicitly, they
12641265
* are shared if static, or specially cloned if animated.
12651266
*
1266-
* All controls will be cloned using the Control.cloneForSpatial method
1267-
* on the clone.
1268-
*
12691267
* @see Mesh#cloneForAnim()
12701268
*/
1271-
public Spatial clone(boolean cloneMaterial) {
1269+
public Spatial clone( boolean cloneMaterial ) {
1270+
1271+
// Setup the cloner for the type of cloning we want to do.
1272+
Cloner cloner = new Cloner();
1273+
1274+
// First, we definitely do not want to clone our own parent
1275+
cloner.setClonedValue(parent, null);
1276+
1277+
// If we aren't cloning materials then we will make sure those
1278+
// aren't cloned also
1279+
if( !cloneMaterial ) {
1280+
cloner.setCloneFunction(Material.class, new IdentityCloneFunction<Material>());
1281+
}
1282+
1283+
// By default the meshes are not cloned. The geometry
1284+
// may choose to selectively force them to be cloned but
1285+
// normally they will be shared
1286+
cloner.setCloneFunction(Mesh.class, new IdentityCloneFunction<Mesh>());
1287+
1288+
// Clone it!
1289+
Spatial clone = cloner.clone(this);
1290+
1291+
// Because we've nulled the parent out we need to make sure
1292+
// the transforms and stuff get refreshed.
1293+
clone.setTransformRefresh();
1294+
clone.setLightListRefresh();
1295+
1296+
return clone;
1297+
}
1298+
1299+
/**
1300+
* The old clone() method that did not use the new Cloner utility.
1301+
*/
1302+
public Spatial oldClone(boolean cloneMaterial) {
12721303
try {
12731304
Spatial clone = (Spatial) super.clone();
12741305
if (worldBound != null) {
@@ -1344,7 +1375,22 @@ public Spatial clone() {
13441375
*
13451376
* @see Spatial#clone()
13461377
*/
1347-
public abstract Spatial deepClone();
1378+
public Spatial deepClone() {
1379+
// Setup the cloner for the type of cloning we want to do.
1380+
Cloner cloner = new Cloner();
1381+
1382+
// First, we definitely do not want to clone our own parent
1383+
cloner.setClonedValue(parent, null);
1384+
1385+
Spatial clone = cloner.clone(this);
1386+
1387+
// Because we've nulled the parent out we need to make sure
1388+
// the transforms and stuff get refreshed.
1389+
clone.setTransformRefresh();
1390+
clone.setLightListRefresh();
1391+
1392+
return clone;
1393+
}
13481394

13491395
/**
13501396
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
@@ -1381,13 +1427,15 @@ public void cloneFields( Cloner cloner, Object original ) {
13811427
// to avoid all of the nasty cloneForSpatial() fixup style code that
13821428
// used to inject stuff into the clone's user data. By using cloner
13831429
// to clone the user data we get this automatically.
1384-
userData = (HashMap<String, Savable>)userData.clone();
1385-
for( Map.Entry<String, Savable> e : userData.entrySet() ) {
1386-
Savable value = e.getValue();
1387-
if( value instanceof Cloneable ) {
1388-
// Note: all JmeCloneable objects are also Cloneable so this
1389-
// catches both cases.
1390-
e.setValue(cloner.clone(value));
1430+
if( userData != null ) {
1431+
userData = (HashMap<String, Savable>)userData.clone();
1432+
for( Map.Entry<String, Savable> e : userData.entrySet() ) {
1433+
Savable value = e.getValue();
1434+
if( value instanceof Cloneable ) {
1435+
// Note: all JmeCloneable objects are also Cloneable so this
1436+
// catches both cases.
1437+
e.setValue(cloner.clone(value));
1438+
}
13911439
}
13921440
}
13931441
}

jme3-core/src/main/java/com/jme3/scene/instancing/InstancedGeometry.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ public VertexBuffer[] getAllInstanceData() {
349349
*/
350350
@Override
351351
public void cloneFields( Cloner cloner, Object original ) {
352+
super.cloneFields(cloner, original);
353+
352354
this.globalInstanceData = cloner.clone(globalInstanceData);
353355
this.transformInstanceData = cloner.clone(transformInstanceData);
354356
this.geometries = cloner.clone(geometries);

jme3-core/src/main/java/com/jme3/scene/instancing/InstancedNode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@ public Node clone(boolean cloneMaterials) {
350350
*/
351351
@Override
352352
public void cloneFields( Cloner cloner, Object original ) {
353+
super.cloneFields(cloner, original);
354+
353355
this.control = cloner.clone(control);
354356
this.lookUp = cloner.clone(lookUp);
355357

0 commit comments

Comments
 (0)