Răsfoiți Sursa

working on sparse accessors... still haven't figured out how they fit into the GPU

Vicente Penades 7 ani în urmă
părinte
comite
48b6903e6c

+ 66 - 0
src/glTF2Sharp.DOM/Memory/SparseAccesor.cs

@@ -0,0 +1,66 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+namespace glTF2Sharp.Memory
+{
+    /// <summary>
+    /// Special accessor to wrap over a base accessor and a sparse accessor
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public struct SparseAccessor<T> : IAccessor<T>
+        where T : unmanaged
+    {
+        #region lifecycle
+
+        public SparseAccessor(IAccessor<T> bottom, IAccessor<T> top, IntegerAccessor topMapping)
+        {
+            _BottomItems = bottom;
+            _TopItems = top;
+            _Mapping = new Dictionary<int, int>();
+
+            for (int val = 0; val < topMapping.Count; ++val)
+            {
+                var key = (int)topMapping[val];
+                _Mapping[key] = val;
+            }
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly IAccessor<T> _BottomItems;
+        private readonly IAccessor<T> _TopItems;
+        private readonly Dictionary<int, int> _Mapping;
+
+        #endregion
+
+        #region API
+
+        public T this[int index]
+        {
+            get => _Mapping.TryGetValue(index, out int topIndex) ? _TopItems[topIndex] : _BottomItems[index];
+            set
+            {
+                if (_Mapping.TryGetValue(index, out int topIndex)) _TopItems[topIndex] = value;
+            }
+        }
+
+        public int Count => _BottomItems.Count;
+
+        public void CopyTo(ArraySegment<T> dst) { AccessorsUtils.Copy(this, dst); }
+
+        public (T, T) GetBounds()
+        {
+            throw new NotImplementedException();
+        }
+
+        public IEnumerator<T> GetEnumerator() { return new AccessorEnumerator<T>(this); }
+
+        IEnumerator IEnumerable.GetEnumerator() { return new AccessorEnumerator<T>(this); }
+
+        #endregion
+    }
+}

+ 88 - 45
src/glTF2Sharp.DOM/Schema2/gltf.AccessorSparse.cs

@@ -5,87 +5,130 @@ using System.Text;
 
 namespace glTF2Sharp.Schema2
 {
+    // TODO:
+    // AccessorSparse is a single child of an Accessor
+    // when an Accessor defines an AccessorSparse, it becomes a "two layers" collection.
+    // the layer at the bottom is the data of the base accessor
+    // the layer on top, replaces just a few elements in the base accessor.
+    // Unlike many other objects in the API, AccessorSparse does not implement IChildOf<Accessor>
+    // which would allow AccessorSparse to access the interal data of its parent.
+    // So we have two choices here:
+    // 1- Implement IChildOf<Accessor> and finish the SingleChild<T> collection object
+    // 2- Make these classes non public, and expose them with a public view object.
+    // 3- Make the whole Accessor+AccessorSparse block non public, and expose them with a public view.
+
     using ROOT = ModelRoot;
 
     public partial class AccessorSparse
     {
-        public void CopyTo(Accessor srcAccessor, Byte[] dstBuffer, int dstStride)
+        internal AccessorSparse() { }
+
+        internal AccessorSparse(BufferView indices, int indicesOffset, IndexType indicesEncoding, BufferView values, int valuesOffset, int count)
         {
-            if (this._count == 0) return;
+            Guard.NotNull(indices, nameof(indices));
+            Guard.NotNull(values, nameof(values));
+            Guard.MustBeGreaterThanOrEqualTo(count, _countMinimum,nameof(count));
+
+            this._count = count;
+            this._indices = new AccessorSparseIndices(indices, indicesOffset, indicesEncoding);
+            this._values = new AccessorSparseValues(values, valuesOffset);
+        }
 
-            var idxDecoder = this._indices.GetDecoder(srcAccessor.LogicalParent);
-            var valCopier = this._values.CopyTo(srcAccessor.LogicalParent, srcAccessor.Dimensions, srcAccessor.Encoding);
+        public int Count => _count; // what is this!?? TODO: check with specs        
 
-            for (int i = 0; i < this._count; ++i)
-            {
-                var key = idxDecoder.Invoke(i);
+        public Memory.SparseAccessor<Single> GetScalarAccesor(Accessor baseAccessor)
+        {
+            var bot = baseAccessor.CastToScalarAccessor();
+            var top = this._values.CastToScalarAccessor(baseAccessor.LogicalParent, baseAccessor.Encoding, baseAccessor.Normalized);
+            var idx = this._indices.CastToIndicesAccessor(baseAccessor.LogicalParent);
 
-                valCopier(i, dstBuffer, dstStride, key);
-            }
+            return new Memory.SparseAccessor<Single>(bot, top, idx);
         }
 
-        public void CopyTo(Accessor srcAccessor, Vector4[] dstBuffer)
+        public Memory.SparseAccessor<Vector2> GetVector2Accesor(Accessor baseAccessor)
         {
-            if (this._count == 0) return;
+            var bot = baseAccessor.CastToVector2Accessor();
+            var top = this._values.CastToVector2Accessor(baseAccessor.LogicalParent, baseAccessor.Encoding, baseAccessor.Normalized);
+            var idx = this._indices.CastToIndicesAccessor(baseAccessor.LogicalParent);
+
+            return new Memory.SparseAccessor<Vector2>(bot, top, idx);
+        }
 
-            var idxDecoder = this._indices.GetDecoder(srcAccessor.LogicalParent);
-            var valDecoder = this._values.GetDecoder(srcAccessor.LogicalParent, srcAccessor.Encoding, srcAccessor.Dimensions, srcAccessor.Normalized);
+        public Memory.SparseAccessor<Vector3> GetVector3Accesor(Accessor baseAccessor)
+        {
+            var bot = baseAccessor.CastToVector3Accessor();
+            var top = this._values.CastToVector3Accessor(baseAccessor.LogicalParent, baseAccessor.Encoding, baseAccessor.Normalized);
+            var idx = this._indices.CastToIndicesAccessor(baseAccessor.LogicalParent);
 
-            for (int i = 0; i < this._count; ++i)
-            {
-                var key = idxDecoder.Invoke(i);
-                var val = valDecoder[i];
-                dstBuffer[key] = val;
-            }
+            return new Memory.SparseAccessor<Vector3>(bot, top, idx);
+        }
+
+        public Memory.SparseAccessor<Vector4> GetVector4Accesor(Accessor baseAccessor)
+        {
+            var bot = baseAccessor.CastToVector4Accessor();
+            var top = this._values.CastToVector4Accessor(baseAccessor.LogicalParent, baseAccessor.Encoding, baseAccessor.Normalized);
+            var idx = this._indices.CastToIndicesAccessor(baseAccessor.LogicalParent);
+
+            return new Memory.SparseAccessor<Vector4>(bot, top, idx);
         }
     }
 
     public partial class AccessorSparseIndices
     {
-        public Func<int, int> GetDecoder(ROOT root)
-        {
-            var srcBuffer = root.LogicalBufferViews[this._bufferView];
+        internal AccessorSparseIndices() { }
 
-            var accessor = srcBuffer.CreateIndicesAccessor(this._byteOffset ?? 0, this._componentType);
+        internal AccessorSparseIndices(BufferView bv, int byteOffset, IndexType encoding)
+        {
+            Guard.NotNull(bv,nameof(bv));
+            Guard.MustBeGreaterThanOrEqualTo(byteOffset, _byteOffsetMinimum, nameof(byteOffset));
 
-            return index => (int)accessor[index];
+            this._bufferView = bv.LogicalIndex;
+            this._byteOffset = byteOffset.AsNullable(_byteOffsetDefault);
+            this._componentType = encoding;
         }
 
-        public IReadOnlyList<int> GetIndices(ROOT root, int count)
+        public Memory.IntegerAccessor CastToIndicesAccessor(ROOT root)
         {
-            var srcDecoder = GetDecoder(root);
+            var srcBuffer = root.LogicalBufferViews[this._bufferView];
+            return srcBuffer.CreateIndicesAccessor(this._byteOffset ?? 0, this._componentType);
+        }        
+    }
 
-            var indices = new int[count];
+    public partial class AccessorSparseValues
+    {
+        internal AccessorSparseValues() { }
 
-            for (int i = 0; i < indices.Length; ++i)
-            {
-                indices[i] = srcDecoder(i);
-            }
+        internal AccessorSparseValues(BufferView bv, int byteOffset)
+        {
+            Guard.NotNull(bv, nameof(bv));
+            Guard.MustBeGreaterThanOrEqualTo(byteOffset, _byteOffsetMinimum, nameof(byteOffset));
 
-            return indices;
+            this._bufferView = bv.LogicalIndex;
+            this._byteOffset = byteOffset.AsNullable(_byteOffsetDefault);            
         }
-    }
 
-    public partial class AccessorSparseValues
-    {
-        public Memory.IAccessor<Vector4> GetDecoder(ROOT root, ComponentType encoding, ElementType dimensions, Boolean normalized)
+        public Memory.ScalarAccessor CastToScalarAccessor(ROOT root, ComponentType encoding, Boolean normalized)
         {
             var srcBuffer = root.LogicalBufferViews[this._bufferView];
-
-            return srcBuffer.CreateVertexAccessor(this._byteOffset ?? 0, dimensions, encoding, normalized);
+            return srcBuffer.CreateScalarAccessor(this._byteOffset ?? 0, encoding, normalized);
         }
 
-        public Action<int, IList<Byte>, int, int> CopyTo(ROOT root, ElementType et, ComponentType ct)
+        public Memory.Vector2Accessor CastToVector2Accessor(ROOT root, ComponentType encoding, Boolean normalized)
         {
             var srcBuffer = root.LogicalBufferViews[this._bufferView];
+            return srcBuffer.CreateVector2Accessor(this._byteOffset ?? 0, encoding, normalized);
+        }
 
-            var itemLen = et.DimCount() * ct.ByteLength();
-            var srcStride = Math.Max(srcBuffer.ByteStride, itemLen);
+        public Memory.Vector3Accessor CastToVector3Accessor(ROOT root, ComponentType encoding, Boolean normalized)
+        {
+            var srcBuffer = root.LogicalBufferViews[this._bufferView];
+            return srcBuffer.CreateVector3Accessor(this._byteOffset ?? 0, encoding, normalized);
+        }
 
-            return (srcIdx, dstBuff, dstStride, dstIdx) =>
-            {
-                srcBuffer.Data.CopyTo(srcStride * srcIdx, dstBuff, dstStride * dstIdx, itemLen);
-            };
+        public Memory.Vector4Accessor CastToVector4Accessor(ROOT root, ComponentType encoding, Boolean normalized)
+        {
+            var srcBuffer = root.LogicalBufferViews[this._bufferView];
+            return srcBuffer.CreateVector4Accessor(this._byteOffset ?? 0, encoding, normalized);
         }
     }
 }

+ 2 - 0
src/glTF2Sharp.DOM/Schema2/gltf.Accessors.cs

@@ -90,6 +90,7 @@ namespace glTF2Sharp.Schema2
 
         public Memory.Matrix4x4Accessor CastToMatrix4x4Accessor()
         {
+            Guard.IsFalse(this.IsSparse, nameof(IsSparse));
             Guard.IsTrue(this.Dimensions == ElementType.MAT4, nameof(Dimensions));
 
             return SourceBufferView.CreateMatrix4x4Accessor(this.ByteOffset, this.Encoding, this.Normalized);
@@ -121,6 +122,7 @@ namespace glTF2Sharp.Schema2
 
         public Memory.IntegerAccessor CastToIndicesAccessor()
         {
+            Guard.IsFalse(this.IsSparse, nameof(IsSparse));
             Guard.IsTrue(this.Dimensions == ElementType.SCALAR, nameof(Dimensions));
             return SourceBufferView.CreateIndicesAccessor(this.ByteOffset, this.Encoding.ToIndex());
         }