Started implementing the JmeCloneable stuff for Spatial

and Mesh.  Still need to catch some of the outer subclasses of
Node and Geometry.  Nothing is hooked up or tested yet.
This commit is contained in:
Paul Speed 2016-03-25 04:31:10 -04:00
parent 911b4be868
commit 2bdb3de2f5
14 changed files with 827 additions and 545 deletions

View File

@ -123,7 +123,7 @@ public class StatsView extends Node implements Control, JmeCloneable {
} }
@Override @Override
public Object jmeClone() { public StatsView jmeClone() {
throw new UnsupportedOperationException("Not yet implemented."); throw new UnsupportedOperationException("Not yet implemented.");
} }

View File

@ -33,6 +33,8 @@ package com.jme3.light;
import com.jme3.export.*; import com.jme3.export.*;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import com.jme3.util.SortUtil; import com.jme3.util.SortUtil;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
@ -43,7 +45,7 @@ import java.util.*;
* *
* @author Kirill Vainer * @author Kirill Vainer
*/ */
public final class LightList implements Iterable<Light>, Savable, Cloneable { public final class LightList implements Iterable<Light>, Savable, Cloneable, JmeCloneable {
private Light[] list, tlist; private Light[] list, tlist;
private float[] distToOwner; private float[] distToOwner;
@ -302,6 +304,24 @@ public final class LightList implements Iterable<Light>, Savable, Cloneable {
} }
} }
@Override
public LightList jmeClone() {
try{
LightList clone = (LightList)super.clone();
clone.tlist = null; // list used for sorting only
return clone;
}catch (CloneNotSupportedException ex){
throw new AssertionError();
}
}
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.owner = cloner.clone(owner);
this.list = cloner.clone(list);
this.distToOwner = cloner.clone(distToOwner);
}
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this); OutputCapsule oc = ex.getCapsule(this);
// oc.write(owner, "owner", null); // oc.write(owner, "owner", null);

View File

