Prechádzať zdrojové kódy

Merge remote-tracking branch 'origin/master' into opengles2-fixes

Kirill Vainer 8 rokov pred
rodič
commit
134c3651c8

+ 3 - 0
.travis.yml

@@ -19,6 +19,9 @@ matrix:
 
 addons:
   ssh_known_hosts: github.com
+  hosts:
+    - travisci
+  hostname: travisci
   apt:
     packages:
     - gcc-multilib

+ 3 - 1
jme3-core/src/main/java/com/jme3/animation/Skeleton.java

@@ -70,7 +70,7 @@ public final class Skeleton implements Savable, JmeCloneable {
     public Skeleton(Bone[] boneList) {
         this.boneList = boneList;
 
-        List<Bone> rootBoneList = new ArrayList<Bone>();
+        List<Bone> rootBoneList = new ArrayList<>();
         for (int i = boneList.length - 1; i >= 0; i--) {
             Bone b = boneList[i];
             if (b.getParent() == null) {
@@ -289,6 +289,7 @@ public final class Skeleton implements Savable, JmeCloneable {
         return sb.toString();
     }
 
+    @Override
     public void read(JmeImporter im) throws IOException {
         InputCapsule input = im.getCapsule(this);
 
@@ -308,6 +309,7 @@ public final class Skeleton implements Savable, JmeCloneable {
         }
     }
 
+    @Override
     public void write(JmeExporter ex) throws IOException {
         OutputCapsule output = ex.getCapsule(this);
         output.write(rootBones, "rootBones", null);

+ 52 - 83
jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java

@@ -32,8 +32,7 @@
 package com.jme3.animation;
 
 import com.jme3.export.*;
-import com.jme3.material.MatParam;
-import com.jme3.material.Material;
+import com.jme3.material.MatParamOverride;
 import com.jme3.math.FastMath;
 import com.jme3.math.Matrix4f;
 import com.jme3.renderer.RenderManager;
@@ -43,6 +42,7 @@ import com.jme3.scene.*;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.control.AbstractControl;
 import com.jme3.scene.control.Control;
+import com.jme3.scene.mesh.IndexBuffer;
 import com.jme3.shader.VarType;
 import com.jme3.util.*;
 import com.jme3.util.clone.Cloner;
@@ -51,8 +51,6 @@ import java.io.IOException;
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.FloatBuffer;
-import java.util.HashSet;
-import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -107,13 +105,11 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
      * Bone offset matrices, recreated each frame
      */
     private transient Matrix4f[] offsetMatrices;
-    /**
-     * Material references used for hardware skinning
-     */
-    private Set<Material> materials = new HashSet<Material>();
 
-    //temp reader
-    private BufferUtils.ByteShortIntBufferReader indexReader = new BufferUtils.ByteShortIntBufferReader();
+    
+    private MatParamOverride numberOfBonesParam;
+    private MatParamOverride boneMatricesParam;
+    
     /**
      * Serialization only. Do not use.
      */
@@ -121,11 +117,13 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
     }
 
     private void switchToHardware() {
+        numberOfBonesParam.setEnabled(true);
+        boneMatricesParam.setEnabled(true);
+        
         // Next full 10 bones (e.g. 30 on 24 bones)
         int numBones = ((skeleton.getBoneCount() / 10) + 1) * 10;
-        for (Material m : materials) {
-            m.setInt("NumberOfBones", numBones);
-        }
+        numberOfBonesParam.setValue(numBones);
+        
         for (Geometry geometry : targets) {
             Mesh mesh = geometry.getMesh();
             if (mesh != null && mesh.isAnimated()) {
@@ -135,11 +133,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
     }
 
     private void switchToSoftware() {
-        for (Material m : materials) {
-            if (m.getParam("NumberOfBones") != null) {
-                m.clearParam("NumberOfBones");
-            }
-        }
+        numberOfBonesParam.setEnabled(false);
+        boneMatricesParam.setEnabled(false);
+        
         for (Geometry geometry : targets) {
             Mesh mesh = geometry.getMesh();
             if (mesh != null && mesh.isAnimated()) {
@@ -149,19 +145,6 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
     }
 
     private boolean testHardwareSupported(RenderManager rm) {
-        for (Material m : materials) {
-            // Some of the animated mesh(es) do not support hardware skinning,
-            // so it is not supported by the model.
-            if (m.getMaterialDef().getMaterialParam("NumberOfBones") == null) {
-                Logger.getLogger(SkeletonControl.class.getName()).log(Level.WARNING, 
-                        "Not using hardware skinning for {0}, " + 
-                        "because material {1} doesn''t support it.", 
-                        new Object[]{spatial, m.getMaterialDef().getName()});
-                
-                return false;
-            }
-        }
-
         switchToHardware();
         
         try {
@@ -178,6 +161,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
      * supported by GPU, it shall be enabled, if its not preferred, or not
      * supported by GPU, then it shall be disabled.
      * 
+     * @param preferred
      * @see #isHardwareSkinningUsed() 
      */
     public void setHardwareSkinningPreferred(boolean preferred) {
@@ -212,6 +196,8 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
             throw new IllegalArgumentException("skeleton cannot be null");
         }
         this.skeleton = skeleton;
+        this.numberOfBonesParam = new MatParamOverride(VarType.Int, "NumberOfBones", null);
+        this.boneMatricesParam = new MatParamOverride(VarType.Matrix4Array, "BoneMatrices", null);
     }
 
     /**
@@ -222,8 +208,8 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
         Mesh mesh = geometry.getMesh();
         if (mesh != null && mesh.isAnimated()) {
             targets.add(geometry);
-            materials.add(geometry.getMaterial());
         }
+        
     }
 
     private void findTargets(Node node) {
@@ -238,8 +224,21 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
 
     @Override
     public void setSpatial(Spatial spatial) {
+        Spatial oldSpatial = this.spatial;
         super.setSpatial(spatial);
         updateTargetsAndMaterials(spatial);
+        
+        if (oldSpatial != null) {
+            oldSpatial.removeMatParamOverride(numberOfBonesParam);
+            oldSpatial.removeMatParamOverride(boneMatricesParam);
+        }
+        
+        if (spatial != null) {
+            spatial.removeMatParamOverride(numberOfBonesParam);
+            spatial.removeMatParamOverride(boneMatricesParam);
+            spatial.addMatParamOverride(numberOfBonesParam);
+            spatial.addMatParamOverride(boneMatricesParam);
+        }
     }
 
     private void controlRenderSoftware() {
@@ -258,27 +257,8 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
     
     private void controlRenderHardware() {
         offsetMatrices = skeleton.computeSkinningMatrices();
-        for (Material m : materials) {
-            MatParam currentParam = m.getParam("BoneMatrices");
-
-            if (currentParam != null) {
-                if (currentParam.getValue() != offsetMatrices) {
-                    // Check to see if other SkeletonControl
-                    // is operating on this material, in that case, user
-                    // is sharing materials between models which is NOT allowed
-                    // when hardware skinning used.
-                    
-                    Logger.getLogger(SkeletonControl.class.getName()).log(Level.SEVERE,
-                            "Material instances cannot be shared when hardware skinning is used. " +
-                            "Ensure all models use unique material instances."
-                    );
-                }
-            }
-            
-            m.setParam("BoneMatrices", VarType.Matrix4Array, offsetMatrices);
-        }
+        boneMatricesParam.setValue(offsetMatrices);
     }
-
     
     @Override
     protected void controlRender(RenderManager rm, ViewPort vp) {
@@ -296,7 +276,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
                 if (hwSkinningSupported) {
                     hwSkinningEnabled = true;
                     
-                    Logger.getLogger(SkeletonControl.class.getName()).log(Level.INFO, "Hardware skinning engaged for " + spatial);
+                    Logger.getLogger(SkeletonControl.class.getName()).log(Level.INFO, "Hardware skinning engaged for {0}", spatial);
                 } else {
                     switchToSoftware();
                 }
@@ -420,28 +400,8 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
         // were shared then this will share them.
         this.targets = cloner.clone(targets);
         
-        // Not automatic set cloning yet
-        Set<Material> newMaterials = new HashSet<Material>();
-        for( Material m : this.materials ) {
-            Material mClone = cloner.clone(m);
-            newMaterials.add(mClone);
-            if( mClone != m ) {
-                // Material was really cloned so clear the bone matrices in case
-                // this is hardware skinned.  This allows a local version to be
-                // used and will be reset on the material.  Really this just avoids
-                // the 'safety' check in controlRenderHardware().  Right now material
-                // doesn't clone itself with the cloner (and doesn't clone its parameters)
-                // else this would be unnecessary.
-                MatParam boneMatrices = mClone.getParam("BoneMatrices");
-                
-                // ...because for some strange reason you can't clear a non-existant 
-                // parameter.
-                if( boneMatrices != null ) {                    
-                    mClone.clearParam("BoneMatrices");
-                }
-            }
-        }
-        this.materials = newMaterials;
+        this.numberOfBonesParam = cloner.clone(numberOfBonesParam);
+        this.boneMatricesParam = cloner.clone(boneMatricesParam);
     }
          
     /**
@@ -547,10 +507,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
         fnb.rewind();
 
         // get boneIndexes and weights for mesh
-        indexReader.setBuffer(mesh.getBuffer(Type.BoneIndex).getData());
+        IndexBuffer ib = IndexBuffer.wrapIndexBuffer(mesh.getBuffer(Type.BoneIndex).getData());
         FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
 
-        indexReader.rewind();
         wb.rewind();
 
         float[] weights = wb.array();
@@ -591,7 +550,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
 
                 for (int w = maxWeightsPerVert - 1; w >= 0; w--) {
                     float weight = weights[idxWeights];
-                    Matrix4f mat = offsetMatrices[indexReader.getUnsigned(idxWeights++)];
+                    Matrix4f mat = offsetMatrices[ib.get(idxWeights++)];
 
                     rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight;
                     ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight;
@@ -664,10 +623,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
 
 
         // get boneIndexes and weights for mesh
-        indexReader.setBuffer(mesh.getBuffer(Type.BoneIndex).getData());
+        IndexBuffer ib = IndexBuffer.wrapIndexBuffer(mesh.getBuffer(Type.BoneIndex).getData());
         FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
 
-        indexReader.rewind();
         wb.rewind();
 
         float[] weights = wb.array();
@@ -723,7 +681,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
 
                 for (int w = maxWeightsPerVert - 1; w >= 0; w--) {
                     float weight = weights[idxWeights];
-                    Matrix4f mat = offsetMatrices[indexReader.getUnsigned(idxWeights++)];
+                    Matrix4f mat = offsetMatrices[ib.get(idxWeights++)];
 
                     rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight;
                     ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight;
@@ -781,7 +739,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
         super.write(ex);
         OutputCapsule oc = ex.getCapsule(this);
         oc.write(skeleton, "skeleton", null);
-        //Targets and materials don't need to be saved, they'll be gathered on each frame
+        
+        oc.write(numberOfBonesParam, "numberOfBonesParam", null);
+        oc.write(boneMatricesParam, "boneMatricesParam", null);
     }
 
     @Override
@@ -789,6 +749,16 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
         super.read(im);
         InputCapsule in = im.getCapsule(this);
         skeleton = (Skeleton) in.readSavable("skeleton", null);
+        
+        numberOfBonesParam = (MatParamOverride) in.readSavable("numberOfBonesParam", null);
+        boneMatricesParam = (MatParamOverride) in.readSavable("boneMatricesParam", null);
+        
+        if (numberOfBonesParam == null) {
+            numberOfBonesParam = new MatParamOverride(VarType.Int, "NumberOfBones", null);
+            boneMatricesParam = new MatParamOverride(VarType.Matrix4Array, "BoneMatrices", null);
+            getSpatial().addMatParamOverride(numberOfBonesParam);
+            getSpatial().addMatParamOverride(boneMatricesParam);
+        }
     }
 
     /**
@@ -798,7 +768,6 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
      */
     private void updateTargetsAndMaterials(Spatial spatial) {
         targets.clear();
-        materials.clear();
 
         if (spatial instanceof Node) {
             findTargets((Node) spatial);

+ 6 - 1
jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java

@@ -216,9 +216,14 @@ public final class GLImageFormats {
         
         // Need to check if Caps.DepthTexture is supported prior to using for textures
         // But for renderbuffers its OK.
-        format(formatToGL, Format.Depth,   GL.GL_DEPTH_COMPONENT,    GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_BYTE);
         format(formatToGL, Format.Depth16, GL.GL_DEPTH_COMPONENT16,  GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_SHORT);
         
+        // NOTE: OpenGL ES 2.0 does not support DEPTH_COMPONENT as internal format -- fallback to 16-bit depth.
+        if (caps.contains(Caps.OpenGLES20)) {
+            format(formatToGL, Format.Depth, GL.GL_DEPTH_COMPONENT16, GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_BYTE);
+        } else {
+            format(formatToGL, Format.Depth, GL.GL_DEPTH_COMPONENT, GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_BYTE);
+        }
         if (caps.contains(Caps.OpenGL20)) {
             format(formatToGL, Format.Depth24, GL2.GL_DEPTH_COMPONENT24,  GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_INT);
         }

+ 1 - 1
jme3-core/src/main/java/com/jme3/scene/Mesh.java

@@ -1447,7 +1447,7 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
             return false; // no bone animation data
         }
 
-        BufferUtils.ByteShortIntBufferReader boneIndexBuffer = new BufferUtils.ByteShortIntBufferReader(biBuf.getData());
+        IndexBuffer boneIndexBuffer = IndexBuffer.wrapIndexBuffer(biBuf.getData());
         boneIndexBuffer.rewind();
         int numBoneIndices = boneIndexBuffer.remaining();
         assert numBoneIndices % 4 == 0 : numBoneIndices;

+ 23 - 1
jme3-core/src/main/java/com/jme3/scene/mesh/IndexBuffer.java

@@ -75,7 +75,29 @@ public abstract class IndexBuffer {
             return new IndexShortBuffer(BufferUtils.createShortBuffer(indexCount));
         }
     }
-    
+
+    /**
+     * @see Buffer#rewind()
+     */
+    public void rewind() {
+        getBuffer().rewind();
+    }
+
+    /**
+     * @return
+     * @see Buffer#remaining()
+     */
+    public int remaining() {
+        return getBuffer().remaining();
+    }
+
+    /**
+     * Returns the vertex index for the current position.
+     *
+     * @return
+     */
+    public abstract int get();
+
     /**
      * Returns the vertex index for the given index in the index buffer.
      * 

+ 6 - 1
jme3-core/src/main/java/com/jme3/scene/mesh/IndexByteBuffer.java

@@ -47,7 +47,12 @@ public class IndexByteBuffer extends IndexBuffer {
         buf = buffer;
         buf.rewind();
     }
-    
+
+    @Override
+    public int get() {
+        return buf.get() & 0x000000FF;
+    }
+
     @Override
     public int get(int i) {
         return buf.get(i) & 0x000000FF;

+ 4 - 0
jme3-core/src/main/java/com/jme3/scene/mesh/IndexIntBuffer.java

@@ -48,6 +48,10 @@ public class IndexIntBuffer extends IndexBuffer {
         buf.rewind();
     }
 
+    @Override
+    public int get() {
+        return buf.get();
+    }
     @Override
     public int get(int i) {
         return buf.get(i);

+ 4 - 0
jme3-core/src/main/java/com/jme3/scene/mesh/IndexShortBuffer.java

@@ -48,6 +48,10 @@ public class IndexShortBuffer extends IndexBuffer {
         buf.rewind();
     }
 
+    @Override
+    public int get() {
+        return buf.get() & 0x0000FFFF;
+    }
     @Override
     public int get(int i) {
         return buf.get(i) & 0x0000FFFF;

+ 18 - 0
jme3-core/src/main/java/com/jme3/scene/mesh/VirtualIndexBuffer.java

@@ -55,6 +55,7 @@ public class VirtualIndexBuffer extends IndexBuffer {
     protected int numVerts = 0;
     protected int numIndices = 0;
     protected Mode meshMode;
+    protected int position = 0;
  
     public VirtualIndexBuffer(int numVerts, Mode meshMode){
         this.numVerts = numVerts;
@@ -86,6 +87,23 @@ public class VirtualIndexBuffer extends IndexBuffer {
         }
     }
 
+    @Override
+    public int get() {
+        int i = get(position);
+        position++;
+        return i;
+    }
+
+    @Override
+    public void rewind() {
+        position = 0;
+    }
+
+    @Override
+    public int remaining() {
+        return numIndices - position;
+    }
+
     @Override
     public int get(int i) {
         if (meshMode == Mode.Triangles || meshMode == Mode.Lines || meshMode == Mode.Points){

+ 0 - 58
jme3-core/src/main/java/com/jme3/util/BufferUtils.java

@@ -1341,62 +1341,4 @@ public final class BufferUtils {
         }
     }
 
-    public static class ByteShortIntBufferReader {
-        Buffer buffer;
-
-        public ByteShortIntBufferReader() {
-        }
-
-        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 int getUnsigned(int index) {
-            if (buffer instanceof ByteBuffer) {
-                return ((ByteBuffer) buffer).get(index) & 0xff;
-            } else if (buffer instanceof ShortBuffer) {
-                return ((ShortBuffer) buffer).get(index) & 0xffff;
-            } else if (buffer instanceof IntBuffer) {
-                return ((IntBuffer) buffer).get(index) & 0xffffff;
-            } else {
-                throw new UnsupportedOperationException("Buffer must be a ByteBuffer, a ShortBuffer or an IntBuffer");
-            }
-        }
-
-        public void setBuffer(Buffer buffer) {
-            this.buffer = buffer;
-        }
-
-        public void rewind() {
-            buffer.rewind();
-        }
-
-        public int remaining() {
-            return buffer.remaining();
-        }
-    }
 }

+ 4 - 1
jme3-lwjgl3/build.gradle

@@ -2,7 +2,7 @@ if (!hasProperty('mainClass')) {
     ext.mainClass = ''
 }
 
-def lwjglVersion = '3.1.0'
+def lwjglVersion = '3.1.2'
 
 sourceCompatibility = '1.8'
 
@@ -25,6 +25,9 @@ dependencies {
     runtime "org.lwjgl:lwjgl-jemalloc:${lwjglVersion}:natives-windows"
     runtime "org.lwjgl:lwjgl-jemalloc:${lwjglVersion}:natives-linux"
     runtime "org.lwjgl:lwjgl-jemalloc:${lwjglVersion}:natives-macos"
+    runtime "org.lwjgl:lwjgl-opengl:${lwjglVersion}:natives-windows"
+    runtime "org.lwjgl:lwjgl-opengl:${lwjglVersion}:natives-linux"
+    runtime "org.lwjgl:lwjgl-opengl:${lwjglVersion}:natives-macos"
     runtime "org.lwjgl:lwjgl-openal:${lwjglVersion}:natives-windows"
     runtime "org.lwjgl:lwjgl-openal:${lwjglVersion}:natives-linux"
     runtime "org.lwjgl:lwjgl-openal:${lwjglVersion}:natives-macos"

+ 6 - 6
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java

@@ -67,7 +67,7 @@ public class LwjglBuffer extends Buffer {
         //Note: LWJGL does not support the size parameter, I have to set the buffer limit
         dest.limit((int) (dest.position() + size));
         int ret = CL10.clEnqueueReadBuffer(((LwjglCommandQueue)queue).getQueue(), 
-                buffer, CL10.CL_TRUE, offset, dest, null, null);
+                buffer, true, offset, dest, null, null);
         Utils.checkError(ret, "clEnqueueReadBuffer");
     }
 
@@ -77,7 +77,7 @@ public class LwjglBuffer extends Buffer {
         dest.limit((int) (dest.position() + size));
         Utils.pointerBuffers[0].rewind();
         long q = ((LwjglCommandQueue)queue).getQueue();
-        int ret = CL10.clEnqueueReadBuffer(q, buffer, CL10.CL_FALSE, offset, dest, null, Utils.pointerBuffers[0]);
+        int ret = CL10.clEnqueueReadBuffer(q, buffer, false, offset, dest, null, Utils.pointerBuffers[0]);
         Utils.checkError(ret, "clEnqueueReadBuffer");
         long event = Utils.pointerBuffers[0].get(0);
         return new LwjglEvent(event);
@@ -88,7 +88,7 @@ public class LwjglBuffer extends Buffer {
         //Note: LWJGL does not support the size parameter, I have to set the buffer limit
         src.limit((int) (src.position() + size));
         long q = ((LwjglCommandQueue)queue).getQueue();
-        int ret = CL10.clEnqueueWriteBuffer(q, buffer, CL10.CL_TRUE, offset, src, null, null);
+        int ret = CL10.clEnqueueWriteBuffer(q, buffer, true, offset, src, null, null);
         Utils.checkError(ret, "clEnqueueWriteBuffer");
     }
 
@@ -98,7 +98,7 @@ public class LwjglBuffer extends Buffer {
         src.limit((int) (src.position() + size));
         Utils.pointerBuffers[0].rewind();
         long q = ((LwjglCommandQueue)queue).getQueue();
-        int ret = CL10.clEnqueueWriteBuffer(q, buffer, CL10.CL_FALSE, offset, src, null, Utils.pointerBuffers[0]);
+        int ret = CL10.clEnqueueWriteBuffer(q, buffer, false, offset, src, null, Utils.pointerBuffers[0]);
         Utils.checkError(ret, "clEnqueueWriteBuffer");
         long event = Utils.pointerBuffers[0].get(0);
         return new LwjglEvent(event);
@@ -130,7 +130,7 @@ public class LwjglBuffer extends Buffer {
         long q = ((LwjglCommandQueue) queue).getQueue();
         long flags = Utils.getMappingAccessFlags(access);
         Utils.errorBuffer.rewind();
-        ByteBuffer b = CL10.clEnqueueMapBuffer(q, buffer, CL10.CL_TRUE, flags, offset, size, null, null, Utils.errorBuffer, null);
+        ByteBuffer b = CL10.clEnqueueMapBuffer(q, buffer, true, flags, offset, size, null, null, Utils.errorBuffer, null);
         Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer");
         return b;
     }
@@ -153,7 +153,7 @@ public class LwjglBuffer extends Buffer {
         Utils.errorBuffer.rewind();
         long q = ((LwjglCommandQueue) queue).getQueue();
         long flags = Utils.getMappingAccessFlags(access);
-        ByteBuffer buf = CL10.clEnqueueMapBuffer(q, buffer, CL10.CL_FALSE, flags, offset, size, null, Utils.pointerBuffers[0], Utils.errorBuffer, null);
+        ByteBuffer buf = CL10.clEnqueueMapBuffer(q, buffer, false, flags, offset, size, null, Utils.pointerBuffers[0], Utils.errorBuffer, null);
         Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer");
         long event = Utils.pointerBuffers[0].get(0);
         return new com.jme3.opencl.Buffer.AsyncMapping(new LwjglEvent(event), buf);

+ 6 - 6
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java

@@ -302,7 +302,7 @@ public class LwjglImage extends Image {
         Utils.pointerBuffers[1].put(origin).position(0);
         Utils.pointerBuffers[2].put(region).position(0);
         long q = ((LwjglCommandQueue) queue).getQueue();
-        int ret = CL10.clEnqueueReadImage(q, image, CL10.CL_TRUE, 
+        int ret = CL10.clEnqueueReadImage(q, image, true, 
                 Utils.pointerBuffers[1], Utils.pointerBuffers[2], 
                 rowPitch, slicePitch, dest, null, null);
         Utils.checkError(ret, "clEnqueueReadImage");
@@ -319,7 +319,7 @@ public class LwjglImage extends Image {
         Utils.pointerBuffers[1].put(origin).position(0);
         Utils.pointerBuffers[2].put(region).position(0);
         long q = ((LwjglCommandQueue) queue).getQueue();
-        int ret = CL10.clEnqueueReadImage(q, image, CL10.CL_FALSE, 
+        int ret = CL10.clEnqueueReadImage(q, image, false, 
                 Utils.pointerBuffers[1], Utils.pointerBuffers[2], 
                 rowPitch, slicePitch, dest, null, Utils.pointerBuffers[0]);
         Utils.checkError(ret, "clEnqueueReadImage");
@@ -337,7 +337,7 @@ public class LwjglImage extends Image {
         Utils.pointerBuffers[1].put(origin).position(0);
         Utils.pointerBuffers[2].put(region).position(0);
         long q = ((LwjglCommandQueue) queue).getQueue();
-        int ret = CL10.clEnqueueWriteImage(q, image, CL10.CL_TRUE, 
+        int ret = CL10.clEnqueueWriteImage(q, image, true, 
                 Utils.pointerBuffers[1], Utils.pointerBuffers[2], 
                 rowPitch, slicePitch, dest, null, null);
         Utils.checkError(ret, "clEnqueueWriteImage");
@@ -354,7 +354,7 @@ public class LwjglImage extends Image {
         Utils.pointerBuffers[1].put(origin).position(0);
         Utils.pointerBuffers[2].put(region).position(0);
         long q = ((LwjglCommandQueue) queue).getQueue();
-        int ret = CL10.clEnqueueWriteImage(q, image, CL10.CL_FALSE, 
+        int ret = CL10.clEnqueueWriteImage(q, image, false, 
                 Utils.pointerBuffers[1], Utils.pointerBuffers[2], 
                 rowPitch, slicePitch, dest, null, Utils.pointerBuffers[0]);
         Utils.checkError(ret, "clEnqueueWriteImage");
@@ -419,7 +419,7 @@ public class LwjglImage extends Image {
         long q = ((LwjglCommandQueue) queue).getQueue();
         long flags = Utils.getMappingAccessFlags(access);
         Utils.errorBuffer.rewind();
-        ByteBuffer buf = CL10.clEnqueueMapImage(q, image, CL10.CL_TRUE, flags, 
+        ByteBuffer buf = CL10.clEnqueueMapImage(q, image, true, flags, 
                 Utils.pointerBuffers[1], Utils.pointerBuffers[2], 
                 Utils.pointerBuffers[3], Utils.pointerBuffers[4], null, null, 
                 Utils.errorBuffer, null);
@@ -442,7 +442,7 @@ public class LwjglImage extends Image {
         long q = ((LwjglCommandQueue) queue).getQueue();
         long flags = Utils.getMappingAccessFlags(access);
         Utils.errorBuffer.rewind();
-        ByteBuffer buf = CL10.clEnqueueMapImage(q, image, CL10.CL_FALSE, flags, 
+        ByteBuffer buf = CL10.clEnqueueMapImage(q, image, false, flags, 
                 Utils.pointerBuffers[1], Utils.pointerBuffers[2], 
                 Utils.pointerBuffers[3], Utils.pointerBuffers[4], null, Utils.pointerBuffers[0], 
                 Utils.errorBuffer, null);

+ 1 - 1
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/info/CLUtil.java

@@ -4,7 +4,7 @@
  */
 package com.jme3.opencl.lwjgl.info;
 
-import com.jme3.lwjgl3.utils.APIUtil.TokenFilter;
+import static com.jme3.lwjgl3.utils.APIUtil.apiOptionalClass;
 import com.jme3.opencl.OpenCLException;
 import java.lang.reflect.Field;
 import java.nio.ByteBuffer;

+ 12 - 0
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/BinDataKey.java

@@ -0,0 +1,12 @@
+package com.jme3.scene.plugins.gltf;
+
+import com.jme3.asset.AssetKey;
+
+/**
+ * Created by Nehon on 09/09/2017.
+ */
+class BinDataKey extends AssetKey<Object> {
+    public BinDataKey(String name) {
+        super(name);
+    }
+}

+ 6 - 2
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/BinLoader.java

@@ -1,7 +1,6 @@
 package com.jme3.scene.plugins.gltf;
 
-import com.jme3.asset.AssetInfo;
-import com.jme3.asset.AssetLoader;
+import com.jme3.asset.*;
 
 import java.io.IOException;
 
@@ -11,6 +10,11 @@ import java.io.IOException;
 public class BinLoader implements AssetLoader {
     @Override
     public Object load(AssetInfo assetInfo) throws IOException {
+
+        if (!(assetInfo.getKey() instanceof BinDataKey)) {
+            throw new AssetLoadException(".bin files cannot be loaded directly, load the associated .gltf file");
+        }
+
         return assetInfo.openStream();
     }
 }

+ 10 - 9
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);
 
     }
 
@@ -499,7 +499,8 @@ public class GltfLoader implements AssetLoader {
                     throw new AssetLoadException("Cannot load " + uri + ", a .bin extension is required.");
                 }
 
-                InputStream input = (InputStream) info.getManager().loadAsset(info.getKey().getFolder() + uri);
+                BinDataKey key = new BinDataKey(info.getKey().getFolder() + uri);
+                InputStream input = (InputStream) info.getManager().loadAsset(key);
                 data = new byte[bufferLength];
                 input.read(data);
             }
@@ -1260,7 +1261,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 +1287,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 +1308,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 +1327,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 +1347,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 +1374,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());

+ 87 - 49
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)));
     }