From e09a5a5b092d415307c9116dba4dd65272701cef Mon Sep 17 00:00:00 2001 From: Nehon Date: Sat, 9 Sep 2017 14:31:26 +0200 Subject: [PATCH] glTF: fixed data reading to properly support interleaved data. --- .../jme3/scene/plugins/gltf/GltfLoader.java | 16 +-- .../jme3/scene/plugins/gltf/GltfUtils.java | 136 +++++++++++------- 2 files changed, 95 insertions(+), 57 deletions(-) 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 88a3e8382..25ce90977 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 @@ -455,7 +455,7 @@ public class GltfLoader implements AssetLoader { return data; } - public void readBuffer(Integer bufferViewIndex, int byteOffset, int bufferSize, Object store, int numComponents, VertexBuffer.Format format) throws IOException { + public void readBuffer(Integer bufferViewIndex, int byteOffset, int count, Object store, int numComponents, VertexBuffer.Format format) throws IOException { JsonObject bufferView = bufferViews.get(bufferViewIndex).getAsJsonObject(); Integer bufferIndex = getAsInteger(bufferView, "buffer"); @@ -473,7 +473,7 @@ public class GltfLoader implements AssetLoader { data = customContentManager.readExtensionAndExtras("bufferView", bufferView, data); - populateBuffer(store, data, bufferSize, byteOffset + bvByteOffset, byteStride, numComponents, format); + populateBuffer(store, data, count, byteOffset + bvByteOffset, byteStride, numComponents, format); } @@ -1260,7 +1260,7 @@ public class GltfLoader implements AssetLoader { //no referenced buffer, specs says to pad the buffer with zeros. padBuffer(buff, bufferSize); } else { - readBuffer(bufferViewIndex, byteOffset, bufferSize, buff, numComponents, originalFormat); + readBuffer(bufferViewIndex, byteOffset, count, buff, numComponents, originalFormat); } if (bufferType == VertexBuffer.Type.Index) { @@ -1286,7 +1286,7 @@ public class GltfLoader implements AssetLoader { //no referenced buffer, specs says to pad the data with zeros. padBuffer(data, dataSize); } else { - readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, getVertexBufferFormat(componentType)); + readBuffer(bufferViewIndex, byteOffset, count, data, numComponents, getVertexBufferFormat(componentType)); } return data; @@ -1307,7 +1307,7 @@ public class GltfLoader implements AssetLoader { //no referenced buffer, specs says to pad the data with zeros. padBuffer(data, dataSize); } else { - readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, getVertexBufferFormat(componentType)); + readBuffer(bufferViewIndex, byteOffset, count, data, numComponents, getVertexBufferFormat(componentType)); } return data; } @@ -1326,7 +1326,7 @@ public class GltfLoader implements AssetLoader { //no referenced buffer, specs says to pad the data with zeros. padBuffer(data, dataSize); } else { - readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, getVertexBufferFormat(componentType)); + readBuffer(bufferViewIndex, byteOffset, count, data, numComponents, getVertexBufferFormat(componentType)); } return data; @@ -1346,7 +1346,7 @@ public class GltfLoader implements AssetLoader { //no referenced buffer, specs says to pad the data with zeros. padBuffer(data, dataSize); } else { - readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, getVertexBufferFormat(componentType)); + readBuffer(bufferViewIndex, byteOffset, count, data, numComponents, getVertexBufferFormat(componentType)); } return data; @@ -1373,7 +1373,7 @@ public class GltfLoader implements AssetLoader { //no referenced buffer, specs says to pad the data with zeros. padBuffer(data, dataSize); } else { - readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, format); + readBuffer(bufferViewIndex, byteOffset, count, data, numComponents, format); } return new SkinBuffers(data, format.getComponentSize()); diff --git a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfUtils.java b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfUtils.java index bd92d6c01..75d48d06c 100644 --- a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfUtils.java +++ b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfUtils.java @@ -3,13 +3,8 @@ package com.jme3.scene.plugins.gltf; import com.google.gson.*; import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetLoadException; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Matrix4f; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; -import com.jme3.scene.Spatial; -import com.jme3.scene.VertexBuffer; +import com.jme3.math.*; +import com.jme3.scene.*; import com.jme3.texture.Texture; import com.jme3.util.*; @@ -237,92 +232,113 @@ public class GltfUtils { } } - public static void populateBuffer(Object store, byte[] source, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { + public static void populateBuffer(Object store, byte[] source, int count, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { if (store instanceof Buffer) { Buffer buffer = (Buffer) store; buffer.clear(); if (buffer instanceof ByteBuffer) { - populateByteBuffer((ByteBuffer) buffer, source, length, byteOffset, byteStride, numComponents, format); + populateByteBuffer((ByteBuffer) buffer, source, count, byteOffset, byteStride, numComponents, format); return; } LittleEndien stream = getStream(source); if (buffer instanceof ShortBuffer) { - populateShortBuffer((ShortBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, format); + populateShortBuffer((ShortBuffer) buffer, stream, count, byteOffset, byteStride, numComponents, format); } else if (buffer instanceof IntBuffer) { - populateIntBuffer((IntBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, format); + populateIntBuffer((IntBuffer) buffer, stream, count, byteOffset, byteStride, numComponents, format); } else if (buffer instanceof FloatBuffer) { - populateFloatBuffer((FloatBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, format); + populateFloatBuffer((FloatBuffer) buffer, stream, count, byteOffset, byteStride, numComponents, format); } buffer.rewind(); return; } LittleEndien stream = getStream(source); if (store instanceof short[]) { - populateShortArray((short[]) store, stream, length, byteOffset, byteStride, numComponents, format); + populateShortArray((short[]) store, stream, count, byteOffset, byteStride, numComponents, format); } else if (store instanceof float[]) { - populateFloatArray((float[]) store, stream, length, byteOffset, byteStride, numComponents, format); + populateFloatArray((float[]) store, stream, count, byteOffset, byteStride, numComponents, format); } else if (store instanceof Vector3f[]) { - populateVector3fArray((Vector3f[]) store, stream, length, byteOffset, byteStride, numComponents, format); + populateVector3fArray((Vector3f[]) store, stream, count, byteOffset, byteStride, numComponents, format); } else if (store instanceof Quaternion[]) { - populateQuaternionArray((Quaternion[]) store, stream, length, byteOffset, byteStride, numComponents, format); + populateQuaternionArray((Quaternion[]) store, stream, count, byteOffset, byteStride, numComponents, format); } else if (store instanceof Matrix4f[]) { - populateMatrix4fArray((Matrix4f[]) store, stream, length, byteOffset, byteStride, numComponents, format); + populateMatrix4fArray((Matrix4f[]) store, stream, count, byteOffset, byteStride, numComponents, format); } } - private static void populateByteBuffer(ByteBuffer buffer, byte[] source, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) { + private static void populateByteBuffer(ByteBuffer buffer, byte[] source, int count, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) { int componentSize = format.getComponentSize(); int index = byteOffset; - while (index < length + byteOffset) { + int dataLength = componentSize * numComponents; + int stride = Math.max(dataLength, byteStride); + int end = count * stride + byteOffset; + while (index < end) { for (int i = 0; i < numComponents; i++) { buffer.put(source[index + i]); } - index += Math.max(componentSize * numComponents, byteStride); + index += stride; } } - private static void populateShortBuffer(ShortBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { + private static void populateShortBuffer(ShortBuffer buffer, LittleEndien stream, int count, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { int componentSize = format.getComponentSize(); int index = byteOffset; - int end = length * componentSize + byteOffset; + int dataLength = componentSize * numComponents; + int stride = Math.max(dataLength, byteStride); + int end = count * stride + byteOffset; stream.skipBytes(byteOffset); while (index < end) { for (int i = 0; i < numComponents; i++) { buffer.put(stream.readShort()); } - index += Math.max(componentSize * numComponents, byteStride); + + if (dataLength < stride) { + stream.skipBytes(stride - dataLength); + } + index += stride; } + System.err.println(""); } - private static void populateIntBuffer(IntBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { + + private static void populateIntBuffer(IntBuffer buffer, LittleEndien stream, int count, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { int componentSize = format.getComponentSize(); int index = byteOffset; - int end = length * componentSize + byteOffset; + int dataLength = componentSize * numComponents; + int stride = Math.max(dataLength, byteStride); + int end = count * stride + byteOffset; stream.skipBytes(byteOffset); while (index < end) { for (int i = 0; i < numComponents; i++) { buffer.put(stream.readInt()); } - index += Math.max(componentSize * numComponents, byteStride); + if (dataLength < stride) { + stream.skipBytes(stride - dataLength); + } + index += stride; } } - private static void populateFloatBuffer(FloatBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { + private static void populateFloatBuffer(FloatBuffer buffer, LittleEndien stream, int count, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { int componentSize = format.getComponentSize(); int index = byteOffset; - int end = length * componentSize + byteOffset; + int dataLength = componentSize * numComponents; + int stride = Math.max(dataLength, byteStride); + int end = count * stride + byteOffset; stream.skipBytes(byteOffset); while (index < end) { for (int i = 0; i < numComponents; i++) { buffer.put(readAsFloat(stream, format)); } - index += Math.max(componentSize * numComponents, byteStride); + if (dataLength < stride) { + stream.skipBytes(stride - dataLength); + } + index += stride; } } - private static float readAsFloat(LittleEndien stream, VertexBuffer.Format format) throws IOException { + public static float readAsFloat(LittleEndien stream, VertexBuffer.Format format) throws IOException { //We may have packed data so depending on the format, we need to read data differently and unpack it // Implementations must use following equations to get corresponding floating-point value f from a normalized integer c and vise-versa: // accessor.componentType int-to-float float-to-int @@ -351,10 +367,12 @@ public class GltfUtils { } - private static void populateShortArray(short[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { + private static void populateShortArray(short[] array, LittleEndien stream, int count, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { int componentSize = format.getComponentSize(); int index = byteOffset; - int end = length * componentSize + byteOffset; + int dataLength = componentSize * numComponents; + int stride = Math.max(dataLength, byteStride); + int end = count * stride + byteOffset; stream.skipBytes(byteOffset); int arrayIndex = 0; while (index < end) { @@ -366,8 +384,10 @@ public class GltfUtils { } arrayIndex++; } - - index += Math.max(componentSize * numComponents, byteStride); + if (dataLength < stride) { + stream.skipBytes(stride - dataLength); + } + index += stride; } } @@ -447,10 +467,12 @@ public class GltfUtils { mesh.setBuffer(VertexBuffer.Type.BoneWeight, 4, BufferUtils.createFloatBuffer(weightsArray)); } - private static void populateFloatArray(float[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { + private static void populateFloatArray(float[] array, LittleEndien stream, int count, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { int componentSize = format.getComponentSize(); int index = byteOffset; - int end = length * componentSize + byteOffset; + int dataLength = componentSize * numComponents; + int stride = Math.max(dataLength, byteStride); + int end = count * stride + byteOffset; stream.skipBytes(byteOffset); int arrayIndex = 0; while (index < end) { @@ -458,15 +480,19 @@ public class GltfUtils { array[arrayIndex] = readAsFloat(stream, format); arrayIndex++; } - - index += Math.max(componentSize * numComponents, byteStride); + if (dataLength < stride) { + stream.skipBytes(stride - dataLength); + } + index += stride; } } - private static void populateVector3fArray(Vector3f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { + private static void populateVector3fArray(Vector3f[] array, LittleEndien stream, int count, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { int componentSize = format.getComponentSize(); int index = byteOffset; - int end = length * componentSize + byteOffset; + int dataLength = componentSize * numComponents; + int stride = Math.max(dataLength, byteStride); + int end = count * stride + byteOffset; stream.skipBytes(byteOffset); int arrayIndex = 0; while (index < end) { @@ -477,15 +503,20 @@ public class GltfUtils { ); arrayIndex++; + if (dataLength < stride) { + stream.skipBytes(stride - dataLength); + } - index += Math.max(componentSize * numComponents, byteStride); + index += stride; } } - private static void populateQuaternionArray(Quaternion[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { + private static void populateQuaternionArray(Quaternion[] array, LittleEndien stream, int count, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { int componentSize = format.getComponentSize(); int index = byteOffset; - int end = length * componentSize + byteOffset; + int dataLength = componentSize * numComponents; + int stride = Math.max(dataLength, byteStride); + int end = count * stride + byteOffset; stream.skipBytes(byteOffset); int arrayIndex = 0; while (index < end) { @@ -497,15 +528,19 @@ public class GltfUtils { ); arrayIndex++; - - index += Math.max(componentSize * numComponents, byteStride); + if (dataLength < stride) { + stream.skipBytes(stride - dataLength); + } + index += stride; } } - private static void populateMatrix4fArray(Matrix4f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { + private static void populateMatrix4fArray(Matrix4f[] array, LittleEndien stream, int count, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException { int componentSize = format.getComponentSize(); int index = byteOffset; - int end = length * componentSize + byteOffset; + int dataLength = componentSize * numComponents; + int stride = Math.max(dataLength, byteStride); + int end = count * stride + byteOffset; stream.skipBytes(byteOffset); int arrayIndex = 0; while (index < end) { @@ -531,8 +566,11 @@ public class GltfUtils { //gltf matrix are column major, JME ones are row major. arrayIndex++; + if (dataLength < stride) { + stream.skipBytes(stride - dataLength); + } - index += Math.max(componentSize * numComponents, byteStride); + index += stride; } } @@ -566,7 +604,7 @@ public class GltfUtils { return key.isKeepSkeletonPose(); } - private static LittleEndien getStream(byte[] buffer) { + public static LittleEndien getStream(byte[] buffer) { return new LittleEndien(new DataInputStream(new ByteArrayInputStream(buffer))); }