Bladeren bron

improving compatibility

Vicente Penades 6 jaren geleden
bovenliggende
commit
4f1c04e7e8

+ 95 - 0
src/SharpGLTF.Core/Memory/ColorArray.cs

@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Numerics;
+using System.Collections;
+using System.Linq;
+
+namespace SharpGLTF.Memory
+{
+    using BYTES = ArraySegment<Byte>;
+
+    using ENCODING = Schema2.EncodingType;
+
+    /// <summary>
+    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an array of <see cref="Vector4"/> values.
+    /// </summary>
+    [System.Diagnostics.DebuggerDisplay("Vector4 Accessor {Count}")]
+    public struct ColorArray : IList<Vector4>, IReadOnlyList<Vector4>
+    {
+        #region constructors
+
+        public ColorArray(Byte[] source, int byteOffset, int itemsCount, int byteStride, int dimensions = 4, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(new BYTES(source), byteOffset, itemsCount, byteStride, dimensions, encoding, normalized) { }
+
+        public ColorArray(BYTES source, int byteStride = 0, int dimensions = 4, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(source, 0, int.MaxValue, byteStride, dimensions, encoding, normalized) { }
+
+        public ColorArray(BYTES source, int byteOffset, int itemsCount, int byteStride, int dimensions = 4, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+        {
+            Guard.MustBeBetweenOrEqualTo(dimensions, 3, 4, nameof(dimensions));
+
+            _Accessor = new FloatingAccessor(source, byteOffset, itemsCount, byteStride, dimensions, encoding, normalized);
+            _Dimensions = dimensions;
+        }
+
+        #endregion
+
+        #region data
+
+        [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+        private FloatingAccessor _Accessor;
+
+        private readonly int _Dimensions;
+
+        [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+        private Vector4[] _DebugItems => this.ToArray();
+
+        #endregion
+
+        #region API
+
+        [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+        public int Count => _Accessor.Count;
+
+        bool ICollection<Vector4>.IsReadOnly => false;
+
+        public Vector4 this[int index]
+        {
+            get
+            {
+                return new Vector4(_Accessor[index, 0], _Accessor[index, 1], _Accessor[index, 2], _Dimensions < 4 ? 1 : _Accessor[index, 3]);
+            }
+
+            set
+            {
+                _Accessor[index, 0] = value.X;
+                _Accessor[index, 1] = value.Y;
+                _Accessor[index, 2] = value.Z;
+                if (_Dimensions >= 4 ) _Accessor[index, 3] = value.W;
+            }
+        }
+
+        public IEnumerator<Vector4> GetEnumerator() { return new EncodedArrayEnumerator<Vector4>(this); }
+
+        IEnumerator IEnumerable.GetEnumerator() { return new EncodedArrayEnumerator<Vector4>(this); }
+
+        public bool Contains(Vector4 item) { return IndexOf(item) >= 0; }
+
+        public int IndexOf(Vector4 item) { return EncodedArrayUtils.FirstIndexOf(this, item); }
+
+        public void CopyTo(Vector4[] array, int arrayIndex) { EncodedArrayUtils.CopyTo(this, array, arrayIndex); }
+
+        void IList<Vector4>.Insert(int index, Vector4 item) { throw new NotSupportedException(); }
+
+        void IList<Vector4>.RemoveAt(int index) { throw new NotSupportedException(); }
+
+        void ICollection<Vector4>.Add(Vector4 item) { throw new NotSupportedException(); }
+
+        void ICollection<Vector4>.Clear() { throw new NotSupportedException(); }
+
+        bool ICollection<Vector4>.Remove(Vector4 item) { throw new NotSupportedException(); }
+
+        #endregion
+    }
+}

+ 23 - 4
src/SharpGLTF.Core/Memory/MemoryAccessor.cs

@@ -90,7 +90,10 @@ namespace SharpGLTF.Memory
 
 
         #region API
         #region API
 
 
-        public int ByteLength => this.Dimensions.DimCount() * this.Encoding.ByteLength();
+        /// <summary>
+        /// Gets the number of bytes of the current encoded Item, padded to 4 bytes.
+        /// </summary>
+        public int PaddedByteLength => (this.Dimensions.DimCount() * this.Encoding.ByteLength()).PaddingSize(4);
 
 
         public Boolean IsValidVertexAttribute
         public Boolean IsValidVertexAttribute
         {
         {
@@ -99,8 +102,7 @@ namespace SharpGLTF.Memory
                 if (this.ByteOffset < 0) return false;
                 if (this.ByteOffset < 0) return false;
                 if (this.ItemsCount < 0) return false;
                 if (this.ItemsCount < 0) return false;
                 if (this.ByteStride < 0) return false;
                 if (this.ByteStride < 0) return false;
-                var blen = this.ByteLength;
-                if (blen == 0 || (blen & 3) != 0) return false;
+                var blen = this.PaddedByteLength;
 
 
                 if (this.ByteStride > 0 && this.ByteStride < blen) return false;
                 if (this.ByteStride > 0 && this.ByteStride < blen) return false;
                 if ((this.ByteStride & 3) != 0) return false;
                 if ((this.ByteStride & 3) != 0) return false;
@@ -137,7 +139,7 @@ namespace SharpGLTF.Memory
                 a.ByteOffset = byteOffset;
                 a.ByteOffset = byteOffset;
                 a.ItemsCount = itemsCount;
                 a.ItemsCount = itemsCount;
 
 
-                var attributeStride = a.ByteLength;
+                var attributeStride = a.PaddedByteLength;
 
 
                 byteStride += attributeStride;
                 byteStride += attributeStride;
                 byteOffset += attributeStride;
                 byteOffset += attributeStride;
@@ -278,6 +280,13 @@ namespace SharpGLTF.Memory
             return new Vector4Array(_Data, _Attribute.ByteOffset, _Attribute.ItemsCount, _Attribute.ByteStride, _Attribute.Encoding, _Attribute.Normalized);
             return new Vector4Array(_Data, _Attribute.ByteOffset, _Attribute.ItemsCount, _Attribute.ByteStride, _Attribute.Encoding, _Attribute.Normalized);
         }
         }
 
 
+        public ColorArray AsColorArray()
+        {
+            Guard.IsTrue(_Attribute.IsValidVertexAttribute, nameof(_Attribute));
+            Guard.IsTrue(_Attribute.Dimensions == DIMENSIONS.VEC3 || _Attribute.Dimensions == DIMENSIONS.VEC4, nameof(_Attribute));
+            return new ColorArray(_Data, _Attribute.ByteOffset, _Attribute.ItemsCount, _Attribute.ByteStride, _Attribute.Dimensions.DimCount(), _Attribute.Encoding, _Attribute.Normalized);
+        }
+
         public void Fill(IReadOnlyList<Quaternion> values) { values.CopyTo(AsQuaternionArray()); }
         public void Fill(IReadOnlyList<Quaternion> values) { values.CopyTo(AsQuaternionArray()); }
 
 
         public QuaternionArray AsQuaternionArray()
         public QuaternionArray AsQuaternionArray()
@@ -336,6 +345,16 @@ namespace SharpGLTF.Memory
             return new SparseArray<Vector4>(bottom.AsVector4Array(), topValues.AsVector4Array(), topKeys);
             return new SparseArray<Vector4>(bottom.AsVector4Array(), topValues.AsVector4Array(), topKeys);
         }
         }
 
 
+        public static IList<Vector4> CreateColorSparseArray(MemoryAccessor bottom, IntegerArray topKeys, MemoryAccessor topValues)
+        {
+            Guard.IsTrue(bottom._Attribute.Dimensions == topValues._Attribute.Dimensions, nameof(topValues));
+            Guard.IsTrue(topKeys.Count <= bottom._Attribute.ItemsCount, nameof(topKeys));
+            Guard.IsTrue(topKeys.Count == topValues._Attribute.ItemsCount, nameof(topValues));
+            Guard.IsTrue(topKeys.All(item => item < (uint)bottom._Attribute.ItemsCount), nameof(topKeys));
+
+            return new SparseArray<Vector4>(bottom.AsColorArray(), topValues.AsColorArray(), topKeys);
+        }
+
         #endregion
         #endregion
     }
     }
 }
 }

