From 1bdebd55055818edd05f1e68d0d4bd6f48670652 Mon Sep 17 00:00:00 2001 From: Nehon Date: Thu, 24 Aug 2017 08:00:47 +0200 Subject: [PATCH] Added support for attachment nodes. JME now supports byte buffers for index buffer --- .../com/jme3/renderer/opengl/GLRenderer.java | 1 + .../src/main/java/com/jme3/scene/Mesh.java | 27 +++++++++---- .../main/java/com/jme3/util/BufferUtils.java | 40 +++++++++++++++++++ .../jme3/scene/plugins/gltf/GltfLoader.java | 37 +++++++++++++++-- 4 files changed, 93 insertions(+), 12 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index 7caa76159..db018cc64 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -2592,6 +2592,7 @@ public final class GLRenderer implements Renderer { } switch (indexBuf.getFormat()) { + case UnsignedByte: case UnsignedShort: // OK: Works on all platforms. break; 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 aa703393c..7c626e8b5 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Mesh.java +++ b/jme3-core/src/main/java/com/jme3/scene/Mesh.java @@ -53,6 +53,8 @@ import com.jme3.util.IntMap.Entry; import com.jme3.util.SafeArrayList; import com.jme3.util.clone.Cloner; import com.jme3.util.clone.JmeCloneable; +import com.sun.javaws.exceptions.InvalidArgumentException; + import java.io.IOException; import java.nio.*; import java.util.ArrayList; @@ -402,11 +404,20 @@ public class Mesh implements Savable, Cloneable, JmeCloneable { // 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); + if (indices.getFormat() == Format.UnsignedByte) { + ByteBuffer originalIndex = (ByteBuffer) indices.getData(); + ByteBuffer arrayIndex = ByteBuffer.allocate(originalIndex.capacity()); + originalIndex.clear(); + arrayIndex.put(originalIndex); + indices.updateData(arrayIndex); + } else { + //bone indices can be stored in an UnsignedShort buffer + ShortBuffer originalIndex = (ShortBuffer) indices.getData(); + ShortBuffer arrayIndex = ShortBuffer.allocate(originalIndex.capacity()); + originalIndex.clear(); + arrayIndex.put(originalIndex); + indices.updateData(arrayIndex); + } } indices.setUsage(Usage.CpuOnly); @@ -1437,7 +1448,7 @@ public class Mesh implements Savable, Cloneable, JmeCloneable { return false; // no bone animation data } - ByteBuffer boneIndexBuffer = (ByteBuffer) biBuf.getData(); + BufferUtils.ByteShortIntBufferReader boneIndexBuffer = new BufferUtils.ByteShortIntBufferReader(biBuf.getData()); boneIndexBuffer.rewind(); int numBoneIndices = boneIndexBuffer.remaining(); assert numBoneIndices % 4 == 0 : numBoneIndices; @@ -1450,10 +1461,10 @@ public class Mesh implements Savable, Cloneable, JmeCloneable { /* * Test each vertex to determine whether the bone affects it. */ - byte biByte = (byte) boneIndex; // bone indices wrap after 127 + int biByte = boneIndex; for (int vIndex = 0; vIndex < numVertices; vIndex++) { for (int wIndex = 0; wIndex < 4; wIndex++) { - byte bIndex = boneIndexBuffer.get(); + int bIndex = boneIndexBuffer.get(); float weight = weightBuffer.get(); if (wIndex < maxNumWeights && bIndex == biByte && weight != 0f) { return true; diff --git a/jme3-core/src/main/java/com/jme3/util/BufferUtils.java b/jme3-core/src/main/java/com/jme3/util/BufferUtils.java index d8b6bca03..b589c7bab 100644 --- a/jme3-core/src/main/java/com/jme3/util/BufferUtils.java +++ b/jme3-core/src/main/java/com/jme3/util/BufferUtils.java @@ -1340,4 +1340,44 @@ public final class BufferUtils { } } } + + public static class ByteShortIntBufferReader { + Buffer buffer; + + public ByteShortIntBufferReader(Buffer buffer) { + this.buffer = buffer; + } + + public int get() { + if (buffer instanceof ByteBuffer) { + return ((ByteBuffer) buffer).get(); + } else if (buffer instanceof ShortBuffer) { + return ((ShortBuffer) buffer).get(); + } else if (buffer instanceof IntBuffer) { + return ((IntBuffer) buffer).get(); + } else { + throw new UnsupportedOperationException("Buffer must be a ByteBuffer, a ShortBuffer or an IntBuffer"); + } + } + + public int get(int index) { + if (buffer instanceof ByteBuffer) { + return ((ByteBuffer) buffer).get(index); + } else if (buffer instanceof ShortBuffer) { + return ((ShortBuffer) buffer).get(index); + } else if (buffer instanceof IntBuffer) { + return ((IntBuffer) buffer).get(index); + } else { + throw new UnsupportedOperationException("Buffer must be a ByteBuffer, a ShortBuffer or an IntBuffer"); + } + } + + public void rewind() { + buffer.rewind(); + } + + public int remaining() { + return buffer.remaining(); + } + } } diff --git a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java index 018e374ea..8b8e3f350 100644 --- a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java +++ b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java @@ -894,7 +894,6 @@ public class GltfLoader implements AssetLoader { int boneIndex = joints.get(i).getAsInt(); //we don't need the inverse bind matrix, we need the bind matrix so let's invert it. Matrix4f modelBindMatrix = inverseBindMatrices[i].invertLocal(); - //TODO actually a regular node or a geometry can be attached to a bone, we have to handle this and attach it to the AttachementNode. bones[i] = readNodeAsBone(boneIndex, i, index, modelBindMatrix); } @@ -990,10 +989,11 @@ public class GltfLoader implements AssetLoader { return bone; } - private void findChildren(int nodeIndex) { + private void findChildren(int nodeIndex) throws IOException { BoneWrapper bw = fetchFromCache("nodes", nodeIndex, BoneWrapper.class); JsonObject nodeData = nodes.get(nodeIndex).getAsJsonObject(); JsonArray children = nodeData.getAsJsonArray("children"); + if (children != null) { for (JsonElement child : children) { int childIndex = child.getAsInt(); @@ -1001,8 +1001,18 @@ public class GltfLoader implements AssetLoader { if (cbw != null) { bw.bone.addChild(cbw.bone); bw.children.add(childIndex); + } else { + JsonObject childNode = nodes.get(childIndex).getAsJsonObject(); + //The child might be a Geom + if (getAsInteger(childNode, "mesh") != null) { + //this is a geometry, let's load it as a spatial + Spatial s = (Spatial) readNode(childIndex); + bw.attachedSpatial = s; + // addToCache("nodes", nodeIndex, s, nodes.size()); + } } } + } } @@ -1010,6 +1020,10 @@ public class GltfLoader implements AssetLoader { for (SkinData skinData : skinnedSpatials.keySet()) { List spatials = skinnedSpatials.get(skinData); Spatial spatial; + if (spatials.isEmpty()) { + //can happen when a file contains a skin that is not used by any mesh... + continue; + } if (spatials.size() >= 1) { spatial = findCommonAncestor(spatials); } else { @@ -1028,9 +1042,17 @@ public class GltfLoader implements AssetLoader { if (skinData.animControl != null) { spatial.addControl(skinData.animControl); - spatial.addControl(skinData.skeletonControl); } + spatial.addControl(skinData.skeletonControl); + } + for (int i = 0; i < nodes.size(); i++) { + BoneWrapper bw = fetchFromCache("nodes", i, BoneWrapper.class); + if (bw == null || bw.attachedSpatial == null) { + continue; + } + SkinData skinData = fetchFromCache("skins", bw.skinIndex, SkinData.class); + skinData.skeletonControl.getAttachmentsNode(bw.bone.getName()).attachChild(bw.attachedSpatial); } } @@ -1044,7 +1066,13 @@ public class GltfLoader implements AssetLoader { if (data == null) { return null; } - return type.cast(data[index]); + try { + T ret = type.cast(data[index]); + return ret; + } catch (ClassCastException e) { + return null; + } + } public void addToCache(String name, int index, Object object, int maxLength) { @@ -1128,6 +1156,7 @@ public class GltfLoader implements AssetLoader { Transform localTransform; Matrix4f modelBindMatrix; boolean isRoot = false; + Spatial attachedSpatial; List children = new ArrayList<>(); public BoneWrapper(Bone bone, int boneIndex, int skinIndex, Matrix4f modelBindMatrix, Transform localTransform) {