|
@@ -2,6 +2,9 @@ package com.jme3.scene.plugins.gltf;
|
|
|
|
|
|
import com.google.gson.*;
|
|
import com.google.gson.*;
|
|
import com.google.gson.stream.JsonReader;
|
|
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.asset.*;
|
|
import com.jme3.material.Material;
|
|
import com.jme3.material.Material;
|
|
import com.jme3.material.RenderState;
|
|
import com.jme3.material.RenderState;
|
|
@@ -41,9 +44,14 @@ public class GltfLoader implements AssetLoader {
|
|
private JsonArray textures;
|
|
private JsonArray textures;
|
|
private JsonArray images;
|
|
private JsonArray images;
|
|
private JsonArray samplers;
|
|
private JsonArray samplers;
|
|
|
|
+ private JsonArray animations;
|
|
|
|
+
|
|
private Material defaultMat;
|
|
private Material defaultMat;
|
|
private AssetInfo info;
|
|
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 static Map<String, MaterialAdapter> defaultMaterialAdapters = new HashMap<>();
|
|
private boolean useNormalsFlag = false;
|
|
private boolean useNormalsFlag = false;
|
|
|
|
|
|
@@ -85,6 +93,7 @@ public class GltfLoader implements AssetLoader {
|
|
textures = root.getAsJsonArray("textures");
|
|
textures = root.getAsJsonArray("textures");
|
|
images = root.getAsJsonArray("images");
|
|
images = root.getAsJsonArray("images");
|
|
samplers = root.getAsJsonArray("samplers");
|
|
samplers = root.getAsJsonArray("samplers");
|
|
|
|
+ animations = root.getAsJsonArray("animations");
|
|
|
|
|
|
JsonPrimitive defaultScene = root.getAsJsonPrimitive("scene");
|
|
JsonPrimitive defaultScene = root.getAsJsonPrimitive("scene");
|
|
|
|
|
|
@@ -127,6 +136,13 @@ public class GltfLoader implements AssetLoader {
|
|
root.attachChild(sceneNode);
|
|
root.attachChild(sceneNode);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //Loading animations
|
|
|
|
+ if (animations != null) {
|
|
|
|
+ for (JsonElement animation : animations) {
|
|
|
|
+ loadAnimation(animation.getAsJsonObject());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
//Setting the default scene cul hint to inherit.
|
|
//Setting the default scene cul hint to inherit.
|
|
int activeChild = 0;
|
|
int activeChild = 0;
|
|
if (defaultScene != null) {
|
|
if (defaultScene != null) {
|
|
@@ -147,9 +163,7 @@ public class GltfLoader implements AssetLoader {
|
|
JsonArray children = nodeData.getAsJsonArray("children");
|
|
JsonArray children = nodeData.getAsJsonArray("children");
|
|
Integer meshIndex = getAsInteger(nodeData, "mesh");
|
|
Integer meshIndex = getAsInteger(nodeData, "mesh");
|
|
if (meshIndex != null) {
|
|
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),
|
|
//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.
|
|
//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();
|
|
JsonObject meshData = meshes.get(meshIndex).getAsJsonObject();
|
|
JsonArray primitives = meshData.getAsJsonArray("primitives");
|
|
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");
|
|
String name = getAsString(meshData, "name");
|
|
|
|
|
|
geomArray = new Geometry[primitives.size()];
|
|
geomArray = new Geometry[primitives.size()];
|
|
@@ -256,13 +269,12 @@ public class GltfLoader implements AssetLoader {
|
|
mesh.setMode(getMeshMode(mode));
|
|
mesh.setMode(getMeshMode(mode));
|
|
Integer indices = getAsInteger(meshObject, "indices");
|
|
Integer indices = getAsInteger(meshObject, "indices");
|
|
if (indices != null) {
|
|
if (indices != null) {
|
|
- mesh.setBuffer(loadVertexBuffer(indices, VertexBuffer.Type.Index));
|
|
|
|
-
|
|
|
|
|
|
+ mesh.setBuffer(loadAccessorData(indices, new VertexBufferPopulator(VertexBuffer.Type.Index)));
|
|
}
|
|
}
|
|
JsonObject attributes = meshObject.getAsJsonObject("attributes");
|
|
JsonObject attributes = meshObject.getAsJsonObject("attributes");
|
|
assertNotNull(attributes, "No attributes defined for mesh " + mesh);
|
|
assertNotNull(attributes, "No attributes defined for mesh " + mesh);
|
|
for (Map.Entry<String, JsonElement> entry : attributes.entrySet()) {
|
|
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);
|
|
Geometry geom = new Geometry(null, mesh);
|
|
|
|
|
|
@@ -297,11 +309,10 @@ public class GltfLoader implements AssetLoader {
|
|
return geomArray;
|
|
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();
|
|
JsonObject accessor = accessors.get(accessorIndex).getAsJsonObject();
|
|
Integer bufferViewIndex = getAsInteger(accessor, "bufferView");
|
|
Integer bufferViewIndex = getAsInteger(accessor, "bufferView");
|
|
int byteOffset = getAsInteger(accessor, "byteOffset", 0);
|
|
int byteOffset = getAsInteger(accessor, "byteOffset", 0);
|
|
@@ -313,30 +324,16 @@ public class GltfLoader implements AssetLoader {
|
|
String type = getAsString(accessor, "type");
|
|
String type = getAsString(accessor, "type");
|
|
assertNotNull(type, "No type attribute defined for accessor " + accessorIndex);
|
|
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 min / max
|
|
//TODO sparse
|
|
//TODO sparse
|
|
//TODO extensions?
|
|
//TODO extensions?
|
|
//TODO extras?
|
|
//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();
|
|
JsonObject bufferView = bufferViews.get(bufferViewIndex).getAsJsonObject();
|
|
Integer bufferIndex = getAsInteger(bufferView, "buffer");
|
|
Integer bufferIndex = getAsInteger(bufferView, "buffer");
|
|
@@ -351,7 +348,7 @@ public class GltfLoader implements AssetLoader {
|
|
//int target = getAsInteger(bufferView, "target", 0);
|
|
//int target = getAsInteger(bufferView, "target", 0);
|
|
|
|
|
|
byte[] data = readData(bufferIndex);
|
|
byte[] data = readData(bufferIndex);
|
|
- populateBuffer(buff, data, bufferSize, byteOffset + bvByteOffset, byteStride, numComponents);
|
|
|
|
|
|
+ populateBuffer(store, data, bufferSize, byteOffset + bvByteOffset, byteStride, numComponents);
|
|
|
|
|
|
//TODO extensions?
|
|
//TODO extensions?
|
|
//TODO extras?
|
|
//TODO extras?
|
|
@@ -360,9 +357,8 @@ public class GltfLoader implements AssetLoader {
|
|
|
|
|
|
private byte[] readData(int bufferIndex) throws IOException {
|
|
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();
|
|
JsonObject buffer = buffers.get(bufferIndex).getAsJsonObject();
|
|
String uri = getAsString(buffer, "uri");
|
|
String uri = getAsString(buffer, "uri");
|
|
Integer bufferLength = getAsInteger(buffer, "byteLength");
|
|
Integer bufferLength = getAsInteger(buffer, "byteLength");
|
|
@@ -398,9 +394,8 @@ public class GltfLoader implements AssetLoader {
|
|
}
|
|
}
|
|
|
|
|
|
private Material loadMaterial(int materialIndex) {
|
|
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 matData = materials.get(materialIndex).getAsJsonObject();
|
|
JsonObject pbrMat = matData.getAsJsonObject("pbrMetallicRoughness");
|
|
JsonObject pbrMat = matData.getAsJsonObject("pbrMetallicRoughness");
|
|
|
|
|
|
@@ -448,12 +443,9 @@ public class GltfLoader implements AssetLoader {
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
Integer textureIndex = getAsInteger(texture, "index");
|
|
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();
|
|
JsonObject textureData = textures.get(textureIndex).getAsJsonObject();
|
|
Integer sourceIndex = getAsInteger(textureData, "source");
|
|
Integer sourceIndex = getAsInteger(textureData, "source");
|
|
Integer samplerIndex = getAsInteger(textureData, "sampler");
|
|
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) {
|
|
private void readSampler(int samplerIndex, Texture2D texture) {
|
|
if (samplers == null) {
|
|
if (samplers == null) {
|
|
throw new AssetLoadException("No samplers defined");
|
|
throw new AssetLoadException("No samplers defined");
|
|
@@ -529,5 +630,112 @@ public class GltfLoader implements AssetLoader {
|
|
data[index] = object;
|
|
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;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|