+ 10 - 0
src/SharpGLTF.Core/Schema2/gltf.Accessors.cs

@@ -249,6 +249,16 @@ namespace SharpGLTF.Schema2
             return MemoryAccessor.CreateVector4SparseArray(memory, sparseKV.Key, sparseKV.Value);
             return MemoryAccessor.CreateVector4SparseArray(memory, sparseKV.Key, sparseKV.Value);
         }
         }
 
 
+        public IList<Vector4> AsColorArray()
+        {
+            var memory = _GetMemoryAccessor();
+
+            if (this._sparse == null) return memory.AsColorArray();
+
+            var sparseKV = this._sparse._CreateMemoryAccessors(this);
+            return MemoryAccessor.CreateColorSparseArray(memory, sparseKV.Key, sparseKV.Value);
+        }
+
         public IList<Quaternion> AsQuaternionArray()
         public IList<Quaternion> AsQuaternionArray()
         {
         {
             var memory = _GetMemoryAccessor();
             var memory = _GetMemoryAccessor();

+ 4 - 1
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexColumns.cs

@@ -40,7 +40,10 @@ namespace SharpGLTF.Geometry.VertexTypes
 
 
             for (int i = 0; i < Normals.Count; ++i)
             for (int i = 0; i < Normals.Count; ++i)
             {
             {
-                Normals[i] = normalsMap[Positions[i]];
+                if (normalsMap.TryGetValue(Positions[i], out Vector3 nrm))
+                {
+                    Normals[i] = nrm;
+                }
             }
             }
         }
         }
 
 

