Przeglądaj źródła

refactored Memory Accessors

Vicente Penades 7 lat temu
rodzic
commit
5df75be035

+ 143 - 0
src/glTF2Sharp.DOM/Memory/Accessors.cs

@@ -0,0 +1,143 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Text;
+
+namespace glTF2Sharp.Memory
+{
+    public interface IAccessor<T> // : IReadOnlyList<T>
+        where T : unmanaged
+    {
+        int Count { get; }
+        T this[int index] { get; set; }
+
+        void CopyTo(ArraySegment<T> dst);
+    }
+
+
+    struct AccessorEnumerator<T> : IEnumerator<T>
+        where T: unmanaged
+    {
+        #region lifecycle
+
+        public AccessorEnumerator(IAccessor<T> accessor)
+        {
+            this._Accessor = accessor;
+            this._Count = accessor.Count;
+            this._Index = -1;            
+        }
+
+        public void Dispose()
+        {
+
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly IAccessor<T> _Accessor;
+        private readonly int _Count;
+        private int _Index;
+
+        #endregion
+
+        #region API
+
+        public T Current => _Accessor[_Index];
+
+        object IEnumerator.Current => _Accessor[_Index];        
+
+        public bool MoveNext()
+        {
+            ++_Index;
+            return _Index < _Count;
+        }
+
+        public void Reset()
+        {
+            _Index = -1;
+        }
+
+        #endregion
+    }
+
+    public static class AccessorsUtils
+    {
+        public static void Copy<T>(IAccessor<T> src, T[] dst) where T : unmanaged
+        {
+            Copy<T>(src, new ArraySegment<T>(dst));
+        }
+
+        public static void Copy<T>(IAccessor<T> src, ArraySegment<T> dst) where T : unmanaged
+        {
+            var c = src.Count;
+            for (int i = 0; i < c; ++i) dst.Array[dst.Offset + i] = src[i];
+        }        
+
+        public static (Single, Single) GetBounds(ScalarAccessor accesor)
+        {
+            var min = Single.MaxValue;
+            var max = Single.MinValue;
+
+            int c = accesor.Count;
+            for (int i = 0; i < c; ++i)
+            {
+                var v = accesor[i];
+                min = Math.Min(min, v);
+                max = Math.Max(max, v);
+            }
+
+            return (min, max);
+        }
+
+        public static (Vector2, Vector2) GetBounds(Vector2Accessor accesor)
+        {
+            var min = new Vector2(Single.MaxValue);
+            var max = new Vector2(Single.MinValue);
+
+            int c = accesor.Count;
+            for (int i = 0; i < c; ++i)
+            {
+                var v = accesor[i];
+                min = Vector2.Min(min, v);
+                max = Vector2.Max(max, v);
+            }
+
+            return (min, max);
+        }
+
+        public static (Vector3, Vector3) GetBounds(Vector3Accessor accesor)
+        {
+            var min = new Vector3(Single.MaxValue);
+            var max = new Vector3(Single.MinValue);
+
+            int c = accesor.Count;
+            for (int i = 0; i < c; ++i)
+            {
+                var v = accesor[i];
+                min = Vector3.Min(min, v);
+                max = Vector3.Max(max, v);
+            }
+
+            return (min, max);
+        }
+
+        public static (Vector4, Vector4) GetBounds(Vector4Accessor accesor)
+        {
+            var min = new Vector4(Single.MaxValue);
+            var max = new Vector4(Single.MinValue);
+
+            int c = accesor.Count;
+            for (int i = 0; i < c; ++i)
+            {
+                var v = accesor[i];
+                min = Vector4.Min(min, v);
+                max = Vector4.Max(max, v);
+            }
+
+            return (min, max);
+        }
+    }
+}

+ 72 - 121
src/glTF2Sharp.DOM/Memory/ByteArrayAccessors.cs → src/glTF2Sharp.DOM/Memory/FloatingAccessors.cs

@@ -1,15 +1,19 @@
 using System;
 using System.Collections.Generic;
 using System.Text;
+using System.Numerics;
 
 namespace glTF2Sharp.Memory
 {
+    
     using BYTES = ArraySegment<Byte>;
 
+    
+
     /// <summary>
     /// Helper structure to access any Byte array as an array of <see cref="Schema2.ComponentType"/>
     /// </summary>
-    public struct FloatingAccessor
+    struct FloatingAccessor
     {
         #region constructors
 
@@ -162,6 +166,8 @@ namespace glTF2Sharp.Memory
 
         #region API
 
+        public int ByteLength => _Data.Count;
+
         public Single this[int index]
         {
             get => _Getter(0, index);
@@ -172,103 +178,12 @@ namespace glTF2Sharp.Memory
         {
             get => _Getter(byteOffset, index);
             set => _Setter(byteOffset, index, value);
-        }
-
-        #endregion
-    }
-
-    /// <summary>
-    /// Helper structure to access any Byte array as an array of <see cref="Schema2.IndexType"/>
-    /// </summary>
-    public struct IntegerAccessor
-    {
-        #region constructors
-
-        public static IntegerAccessor Create(Byte[] data, Schema2.IndexType type)
-        {
-            return Create(new BYTES(data), type);
-        }
-
-        public static IntegerAccessor Create(BYTES data, Schema2.IndexType type)
-        {
-            var accessor = new IntegerAccessor { _Data = data };
-
-            switch (type)
-            {
-                case Schema2.IndexType.UNSIGNED_BYTE:
-                    {
-                        accessor._Setter = accessor._SetValueU8;
-                        accessor._Getter = accessor._GetValueU8;
-                        return accessor;
-                    }
-
-                case Schema2.IndexType.UNSIGNED_SHORT:
-                    {
-                        accessor._Setter = accessor._SetValueU16;
-                        accessor._Getter = accessor._GetValueU16;
-                        return accessor;
-                    }
-
-                case Schema2.IndexType.UNSIGNED_INT:
-                    {
-                        accessor._Setter = accessor._SetValue<UInt32>;
-                        accessor._Getter = accessor._GetValue<UInt32>;
-                        return accessor;
-                    }
-            }
-
-            throw new NotSupportedException();
-        }
-
-        private UInt32 _GetValueU8(int index) { return _GetValue<Byte>(index); }
-        private void _SetValueU8(int index, UInt32 value) { _SetValue<Byte>(index, (Byte)value); }
-
-        private UInt32 _GetValueU16(int index) { return _GetValue<UInt16>(index); }
-        private void _SetValueU16(int index, UInt32 value) { _SetValue<UInt16>(index, (UInt16)value); }
-
-        private T _GetValue<T>(int index) where T : unmanaged
-        {
-            return System.Runtime.InteropServices.MemoryMarshal.Cast<Byte, T>(_Data)[index];
-        }
-
-        private void _SetValue<T>(int index, T value) where T : unmanaged
-        {
-            System.Runtime.InteropServices.MemoryMarshal.Cast<Byte, T>(_Data)[index] = value;
-        }
-
-        #endregion
-
-        #region data
-
-        delegate UInt32 _GetterCallback(int index);
-
-        delegate void _SetterCallback(int index, UInt32 value);
-
-        private BYTES _Data;
-        private _GetterCallback _Getter;
-        private _SetterCallback _Setter;
-
-        #endregion
-
-        #region API
-
-        public UInt32 this[int idx]
-        {
-            get => _Getter(idx);
-            set => _Setter(idx, value);
-        }
+        }        
 
         #endregion
     }
 
-    public interface IWordAccessor
-    {
-        System.Numerics.Vector4 GetWord(int index);
-
-        void SetWord(int index, in System.Numerics.Vector4 word);
-    }
-
-    public struct ScalarAccessor : IWordAccessor
+    public struct ScalarAccessor : IAccessor<Single> , IAccessor<Vector4>
     {
         public ScalarAccessor(BYTES data, int byteStride, Schema2.ComponentType type, Boolean normalized)
         {
@@ -279,18 +194,26 @@ namespace glTF2Sharp.Memory
         private FloatingAccessor _Accesor;
         private readonly int _ByteStride;
 
+        public int Count => _Accesor.ByteLength / _ByteStride;
+        
         public Single this[int index]
         {
             get => _Accesor[index * _ByteStride, 0];
             set => _Accesor[index * _ByteStride, 0] = value;
+        }        
+
+        Vector4 IAccessor<Vector4>.this[int index]
+        {
+            get => new Vector4(this[index], 0, 0, 0);
+            set => this[index] = value.X;
         }
 
-        public System.Numerics.Vector4 GetWord(int index) => new System.Numerics.Vector4(this[index], 0, 0, 0);
+        public void CopyTo(ArraySegment<Single> dst) { AccessorsUtils.Copy<Single>(this, dst); }
 
-        public void SetWord(int index, in System.Numerics.Vector4 word) => this[index] = word.X;
+        public void CopyTo(ArraySegment<Vector4> dst) { AccessorsUtils.Copy<Vector4>(this, dst); }        
     }
 
-    public struct Vector2Accessor : IWordAccessor
+    public struct Vector2Accessor : IAccessor<Vector2>, IAccessor<Vector4>
     {
         public Vector2Accessor(BYTES data, int byteStride, Schema2.ComponentType type, Boolean normalized)
         {
@@ -301,12 +224,14 @@ namespace glTF2Sharp.Memory
         private FloatingAccessor _Accesor;
         private readonly int _ByteStride;
 
-        public System.Numerics.Vector2 this[int index]
+        public int Count => _Accesor.ByteLength / _ByteStride;
+
+        public Vector2 this[int index]
         {
             get
             {
                 index *= _ByteStride;
-                return new System.Numerics.Vector2(_Accesor[index, 0], _Accesor[index, 1]);
+                return new Vector2(_Accesor[index, 0], _Accesor[index, 1]);
             }
 
             set
@@ -317,12 +242,18 @@ namespace glTF2Sharp.Memory
             }
         }
 
-        public System.Numerics.Vector4 GetWord(int index) { var v = this[index]; return new System.Numerics.Vector4(v.X, v.Y, 0, 0); }
+        Vector4 IAccessor<Vector4>.this[int index]
+        {
+            get { var v = this[index]; return new Vector4(v.X, v.Y, 0, 0); }
+            set => this[index] = new Vector2(value.X, value.Y);
+        }
 
-        public void SetWord(int index, in System.Numerics.Vector4 word) => this[index] = new System.Numerics.Vector2(word.X, word.Y);
+        public void CopyTo(ArraySegment<Vector2> dst) { AccessorsUtils.Copy<Vector2>(this, dst); }
+
+        public void CopyTo(ArraySegment<Vector4> dst) { AccessorsUtils.Copy<Vector4>(this, dst); }
     }
 
-    public struct Vector3Accessor: IWordAccessor
+    public struct Vector3Accessor: IAccessor<Vector3>, IAccessor<Vector4>
     {
         public Vector3Accessor(BYTES data, int byteStride, Schema2.ComponentType type, Boolean normalized)
         {
@@ -333,12 +264,14 @@ namespace glTF2Sharp.Memory
         private FloatingAccessor _Accesor;
         private readonly int _ByteStride;
 
-        public System.Numerics.Vector3 this[int index]
+        public int Count => _Accesor.ByteLength / _ByteStride;
+
+        public Vector3 this[int index]
         {
             get
             {
                 index *= _ByteStride;
-                return new System.Numerics.Vector3(_Accesor[index, 0], _Accesor[index, 1], _Accesor[index, 2]);
+                return new Vector3(_Accesor[index, 0], _Accesor[index, 1], _Accesor[index, 2]);
             }
 
             set
@@ -350,12 +283,18 @@ namespace glTF2Sharp.Memory
             }
         }
 
-        public System.Numerics.Vector4 GetWord(int index) { var v = this[index]; return new System.Numerics.Vector4(v.X, v.Y, v.Z, 0); }
+        Vector4 IAccessor<Vector4>.this[int index]
+        {
+            get { var v = this[index]; return new Vector4(v.X, v.Y, v.Z, 0); }
+            set => this[index] = new Vector3(value.X, value.Y, value.Z);
+        }
 
-        public void SetWord(int index, in System.Numerics.Vector4 word) => this[index] = new System.Numerics.Vector3(word.X, word.Y, word.Z);
+        public void CopyTo(ArraySegment<Vector3> dst) { AccessorsUtils.Copy<Vector3>(this, dst); }
+
+        public void CopyTo(ArraySegment<Vector4> dst) { AccessorsUtils.Copy<Vector4>(this, dst); }
     }
 
-    public struct Vector4Accessor: IWordAccessor
+    public struct Vector4Accessor: IAccessor<Vector4>
     {
         public Vector4Accessor(BYTES data, int byteStride, Schema2.ComponentType type, Boolean normalized)
         {
@@ -366,12 +305,14 @@ namespace glTF2Sharp.Memory
         private FloatingAccessor _Accesor;
         private readonly int _ByteStride;
 
-        public System.Numerics.Vector4 this[int index]
+        public int Count => _Accesor.ByteLength / _ByteStride;
+
+        public Vector4 this[int index]
         {
             get
             {
                 index *= _ByteStride;
-                return new System.Numerics.Vector4(_Accesor[index, 0], _Accesor[index, 1], _Accesor[index, 2], _Accesor[index, 3]);
+                return new Vector4(_Accesor[index, 0], _Accesor[index, 1], _Accesor[index, 2], _Accesor[index, 3]);
             }
 
             set
@@ -382,14 +323,12 @@ namespace glTF2Sharp.Memory
                 _Accesor[index, 2] = value.Z;
                 _Accesor[index, 3] = value.W;
             }
-        }
-
-        public System.Numerics.Vector4 GetWord(int index) => this[index];
+        }        
 
-        public void SetWord(int index, in System.Numerics.Vector4 word) => this[index] = word;
+        public void CopyTo(ArraySegment<Vector4> dst) { AccessorsUtils.Copy<Vector4>(this, dst); }
     }
 
-    public struct QuaternionAccessor : IWordAccessor
+    public struct QuaternionAccessor : IAccessor<Quaternion>, IAccessor<Vector4>
     {
         public QuaternionAccessor(BYTES data, int byteStride, Schema2.ComponentType type, Boolean normalized)
         {
@@ -400,12 +339,14 @@ namespace glTF2Sharp.Memory
         private FloatingAccessor _Accesor;
         private readonly int _ByteStride;
 
-        public System.Numerics.Quaternion this[int index]
+        public int Count => _Accesor.ByteLength / _ByteStride;
+
+        public Quaternion this[int index]
         {
             get
             {
                 index *= _ByteStride;
-                return new System.Numerics.Quaternion(_Accesor[index, 0], _Accesor[index, 1], _Accesor[index, 2], _Accesor[index, 3]);
+                return new Quaternion(_Accesor[index, 0], _Accesor[index, 1], _Accesor[index, 2], _Accesor[index, 3]);
             }
 
             set
@@ -418,12 +359,18 @@ namespace glTF2Sharp.Memory
             }
         }
 
-        public System.Numerics.Vector4 GetWord(int index) { var v = this[index]; return new System.Numerics.Vector4(v.X, v.Y, v.Z, v.W); }
+        Vector4 IAccessor<Vector4>.this[int index]
+        {
+            get { var v = this[index]; return new Vector4(v.X, v.Y, v.Z, v.W); }
+            set => this[index] = new Quaternion(value.X, value.Y, value.Z, value.W);
+        }
+
+        public void CopyTo(ArraySegment<Quaternion> dst) { AccessorsUtils.Copy<Quaternion>(this, dst); }
 
-        public void SetWord(int index, in System.Numerics.Vector4 word) => this[index] = new System.Numerics.Quaternion(word.X, word.Y, word.Z, word.W);
+        public void CopyTo(ArraySegment<Vector4> dst) { AccessorsUtils.Copy<Vector4>(this, dst); }
     }
 
-    public struct Matrix4x4Accessor
+    public struct Matrix4x4Accessor : IAccessor<Matrix4x4>
     {
         public Matrix4x4Accessor(BYTES data, int byteStride, Schema2.ComponentType type, Boolean normalized)
         {
@@ -434,12 +381,14 @@ namespace glTF2Sharp.Memory
         private FloatingAccessor _Accesor;
         private readonly int _ByteStride;
 
-        public System.Numerics.Matrix4x4 this[int index]
+        public int Count => _Accesor.ByteLength / _ByteStride;
+
+        public Matrix4x4 this[int index]
         {
             get
             {
                 index *= _ByteStride;
-                return new System.Numerics.Matrix4x4
+                return new Matrix4x4
                     (
                     _Accesor[index, 0], _Accesor[index, 1], _Accesor[index, 2], _Accesor[index, 3],
                     _Accesor[index, 4], _Accesor[index, 5], _Accesor[index, 6], _Accesor[index, 7],
@@ -469,5 +418,7 @@ namespace glTF2Sharp.Memory
                 _Accesor[index, 15] = value.M44;
             }
         }
+
+        public void CopyTo(ArraySegment<Matrix4x4> dst) { AccessorsUtils.Copy<Matrix4x4>(this, dst); }
     }
 }

+ 109 - 0
src/glTF2Sharp.DOM/Memory/IntegerAccessor.cs

@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace glTF2Sharp.Memory
+{
+    using BYTES = ArraySegment<Byte>;
+
+    /// <summary>
+    /// Helper structure to access any Byte array as an array of <see cref="Schema2.IndexType"/>
+    /// </summary>
+    public struct IntegerAccessor : IAccessor<UInt32>, IAccessor<Int32>
+    {
+        #region constructors
+
+        public static IntegerAccessor Create(Byte[] data, Schema2.IndexType encoding)
+        {
+            return Create(new BYTES(data), encoding);
+        }
+
+        public static IntegerAccessor Create(BYTES data, Schema2.IndexType encoding)
+        {
+            var accessor = new IntegerAccessor
+            {
+                _Data = data,
+                _ByteStride = encoding.ByteLength()
+            };
+
+            switch (encoding)
+            {
+                case Schema2.IndexType.UNSIGNED_BYTE:
+                    {
+                        accessor._Setter = accessor._SetValueU8;
+                        accessor._Getter = accessor._GetValueU8;
+                        return accessor;
+                    }
+
+                case Schema2.IndexType.UNSIGNED_SHORT:
+                    {
+                        accessor._Setter = accessor._SetValueU16;
+                        accessor._Getter = accessor._GetValueU16;
+                        return accessor;
+                    }
+
+                case Schema2.IndexType.UNSIGNED_INT:
+                    {
+                        accessor._Setter = accessor._SetValue<UInt32>;
+                        accessor._Getter = accessor._GetValue<UInt32>;
+                        return accessor;
+                    }
+            }
+
+            throw new NotSupportedException();
+        }
+
+        private UInt32 _GetValueU8(int index) { return _GetValue<Byte>(index); }
+        private void _SetValueU8(int index, UInt32 value) { _SetValue<Byte>(index, (Byte)value); }
+
+        private UInt32 _GetValueU16(int index) { return _GetValue<UInt16>(index); }
+        private void _SetValueU16(int index, UInt32 value) { _SetValue<UInt16>(index, (UInt16)value); }
+
+        private T _GetValue<T>(int index) where T : unmanaged
+        {
+            return System.Runtime.InteropServices.MemoryMarshal.Cast<Byte, T>(_Data)[index];
+        }
+
+        private void _SetValue<T>(int index, T value) where T : unmanaged
+        {
+            System.Runtime.InteropServices.MemoryMarshal.Cast<Byte, T>(_Data)[index] = value;
+        }
+
+        #endregion
+
+        #region data
+
+        delegate UInt32 _GetterCallback(int index);
+
+        delegate void _SetterCallback(int index, UInt32 value);
+
+        private BYTES _Data;
+        private int _ByteStride;
+        private _GetterCallback _Getter;
+        private _SetterCallback _Setter;
+
+        #endregion
+
+        #region API
+
+        public int Count => _Data.Count / _ByteStride;
+
+        public UInt32 this[int index]
+        {
+            get => _Getter(index);
+            set => _Setter(index, value);
+        }
+
+        int IAccessor<int>.this[int index]
+        {
+            get => (Int32)_Getter(index);
+            set => _Setter(index, (UInt32)value);
+        }
+
+        public void CopyTo(ArraySegment<UInt32> dst) { AccessorsUtils.Copy<UInt32>(this, dst); }
+
+        public void CopyTo(ArraySegment<Int32> dst) { AccessorsUtils.Copy<Int32>(this, dst); }
+
+        #endregion
+    }
+}

+ 91 - 0
src/glTF2Sharp.DOM/Schema2/gltf.AccessorSparse.cs

@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Text;
+
+namespace glTF2Sharp.Schema2
+{
+    using ROOT = ModelRoot;
+
+    public partial class AccessorSparse
+    {
+        public void CopyTo(Accessor srcAccessor, Byte[] dstBuffer, int dstStride)
+        {
+            if (this._count == 0) return;
+
+            var idxDecoder = this._indices.GetDecoder(srcAccessor.LogicalParent);
+            var valCopier = this._values.CopyTo(srcAccessor.LogicalParent, srcAccessor.Dimensions, srcAccessor.Encoding);
+
+            for (int i = 0; i < this._count; ++i)
+            {
+                var key = idxDecoder.Invoke(i);
+
+                valCopier(i, dstBuffer, dstStride, key);
+            }
+        }
+
+        public void CopyTo(Accessor srcAccessor, Vector4[] dstBuffer)
+        {
+            if (this._count == 0) return;
+
+            var idxDecoder = this._indices.GetDecoder(srcAccessor.LogicalParent);
+            var valDecoder = this._values.GetDecoder(srcAccessor.LogicalParent, srcAccessor.Encoding, srcAccessor.Dimensions, srcAccessor.Normalized);
+
+            for (int i = 0; i < this._count; ++i)
+            {
+                var key = idxDecoder.Invoke(i);
+                var val = valDecoder[i];
+                dstBuffer[key] = val;
+            }
+        }
+    }
+
+    public partial class AccessorSparseIndices
+    {
+        public Func<int, int> GetDecoder(ROOT root)
+        {
+            var srcBuffer = root.LogicalBufferViews[this._bufferView];
+
+            var accessor = srcBuffer.CreateIndexDecoder(this._byteOffset ?? 0, this._componentType) as Memory.IAccessor<int>;
+
+            return index => accessor[index];
+        }
+
+        public IReadOnlyList<int> GetIndices(ROOT root, int count)
+        {
+            var srcDecoder = GetDecoder(root);
+
+            var indices = new int[count];
+
+            for (int i = 0; i < indices.Length; ++i)
+            {
+                indices[i] = srcDecoder(i);
+            }
+
+            return indices;
+        }
+    }
+
+    public partial class AccessorSparseValues
+    {
+        public Memory.IAccessor<Vector4> GetDecoder(ROOT root, ComponentType encoding, ElementType dimensions, Boolean normalized)
+        {
+            var srcBuffer = root.LogicalBufferViews[this._bufferView];
+
+            return srcBuffer.CreateVertexDecoder(this._byteOffset ?? 0, dimensions, encoding, normalized);
+        }
+
+        public Action<int, IList<Byte>, int, int> CopyTo(ROOT root, ElementType et, ComponentType ct)
+        {
+            var srcBuffer = root.LogicalBufferViews[this._bufferView];
+
+            var itemLen = et.DimCount() * ct.ByteLength();
+            var srcStride = Math.Max(srcBuffer.ByteStride, itemLen);
+
+            return (srcIdx, dstBuff, dstStride, dstIdx) =>
+            {
+                srcBuffer.Data.CopyTo(srcStride * srcIdx, dstBuff, dstStride * dstIdx, itemLen);
+            };
+        }
+    }
+}

+ 64 - 222
src/glTF2Sharp.DOM/Schema2/gltf.Accessors.cs

@@ -17,7 +17,7 @@ namespace glTF2Sharp.Schema2
 
         internal string _DebuggerDisplay_TryIdentifyContent()
         {
-            return $"{Element}_{Component}[{_count}]";
+            return $"{Dimensions}_{Encoding}[{_count}]";
         }
 
         #endregion
@@ -34,25 +34,25 @@ namespace glTF2Sharp.Schema2
 
         #region properties
 
-        public int LogicalIndex => this.LogicalParent.LogicalAccessors.IndexOfReference(this);
+        public int LogicalIndex                 => this.LogicalParent.LogicalAccessors.IndexOfReference(this);
+        
+        internal int _LogicalBufferViewIndex    => this._bufferView.AsValue(-1);
 
-        internal int _LogicalBufferViewIndex => this._bufferView ?? -1; // todo: clarify behaviour when BufferView is not define.
+        public BufferView SourceBufferView      => this._bufferView.HasValue ? this.LogicalParent.LogicalBufferViews[this._bufferView.Value] : null;
 
-        public BufferView Buffer => this._bufferView.HasValue ? this.LogicalParent.LogicalBufferViews[this._bufferView.Value] : null;
+        public int Count                        => this._count;
 
-        public int Count => this._count;
+        public int ByteOffset                   => this._byteOffset.AsValue(0);
 
-        public int ByteOffset => _byteOffset ?? 0;
+        public ElementType Dimensions           => this._type;
 
-        public ElementType Element => this._type;
+        public ComponentType Encoding           => this._componentType;
 
-        public ComponentType Component => this._componentType;
+        public Boolean Normalized               => this._normalized.AsValue(false);
 
-        public Boolean Normalized => this._normalized ?? false;
+        public Boolean IsSparse                 => this._sparse != null;
 
-        public int ItemByteSize => Component.ByteLength() * Element.Length();
-
-        public bool IsSparse => _sparse != null;
+        public int ItemByteSize                 => Encoding.ByteLength() * Dimensions.DimCount();        
 
         public BoundingBox3? LocalBounds3
         {
@@ -84,9 +84,20 @@ namespace glTF2Sharp.Schema2
             this._byteOffset = byteOffset;
             this._count = count;
 
-            _UpdateBounds(this._type.Length());
+            _UpdateBounds();
         }
 
+        public Memory.Matrix4x4Accessor CastToMatrix4x4Array()
+        {
+            Guard.IsTrue(this.Dimensions == ElementType.MAT4, nameof(Dimensions));
+
+            return SourceBufferView.CreateMatrix4x4Decoder(this.ByteOffset, this._componentType, this.Normalized);
+        }
+
+        #endregion
+
+        #region Index Buffer API
+
         public void SetIndexData(BufferView buffer, int byteOffset, IndexType encoding, int count)
         {
             Guard.NotNull(buffer,nameof(buffer));
@@ -103,9 +114,26 @@ namespace glTF2Sharp.Schema2
             this._byteOffset = byteOffset;
             this._count = count;
 
-            _UpdateBounds(1);
+            _UpdateBounds();
+        }
+
+        public Int32[] TryGetIndices()
+        {
+            Guard.IsTrue(this.Dimensions == ElementType.SCALAR, nameof(Dimensions));            
+
+            var accessor = SourceBufferView.CreateIndexDecoder(this.ByteOffset, this.Encoding.ToIndex());
+
+            var indices = new int[accessor.Count];
+
+            Memory.AccessorsUtils.Copy<Int32>(accessor, indices);
+
+            return indices;
         }
 
+        #endregion
+
+        #region Vertex Buffer API
+
         public void SetVertexData(BufferView buffer, int byteOffset, ComponentType encoding, ElementType dimensions, bool normalized, int count)
         {
             Guard.NotNull(buffer,nameof(buffer));
@@ -122,124 +150,24 @@ namespace glTF2Sharp.Schema2
             this._byteOffset = byteOffset;
             this._count = count;
 
-            _UpdateBounds(this._type.Length());
+            _UpdateBounds();
         }
 
-        public ArraySegment<Byte> GetVertexBytes(int vertexIdx)
+        public ArraySegment<Byte> TryGetVertexBytes(int vertexIdx)
         {
             if (_sparse != null) throw new InvalidOperationException("Can't be used on Acessors with Sparse Data");
 
-            var byteSize = Component.ByteLength() * Element.Length();
-            var byteStride = Math.Max(byteSize, Buffer.ByteStride);
+            var byteSize = Encoding.ByteLength() * Dimensions.DimCount();
+            var byteStride = Math.Max(byteSize, SourceBufferView.ByteStride);
             var byteOffset = vertexIdx * byteStride;
 
-            return Buffer.Data.GetSegment(this.ByteOffset + vertexIdx * byteStride, byteSize);
-        }
-
-        public IReadOnlyList<ArraySegment<Byte>> GetVertices()
-        {
-            throw new NotImplementedException();
-
-            // if sparse exist, create a dictionary with the indices
-        }
-
-        /*
-        public Byte[] GetColumnBytes()
-        {
-            var dstStride = Component.ByteLength() * Element.Length();
-            var srcStride = Math.Max(dstStride, Buffer.ByteStride);
-
-            var srcData = Buffer.Data.GetSegment(this.ByteOffset, srcStride * Count);
-            var dstData = new Byte[dstStride * Count];
-
-            for(int i=0; i < Count; ++i)
-            {
-                srcData.CopyTo(i * srcStride, dstData, i * dstStride, dstStride);
-            }
-
-            if (this._sparse != null)
-            {
-                this._sparse.CopyTo(this, dstData, dstStride);
-            }
-
-            return dstData;
-        }*/
-
-        public Int32[] TryGetIndices()
-        {
-            if (this._type != ElementType.SCALAR) throw new InvalidOperationException();
-
-            var decoder = Buffer.CreateIndexDecoder(this.Component.ToIndex(), this.ByteOffset);
-
-            return _TryGetColumn<int>(decoder);
+            return SourceBufferView.Data.GetSegment(this.ByteOffset + vertexIdx * byteStride, byteSize);
         }
 
-        public T[] TryGetAttribute<T>() where T : struct
+        internal void _UpdateBounds()
         {
-            switch (this._type)
-            {
-                case ElementType.SCALAR:
-                    {
-                        var decoder = Buffer.CreateScalarDecoder(this._componentType, this.ByteOffset);
-                        return (T[])(Array)_TryGetColumn(decoder);
-                    }
-
-                case ElementType.VEC2:
-                    {
-                        var decoder = Buffer.CreateVector2Decoder(this._componentType, this.Normalized, this.ByteOffset);
-                        return (T[])(Array)_TryGetColumn(decoder);
-                    }
-
-                case ElementType.VEC3:
-                    {
-                        var decoder = Buffer.CreateVector3Decoder(this._componentType, this.Normalized, this.ByteOffset);
-
-                        // this is a special case because although Tangets
-                        // are expected to be Vector4, sometimes are found as Vector3
-                        // Bug found in AnimatedMorphCube
-
-                        if (typeof(T) == typeof(Vector3)) return (T[])(Array)_TryGetColumn(decoder);
-                        if (typeof(T) == typeof(Vector4)) return (T[])(Array)_TryGetColumn(decoder).Select(item => new Vector4(item, 0)).ToArray();
-
-                        throw new NotImplementedException();
-                    }
-
-                case ElementType.VEC4:
-                    {
-                        var decoder = Buffer.CreateVector4Decoder(this._componentType, this.Normalized, this.ByteOffset);
-                        return (T[])(Array)_TryGetColumn(decoder);
-                    }
-
-                case ElementType.MAT4:
-                    {
-                        var decoder = Buffer.CreateMatrix4x4Decoder(this._componentType, this.Normalized, this.ByteOffset);
-                        return (T[])(Array)_TryGetColumn(decoder);
-                    }
-
-                default: throw new NotImplementedException();
-            }
-        }
+            var count = this._type.DimCount();
 
-        private T[] _TryGetColumn<T>(Func<int, T> decoder)
-            where T : struct
-        {
-            var dstBuff = new T[_count];
-
-            for (int i = 0; i < dstBuff.Length; ++i)
-            {
-                dstBuff[i] = decoder.Invoke(i);
-            }
-
-            if (this._sparse != null)
-            {
-                this._sparse.CopyTo(this, dstBuff);
-            }
-
-            return dstBuff;
-        }
-
-        internal void _UpdateBounds(int count)
-        {
             var bounds = new double[count];
             this._min.Clear();
             this._min.AddRange(bounds);
@@ -251,24 +179,21 @@ namespace glTF2Sharp.Schema2
 
             if (count == 1)
             {
-                var decoder = Buffer.CreateScalarDecoder(this.Component, this.ByteOffset);
+                var accessor = SourceBufferView.CreateScalarDecoder(this.ByteOffset, this.Encoding, this.Normalized);
 
-                for (int i = 0; i < Count; ++i)
-                {
-                    var scalar = decoder.Invoke(i);
+                var minmax = Memory.AccessorsUtils.GetBounds(accessor);
 
-                    if (scalar < this._min[0]) this._min[0] = scalar;
-                    if (scalar > this._max[0]) this._max[0] = scalar;
-                }
+                this._min[0] = minmax.Item1;
+                this._max[0] = minmax.Item2;
             }
 
             if (count == 2)
             {
-                var decoder = Buffer.CreateVector2Decoder(this.Component, this.Normalized, this.ByteOffset);
+                var accessor = SourceBufferView.CreateVector2Decoder(this.ByteOffset, this.Encoding, this.Normalized);
 
                 for (int i = 0; i < Count; ++i)
                 {
-                    var v2 = decoder.Invoke(i);
+                    var v2 = accessor[i];
 
                     if (v2.X < this._min[0]) this._min[0] = v2.X;
                     if (v2.X > this._max[0]) this._max[0] = v2.X;
@@ -279,11 +204,11 @@ namespace glTF2Sharp.Schema2
 
             if (count == 3)
             {
-                var decoder = Buffer.CreateVector3Decoder(this.Component, this.Normalized, this.ByteOffset);
+                var accessor = SourceBufferView.CreateVector3Decoder(this.ByteOffset, this.Encoding, this.Normalized);
 
                 for (int i = 0; i < Count; ++i)
                 {
-                    var v3 = decoder.Invoke(i);
+                    var v3 = accessor[i];
 
                     if (v3.X < this._min[0]) this._min[0] = v3.X;
                     if (v3.X > this._max[0]) this._max[0] = v3.X;
@@ -296,11 +221,11 @@ namespace glTF2Sharp.Schema2
 
             if (count == 4)
             {
-                var decoder = Buffer.CreateVector4Decoder(this.Component, this.Normalized, this.ByteOffset);
+                var accessor = SourceBufferView.CreateVector4Decoder(this.ByteOffset, this.Encoding, this.Normalized);
 
                 for (int i = 0; i < Count; ++i)
                 {
-                    var v4 = decoder.Invoke(i);
+                    var v4 = accessor[i];
 
                     if (v4.X < this._min[0]) this._min[0] = v4.X;
                     if (v4.X > this._max[0]) this._max[0] = v4.X;
@@ -330,15 +255,15 @@ namespace glTF2Sharp.Schema2
             if (_count < 0) exxx.Add(new ModelException(this, $"Count is out of range"));
             if (_byteOffset < 0) exxx.Add(new ModelException(this, $"ByteOffset is out of range"));
 
-            if (Buffer.DeviceBufferTarget == BufferMode.ARRAY_BUFFER)
+            if (SourceBufferView.DeviceBufferTarget == BufferMode.ARRAY_BUFFER)
             {
-                var len = Component.ByteLength() * Element.Length();
+                var len = Encoding.ByteLength() * Dimensions.DimCount();
                 if ((len & 3) != 0) exxx.Add(new ModelException(this, $"Expected length to be multiple of 4, found {len}"));
             }
 
-            if (Buffer.DeviceBufferTarget == BufferMode.ELEMENT_ARRAY_BUFFER)
+            if (SourceBufferView.DeviceBufferTarget == BufferMode.ELEMENT_ARRAY_BUFFER)
             {
-                var len = Component.ByteLength() * Element.Length();
+                var len = Encoding.ByteLength() * Dimensions.DimCount();
                 if (len != 1 && len != 2 && len != 4) exxx.Add(new ModelException(this, $"Expected length to be 1, 2 or 4, found {len}"));
             }
 
@@ -355,90 +280,7 @@ namespace glTF2Sharp.Schema2
         }
 
         #endregion
-    }
-
-    public partial class AccessorSparse
-    {
-        public void CopyTo(Accessor srcAccessor, Byte[] dstBuffer, int dstStride)
-        {
-            if (this._count == 0) return;
-
-            var idxDecoder = this._indices.GetDecoder(srcAccessor.LogicalParent);
-            var valCopier = this._values.CopyTo(srcAccessor.LogicalParent, srcAccessor.Element, srcAccessor.Component);
-
-            for (int i = 0; i < this._count; ++i)
-            {
-                var key = idxDecoder.Invoke(i);
-
-                valCopier(i, dstBuffer, dstStride, key);
-            }
-        }
-
-        public void CopyTo<T>(Accessor srcAccessor, T[] dstBuffer) where T : struct
-        {
-            if (this._count == 0) return;
-
-            var idxDecoder = this._indices.GetDecoder(srcAccessor.LogicalParent);
-            var valDecoder = this._values.GetDecoder<T>(srcAccessor.LogicalParent, srcAccessor.Element, srcAccessor.Component, srcAccessor.Normalized);
-
-            for (int i = 0; i < this._count; ++i)
-            {
-                var key = idxDecoder.Invoke(i);
-                var val = valDecoder.Invoke(i);
-                dstBuffer[key] = val;
-            }
-        }
-    }
-
-    public partial class AccessorSparseIndices
-    {
-        public Func<int, int> GetDecoder(ROOT root)
-        {
-            var srcBuffer = root.LogicalBufferViews[this._bufferView];
-
-            return srcBuffer.CreateIndexDecoder(this._componentType, this._byteOffset ?? 0);
-        }
-
-        public IReadOnlyList<int> GetIndices(ROOT root, int count)
-        {
-            var srcDecoder = GetDecoder(root);
-
-            var indices = new int[count];
-
-            for (int i = 0; i < indices.Length; ++i)
-            {
-                indices[i] = srcDecoder(i);
-            }
-
-            return indices;
-        }
-    }
-
-    public partial class AccessorSparseValues
-    {
-        public Func<int, T> GetDecoder<T>(ROOT root, ElementType et, ComponentType ct, bool normalized)
-            where T : struct
-        {
-            var srcBuffer = root.LogicalBufferViews[this._bufferView];
-
-            var decoder = srcBuffer.CreateValueDecoder(et, ct, normalized, this._byteOffset ?? 0);
-
-            return idx => (T)decoder(idx);
-        }
-
-        public Action<int, IList<Byte>, int, int> CopyTo(ROOT root, ElementType et, ComponentType ct)
-        {
-            var srcBuffer = root.LogicalBufferViews[this._bufferView];
-
-            var itemLen = et.Length() * ct.ByteLength();
-            var srcStride = Math.Max(srcBuffer.ByteStride, itemLen);
-
-            return (srcIdx, dstBuff, dstStride, dstIdx) =>
-            {
-                srcBuffer.Data.CopyTo(srcStride * srcIdx, dstBuff, dstStride * dstIdx, itemLen);
-            };
-        }
-    }
+    }   
 
     public partial class ModelRoot
     {

+ 27 - 40
src/glTF2Sharp.DOM/Schema2/gltf.BufferView.cs

@@ -49,11 +49,11 @@ namespace glTF2Sharp.Schema2
 
         #region properties
 
-        public int LogicalIndex => this.LogicalParent.LogicalBufferViews.IndexOfReference(this);
+        public int LogicalIndex                 => this.LogicalParent.LogicalBufferViews.IndexOfReference(this);
 
-        public BufferMode? DeviceBufferTarget => this._target;
+        public BufferMode? DeviceBufferTarget   => this._target;
 
-        public int ByteStride => this._byteStride ?? 0;
+        public int ByteStride                   => this._byteStride.AsValue(0);
 
         public BYTES Data
         {
@@ -100,68 +100,55 @@ namespace glTF2Sharp.Schema2
             return String.Join(" ", accessors.Select(item => item._DebuggerDisplay_TryIdentifyContent()));
         }
 
-        public Func<int, int> CreateIndexDecoder(IndexType it, int byteOffset)
+        public Memory.IntegerAccessor CreateIndexDecoder(int byteOffset, IndexType encoding)
         {
             Guard.IsTrue(this.ByteStride == 0,null, "bytestride must be zero");
 
-            var reader = Memory.IntegerAccessor.Create(this.Data.Slice(byteOffset), it);
-
-            return idx => (int)reader[idx];
+            return Memory.IntegerAccessor.Create(this.Data.Slice(byteOffset), encoding);
         }
 
-        public Func<int, Object> CreateValueDecoder(ElementType et, ComponentType ct, bool normalized, int offset)
+        public Memory.IAccessor<Vector4> CreateVertexDecoder(int byteOffset, ElementType dimensions, ComponentType encoding, Boolean normalized)
         {
-            switch (et)
+            var srcData = this.Data.Slice(byteOffset);
+
+            switch (dimensions)
             {
-                case ElementType.SCALAR: { var d = CreateScalarDecoder(ct, offset); return idx => d(idx); }
-                case ElementType.VEC2: { var d = CreateVector2Decoder(ct, normalized, offset); return idx => d(idx); }
-                case ElementType.VEC3: { var d = CreateVector3Decoder(ct, normalized, offset); return idx => d(idx); }
-                case ElementType.VEC4: { var d = CreateVector4Decoder(ct, normalized, offset); return idx => d(idx); }
-                case ElementType.MAT4: { var d = CreateMatrix4x4Decoder(ct, normalized, offset); return idx => d(idx); }
+                case ElementType.SCALAR: return new Memory.ScalarAccessor(srcData, this.ByteStride, encoding, normalized);
+                case ElementType.VEC2: return new Memory.Vector2Accessor(srcData, this.ByteStride, encoding, normalized);
+                case ElementType.VEC3: return new Memory.Vector3Accessor(srcData, this.ByteStride, encoding, normalized);
+                case ElementType.VEC4: return new Memory.Vector4Accessor(srcData, this.ByteStride, encoding, normalized);
                 default: throw new NotImplementedException();
-            }
+            }            
         }
 
-        public Func<int, Single> CreateScalarDecoder(ComponentType ct, int offset)
+        public Memory.ScalarAccessor CreateScalarDecoder(int byteOffset, ComponentType encoding, Boolean normalized)
         {
-            var reader = new Memory.ScalarAccessor(this.Data.Slice(offset), this.ByteStride, ct, false);
-
-            return idx => reader[idx];
+            return new Memory.ScalarAccessor(this.Data.Slice(byteOffset), this.ByteStride, encoding, normalized);            
         }
 
-        public Func<int,Vector2> CreateVector2Decoder(ComponentType ct,bool normalized, int offset)
+        public Memory.Vector2Accessor CreateVector2Decoder(int byteOffset, ComponentType encoding, Boolean normalized)
         {
-            var reader = new Memory.Vector2Accessor(this.Data.Slice(offset), this.ByteStride, ct, normalized);
-
-            return idx => reader[idx];
+            return new Memory.Vector2Accessor(this.Data.Slice(byteOffset), this.ByteStride, encoding, normalized);
         }
 
-        public Func<int, Vector3> CreateVector3Decoder(ComponentType ct, bool normalized, int offset)
+        public Memory.Vector3Accessor CreateVector3Decoder(int byteOffset, ComponentType encoding, Boolean normalized)
         {
-            var reader = new Memory.Vector3Accessor(this.Data.Slice(offset), this.ByteStride, ct, normalized);
-
-            return idx => reader[idx];
+            return new Memory.Vector3Accessor(this.Data.Slice(byteOffset), this.ByteStride, encoding, normalized);
         }
 
-        public Func<int, Vector4> CreateVector4Decoder(ComponentType ct, bool normalized, int offset)
+        public Memory.Vector4Accessor CreateVector4Decoder(int byteOffset, ComponentType encoding, Boolean normalized)
         {
-            var reader = new Memory.Vector4Accessor(this.Data.Slice(offset), this.ByteStride, ct, normalized);
-
-            return idx => reader[idx];
+            return new Memory.Vector4Accessor(this.Data.Slice(byteOffset), this.ByteStride, encoding, normalized);
         }
 
-        public Func<int, Quaternion> CreateQuaternionDecoder(ComponentType ct, bool normalized, int offset)
+        public Memory.QuaternionAccessor CreateQuaternionDecoder(int byteOffset, ComponentType encoding, Boolean normalized)
         {
-            var reader = new Memory.QuaternionAccessor(this.Data.Slice(offset), this.ByteStride, ct, normalized);
-
-            return idx => reader[idx];
+            return new Memory.QuaternionAccessor(this.Data.Slice(byteOffset), this.ByteStride, encoding, normalized);
         }
 
-        public Func<int, Matrix4x4> CreateMatrix4x4Decoder(ComponentType ct, bool normalized, int offset)
+        public Memory.Matrix4x4Accessor CreateMatrix4x4Decoder(int byteOffset, ComponentType encoding, Boolean normalized)
         {
-            var reader = new Memory.Matrix4x4Accessor(this.Data.Slice(offset), this.ByteStride, ct, normalized);
-
-            return idx => reader[idx];
+            return new Memory.Matrix4x4Accessor(this.Data.Slice(byteOffset), this.ByteStride, encoding, normalized);
         }
 
         /// <summary>
@@ -172,7 +159,7 @@ namespace glTF2Sharp.Schema2
         public bool IsInterleaved(IEnumerable<Accessor> accessors)
         {
             Guard.NotNullOrEmpty(Accessors, nameof(accessors));
-            Guard.IsTrue(accessors.All(item => item.Buffer == this), nameof(accessors));
+            Guard.IsTrue(accessors.All(item => item.SourceBufferView == this), nameof(accessors));
 
             return accessors
                 .Select(item => item.ByteOffset)

+ 1 - 1
src/glTF2Sharp.DOM/Schema2/gltf.MeshPrimitive.cs

@@ -169,7 +169,7 @@ namespace glTF2Sharp.Schema2
             Guard.MustShareLogicalParent(this.LogicalParent, vb, nameof(vb));
 
             return VertexAccessors
-                .Where(key => key.Value.Buffer == vb)
+                .Where(key => key.Value.SourceBufferView == vb)
                 .OrderBy(item => item.Value.ByteOffset)
                 .ToArray();
         }

+ 1 - 1
src/glTF2Sharp.DOM/Schema2/gltf.Skin.cs

@@ -75,7 +75,7 @@ namespace glTF2Sharp.Schema2
 
             var node = this.LogicalParent.LogicalNodes[nodeIdx];
 
-            var matrix = (Matrix4x4)GetInverseBindMatricesAccessor().TryGetAttribute<Matrix4x4>()[idx];
+            var matrix = (Matrix4x4)GetInverseBindMatricesAccessor().CastToMatrix4x4Array()[idx];
 
             return new KeyValuePair<Node, Matrix4x4>(node, matrix);
         }

+ 22 - 22
src/glTF2Sharp.DOM/_Extensions.cs

@@ -203,9 +203,9 @@ namespace glTF2Sharp
 
         #region vertex & index accessors
 
-        public static int ByteLength(this IndexType t)
+        public static int ByteLength(this IndexType encoding)
         {
-            switch (t)
+            switch (encoding)
             {
                 case IndexType.UNSIGNED_BYTE: return 1;
                 case IndexType.UNSIGNED_SHORT: return 2;
@@ -215,6 +215,22 @@ namespace glTF2Sharp
             }
         }
 
+        public static int ByteLength(this ComponentType encoding)
+        {
+            switch (encoding)
+            {
+                case ComponentType.BYTE: return 1;
+                case ComponentType.SHORT: return 2;
+                case ComponentType.FLOAT: return 4;
+
+                case ComponentType.UNSIGNED_BYTE: return 1;
+                case ComponentType.UNSIGNED_SHORT: return 2;
+                case ComponentType.UNSIGNED_INT: return 4;
+
+                default: throw new NotImplementedException();
+            }
+        }
+
         public static ComponentType ToComponent(this IndexType t)
         {
             switch (t)
@@ -237,27 +253,11 @@ namespace glTF2Sharp
 
                 default: throw new NotImplementedException();
             }
-        }
-
-        public static int ByteLength(this ComponentType t)
-        {
-            switch (t)
-            {
-                case ComponentType.BYTE: return 1;
-                case ComponentType.SHORT: return 2;
-                case ComponentType.FLOAT: return 4;
-
-                case ComponentType.UNSIGNED_BYTE: return 1;
-                case ComponentType.UNSIGNED_SHORT: return 2;
-                case ComponentType.UNSIGNED_INT: return 4;
-
-                default: throw new NotImplementedException();
-            }
-        }        
+        }           
 
-        public static int Length(this ElementType t)
+        public static int DimCount(this ElementType dimension)
         {
-            switch (t)
+            switch (dimension)
             {
                 case ElementType.SCALAR: return 1;
                 case ElementType.VEC2: return 2;
@@ -270,7 +270,7 @@ namespace glTF2Sharp
             }
         }
 
-        internal static ElementType ToElement(this int l)
+        internal static ElementType ToDimension(this int l)
         {
             switch (l)
             {