Gltf Spatial animation loading
This commit is contained in:
parent
4daa0b5d9b
commit
42aec10020
@ -2,6 +2,9 @@ package com.jme3.scene.plugins.gltf;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.jme3.animation.AnimControl;
|
||||
import com.jme3.animation.Animation;
|
||||
import com.jme3.animation.SpatialTrack;
|
||||
import com.jme3.asset.*;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.material.RenderState;
|
||||
@ -41,9 +44,14 @@ public class GltfLoader implements AssetLoader {
|
||||
private JsonArray textures;
|
||||
private JsonArray images;
|
||||
private JsonArray samplers;
|
||||
private JsonArray animations;
|
||||
|
||||
private Material defaultMat;
|
||||
private AssetInfo info;
|
||||
|
||||
private FloatArrayPopulator floatArrayPopulator = new FloatArrayPopulator();
|
||||
private Vector3fArrayPopulator vector3fArrayPopulator = new Vector3fArrayPopulator();
|
||||
private QuaternionArrayPopulator quaternionArrayPopulator = new QuaternionArrayPopulator();
|
||||
private static Map<String, MaterialAdapter> defaultMaterialAdapters = new HashMap<>();
|
||||
private boolean useNormalsFlag = false;
|
||||
|
||||
@ -85,6 +93,7 @@ public class GltfLoader implements AssetLoader {
|
||||
textures = root.getAsJsonArray("textures");
|
||||
images = root.getAsJsonArray("images");
|
||||
samplers = root.getAsJsonArray("samplers");
|
||||
animations = root.getAsJsonArray("animations");
|
||||
|
||||
JsonPrimitive defaultScene = root.getAsJsonPrimitive("scene");
|
||||
|
||||
@ -127,6 +136,13 @@ public class GltfLoader implements AssetLoader {
|
||||
root.attachChild(sceneNode);
|
||||
}
|
||||
|
||||
//Loading animations
|
||||
if (animations != null) {
|
||||
for (JsonElement animation : animations) {
|
||||
loadAnimation(animation.getAsJsonObject());
|
||||
}
|
||||
}
|
||||
|
||||
//Setting the default scene cul hint to inherit.
|
||||
int activeChild = 0;
|
||||
if (defaultScene != null) {
|
||||
@ -147,9 +163,7 @@ public class GltfLoader implements AssetLoader {
|
||||
JsonArray children = nodeData.getAsJsonArray("children");
|
||||
Integer meshIndex = getAsInteger(nodeData, "mesh");
|
||||
if (meshIndex != null) {
|
||||
if (meshes == null) {
|
||||
throw new AssetLoadException("Can't find any mesh data, yet a node references a mesh");
|
||||
}
|
||||
assertNotNull(meshes, "Can't find any mesh data, yet a node references a mesh");
|
||||
|
||||
//there is a mesh in this node, however gltf can split meshes in primitives (some kind of sub meshes),
|
||||
//We don't have this in JME so we have to make one mesh and one Geometry for each primitive.
|
||||
@ -242,9 +256,8 @@ public class GltfLoader implements AssetLoader {
|
||||
}
|
||||
JsonObject meshData = meshes.get(meshIndex).getAsJsonObject();
|
||||
JsonArray primitives = meshData.getAsJsonArray("primitives");
|
||||
if (primitives == null) {
|
||||
throw new AssetLoadException("Can't find any primitives in mesh " + meshIndex);
|
||||
}
|
||||
assertNotNull(primitives, "Can't find any primitives in mesh " + meshIndex);
|
||||
|
||||
String name = getAsString(meshData, "name");
|
||||
|
||||
geomArray = new Geometry[primitives.size()];
|
||||
@ -256,13 +269,12 @@ public class GltfLoader implements AssetLoader {
|
||||
mesh.setMode(getMeshMode(mode));
|
||||
Integer indices = getAsInteger(meshObject, "indices");
|
||||
if (indices != null) {
|
||||
mesh.setBuffer(loadVertexBuffer(indices, VertexBuffer.Type.Index));
|
||||
|
||||
mesh.setBuffer(loadAccessorData(indices, new VertexBufferPopulator(VertexBuffer.Type.Index)));
|
||||
}
|
||||
JsonObject attributes = meshObject.getAsJsonObject("attributes");
|
||||
assertNotNull(attributes, "No attributes defined for mesh " + mesh);
|
||||
for (Map.Entry<String, JsonElement> entry : attributes.entrySet()) {
|
||||
mesh.setBuffer(loadVertexBuffer(entry.getValue().getAsInt(), getVertexBufferType(entry.getKey())));
|
||||
mesh.setBuffer(loadAccessorData(entry.getValue().getAsInt(), new VertexBufferPopulator(getVertexBufferType(entry.getKey()))));
|
||||
}
|
||||
Geometry geom = new Geometry(null, mesh);
|
||||
|
||||
@ -297,11 +309,10 @@ public class GltfLoader implements AssetLoader {
|
||||
return geomArray;
|
||||
}
|
||||
|
||||
private VertexBuffer loadVertexBuffer(int accessorIndex, VertexBuffer.Type bufferType) throws IOException {
|
||||
private <R> R loadAccessorData(int accessorIndex, Populator<R> populator) throws IOException {
|
||||
|
||||
assertNotNull(accessors, "No accessor attribute in the gltf file");
|
||||
|
||||
if (accessors == null) {
|
||||
throw new AssetLoadException("No accessor attribute in the gltf file");
|
||||
}
|
||||
JsonObject accessor = accessors.get(accessorIndex).getAsJsonObject();
|
||||
Integer bufferViewIndex = getAsInteger(accessor, "bufferView");
|
||||
int byteOffset = getAsInteger(accessor, "byteOffset", 0);
|
||||
@ -313,30 +324,16 @@ public class GltfLoader implements AssetLoader {
|
||||
String type = getAsString(accessor, "type");
|
||||
assertNotNull(type, "No type attribute defined for accessor " + accessorIndex);
|
||||
|
||||
VertexBuffer vb = new VertexBuffer(bufferType);
|
||||
VertexBuffer.Format format = getVertexBufferFormat(componentType);
|
||||
int numComponents = getNumberOfComponents(type);
|
||||
|
||||
Buffer buff = VertexBuffer.createBuffer(format, numComponents, count);
|
||||
readBuffer(bufferViewIndex, byteOffset, numComponents * count, buff, numComponents);
|
||||
if (bufferType == VertexBuffer.Type.Index) {
|
||||
numComponents = 3;
|
||||
}
|
||||
vb.setupData(VertexBuffer.Usage.Dynamic, numComponents, format, buff);
|
||||
|
||||
//TODO min / max
|
||||
//TODO sparse
|
||||
//TODO extensions?
|
||||
//TODO extras?
|
||||
return vb;
|
||||
|
||||
return populator.populate(bufferViewIndex, componentType, type, count, byteOffset);
|
||||
}
|
||||
|
||||
private void readBuffer(Integer bufferViewIndex, int byteOffset, int bufferSize, Buffer buff, int numComponents) throws IOException {
|
||||
if (bufferViewIndex == null) {
|
||||
//no referenced buffer, specs says to pad the buffer with zeros.
|
||||
padBuffer(buff, bufferSize);
|
||||
return;
|
||||
}
|
||||
private void readBuffer(Integer bufferViewIndex, int byteOffset, int bufferSize, Object store, int numComponents) throws IOException {
|
||||
|
||||
|
||||
JsonObject bufferView = bufferViews.get(bufferViewIndex).getAsJsonObject();
|
||||
Integer bufferIndex = getAsInteger(bufferView, "buffer");
|
||||
@ -351,7 +348,7 @@ public class GltfLoader implements AssetLoader {
|
||||
//int target = getAsInteger(bufferView, "target", 0);
|
||||
|
||||
byte[] data = readData(bufferIndex);
|
||||
populateBuffer(buff, data, bufferSize, byteOffset + bvByteOffset, byteStride, numComponents);
|
||||
populateBuffer(store, data, bufferSize, byteOffset + bvByteOffset, byteStride, numComponents);
|
||||
|
||||
//TODO extensions?
|
||||
//TODO extras?
|
||||
@ -360,9 +357,8 @@ public class GltfLoader implements AssetLoader {
|
||||
|
||||
private byte[] readData(int bufferIndex) throws IOException {
|
||||
|
||||
if (buffers == null) {
|
||||
throw new AssetLoadException("No buffer defined");
|
||||
}
|
||||
assertNotNull(buffers, "No buffer defined");
|
||||
|
||||
JsonObject buffer = buffers.get(bufferIndex).getAsJsonObject();
|
||||
String uri = getAsString(buffer, "uri");
|
||||
Integer bufferLength = getAsInteger(buffer, "byteLength");
|
||||
@ -398,9 +394,8 @@ public class GltfLoader implements AssetLoader {
|
||||
}
|
||||
|
||||
private Material loadMaterial(int materialIndex) {
|
||||
if (materials == null) {
|
||||
throw new AssetLoadException("There is no material defined yet a mesh references one");
|
||||
}
|
||||
assertNotNull(materials, "There is no material defined yet a mesh references one");
|
||||
|
||||
JsonObject matData = materials.get(materialIndex).getAsJsonObject();
|
||||
JsonObject pbrMat = matData.getAsJsonObject("pbrMetallicRoughness");
|
||||
|
||||
@ -448,12 +443,9 @@ public class GltfLoader implements AssetLoader {
|
||||
return null;
|
||||
}
|
||||
Integer textureIndex = getAsInteger(texture, "index");
|
||||
if (textureIndex == null) {
|
||||
throw new AssetLoadException("Texture as no index");
|
||||
}
|
||||
if (textures == null) {
|
||||
throw new AssetLoadException("There are no textures, yet one is referenced by a material");
|
||||
}
|
||||
assertNotNull(textureIndex, "Texture as no index");
|
||||
assertNotNull(textures, "There are no textures, yet one is referenced by a material");
|
||||
|
||||
JsonObject textureData = textures.get(textureIndex).getAsJsonObject();
|
||||
Integer sourceIndex = getAsInteger(textureData, "source");
|
||||
Integer samplerIndex = getAsInteger(textureData, "sampler");
|
||||
@ -487,6 +479,115 @@ public class GltfLoader implements AssetLoader {
|
||||
|
||||
}
|
||||
|
||||
private void loadAnimation(JsonObject animation) throws IOException {
|
||||
JsonArray channels = animation.getAsJsonArray("channels");
|
||||
JsonArray samplers = animation.getAsJsonArray("samplers");
|
||||
String name = getAsString(animation, "name");
|
||||
assertNotNull(channels, "No channels for animation " + name);
|
||||
assertNotNull(samplers, "No samplers for animation " + name);
|
||||
|
||||
//temp data storage of track data
|
||||
AnimData[] animatedNodes = new AnimData[nodes.size()];
|
||||
|
||||
for (JsonElement channel : channels) {
|
||||
|
||||
JsonObject target = channel.getAsJsonObject().getAsJsonObject("target");
|
||||
|
||||
Integer targetNode = getAsInteger(target, "node");
|
||||
String targetPath = getAsString(target, "path");
|
||||
if (targetNode == null) {
|
||||
//no target node for the channel, specs say to ignore the channel.
|
||||
continue;
|
||||
}
|
||||
assertNotNull(targetPath, "No target path for channel");
|
||||
|
||||
if (targetPath.equals("weight")) {
|
||||
//Morph animation, not implemented in JME, let's warn the user and skip the channel
|
||||
logger.log(Level.WARNING, "Morph animation is not supported by JME yet, skipping animation");
|
||||
continue;
|
||||
}
|
||||
AnimData animData = animatedNodes[targetNode];
|
||||
if (animData == null) {
|
||||
animData = new AnimData();
|
||||
animatedNodes[targetNode] = animData;
|
||||
}
|
||||
|
||||
Integer samplerIndex = getAsInteger(channel.getAsJsonObject(), "sampler");
|
||||
assertNotNull(samplerIndex, "No animation sampler provided for channel");
|
||||
JsonObject sampler = samplers.get(samplerIndex).getAsJsonObject();
|
||||
Integer timeIndex = getAsInteger(sampler, "input");
|
||||
assertNotNull(timeIndex, "No input accessor Provided for animation sampler");
|
||||
Integer dataIndex = getAsInteger(sampler, "output");
|
||||
assertNotNull(dataIndex, "No output accessor Provided for animation sampler");
|
||||
|
||||
String interpolation = getAsString(sampler, "interpolation");
|
||||
if (interpolation == null || !interpolation.equals("LINEAR")) {
|
||||
//JME anim system only supports Linear interpolation (will be possible with monkanim though)
|
||||
//TODO rework this once monkanim is core, or allow a hook for animation loading to fit custom animation systems
|
||||
logger.log(Level.WARNING, "JME only supports linear interpolation for animations");
|
||||
}
|
||||
|
||||
float[] times = fetchFromCache("accessors", timeIndex, float[].class);
|
||||
if (times == null) {
|
||||
times = loadAccessorData(timeIndex, floatArrayPopulator);
|
||||
addToCache("accessors", timeIndex, times, accessors.size());
|
||||
}
|
||||
if (animData.times == null) {
|
||||
animData.times = times;
|
||||
} else {
|
||||
//check if we are loading the same time array
|
||||
if (animData.times != times) {
|
||||
throw new AssetLoadException("Channel has different input accessors for samplers");
|
||||
}
|
||||
}
|
||||
if (animData.length == null) {
|
||||
//animation length is the last timestamp
|
||||
animData.length = times[times.length - 1];
|
||||
}
|
||||
if (targetPath.equals("translation")) {
|
||||
Vector3f[] translations = loadAccessorData(dataIndex, vector3fArrayPopulator);
|
||||
animData.translations = translations;
|
||||
} else if (targetPath.equals("scale")) {
|
||||
Vector3f[] scales = loadAccessorData(dataIndex, vector3fArrayPopulator);
|
||||
animData.scales = scales;
|
||||
} else if (targetPath.equals("rotation")) {
|
||||
Quaternion[] rotations = loadAccessorData(dataIndex, quaternionArrayPopulator);
|
||||
animData.rotations = rotations;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (int i = 0; i < animatedNodes.length; i++) {
|
||||
AnimData animData = animatedNodes[i];
|
||||
if (animData == null) {
|
||||
continue;
|
||||
}
|
||||
Object node = fetchFromCache("nodes", i, Object.class);
|
||||
if (node instanceof Spatial) {
|
||||
Spatial s = (Spatial) node;
|
||||
AnimControl control = s.getControl(AnimControl.class);
|
||||
if (control == null) {
|
||||
control = new AnimControl();
|
||||
s.addControl(control);
|
||||
}
|
||||
if (name == null) {
|
||||
name = s.getName() + "_anim_" + control.getAnimationNames().size();
|
||||
}
|
||||
Animation anim = new Animation(name, animData.length);
|
||||
anim.addTrack(new SpatialTrack(animData.times, animData.translations, animData.rotations, animData.scales));
|
||||
control.addAnim(anim);
|
||||
|
||||
} else {
|
||||
//At some pont we'll have bone animation
|
||||
//TODO support for bone animation.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//private void readAnimationSampler()
|
||||
|
||||
private void readSampler(int samplerIndex, Texture2D texture) {
|
||||
if (samplers == null) {
|
||||
throw new AssetLoadException("No samplers defined");
|
||||
@ -529,5 +630,112 @@ public class GltfLoader implements AssetLoader {
|
||||
data[index] = object;
|
||||
}
|
||||
|
||||
private class AnimData {
|
||||
Float length;
|
||||
float[] times;
|
||||
Vector3f[] translations;
|
||||
Quaternion[] rotations;
|
||||
Vector3f[] scales;
|
||||
float[] weights;
|
||||
}
|
||||
|
||||
private interface Populator<T> {
|
||||
T populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException;
|
||||
}
|
||||
|
||||
private class VertexBufferPopulator implements Populator<VertexBuffer> {
|
||||
VertexBuffer.Type bufferType;
|
||||
|
||||
public VertexBufferPopulator(VertexBuffer.Type bufferType) {
|
||||
this.bufferType = bufferType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexBuffer populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
|
||||
|
||||
VertexBuffer vb = new VertexBuffer(bufferType);
|
||||
VertexBuffer.Format format = getVertexBufferFormat(componentType);
|
||||
int numComponents = getNumberOfComponents(type);
|
||||
|
||||
Buffer buff = VertexBuffer.createBuffer(format, numComponents, count);
|
||||
int bufferSize = numComponents * count;
|
||||
if (bufferViewIndex == null) {
|
||||
//no referenced buffer, specs says to pad the buffer with zeros.
|
||||
padBuffer(buff, bufferSize);
|
||||
} else {
|
||||
readBuffer(bufferViewIndex, byteOffset, bufferSize, buff, numComponents);
|
||||
}
|
||||
|
||||
if (bufferType == VertexBuffer.Type.Index) {
|
||||
numComponents = 3;
|
||||
}
|
||||
vb.setupData(VertexBuffer.Usage.Dynamic, numComponents, format, buff);
|
||||
|
||||
|
||||
return vb;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class FloatArrayPopulator implements Populator<float[]> {
|
||||
|
||||
@Override
|
||||
public float[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
|
||||
|
||||
int numComponents = getNumberOfComponents(type);
|
||||
int dataSize = numComponents * count;
|
||||
float[] data = new float[count];
|
||||
|
||||
if (bufferViewIndex == null) {
|
||||
//no referenced buffer, specs says to pad the data with zeros.
|
||||
padBuffer(data, dataSize);
|
||||
} else {
|
||||
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class Vector3fArrayPopulator implements Populator<Vector3f[]> {
|
||||
|
||||
@Override
|
||||
public Vector3f[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
|
||||
|
||||
int numComponents = getNumberOfComponents(type);
|
||||
int dataSize = numComponents * count;
|
||||
Vector3f[] data = new Vector3f[count];
|
||||
|
||||
if (bufferViewIndex == null) {
|
||||
//no referenced buffer, specs says to pad the data with zeros.
|
||||
padBuffer(data, dataSize);
|
||||
} else {
|
||||
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
private class QuaternionArrayPopulator implements Populator<Quaternion[]> {
|
||||
|
||||
@Override
|
||||
public Quaternion[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
|
||||
|
||||
int numComponents = getNumberOfComponents(type);
|
||||
int dataSize = numComponents * count;
|
||||
Quaternion[] data = new Quaternion[count];
|
||||
|
||||
if (bufferViewIndex == null) {
|
||||
//no referenced buffer, specs says to pad the data with zeros.
|
||||
padBuffer(data, dataSize);
|
||||
} else {
|
||||
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@ package com.jme3.scene.plugins.gltf;
|
||||
import com.google.gson.*;
|
||||
import com.jme3.asset.AssetLoadException;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Mesh;
|
||||
import com.jme3.scene.VertexBuffer;
|
||||
import com.jme3.texture.Texture;
|
||||
@ -109,7 +111,7 @@ public class GltfUtils {
|
||||
return VertexBuffer.Type.Color;
|
||||
case "JOINTS_0":
|
||||
return VertexBuffer.Type.BoneIndex;
|
||||
case "WEIGHT_0":
|
||||
case "WEIGHTS_0":
|
||||
return VertexBuffer.Type.BoneWeight;
|
||||
default:
|
||||
throw new AssetLoadException("Unsupported buffer attribute: " + attribute);
|
||||
@ -166,48 +168,79 @@ public class GltfUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static void padBuffer(Buffer buffer, int bufferSize) {
|
||||
buffer.clear();
|
||||
if (buffer instanceof IntBuffer) {
|
||||
IntBuffer ib = (IntBuffer) buffer;
|
||||
for (int i = 0; i < bufferSize; i++) {
|
||||
ib.put(0);
|
||||
public static void padBuffer(Object store, int bufferSize) {
|
||||
if (store instanceof Buffer) {
|
||||
Buffer buffer = (Buffer) store;
|
||||
buffer.clear();
|
||||
if (buffer instanceof IntBuffer) {
|
||||
IntBuffer ib = (IntBuffer) buffer;
|
||||
for (int i = 0; i < bufferSize; i++) {
|
||||
ib.put(0);
|
||||
}
|
||||
} else if (buffer instanceof FloatBuffer) {
|
||||
FloatBuffer fb = (FloatBuffer) buffer;
|
||||
for (int i = 0; i < bufferSize; i++) {
|
||||
fb.put(0);
|
||||
}
|
||||
} else if (buffer instanceof ShortBuffer) {
|
||||
ShortBuffer sb = (ShortBuffer) buffer;
|
||||
for (int i = 0; i < bufferSize; i++) {
|
||||
sb.put((short) 0);
|
||||
}
|
||||
} else if (buffer instanceof ByteBuffer) {
|
||||
ByteBuffer bb = (ByteBuffer) buffer;
|
||||
for (int i = 0; i < bufferSize; i++) {
|
||||
bb.put((byte) 0);
|
||||
}
|
||||
}
|
||||
} else if (buffer instanceof FloatBuffer) {
|
||||
FloatBuffer fb = (FloatBuffer) buffer;
|
||||
for (int i = 0; i < bufferSize; i++) {
|
||||
fb.put(0);
|
||||
buffer.rewind();
|
||||
}
|
||||
if (store instanceof float[]) {
|
||||
float[] array = (float[]) store;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = 0;
|
||||
}
|
||||
} else if (buffer instanceof ShortBuffer) {
|
||||
ShortBuffer sb = (ShortBuffer) buffer;
|
||||
for (int i = 0; i < bufferSize; i++) {
|
||||
sb.put((short) 0);
|
||||
} else if (store instanceof Vector3f[]) {
|
||||
Vector3f[] array = (Vector3f[]) store;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = new Vector3f();
|
||||
}
|
||||
} else if (buffer instanceof ByteBuffer) {
|
||||
ByteBuffer bb = (ByteBuffer) buffer;
|
||||
for (int i = 0; i < bufferSize; i++) {
|
||||
bb.put((byte) 0);
|
||||
} else if (store instanceof Quaternion[]) {
|
||||
Quaternion[] array = (Quaternion[]) store;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = new Quaternion();
|
||||
}
|
||||
}
|
||||
buffer.rewind();
|
||||
}
|
||||
|
||||
public static void populateBuffer(Buffer buffer, byte[] source, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
||||
buffer.clear();
|
||||
public static void populateBuffer(Object store, byte[] source, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
||||
|
||||
if (buffer instanceof ByteBuffer) {
|
||||
populateByteBuffer((ByteBuffer) buffer, source, length, byteOffset, byteStride, numComponents);
|
||||
if (store instanceof Buffer) {
|
||||
Buffer buffer = (Buffer) store;
|
||||
buffer.clear();
|
||||
if (buffer instanceof ByteBuffer) {
|
||||
populateByteBuffer((ByteBuffer) buffer, source, length, byteOffset, byteStride, numComponents);
|
||||
return;
|
||||
}
|
||||
LittleEndien stream = getStream(source);
|
||||
if (buffer instanceof ShortBuffer) {
|
||||
populateShortBuffer((ShortBuffer) buffer, stream, length, byteOffset, byteStride, numComponents);
|
||||
} else if (buffer instanceof IntBuffer) {
|
||||
populateIntBuffer((IntBuffer) buffer, stream, length, byteOffset, byteStride, numComponents);
|
||||
} else if (buffer instanceof FloatBuffer) {
|
||||
populateFloatBuffer((FloatBuffer) buffer, stream, length, byteOffset, byteStride, numComponents);
|
||||
}
|
||||
buffer.rewind();
|
||||
return;
|
||||
}
|
||||
LittleEndien stream = getStream(source);
|
||||
if (buffer instanceof ShortBuffer) {
|
||||
populateShortBuffer((ShortBuffer) buffer, stream, length, byteOffset, byteStride, numComponents);
|
||||
} else if (buffer instanceof IntBuffer) {
|
||||
populateIntBuffer((IntBuffer) buffer, stream, length, byteOffset, byteStride, numComponents);
|
||||
} else if (buffer instanceof FloatBuffer) {
|
||||
populateFloatBuffer((FloatBuffer) buffer, stream, length, byteOffset, byteStride, numComponents);
|
||||
if (store instanceof float[]) {
|
||||
populateFloatArray((float[]) store, stream, length, byteOffset, byteStride, numComponents);
|
||||
} else if (store instanceof Vector3f[]) {
|
||||
populateVector3fArray((Vector3f[]) store, stream, length, byteOffset, byteStride, numComponents);
|
||||
} else if (store instanceof Quaternion[]) {
|
||||
populateQuaternionArray((Quaternion[]) store, stream, length, byteOffset, byteStride, numComponents);
|
||||
}
|
||||
buffer.rewind();
|
||||
}
|
||||
|
||||
private static void populateByteBuffer(ByteBuffer buffer, byte[] source, int length, int byteOffset, int byteStride, int numComponents) {
|
||||
@ -260,6 +293,61 @@ public class GltfUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static void populateFloatArray(float[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
||||
int index = byteOffset;
|
||||
int componentSize = 4;
|
||||
int end = length * componentSize + byteOffset;
|
||||
stream.skipBytes(byteOffset);
|
||||
int arrayIndex = 0;
|
||||
while (index < end) {
|
||||
for (int i = 0; i < numComponents; i++) {
|
||||
array[arrayIndex] = stream.readFloat();
|
||||
arrayIndex++;
|
||||
}
|
||||
|
||||
index += Math.max(componentSize * numComponents, byteStride);
|
||||
}
|
||||
}
|
||||
|
||||
private static void populateVector3fArray(Vector3f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
||||
int index = byteOffset;
|
||||
int componentSize = 4;
|
||||
int end = length * componentSize + byteOffset;
|
||||
stream.skipBytes(byteOffset);
|
||||
int arrayIndex = 0;
|
||||
while (index < end) {
|
||||
array[arrayIndex] = new Vector3f(
|
||||
stream.readFloat(),
|
||||
stream.readFloat(),
|
||||
stream.readFloat()
|
||||
);
|
||||
|
||||
arrayIndex++;
|
||||
|
||||
index += Math.max(componentSize * numComponents, byteStride);
|
||||
}
|
||||
}
|
||||
|
||||
private static void populateQuaternionArray(Quaternion[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
||||
int index = byteOffset;
|
||||
int componentSize = 4;
|
||||
int end = length * componentSize + byteOffset;
|
||||
stream.skipBytes(byteOffset);
|
||||
int arrayIndex = 0;
|
||||
while (index < end) {
|
||||
array[arrayIndex] = new Quaternion(
|
||||
stream.readFloat(),
|
||||
stream.readFloat(),
|
||||
stream.readFloat(),
|
||||
stream.readFloat()
|
||||
);
|
||||
|
||||
arrayIndex++;
|
||||
|
||||
index += Math.max(componentSize * numComponents, byteStride);
|
||||
}
|
||||
}
|
||||
|
||||
private static LittleEndien getStream(byte[] buffer) {
|
||||
return new LittleEndien(new DataInputStream(new ByteArrayInputStream(buffer)));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user