+ 2 - 2
src/SharpGLTF.Toolkit/Schema2/MeshExtensions.cs

@@ -329,8 +329,8 @@ namespace SharpGLTF.Schema2
             if (vertexAccessors.ContainsKey("NORMAL")) columns.Normals = vertexAccessors["NORMAL"].AsVector3Array();
             if (vertexAccessors.ContainsKey("NORMAL")) columns.Normals = vertexAccessors["NORMAL"].AsVector3Array();
             if (vertexAccessors.ContainsKey("TANGENT")) columns.Tangents = vertexAccessors["TANGENT"].AsVector4Array();
             if (vertexAccessors.ContainsKey("TANGENT")) columns.Tangents = vertexAccessors["TANGENT"].AsVector4Array();
 
 
-            if (vertexAccessors.ContainsKey("COLOR_0")) columns.Colors0 = vertexAccessors["COLOR_0"].AsVector4Array();
-            if (vertexAccessors.ContainsKey("COLOR_1")) columns.Colors1 = vertexAccessors["COLOR_1"].AsVector4Array();
+            if (vertexAccessors.ContainsKey("COLOR_0")) columns.Colors0 = vertexAccessors["COLOR_0"].AsColorArray();
+            if (vertexAccessors.ContainsKey("COLOR_1")) columns.Colors1 = vertexAccessors["COLOR_1"].AsColorArray();
 
 
             if (vertexAccessors.ContainsKey("TEXCOORD_0")) columns.Textures0 = vertexAccessors["TEXCOORD_0"].AsVector2Array();
             if (vertexAccessors.ContainsKey("TEXCOORD_0")) columns.Textures0 = vertexAccessors["TEXCOORD_0"].AsVector2Array();
             if (vertexAccessors.ContainsKey("TEXCOORD_1")) columns.Textures1 = vertexAccessors["TEXCOORD_1"].AsVector2Array();
             if (vertexAccessors.ContainsKey("TEXCOORD_1")) columns.Textures1 = vertexAccessors["TEXCOORD_1"].AsVector2Array();

+ 33 - 23
tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadGeneratedTests.cs

