Change title: Clone of Spatials
Created classes: CloneCreator
Affected classes: All classes extending Spatial and Controller that want to be cloned (it is optional). LWJGLRenderer and RenderQueue
Summary of changes: Clones are created from a CloneCreator and rendered in the RenderQueue. VBO aren’t currently supported (mostly because it doens’t seem to work on my machine), but would be by changing the getVBOVertexID and setVBOVertexID to check a static HashMap inside CloneCreator against its ZOrder (only if the render state is CLONE of course).
Code:
CloneCreator is straitforward. Mojomonkey has the exact code. Here are a few snippits to give you an idea of how it works.
Box c=new Box("my box",new Vector3f(0,0,0),new Vector3f(1,1,1));
c.setRandomColors();
c.setModelBound(new BoundingBox());
c.updateModelBound();
cc2=new CloneCreator(c);
cc2.addProperty("vertices");
cc2.addProperty("normals");
cc2.addProperty("colors");
cc2.addProperty("texcoords");
cc2.addProperty("indices");
Spatial theCopy=cc2.createCopy();
Spatial.putClone(Spatial Store, CloneCreator properties)
/**
* This function stores into the "store" spatial the attributes of this Spatial.
* This function should be overridden in any Spatial extending classes that wish
* to be cloned. The properties tag signals how cloning should take place.
* @param store The spatial to store this Spatial's information into.
* @param properties This signals how to clone this spatial.
* @return The store spatial, after Clone is complete.
*/
public Spatial putClone(Spatial store,CloneCreator properties){
if (store==null)
return null;
store.setLocalTranslation(new Vector3f(getLocalTranslation()));
store.setLocalRotation(new Quaternion(getLocalRotation()));
store.setLocalScale(new Vector3f(getLocalScale()));
for (int i=0;i<renderStateList.length;i++){
store.renderStateList[i]=renderStateList[i];
}
Iterator I=geometricalControllers.iterator();
while (I.hasNext()){
Controller c=(Controller) I.next();
Controller toAdd=c.putClone(null,properties);
if (toAdd!=null)
store.addController(toAdd);
}
properties.originalToCopy.put(this,store);
return store;
}
Geometry.putClone
public Spatial putClone(Spatial store,CloneCreator properties){
if (store==null)
return null;
super.putClone(store,properties);
Geometry toStore=(Geometry) store; // This should never throw a class cast exception if
// the clone is written correctly.
toStore.setRenderQueueMode(Renderer.QUEUE_CLONE);
// Create a CloneID if none exist for this mesh.
if (!properties.CloneIDExist(this))
properties.createCloneID(this);
toStore.setZOrder(properties.getCloneID(this));
if (properties.isSet("vertices")){
toStore.vertBuf = this.vertBuf;
toStore.vertex = this.vertex;
toStore.vertQuantity = this.vertQuantity;
} else{
Vector3f[] temp=new Vector3f[this.vertex.length];
for (int i=0;i<temp.length;i++){
temp[i]=new Vector3f(this.vertex[i]);
}
toStore.setVertices(temp);
}
if (properties.isSet("colors")){ // if I should shallow copy colors
toStore.colorBuf = this.colorBuf;
toStore.color = this.color;
} else if (color!=null){ // If I should deep copy colors
ColorRGBA[] temp=new ColorRGBA[this.color.length];
for (int i=0;i<temp.length;i++){
temp[i]=new ColorRGBA(this.color[i]);
}
toStore.setColors(temp);
}
if (properties.isSet("normals")){
toStore.normBuf = this.normBuf;
toStore.normal = this.normal;
} else if (normal!=null){
Vector3f[] temp = new Vector3f[this.normal.length];
for (int i=0;i<temp.length;i++){
temp[i] = new Vector3f(this.normal[i]);
}
toStore.setNormals(temp);
}
if (properties.isSet("texcoords")){
toStore.texBuf = this.texBuf;
toStore.texture = this.texture;
} else {
Vector2f[][] temp=new Vector2f[this.texture.length][];
for (int i=0;i<temp.length;i++){
if (this.texBuf[i]==null) continue;
temp[i] = new Vector2f[this.texture[i].length];
for (int j=0;j<temp[i].length;j++){
temp[i][j] = new Vector2f(this.texture[i][j]);
}
toStore.setTextures(temp[i],i);
}
}
if (bound!=null)
toStore.setModelBound((BoundingVolume) bound.clone(null));
return toStore;
}
TriMesh.putClone
public Spatial putClone(Spatial store,CloneCreator properties){
TriMesh toStore;
if (store==null){
toStore=new TriMesh(this.getName()+"copy");
} else {
toStore=(TriMesh) store;
}
super.putClone(toStore,properties);
if (properties.isSet("indices")){
toStore.indices = this.indices;
toStore.indexBuffer = this.indexBuffer;
toStore.triangleQuantity = this.triangleQuantity;
} else{
int[] temp=new int[this.indices.length];
for (int i=0;i<temp.length;i++){
temp[i]=this.indices[i];
}
toStore.setIndices(temp);
}
if (properties.isSet("obbtree")){
toStore.collisionTree = this.collisionTree;
}
return toStore;
}
Node.putClone
public Spatial putClone(Spatial store,CloneCreator properties){
Node toStore;
if (store==null)
toStore=new Node(getName()+"copy");
else
toStore=(Node) store;
super.putClone(toStore,properties);
for (int i=0,size=children.size();i<size;i++){
Spatial child=(Spatial) children.get(i);
toStore.attachChild(child.putClone(null,properties));
}
return toStore;
}
Controller.putClone()
public Controller putClone(Controller store,CloneCreator properties){
if (store==null)
return null;
store.active = active;
store.repeatType = repeatType;
store.minTime = minTime;
store.maxTime = maxTime;
store.speed = speed;
return store;
}
SpatialTransformer.putClone()
public Controller putClone(Controller store,CloneCreator properties){
if (!properties.isSet("spatialcontroller"))
return null;
SpatialTransformer toReturn=new SpatialTransformer(this.numObjects);
super.putClone(toReturn,properties);
toReturn.numObjects=this.numObjects;
System.arraycopy(this.toChange,0,toReturn.toChange,0,toChange.length);
System.arraycopy(this.pivots,0,toReturn.pivots,0,pivots.length);
toReturn.parentIndexes = this.parentIndexes;
toReturn.keyframes = this.keyframes;
toReturn.curTime = this.curTime;
toReturn.haveChanged = this.haveChanged;
properties.queueSpatialTransformer(toReturn);
return toReturn;
}
Part of LWJGLRenderer.draw(TriMesh)
....................
FloatBuffer verticies=t.getVerticeAsFloatBuffer();
if (prevVerts!=verticies){
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
if (t.isVBOVertexEnabled() && GLContext.OpenGL15) {
usingVBO = true;
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, t.getVBOVertexID());
GL11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0);
} else {
if (usingVBO) GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL11.glVertexPointer(3, 0, t.getVerticeAsFloatBuffer());
}
}
prevVerts = verticies;
.......................