@ -39,6 +39,7 @@ import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter; import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule; import com.jme3.export.OutputCapsule;
import com.jme3.export.binary.BinaryImporter; import com.jme3.export.binary.BinaryImporter;
import com.jme3.util.clone.Cloner;
import com.jme3.util.SafeArrayList; import com.jme3.util.SafeArrayList;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
@ -70,6 +71,18 @@ public class AssetLinkNode extends Node {
assetLoaderKeys.add(key); assetLoaderKeys.add(key);
} }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object 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
this.assetLoaderKeys = cloner.clone(assetLoaderKeys);
this.assetChildren = new HashMap<ModelKey, Spatial>();
}
/** /**
* Add a "linked" child. These are loaded from the assetManager when the * Add a "linked" child. These are loaded from the assetManager when the
* AssetLinkNode is loaded from a binary file. * AssetLinkNode is loaded from a binary file.

View File

@ -48,6 +48,8 @@ import com.jme3.math.Vector3f;
import com.jme3.scene.mesh.IndexBuffer; import com.jme3.scene.mesh.IndexBuffer;
import com.jme3.util.SafeArrayList; import com.jme3.util.SafeArrayList;
import com.jme3.util.TempVars; import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
/** /**
* BatchNode holds geometries that are a batched version of all the geometries that are in its sub scenegraph. * BatchNode holds geometries that are a batched version of all the geometries that are in its sub scenegraph.
@ -662,7 +664,7 @@ public class BatchNode extends GeometryGroupNode {
vars.release(); vars.release();
} }
protected class Batch { protected class Batch implements JmeCloneable {
/** /**
* update the batchesByGeom map for this batch with the given List of geometries * update the batchesByGeom map for this batch with the given List of geometries
* @param list * @param list
@ -679,6 +681,21 @@ public class BatchNode extends GeometryGroupNode {
public final Geometry getGeometry() { public final Geometry getGeometry() {
return geometry; return geometry;
} }
@Override
public Batch jmeClone() {
try {
return (Batch)super.clone();
} catch (CloneNotSupportedException ex) {
throw new AssertionError();
}
}
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.geometry = cloner.clone(geometry);
}
} }
protected void setNeedsFullRebatch(boolean needsFullRebatch) { protected void setNeedsFullRebatch(boolean needsFullRebatch) {
@ -705,6 +722,24 @@ public class BatchNode extends GeometryGroupNode {
return clone; return clone;
} }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.batches = cloner.clone(batches);
this.tmpFloat = cloner.clone(tmpFloat);
this.tmpFloatN = cloner.clone(tmpFloatN);
this.tmpFloatT = cloner.clone(tmpFloatT);
HashMap<Geometry, Batch> newBatchesByGeom = new HashMap<Geometry, Batch>();
for( Map.Entry<Geometry, Batch> e : batchesByGeom.entrySet() ) {
newBatchesByGeom.put(cloner.clone(e.getKey()), cloner.clone(e.getValue()));
}
this.batchesByGeom = newBatchesByGeom;
}
@Override @Override
public int collideWith(Collidable other, CollisionResults results) { public int collideWith(Collidable other, CollisionResults results) {
int total = 0; int total = 0;

View File

@ -36,6 +36,7 @@ import com.jme3.export.JmeImporter;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
import com.jme3.scene.control.CameraControl; import com.jme3.scene.control.CameraControl;
import com.jme3.scene.control.CameraControl.ControlDirection; import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.util.clone.Cloner;
import java.io.IOException; import java.io.IOException;
/** /**
@ -94,6 +95,17 @@ public class CameraNode extends Node {
// camControl.getCamera().lookAt(position, upVector); // camControl.getCamera().lookAt(position, upVector);
// } // }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object 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
this.camControl = cloner.clone(camControl);
}
@Override @Override
public void read(JmeImporter im) throws IOException { public void read(JmeImporter im) throws IOException {
super.read(im); super.read(im);

View File

@ -43,6 +43,7 @@ import com.jme3.material.Material;
import com.jme3.math.Matrix4f; import com.jme3.math.Matrix4f;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.clone.Cloner;
import com.jme3.util.TempVars; import com.jme3.util.TempVars;
import java.io.IOException; import java.io.IOException;
import java.util.Queue; import java.util.Queue;
@ -539,6 +540,16 @@ public class Geometry extends Spatial {
return geomClone; return geomClone;
} }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.mesh = cloner.clone(mesh);
this.material = cloner.clone(material);
this.groupNode = cloner.clone(groupNode);
}
@Override @Override
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {
super.write(ex); super.write(ex);

View File

@ -36,6 +36,7 @@ import com.jme3.export.JmeImporter;
import com.jme3.light.Light; import com.jme3.light.Light;
import com.jme3.scene.control.LightControl; import com.jme3.scene.control.LightControl;
import com.jme3.scene.control.LightControl.ControlDirection; import com.jme3.scene.control.LightControl.ControlDirection;
import com.jme3.util.clone.Cloner;
import java.io.IOException; import java.io.IOException;
/** /**
@ -94,6 +95,17 @@ public class LightNode extends Node {
return lightControl.getLight(); return lightControl.getLight();
} }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object 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
this.lightControl = cloner.clone(lightControl);
}
@Override @Override
public void read(JmeImporter im) throws IOException { public void read(JmeImporter im) throws IOException {
super.read(im); super.read(im);

View File

@ -51,6 +51,8 @@ import com.jme3.util.BufferUtils;
import com.jme3.util.IntMap; import com.jme3.util.IntMap;
import com.jme3.util.IntMap.Entry; import com.jme3.util.IntMap.Entry;
import com.jme3.util.SafeArrayList; import com.jme3.util.SafeArrayList;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; import java.io.IOException;
import java.nio.*; import java.nio.*;
import java.util.ArrayList; import java.util.ArrayList;
@ -72,7 +74,7 @@ import java.util.ArrayList;
* *
* @author Kirill Vainer * @author Kirill Vainer
*/ */
public class Mesh implements Savable, Cloneable { public class Mesh implements Savable, Cloneable, JmeCloneable {
/** /**
* The mode of the Mesh specifies both the type of primitive represented * The mode of the Mesh specifies both the type of primitive represented
@ -299,6 +301,35 @@ public class Mesh implements Savable, Cloneable {
return clone; return clone;
} }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public Mesh jmeClone() {
try {
return (Mesh)super.clone();
} catch (CloneNotSupportedException ex) {
throw new AssertionError();
}
}
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
// Probably could clone this now but it will get regenerated anyway.
this.collisionTree = null;
this.meshBound = cloner.clone(meshBound);
this.buffersList = cloner.clone(buffersList);
this.buffers = cloner.clone(buffers);
this.lodLevels = cloner.clone(lodLevels);
this.elementLengths = cloner.clone(elementLengths);
this.modeStart = cloner.clone(modeStart);
}
/** /**
* Generates the {@link Type#BindPosePosition}, {@link Type#BindPoseNormal}, * Generates the {@link Type#BindPosePosition}, {@link Type#BindPoseNormal},
* and {@link Type#BindPoseTangent} * and {@link Type#BindPoseTangent}

View File

@ -40,6 +40,7 @@ import com.jme3.export.Savable;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.util.SafeArrayList; import com.jme3.util.SafeArrayList;
import com.jme3.util.TempVars; import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -707,6 +708,19 @@ public class Node extends Spatial {
return nodeClone; return nodeClone;
} }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.children = cloner.clone(children);
// Only the outer cloning thing knows whether this should be nulled
// or not... after all, we might be cloning a root node in which case
// cloning this list is fine.
this.updateList = cloner.clone(updateList);
}
@Override @Override
public void write(JmeExporter e) throws IOException { public void write(JmeExporter e) throws IOException {
super.write(e); super.write(e);

View File

@ -47,6 +47,8 @@ import com.jme3.renderer.queue.RenderQueue;
import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.renderer.queue.RenderQueue.ShadowMode; import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.control.Control; import com.jme3.scene.control.Control;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import com.jme3.util.SafeArrayList; import com.jme3.util.SafeArrayList;
import com.jme3.util.TempVars; import com.jme3.util.TempVars;
import java.io.IOException; import java.io.IOException;
@ -63,7 +65,7 @@ import java.util.logging.Logger;
* @author Joshua Slack * @author Joshua Slack
* @version $Revision: 4075 $, $Data$ * @version $Revision: 4075 $, $Data$
*/ */
public abstract class Spatial implements Savable, Cloneable, Collidable, CloneableSmartAsset { public abstract class Spatial implements Savable, Cloneable, Collidable, CloneableSmartAsset, JmeCloneable {
private static final Logger logger = Logger.getLogger(Spatial.class.getName()); private static final Logger logger = Logger.getLogger(Spatial.class.getName());
@ -1344,6 +1346,52 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
*/ */
public abstract Spatial deepClone(); public abstract Spatial deepClone();
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public Spatial jmeClone() {
try {
Spatial clone = (Spatial)super.clone();
return clone;
} catch (CloneNotSupportedException ex) {
throw new AssertionError();
}
}
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
// Clone all of the fields that need fix-ups and/or potential
// sharing.
this.parent = cloner.clone(parent);
this.worldBound = cloner.clone(worldBound);
this.worldLights = cloner.clone(worldLights);
this.localLights = cloner.clone(localLights);
this.worldTransform = cloner.clone(worldTransform);
this.localTransform = cloner.clone(localTransform);
this.controls = cloner.clone(controls);
// Cloner doesn't handle maps on its own just yet.
// Note: this is more advanced cloning than the old clone() method
// did because it just shallow cloned the map. In this case, we want
// 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));
}
}
}
public void setUserData(String key, Object data) { public void setUserData(String key, Object data) {
if (userData == null) { if (userData == null) {
userData = new HashMap<String, Savable>(); userData = new HashMap<String, Savable>();

View File

@ -47,6 +47,7 @@ import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.VertexBuffer.Usage; import com.jme3.scene.VertexBuffer.Usage;
import com.jme3.util.BufferUtils; import com.jme3.util.BufferUtils;
import com.jme3.util.TempVars; import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import java.io.IOException; import java.io.IOException;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@ -343,6 +344,16 @@ public class InstancedGeometry extends Geometry {
return allData.toArray(new VertexBuffer[allData.size()]); return allData.toArray(new VertexBuffer[allData.size()]);
} }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.globalInstanceData = cloner.clone(globalInstanceData);
this.transformInstanceData = cloner.clone(transformInstanceData);
this.geometries = cloner.clone(geometries);
}
@Override @Override
public void write(JmeExporter exporter) throws IOException { public void write(JmeExporter exporter) throws IOException {
super.write(exporter); super.write(exporter);

View File

@ -48,6 +48,7 @@ import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable; import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
public class InstancedNode extends GeometryGroupNode { public class InstancedNode extends GeometryGroupNode {
@ -59,7 +60,7 @@ public class InstancedNode extends GeometryGroupNode {
setGeometryStartIndex(geom, startIndex); setGeometryStartIndex(geom, startIndex);
} }
private static final class InstanceTypeKey implements Cloneable { private static final class InstanceTypeKey implements Cloneable, JmeCloneable {
Mesh mesh; Mesh mesh;
Material material; Material material;
@ -106,6 +107,21 @@ public class InstancedNode extends GeometryGroupNode {
throw new AssertionError(); throw new AssertionError();
} }
} }
@Override
public Object jmeClone() {
try {
return super.clone();
} catch( CloneNotSupportedException e ) {
throw new AssertionError();
}
}
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.mesh = cloner.clone(mesh);
this.material = cloner.clone(material);
}
} }
private static class InstancedNodeControl implements Control, JmeCloneable { private static class InstancedNodeControl implements Control, JmeCloneable {
@ -329,6 +345,27 @@ public class InstancedNode extends GeometryGroupNode {
return clone; return clone;
} }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.control = cloner.clone(control);
this.lookUp = cloner.clone(lookUp);
HashMap<Geometry, InstancedGeometry> newIgByGeom = new HashMap<Geometry, InstancedGeometry>();
for( Map.Entry<Geometry, InstancedGeometry> e : igByGeom.entrySet() ) {
newIgByGeom.put(cloner.clone(e.getKey()), cloner.clone(e.getValue()));
}
this.igByGeom = newIgByGeom;
HashMap<InstanceTypeKey, InstancedGeometry> newInstancesMap = new HashMap<InstanceTypeKey, InstancedGeometry>();
for( Map.Entry<InstanceTypeKey, InstancedGeometry> e : instancesMap.entrySet() ) {
newInstancesMap.put(cloner.clone(e.getKey()), cloner.clone(e.getValue()));
}
this.instancesMap = newInstancesMap;
}
@Override @Override
public void onTransformChange(Geometry geom) { public void onTransformChange(Geometry geom) {
// Handled automatically // Handled automatically

View File

@ -32,6 +32,8 @@
package com.jme3.util; package com.jme3.util;
import com.jme3.util.IntMap.Entry; import com.jme3.util.IntMap.Entry;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@ -43,7 +45,7 @@ import java.util.NoSuchElementException;
* *
* @author Nate * @author Nate
*/ */
public final class IntMap<T> implements Iterable<Entry<T>>, Cloneable { public final class IntMap<T> implements Iterable<Entry<T>>, Cloneable, JmeCloneable {
private Entry[] table; private Entry[] table;
private final float loadFactor; private final float loadFactor;
@ -93,6 +95,26 @@ public final class IntMap<T> implements Iterable<Entry<T>>, Cloneable {
return null; return null;
} }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public Object jmeClone() {
try {
return super.clone();
} catch (CloneNotSupportedException ex) {
throw new AssertionError();
}
}
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.table = cloner.clone(table);
}
public boolean containsValue(Object value) { public boolean containsValue(Object value) {
Entry[] table = this.table; Entry[] table = this.table;
for (int i = table.length; i-- > 0;){ for (int i = table.length; i-- > 0;){
@ -268,7 +290,7 @@ public final class IntMap<T> implements Iterable<Entry<T>>, Cloneable {
} }
public static final class Entry<T> implements Cloneable { public static final class Entry<T> implements Cloneable, JmeCloneable {
final int key; final int key;
T value; T value;
@ -303,5 +325,20 @@ public final class IntMap<T> implements Iterable<Entry<T>>, Cloneable {
} }
return null; return null;
} }
@Override
public Object jmeClone() {
try {
return super.clone();
} catch (CloneNotSupportedException ex) {
throw new AssertionError();
}
}
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.value = cloner.clone(value);
this.next = cloner.clone(next);
}
} }
} }

View File

@ -1,11 +1,12 @@
# THIS IS AN AUTO-GENERATED FILE.. # THIS IS AN AUTO-GENERATED FILE..
# DO NOT MODIFY! # DO NOT MODIFY!
build.date=1900-01-01 build.date=2016-03-25
git.revision=0 git.revision=0
git.branch=unknown git.branch=unknown
git.hash= git.hash=
git.hash.short= git.hash.short=
git.tag= git.tag=
name.full=jMonkeyEngine 3.1.0-UNKNOWN name.full=jMonkeyEngine 3.1.0-UNKNOWN
version.full=3.1.0-UNKNOWN
version.number=3.1.0 version.number=3.1.0
version.tag=SNAPSHOT version.tag=SNAPSHOT