@@ -28,39 +28,49 @@ namespace SharpGLTF.Schema2.LoadAndSave
         {
         {
             TestContext.CurrentContext.AttachShowDirLink();
             TestContext.CurrentContext.AttachShowDirLink();
 
 
-            var files = TestFiles.GetReferenceModelPaths()
-                .Where(item => item.Contains("\\Positive\\"));
+            var files = TestFiles.GetReferenceModelPaths();
+
+            bool passed = true;
 
 
             foreach (var f in files)
             foreach (var f in files)
             {
             {
-                // var errors = _LoadNumErrorsForModel(f);
-                // if (errors > 0) continue;
-
                 try
                 try
                 {
                 {
-                    var model = ModelRoot.Load(f);
-                    model.AttachToCurrentTest(System.IO.Path.ChangeExtension(System.IO.Path.GetFileName(f), ".obj"));
+                    var model = ModelRoot.Load(f.Item1);
+
+                    if (!f.Item2)
+                    {
+                        TestContext.Error.WriteLine($"{f.Item1.ToShortDisplayPath()} 👎😦 Should not load!");
+                        passed = false;
+                    }
+                    else
+                    {
+                        TestContext.WriteLine($"{f.Item1.ToShortDisplayPath()} 🙂👍");                        
+                    }                    
                 }
                 }
-                catch (IO.UnsupportedExtensionException eex)
+                catch (Exception ex)
                 {
                 {
-                    TestContext.WriteLine($"{f.ToShortDisplayPath()} ERROR: {eex.Message}");
+                    if (f.Item2)
+                    {
+                        TestContext.Error.WriteLine($"{f.Item1.ToShortDisplayPath()} 👎😦 Should load!");
+                        TestContext.Error.WriteLine($"   ERROR: {ex.Message}");
+                        passed = false;
+                    }
+                    else
+                    {
+                        TestContext.WriteLine($"{f.Item1.ToShortDisplayPath()} 🙂👍");
+                        TestContext.WriteLine($"   Exception: {ex.Message}");
+                    }                    
                 }
                 }
-            }
-        }        
-
-        private static int _LoadNumErrorsForModel(string gltfPath)
-        {
-            var dir = System.IO.Path.GetDirectoryName(gltfPath);
-            var fn = System.IO.Path.GetFileNameWithoutExtension(gltfPath);
 
 
-            var jsonPath = System.IO.Path.Combine(dir, "ValidatorResults", System.IO.Path.ChangeExtension(fn, "json"));
-
-            var content = System.IO.File.ReadAllText(jsonPath);
-            var doc = Newtonsoft.Json.Linq.JObject.Parse(content);
-
-            var token = doc.SelectToken("issues").SelectToken("numErrors");
+                if (f.Item2 && !f.Item1.ToLower().Contains("compatibility"))
+                {
+                    var model = ModelRoot.Load(f.Item1);
+                    model.AttachToCurrentTest(System.IO.Path.ChangeExtension(System.IO.Path.GetFileName(f.Item1), ".obj"));
+                }
+            }
 
 
-            return (int)token;
+            Assert.IsTrue(passed);
         }
         }
     }
     }
 }
 }

+ 31 - 2
tests/SharpGLTF.Tests/TestFiles.cs

@@ -63,9 +63,38 @@ namespace SharpGLTF
             return GetModelPathsInDirectory(_SchemaDir, "extensions", "2.0");         
             return GetModelPathsInDirectory(_SchemaDir, "extensions", "2.0");         
         }
         }
 
 
-        public static IReadOnlyList<string> GetReferenceModelPaths()
+        public static IEnumerable<(string, bool)> GetReferenceModelPaths()
         {
         {
-            return GetModelPathsInDirectory(_GeneratedModelsDir);
+            var dirPath = _GeneratedModelsDir;
+            if (dirPath.EndsWith(".zip")) dirPath = dirPath.Substring(0, dirPath.Length - 4);
+
+            var manifestsPath = System.IO.Path.Combine(dirPath, "Positive");
+
+            var manifests = System.IO.Directory.GetFiles(manifestsPath, "Manifest.json", System.IO.SearchOption.AllDirectories)
+                .Skip(1)
+                .ToArray();
+
+            foreach (var m in manifests)
+            {
+                var d = System.IO.Path.GetDirectoryName(m);
+
+                var content = System.IO.File.ReadAllText(m);
+                var doc = Newtonsoft.Json.Linq.JObject.Parse(content);
+
+                var models = doc.SelectToken("models");
+                
+                foreach(var model in models)
+                {
+                    var mdlPath = (String)model.SelectToken("fileName");
+                    var loadable = (Boolean)model.SelectToken("loadable");
+
+                    mdlPath = System.IO.Path.Combine(d, mdlPath);
+
+                    yield return (mdlPath, loadable);
+                }
+            }
+
+            yield break;
         }
         }
 
 
         public static IReadOnlyList<string> GetSampleModelsPaths()
         public static IReadOnlyList<string> GetSampleModelsPaths()