diff --git a/engine/src/core/com/jme3/scene/Mesh.java b/engine/src/core/com/jme3/scene/Mesh.java
index 38fe7d8e6..c1d214afa 100644
--- a/engine/src/core/com/jme3/scene/Mesh.java
+++ b/engine/src/core/com/jme3/scene/Mesh.java
@@ -43,6 +43,7 @@ import com.jme3.math.Matrix4f;
import com.jme3.math.Triangle;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
+import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Format;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.VertexBuffer.Usage;
@@ -54,6 +55,8 @@ import com.jme3.util.SafeArrayList;
import java.io.IOException;
import java.nio.*;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
/**
* Mesh
is used to store rendering data.
@@ -1051,6 +1054,110 @@ public class Mesh implements Savable, Cloneable {
}
}
+ /**
+ * Extracts the vertex attributes from the given mesh into
+ * this mesh, by using this mesh's {@link #getIndexBuffer() index buffer}
+ * to index into the attributes of the other mesh.
+ * Note that this will also change this mesh's index buffer so that
+ * the references to the vertex data match the new indices.
+ *
+ * @param other The mesh to extract the vertex data from
+ */
+ public void extractVertexData(Mesh other) {
+ // Determine the number of unique vertices need to
+ // be created. Also determine the mappings
+ // between old indices to new indices (since we avoid duplicating
+ // vertices, this is a map and not an array).
+ VertexBuffer oldIdxBuf = getBuffer(Type.Index);
+ IndexBuffer indexBuf = getIndexBuffer();
+ int numIndices = indexBuf.size();
+
+ IntMap oldIndicesToNewIndices = new IntMap(numIndices);
+ ArrayList newIndicesToOldIndices = new ArrayList();
+ int newIndex = 0;
+
+ for (int i = 0; i < numIndices; i++) {
+ int oldIndex = indexBuf.get(i);
+
+ if (!oldIndicesToNewIndices.containsKey(oldIndex)) {
+ // this vertex has not been added, so allocate a
+ // new index for it and add it to the map
+ oldIndicesToNewIndices.put(oldIndex, newIndex);
+ newIndicesToOldIndices.add(oldIndex);
+
+ // increment to have the next index
+ newIndex++;
+ }
+ }
+
+ // Number of unique verts to be created now available
+ int newNumVerts = newIndicesToOldIndices.size();
+
+ if (newIndex != newNumVerts) {
+ throw new AssertionError();
+ }
+
+ // Create the new index buffer.
+ // Do not overwrite the old one because we might be able to
+ // convert from int index buffer to short index buffer
+ IndexBuffer newIndexBuf;
+ if (newNumVerts >= 65536) {
+ newIndexBuf = new IndexIntBuffer(BufferUtils.createIntBuffer(numIndices));
+ } else {
+ newIndexBuf = new IndexShortBuffer(BufferUtils.createShortBuffer(numIndices));
+ }
+
+ for (int i = 0; i < numIndices; i++) {
+ // Map the old indices to the new indices
+ int oldIndex = indexBuf.get(i);
+ newIndex = oldIndicesToNewIndices.get(oldIndex);
+
+ newIndexBuf.put(i, newIndex);
+ }
+
+ VertexBuffer newIdxBuf = new VertexBuffer(Type.Index);
+ newIdxBuf.setupData(oldIdxBuf.getUsage(),
+ oldIdxBuf.getNumComponents(),
+ newIndexBuf instanceof IndexIntBuffer ? Format.UnsignedInt : Format.UnsignedShort,
+ newIndexBuf.getBuffer());
+ clearBuffer(Type.Index);
+ setBuffer(newIdxBuf);
+
+ // Now, create the vertex buffers
+ SafeArrayList oldVertexData = other.getBufferList();
+ for (VertexBuffer oldVb : oldVertexData) {
+ if (oldVb.getBufferType() == VertexBuffer.Type.Index) {
+ // ignore the index buffer
+ continue;
+ }
+
+ // Create a new vertex buffer with similar configuration, but
+ // with the capacity of number of unique vertices
+ Buffer buffer = VertexBuffer.createBuffer(oldVb.getFormat(), oldVb.getNumComponents(), newNumVerts);
+
+ VertexBuffer newVb = new VertexBuffer(oldVb.getBufferType());
+ newVb.setNormalized(oldVb.isNormalized());
+ newVb.setupData(oldVb.getUsage(), oldVb.getNumComponents(), oldVb.getFormat(), buffer);
+
+ // Copy the vertex data from the old buffer into the new buffer
+ for (int i = 0; i < newNumVerts; i++) {
+ int oldIndex = newIndicesToOldIndices.get(i);
+
+ // Copy the vertex attribute from the old index
+ // to the new index
+ oldVb.copyElement(oldIndex, newVb, i);
+ }
+
+ // Set the buffer on the mesh
+ clearBuffer(newVb.getBufferType());
+ setBuffer(newVb);
+ }
+
+ // The data has been copied over, update informations
+ updateCounts();
+ updateBound();
+ }
+
/**
* Scales the texture coordinate buffer on this mesh by the given
* scale factor.
@@ -1138,6 +1245,15 @@ public class Mesh implements Savable, Cloneable {
return buffers;
}
+ /**
+ * Returns a list of all {@link VertexBuffer vertex buffers} on this Mesh.
+ * Using a list instead an IntMap via the {@link #getBuffers() } method is
+ * better for iteration as there's no need to create an iterator instance.
+ * Note that the returned list is a reference to the list used internally,
+ * modifying it will cause undefined results.
+ *
+ * @return list of vertex buffers on this mesh.
+ */
public SafeArrayList getBufferList(){
return buffersList;
}