diff --git a/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java b/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java index b1f3d02df5..a6d168f868 100644 --- a/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java +++ b/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java @@ -124,7 +124,7 @@ private void switchToHardware() { } for (Mesh mesh : targets) { if (mesh.isAnimated()) { - mesh.prepareForAnim(false); + mesh.prepareForAnimHardware(); } } } @@ -137,7 +137,7 @@ private void switchToSoftware() { } for (Mesh mesh : targets) { if (mesh.isAnimated()) { - mesh.prepareForAnim(true); + mesh.prepareForAnimSoftware(); } } } @@ -312,7 +312,7 @@ void resetToBind() { Buffer bwBuff = mesh.getBuffer(Type.BoneWeight).getData(); Buffer biBuff = mesh.getBuffer(Type.BoneIndex).getData(); if (!biBuff.hasArray() || !bwBuff.hasArray()) { - mesh.prepareForAnim(true); // prepare for software animation + mesh.prepareForAnimSoftware(); // prepare for software animation } VertexBuffer bindPos = mesh.getBuffer(Type.BindPosePosition); VertexBuffer bindNorm = mesh.getBuffer(Type.BindPoseNormal); diff --git a/jme3-core/src/main/java/com/jme3/scene/Mesh.java b/jme3-core/src/main/java/com/jme3/scene/Mesh.java index a0f8e1fe6e..01677a6a44 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Mesh.java +++ b/jme3-core/src/main/java/com/jme3/scene/Mesh.java @@ -354,91 +354,93 @@ public void generateBindPose(boolean forSoftwareAnim){ /** * Prepares the mesh for software skinning by converting the bone index - * and weight buffers to heap buffers. - * - * @param forSoftwareAnim Should be true to enable the conversion. + * and weight buffers to heap buffers. */ - public void prepareForAnim(boolean forSoftwareAnim){ - if (forSoftwareAnim) { - // convert indices to ubytes on the heap - VertexBuffer indices = getBuffer(Type.BoneIndex); - if (!indices.getData().hasArray()) { - ByteBuffer originalIndex = (ByteBuffer) indices.getData(); - ByteBuffer arrayIndex = ByteBuffer.allocate(originalIndex.capacity()); - originalIndex.clear(); - arrayIndex.put(originalIndex); - indices.updateData(arrayIndex); - } - indices.setUsage(Usage.CpuOnly); - - // convert weights on the heap - VertexBuffer weights = getBuffer(Type.BoneWeight); - if (!weights.getData().hasArray()) { - FloatBuffer originalWeight = (FloatBuffer) weights.getData(); - FloatBuffer arrayWeight = FloatBuffer.allocate(originalWeight.capacity()); - originalWeight.clear(); - arrayWeight.put(originalWeight); - weights.updateData(arrayWeight); - } - weights.setUsage(Usage.CpuOnly); - // position, normal, and tanget buffers to be in "Stream" mode - VertexBuffer positions = getBuffer(Type.Position); - VertexBuffer normals = getBuffer(Type.Normal); - VertexBuffer tangents = getBuffer(Type.Tangent); - positions.setUsage(Usage.Stream); - if (normals != null) { - normals.setUsage(Usage.Stream); - } - if (tangents != null) { - tangents.setUsage(Usage.Stream); - } - } else { - //if HWBoneIndex and HWBoneWeight are empty, we setup them as direct - //buffers with software anim buffers data - VertexBuffer indicesHW = getBuffer(Type.HWBoneIndex); - if (indicesHW.getData() == null) { - VertexBuffer indices = getBuffer(Type.BoneIndex); - ByteBuffer originalIndex = (ByteBuffer) indices.getData(); - ByteBuffer directIndex = BufferUtils.createByteBuffer(originalIndex.capacity()); - originalIndex.clear(); - directIndex.put(originalIndex); - indicesHW.setupData(Usage.Static, indices.getNumComponents(), indices.getFormat(), directIndex); - } - - VertexBuffer weightsHW = getBuffer(Type.HWBoneWeight); - if (weightsHW.getData() == null) { - VertexBuffer weights = getBuffer(Type.BoneWeight); - FloatBuffer originalWeight = (FloatBuffer) weights.getData(); - FloatBuffer directWeight = BufferUtils.createFloatBuffer(originalWeight.capacity()); - originalWeight.clear(); - directWeight.put(originalWeight); - weightsHW.setupData(Usage.Static, weights.getNumComponents(), weights.getFormat(), directWeight); - } - - // position, normal, and tanget buffers to be in "Static" mode - VertexBuffer positions = getBuffer(Type.Position); - VertexBuffer normals = getBuffer(Type.Normal); - VertexBuffer tangents = getBuffer(Type.Tangent); - - VertexBuffer positionsBP = getBuffer(Type.BindPosePosition); - VertexBuffer normalsBP = getBuffer(Type.BindPoseNormal); - VertexBuffer tangentsBP = getBuffer(Type.BindPoseTangent); - - positions.setUsage(Usage.Static); - positionsBP.copyElements(0, positions, 0, positionsBP.getNumElements()); - positions.setUpdateNeeded(); - - if (normals != null) { - normals.setUsage(Usage.Static); - normalsBP.copyElements(0, normals, 0, normalsBP.getNumElements()); - normals.setUpdateNeeded(); - } - - if (tangents != null) { - tangents.setUsage(Usage.Static); - tangentsBP.copyElements(0, tangents, 0, tangentsBP.getNumElements()); - tangents.setUpdateNeeded(); - } + public void prepareForAnimSoftware(){ + // convert indices to ubytes on the heap + VertexBuffer indices = getBuffer(Type.BoneIndex); + if (!indices.getData().hasArray()) { + ByteBuffer originalIndex = (ByteBuffer) indices.getData(); + ByteBuffer arrayIndex = ByteBuffer.allocate(originalIndex.capacity()); + originalIndex.clear(); + arrayIndex.put(originalIndex); + indices.updateData(arrayIndex); + } + indices.setUsage(Usage.CpuOnly); + + // convert weights on the heap + VertexBuffer weights = getBuffer(Type.BoneWeight); + if (!weights.getData().hasArray()) { + FloatBuffer originalWeight = (FloatBuffer) weights.getData(); + FloatBuffer arrayWeight = FloatBuffer.allocate(originalWeight.capacity()); + originalWeight.clear(); + arrayWeight.put(originalWeight); + weights.updateData(arrayWeight); + } + weights.setUsage(Usage.CpuOnly); + // position, normal, and tanget buffers to be in "Stream" mode + VertexBuffer positions = getBuffer(Type.Position); + VertexBuffer normals = getBuffer(Type.Normal); + VertexBuffer tangents = getBuffer(Type.Tangent); + positions.setUsage(Usage.Stream); + if (normals != null) { + normals.setUsage(Usage.Stream); + } + if (tangents != null) { + tangents.setUsage(Usage.Stream); + } + } + + /** + * Prepares the mesh for hardware skinning by converting the bone index + * and weight buffers to heap buffers. + */ + public void prepareForAnimHardware(){ + //if HWBoneIndex and HWBoneWeight are empty, we setup them as direct + //buffers with software anim buffers data + VertexBuffer indicesHW = getBuffer(Type.HWBoneIndex); + if (indicesHW.getData() == null) { + VertexBuffer indices = getBuffer(Type.BoneIndex); + ByteBuffer originalIndex = (ByteBuffer) indices.getData(); + ByteBuffer directIndex = BufferUtils.createByteBuffer(originalIndex.capacity()); + originalIndex.clear(); + directIndex.put(originalIndex); + indicesHW.setupData(Usage.Static, indices.getNumComponents(), indices.getFormat(), directIndex); + } + + VertexBuffer weightsHW = getBuffer(Type.HWBoneWeight); + if (weightsHW.getData() == null) { + VertexBuffer weights = getBuffer(Type.BoneWeight); + FloatBuffer originalWeight = (FloatBuffer) weights.getData(); + FloatBuffer directWeight = BufferUtils.createFloatBuffer(originalWeight.capacity()); + originalWeight.clear(); + directWeight.put(originalWeight); + weightsHW.setupData(Usage.Static, weights.getNumComponents(), weights.getFormat(), directWeight); + } + + // position, normal, and tanget buffers to be in "Static" mode + VertexBuffer positions = getBuffer(Type.Position); + VertexBuffer normals = getBuffer(Type.Normal); + VertexBuffer tangents = getBuffer(Type.Tangent); + + VertexBuffer positionsBP = getBuffer(Type.BindPosePosition); + VertexBuffer normalsBP = getBuffer(Type.BindPoseNormal); + VertexBuffer tangentsBP = getBuffer(Type.BindPoseTangent); + + positions.setUsage(Usage.Static); + positionsBP.copyElements(0, positions, 0, positionsBP.getNumElements()); + positions.setUpdateNeeded(); + + if (normals != null) { + normals.setUsage(Usage.Static); + normalsBP.copyElements(0, normals, 0, normalsBP.getNumElements()); + normals.setUpdateNeeded(); + } + + if (tangents != null) { + tangents.setUsage(Usage.Static); + tangentsBP.copyElements(0, tangents, 0, tangentsBP.getNumElements()); + tangents.setUpdateNeeded(); } } @@ -632,92 +634,6 @@ public void setStreamed(){ } } - /** - * Interleaves the data in this mesh. This operation cannot be reversed. - * Some GPUs may prefer the data in this format, however it is a good idea - * to avoid using this method as it disables some engine features. - */ - @Deprecated - public void setInterleaved(){ - ArrayList vbs = new ArrayList(); - vbs.addAll(buffersList); - -// ArrayList vbs = new ArrayList(buffers.values()); - // index buffer not included when interleaving - vbs.remove(getBuffer(Type.Index)); - - int stride = 0; // aka bytes per vertex - for (int i = 0; i < vbs.size(); i++){ - VertexBuffer vb = vbs.get(i); -// if (vb.getFormat() != Format.Float){ -// throw new UnsupportedOperationException("Cannot interleave vertex buffer.\n" + -// "Contains not-float data."); -// } - stride += vb.componentsLength; - vb.getData().clear(); // reset position & limit (used later) - } - - VertexBuffer allData = new VertexBuffer(Type.InterleavedData); - ByteBuffer dataBuf = BufferUtils.createByteBuffer(stride * getVertexCount()); - allData.setupData(Usage.Static, 1, Format.UnsignedByte, dataBuf); - - // adding buffer directly so that no update counts is forced - buffers.put(Type.InterleavedData.ordinal(), allData); - buffersList.add(allData); - - for (int vert = 0; vert < getVertexCount(); vert++){ - for (int i = 0; i < vbs.size(); i++){ - VertexBuffer vb = vbs.get(i); - switch (vb.getFormat()){ - case Float: - FloatBuffer fb = (FloatBuffer) vb.getData(); - for (int comp = 0; comp < vb.components; comp++){ - dataBuf.putFloat(fb.get()); - } - break; - case Byte: - case UnsignedByte: - ByteBuffer bb = (ByteBuffer) vb.getData(); - for (int comp = 0; comp < vb.components; comp++){ - dataBuf.put(bb.get()); - } - break; - case Half: - case Short: - case UnsignedShort: - ShortBuffer sb = (ShortBuffer) vb.getData(); - for (int comp = 0; comp < vb.components; comp++){ - dataBuf.putShort(sb.get()); - } - break; - case Int: - case UnsignedInt: - IntBuffer ib = (IntBuffer) vb.getData(); - for (int comp = 0; comp < vb.components; comp++){ - dataBuf.putInt(ib.get()); - } - break; - case Double: - DoubleBuffer db = (DoubleBuffer) vb.getData(); - for (int comp = 0; comp < vb.components; comp++){ - dataBuf.putDouble(db.get()); - } - break; - } - } - } - - int offset = 0; - for (VertexBuffer vb : vbs){ - vb.setOffset(offset); - vb.setStride(stride); - - vb.updateData(null); - //vb.setupData(vb.usage, vb.components, vb.format, null); - offset += vb.componentsLength; - } - } - private int computeNumElements(int bufSize){ switch (mode){ case Triangles: @@ -757,9 +673,6 @@ private int computeInstanceCount() { * based on the current data. This method should be called * after the {@link Buffer#capacity() capacities} of the mesh's * {@link VertexBuffer vertex buffers} has been altered. - * - * @throws IllegalStateException If this mesh is in - * {@link #setInterleaved() interleaved} format. */ public void updateCounts(){ if (getBuffer(Type.InterleavedData) != null) @@ -1188,29 +1101,7 @@ public void extractVertexData(Mesh other) { 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()); + VertexBuffer newIdxBuf = createIndexBuffer(oldIdxBuf, indexBuf, newIndicesToOldIndices); clearBuffer(Type.Index); setBuffer(newIdxBuf); @@ -1222,26 +1113,7 @@ public void extractVertexData(Mesh other) { continue; } - VertexBuffer newVb = new VertexBuffer(oldVb.getBufferType()); - newVb.setNormalized(oldVb.isNormalized()); - //check for data before copying, some buffers are just empty shells - //for caching purpose (HW skinning buffers), and will be filled when - //needed - if(oldVb.getData()!=null){ - // 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); - 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); - } - } + VertexBuffer newVb = createVertexBuffer(oldVb,newIndicesToOldIndices); // Set the buffer on the mesh clearBuffer(newVb.getBufferType()); @@ -1255,6 +1127,62 @@ public void extractVertexData(Mesh other) { updateCounts(); updateBound(); } + + public VertexBuffer createIndexBuffer(VertexBuffer vertexBuf, IndexBuffer indexBuf, ArrayList indices){ + // 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 + + int numIndices = indexBuf.size(); + int numIndex = indices.size(); + + IndexBuffer newIndexBuf; + if (numIndex >= 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); + numIndex = indices.get(oldIndex); + + newIndexBuf.put(i, numIndex); + } + + VertexBuffer newIdxBuf = new VertexBuffer(Type.Index); + newIdxBuf.setupData(vertexBuf.getUsage(), + vertexBuf.getNumComponents(), + newIndexBuf instanceof IndexIntBuffer ? Format.UnsignedInt : Format.UnsignedShort, + newIndexBuf.getBuffer()); + + return newIdxBuf; + } + + public VertexBuffer createVertexBuffer(VertexBuffer oldVb, ArrayList indices) { + VertexBuffer newVb = new VertexBuffer(oldVb.getBufferType()); + newVb.setNormalized(oldVb.isNormalized()); + //check for data before copying, some buffers are just empty shells + //for caching purpose (HW skinning buffers), and will be filled when + //needed + if(oldVb.getData()!=null){ + // 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(), indices.size()); + 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 < indices.size(); i++) { + int oldIndex = indices.get(i); + + // Copy the vertex attribute from the old index + // to the new index + oldVb.copyElement(oldIndex, newVb, i); + } + } + return newVb; + } /** * Scales the texture coordinate buffer on this mesh by the given diff --git a/jme3-core/src/test/java/com/jme3/scene/MeshTest.java b/jme3-core/src/test/java/com/jme3/scene/MeshTest.java new file mode 100644 index 0000000000..6c41d40fba --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/scene/MeshTest.java @@ -0,0 +1,44 @@ +package com.jme3.scene; + +import com.jme3.scene.shape.Box; +import org.junit.Test; + +/** + * Created by arkkadhiratara on 3/22/16. + */ +public class MeshTest { + @Test + public void extractVertexDataTest() { + Box m = new Box(10,10,10); + Box m2 = new Box(20,20,20); + + // Extract Vertex Data m into m2 + m2.extractVertexData(m); + + // Check does the new extracted m2 have the same value with m1. + + // Have the same mode + assert m.getMode() == m2.getMode(); + + // Have the same Instance Count + assert m.getInstanceCount() == m2.getInstanceCount(); + + // Have the same point size + assert m.getPointSize() == m2.getPointSize(); + + // Have the same buffer in general + assert m.getBufferList().size() == m2.getBufferList().size(); + assert m.getIndexBuffer().size() == m2.getIndexBuffer().size(); + assert m.getBuffer(VertexBuffer.Type.Index).getUniqueId() == m2.getBuffer(VertexBuffer.Type.Index).getUniqueId(); + assert m.getBuffer(VertexBuffer.Type.Index).getNumElements() == m2.getBuffer(VertexBuffer.Type.Index).getNumElements(); + + assert m.getBuffer(VertexBuffer.Type.Position).getUniqueId() == m2.getBuffer(VertexBuffer.Type.Position).getUniqueId(); + assert m.getBuffer(VertexBuffer.Type.Position).getNumElements() == m2.getBuffer(VertexBuffer.Type.Position).getNumElements(); + + assert m.getBuffer(VertexBuffer.Type.Normal).getUniqueId() == m2.getBuffer(VertexBuffer.Type.Normal).getUniqueId(); + assert m.getBuffer(VertexBuffer.Type.Normal).getNumElements() == m2.getBuffer(VertexBuffer.Type.Normal).getNumElements(); + + assert m.getBuffer(VertexBuffer.Type.TexCoord).getUniqueId() == m2.getBuffer(VertexBuffer.Type.TexCoord).getUniqueId(); + assert m.getBuffer(VertexBuffer.Type.TexCoord).getNumElements() == m2.getBuffer(VertexBuffer.Type.TexCoord).getNumElements(); + } +}