|
|
|
@ -10,20 +10,21 @@ import com.jme3.scene.Mesh; |
|
|
|
|
import com.jme3.scene.Spatial; |
|
|
|
|
import com.jme3.scene.VertexBuffer; |
|
|
|
|
import com.jme3.texture.Texture; |
|
|
|
|
import com.jme3.util.LittleEndien; |
|
|
|
|
import com.jme3.util.*; |
|
|
|
|
|
|
|
|
|
import java.io.*; |
|
|
|
|
import java.nio.*; |
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
import java.util.HashMap; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Map; |
|
|
|
|
import java.util.*; |
|
|
|
|
import java.util.logging.Level; |
|
|
|
|
import java.util.logging.Logger; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Created by Nehon on 07/08/2017. |
|
|
|
|
*/ |
|
|
|
|
public class GltfUtils { |
|
|
|
|
|
|
|
|
|
private static final Logger logger = Logger.getLogger(GltfUtils.class.getName()); |
|
|
|
|
|
|
|
|
|
public static Mesh.Mode getMeshMode(Integer mode) { |
|
|
|
|
if (mode == null) { |
|
|
|
|
return Mesh.Mode.Triangles; |
|
|
|
@ -120,11 +121,17 @@ public class GltfUtils { |
|
|
|
|
case "WEIGHTS_0": |
|
|
|
|
return VertexBuffer.Type.BoneWeight; |
|
|
|
|
default: |
|
|
|
|
throw new AssetLoadException("Unsupported buffer attribute: " + attribute); |
|
|
|
|
logger.log(Level.WARNING, "Unsupported Vertex Buffer type " + attribute); |
|
|
|
|
return null; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static int getIndex(String name) { |
|
|
|
|
String num = name.substring(name.lastIndexOf("_") + 1); |
|
|
|
|
return Integer.parseInt(num); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static Texture.MagFilter getMagFilter(Integer value) { |
|
|
|
|
if (value == null) { |
|
|
|
|
return null; |
|
|
|
@ -201,7 +208,12 @@ public class GltfUtils { |
|
|
|
|
} |
|
|
|
|
buffer.rewind(); |
|
|
|
|
} |
|
|
|
|
if (store instanceof float[]) { |
|
|
|
|
if (store instanceof short[]) { |
|
|
|
|
short[] array = (short[]) store; |
|
|
|
|
for (int i = 0; i < array.length; i++) { |
|
|
|
|
array[i] = 0; |
|
|
|
|
} |
|
|
|
|
} else if (store instanceof float[]) { |
|
|
|
|
float[] array = (float[]) store; |
|
|
|
|
for (int i = 0; i < array.length; i++) { |
|
|
|
|
array[i] = 0; |
|
|
|
@ -224,41 +236,43 @@ public class GltfUtils { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static void populateBuffer(Object store, byte[] source, int length, int byteOffset, int byteStride, int numComponents) throws IOException { |
|
|
|
|
public static void populateBuffer(Object store, byte[] source, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException { |
|
|
|
|
|
|
|
|
|
if (store instanceof Buffer) { |
|
|
|
|
Buffer buffer = (Buffer) store; |
|
|
|
|
buffer.clear(); |
|
|
|
|
if (buffer instanceof ByteBuffer) { |
|
|
|
|
populateByteBuffer((ByteBuffer) buffer, source, length, byteOffset, byteStride, numComponents); |
|
|
|
|
populateByteBuffer((ByteBuffer) buffer, source, length, byteOffset, byteStride, numComponents, componentSize); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
LittleEndien stream = getStream(source); |
|
|
|
|
if (buffer instanceof ShortBuffer) { |
|
|
|
|
populateShortBuffer((ShortBuffer) buffer, stream, length, byteOffset, byteStride, numComponents); |
|
|
|
|
populateShortBuffer((ShortBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, componentSize); |
|
|
|
|
} else if (buffer instanceof IntBuffer) { |
|
|
|
|
populateIntBuffer((IntBuffer) buffer, stream, length, byteOffset, byteStride, numComponents); |
|
|
|
|
populateIntBuffer((IntBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, componentSize); |
|
|
|
|
} else if (buffer instanceof FloatBuffer) { |
|
|
|
|
populateFloatBuffer((FloatBuffer) buffer, stream, length, byteOffset, byteStride, numComponents); |
|
|
|
|
populateFloatBuffer((FloatBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, componentSize); |
|
|
|
|
} |
|
|
|
|
buffer.rewind(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
LittleEndien stream = getStream(source); |
|
|
|
|
if (store instanceof short[]) { |
|
|
|
|
populateShortArray((short[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize); |
|
|
|
|
} else |
|
|
|
|
if (store instanceof float[]) { |
|
|
|
|
populateFloatArray((float[]) store, stream, length, byteOffset, byteStride, numComponents); |
|
|
|
|
populateFloatArray((float[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize); |
|
|
|
|
} else if (store instanceof Vector3f[]) { |
|
|
|
|
populateVector3fArray((Vector3f[]) store, stream, length, byteOffset, byteStride, numComponents); |
|
|
|
|
populateVector3fArray((Vector3f[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize); |
|
|
|
|
} else if (store instanceof Quaternion[]) { |
|
|
|
|
populateQuaternionArray((Quaternion[]) store, stream, length, byteOffset, byteStride, numComponents); |
|
|
|
|
populateQuaternionArray((Quaternion[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize); |
|
|
|
|
} else if (store instanceof Matrix4f[]) { |
|
|
|
|
populateMatrix4fArray((Matrix4f[]) store, stream, length, byteOffset, byteStride, numComponents); |
|
|
|
|
populateMatrix4fArray((Matrix4f[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void populateByteBuffer(ByteBuffer buffer, byte[] source, int length, int byteOffset, int byteStride, int numComponents) { |
|
|
|
|
private static void populateByteBuffer(ByteBuffer buffer, byte[] source, int length, int byteOffset, int byteStride, int numComponents, int componentSize) { |
|
|
|
|
int index = byteOffset; |
|
|
|
|
int componentSize = 1; |
|
|
|
|
while (index < length + byteOffset) { |
|
|
|
|
for (int i = 0; i < numComponents; i++) { |
|
|
|
|
buffer.put(source[index + i]); |
|
|
|
@ -267,9 +281,8 @@ public class GltfUtils { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void populateShortBuffer(ShortBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException { |
|
|
|
|
private static void populateShortBuffer(ShortBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException { |
|
|
|
|
int index = byteOffset; |
|
|
|
|
int componentSize = 2; |
|
|
|
|
int end = length * componentSize + byteOffset; |
|
|
|
|
stream.skipBytes(byteOffset); |
|
|
|
|
while (index < end) { |
|
|
|
@ -280,9 +293,8 @@ public class GltfUtils { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void populateIntBuffer(IntBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException { |
|
|
|
|
private static void populateIntBuffer(IntBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException { |
|
|
|
|
int index = byteOffset; |
|
|
|
|
int componentSize = 4; |
|
|
|
|
int end = length * componentSize + byteOffset; |
|
|
|
|
stream.skipBytes(byteOffset); |
|
|
|
|
while (index < end) { |
|
|
|
@ -293,9 +305,8 @@ public class GltfUtils { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void populateFloatBuffer(FloatBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException { |
|
|
|
|
private static void populateFloatBuffer(FloatBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException { |
|
|
|
|
int index = byteOffset; |
|
|
|
|
int componentSize = 4; |
|
|
|
|
int end = length * componentSize + byteOffset; |
|
|
|
|
stream.skipBytes(byteOffset); |
|
|
|
|
while (index < end) { |
|
|
|
@ -306,9 +317,94 @@ public class GltfUtils { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void populateFloatArray(float[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException { |
|
|
|
|
private static void populateShortArray(short[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException { |
|
|
|
|
int index = byteOffset; |
|
|
|
|
int end = length * componentSize + byteOffset; |
|
|
|
|
stream.skipBytes(byteOffset); |
|
|
|
|
int arrayIndex = 0; |
|
|
|
|
while (index < end) { |
|
|
|
|
for (int i = 0; i < numComponents; i++) { |
|
|
|
|
if (componentSize == 2) { |
|
|
|
|
array[arrayIndex] = stream.readShort(); |
|
|
|
|
} else { |
|
|
|
|
array[arrayIndex] = stream.readByte(); |
|
|
|
|
} |
|
|
|
|
arrayIndex++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
index += Math.max(componentSize * numComponents, byteStride); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static byte[] toByteArray(short[] shortArray) { |
|
|
|
|
byte[] bytes = new byte[shortArray.length]; |
|
|
|
|
for (int i = 0; i < shortArray.length; i++) { |
|
|
|
|
bytes[i] = (byte) shortArray[i]; |
|
|
|
|
} |
|
|
|
|
return bytes; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void handleSkinningBuffers(Mesh mesh, IntMap<GltfLoader.SkinBuffers> skinBuffers) { |
|
|
|
|
if (skinBuffers.size() > 0) { |
|
|
|
|
if (skinBuffers.size() == 1) { |
|
|
|
|
GltfLoader.SkinBuffers buffs = skinBuffers.get(0); |
|
|
|
|
setSkinBuffers(mesh, buffs.joints, skinBuffers.get(0).weights, buffs.componentSize); |
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
int length = skinBuffers.get(0).joints.length; |
|
|
|
|
short[] jointsArray = new short[length]; |
|
|
|
|
float[] weightsArray = new float[length]; |
|
|
|
|
List<GltfLoader.WeightData> weightData = new ArrayList<>(); |
|
|
|
|
int componentSize = 1; |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < weightsArray.length; i += 4) { |
|
|
|
|
weightData.clear(); |
|
|
|
|
for (int j = 0; j < skinBuffers.size(); j++) { |
|
|
|
|
GltfLoader.SkinBuffers buffs = skinBuffers.get(j); |
|
|
|
|
for (int k = 0; k < 4; k++) { |
|
|
|
|
weightData.add(new GltfLoader.WeightData(buffs.weights[i + k], buffs.joints[i + k], buffs.componentSize)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
Collections.sort(weightData, new Comparator<GltfLoader.WeightData>() { |
|
|
|
|
@Override |
|
|
|
|
public int compare(GltfLoader.WeightData o1, GltfLoader.WeightData o2) { |
|
|
|
|
if (o1.value > o2.value) { |
|
|
|
|
return -1; |
|
|
|
|
} else if (o1.value < o2.value) { |
|
|
|
|
return 1; |
|
|
|
|
} else { |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
for (int j = 0; j < 4; j++) { |
|
|
|
|
GltfLoader.WeightData data = weightData.get(j); |
|
|
|
|
jointsArray[i + j] = data.index; |
|
|
|
|
weightsArray[i + j] = data.value; |
|
|
|
|
if (data.componentSize > componentSize) { |
|
|
|
|
componentSize = data.componentSize; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
setSkinBuffers(mesh, jointsArray, weightsArray, componentSize); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void setSkinBuffers(Mesh mesh, short[] jointsArray, float[] weightsArray, int componentSize) { |
|
|
|
|
if (componentSize == 1) { |
|
|
|
|
mesh.setBuffer(VertexBuffer.Type.BoneIndex, 4, BufferUtils.createByteBuffer(toByteArray(jointsArray))); |
|
|
|
|
} else { |
|
|
|
|
mesh.setBuffer(VertexBuffer.Type.BoneIndex, 4, BufferUtils.createShortBuffer(jointsArray)); |
|
|
|
|
} |
|
|
|
|
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, int componentSize) throws IOException { |
|
|
|
|
int index = byteOffset; |
|
|
|
|
int componentSize = 4; |
|
|
|
|
int end = length * componentSize + byteOffset; |
|
|
|
|
stream.skipBytes(byteOffset); |
|
|
|
|
int arrayIndex = 0; |
|
|
|
@ -322,9 +418,8 @@ public class GltfUtils { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void populateVector3fArray(Vector3f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException { |
|
|
|
|
private static void populateVector3fArray(Vector3f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException { |
|
|
|
|
int index = byteOffset; |
|
|
|
|
int componentSize = 4; |
|
|
|
|
int end = length * componentSize + byteOffset; |
|
|
|
|
stream.skipBytes(byteOffset); |
|
|
|
|
int arrayIndex = 0; |
|
|
|
@ -341,9 +436,8 @@ public class GltfUtils { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void populateQuaternionArray(Quaternion[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException { |
|
|
|
|
private static void populateQuaternionArray(Quaternion[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException { |
|
|
|
|
int index = byteOffset; |
|
|
|
|
int componentSize = 4; |
|
|
|
|
int end = length * componentSize + byteOffset; |
|
|
|
|
stream.skipBytes(byteOffset); |
|
|
|
|
int arrayIndex = 0; |
|
|
|
@ -361,9 +455,8 @@ public class GltfUtils { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void populateMatrix4fArray(Matrix4f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException { |
|
|
|
|
private static void populateMatrix4fArray(Matrix4f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException { |
|
|
|
|
int index = byteOffset; |
|
|
|
|
int componentSize = 4; |
|
|
|
|
int end = length * componentSize + byteOffset; |
|
|
|
|
stream.skipBytes(byteOffset); |
|
|
|
|
int arrayIndex = 0; |
|
|
|
|