Browse Source

Updated nuget packages.
Updated analyzers.
improved extensions validation.

Vicente Penades 5 years ago
parent
commit
ee789d20f5

+ 5 - 25
SharpGLTF.ruleset

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
-<RuleSet Name="SharpGLTF" ToolsVersion="15.0">
+<RuleSet Name="SharpGLTF" ToolsVersion="16.0">
   <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
   <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
     <Rule Id="AD0001" Action="None" />
     <Rule Id="AD0001" Action="None" />
     <Rule Id="CS1591" Action="None" />
     <Rule Id="CS1591" Action="None" />
@@ -20,7 +20,9 @@
     <Rule Id="SA1300" Action="None" />
     <Rule Id="SA1300" Action="None" />
     <Rule Id="SA1306" Action="None" />
     <Rule Id="SA1306" Action="None" />
     <Rule Id="SA1309" Action="None" />
     <Rule Id="SA1309" Action="None" />
+    <Rule Id="SA1310" Action="Info" />
     <Rule Id="SA1400" Action="None" />
     <Rule Id="SA1400" Action="None" />
+    <Rule Id="SA1401" Action="None" />
     <Rule Id="SA1402" Action="None" />
     <Rule Id="SA1402" Action="None" />
     <Rule Id="SA1405" Action="None" />
     <Rule Id="SA1405" Action="None" />
     <Rule Id="SA1413" Action="None" />
     <Rule Id="SA1413" Action="None" />
@@ -29,38 +31,16 @@
     <Rule Id="SA1502" Action="None" />
     <Rule Id="SA1502" Action="None" />
     <Rule Id="SA1503" Action="None" />
     <Rule Id="SA1503" Action="None" />
     <Rule Id="SA1512" Action="None" />
     <Rule Id="SA1512" Action="None" />
-    <Rule Id="SA1516" Action="None" />
     <Rule Id="SA1515" Action="None" />
     <Rule Id="SA1515" Action="None" />
+    <Rule Id="SA1516" Action="None" />
     <Rule Id="SA1600" Action="None" />
     <Rule Id="SA1600" Action="None" />
     <Rule Id="SA1601" Action="None" />
     <Rule Id="SA1601" Action="None" />
     <Rule Id="SA1602" Action="None" />
     <Rule Id="SA1602" Action="None" />
+    <Rule Id="SA1605" Action="None" />
     <Rule Id="SA1625" Action="None" />
     <Rule Id="SA1625" Action="None" />
     <Rule Id="SA1629" Action="None" />
     <Rule Id="SA1629" Action="None" />
     <Rule Id="SA1633" Action="None" />
     <Rule Id="SA1633" Action="None" />
     <Rule Id="SA1649" Action="None" />
     <Rule Id="SA1649" Action="None" />
     <Rule Id="SA1652" Action="None" />
     <Rule Id="SA1652" Action="None" />
-    <Rule Id="SA1605" Action="None" />
-    <Rule Id="SA1310" Action="Info" />
-  </Rules>
-  <Rules AnalyzerId="Microsoft.CodeQuality.CSharp.Analyzers" RuleNamespace="Microsoft.CodeQuality.CSharp.Analyzers">
-    <Rule Id="CA1001" Action="Error" />
-    <Rule Id="CA1032" Action="Info" />
-  </Rules>
-  <Rules AnalyzerId="Microsoft.CodeQuality.Analyzers" RuleNamespace="Microsoft.CodeQuality.Analyzers">
-    <Rule Id="CA1051" Action="None" />
-    <Rule Id="CA1715" Action="None" />
-    <Rule Id="CA1063" Action="Error" />
-    <Rule Id="CA1815" Action="Info" />
-    <Rule Id="CA1710" Action="Info" />
-    <Rule Id="CA2225" Action="Info" />
-  </Rules>
-  <Rules AnalyzerId="Microsoft.NetCore.Analyzers" RuleNamespace="Microsoft.NetCore.Analyzers">
-    <Rule Id="CA1816" Action="Error" />
-    <Rule Id="CA2000" Action="Error" />
-    <Rule Id="CA2213" Action="Error" />
-    <Rule Id="CA2216" Action="Error" />
-    <Rule Id="CA2242" Action="Error" />
-    <Rule Id="CA1303" Action="None" />
-    <Rule Id="CA1308" Action="None" />
   </Rules>
   </Rules>
 </RuleSet>
 </RuleSet>

+ 1 - 1
build/SharpGLTF.CodeGen/SharpGLTF.CodeGen.csproj

@@ -8,7 +8,7 @@
 
 
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="LibGit2Sharp" Version="0.26.2" />    
     <PackageReference Include="LibGit2Sharp" Version="0.26.2" />    
-    <PackageReference Include="NJsonSchema.CodeGeneration.CSharp" Version="10.3.1" />
+    <PackageReference Include="NJsonSchema.CodeGeneration.CSharp" Version="10.3.2" />
   </ItemGroup>
   </ItemGroup>
 
 
 </Project>
 </Project>

+ 1 - 1
examples/Example1/Example1.csproj

@@ -2,7 +2,7 @@
 
 
   <PropertyGroup>
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
-    <TargetFramework>netcoreapp2.2</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>

+ 1 - 1
examples/InfiniteSkinnedTentacle/InfiniteSkinnedTentacle.csproj

@@ -2,7 +2,7 @@
 
 
   <PropertyGroup>
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
-    <TargetFramework>netcoreapp2.2</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>

+ 1 - 1
examples/PointCloudGalaxy/PointCloudGalaxy.csproj

@@ -2,7 +2,7 @@
 
 
   <PropertyGroup>
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
-    <TargetFramework>netcoreapp2.2</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>

+ 5 - 3
src/Analyzers.props

@@ -9,9 +9,11 @@
     <AdditionalFiles Include="$(MsBuildThisFileDirectory)..\stylecop.json" />
     <AdditionalFiles Include="$(MsBuildThisFileDirectory)..\stylecop.json" />
   </ItemGroup>
   </ItemGroup>
 
 
-  <ItemGroup>    
-    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0" PrivateAssets="all" />
-    <PackageReference Include="Microsoft.CodeQuality.Analyzers" Version="3.3.0" PrivateAssets="all" />
+  <ItemGroup>
+    <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.1">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
     <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
     <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
   </ItemGroup>
   </ItemGroup>
 	
 	

+ 2 - 2
src/Shared/_Extensions.cs

@@ -338,9 +338,9 @@ namespace SharpGLTF
             }
             }
         }
         }
 
 
-        internal static IEnumerable<T> ConcatItems<T>(this IEnumerable<T> collection, params T[] instances)
+        internal static IEnumerable<T> ConcatElements<T>(this IEnumerable<T> collection, params T[] elements)
         {
         {
-            return collection.Concat(instances.Where(item => item != null));
+            return collection.Concat(elements.Where(item => item != null));
         }
         }
 
 
         public static void SanitizeNormals(this IList<Vector3> normals)
         public static void SanitizeNormals(this IList<Vector3> normals)

+ 25 - 7
src/SharpGLTF.Core/IO/ReadContext.cs

@@ -64,15 +64,16 @@ namespace SharpGLTF.IO
             return new ReadContext(_loadFile, _uriSolver);
             return new ReadContext(_loadFile, _uriSolver);
         }
         }
 
 
-        public static ReadContext CreateFromDictionary(IReadOnlyDictionary<string, BYTES> dictionary)
+        public static ReadContext CreateFromDictionary(IReadOnlyDictionary<string, BYTES> dictionary, bool checkExtensions = true)
         {
         {
-            return new ReadContext(rawUri => dictionary[rawUri]);
+            return new ReadContext(rawUri => dictionary[rawUri], null, checkExtensions);
         }
         }
 
 
-        private ReadContext(FileReaderCallback reader, UriResolver uriResolver = null)
+        private ReadContext(FileReaderCallback reader, UriResolver uriResolver = null, bool checkExtensions = true)
         {
         {
             _FileReader = reader;
             _FileReader = reader;
             _UriResolver = uriResolver;
             _UriResolver = uriResolver;
+            _CheckSupportedExtensions = checkExtensions;
         }
         }
 
 
         internal ReadContext(ReadContext other)
         internal ReadContext(ReadContext other)
@@ -94,6 +95,11 @@ namespace SharpGLTF.IO
         /// </summary>
         /// </summary>
         private Byte[] _BinaryChunk;
         private Byte[] _BinaryChunk;
 
 
+        /// <summary>
+        /// Gets a value indicating whether to check used/required extensions.
+        /// </summary>
+        internal Boolean _CheckSupportedExtensions { get; private set; } = true;
+
         #endregion
         #endregion
 
 
         #region API - File System
         #region API - File System
@@ -277,9 +283,21 @@ namespace SharpGLTF.IO
 
 
             // schema validation
             // schema validation
 
 
-            root.ValidateReferences(vcontext.GetContext());
-            var ex = vcontext.Errors.FirstOrDefault();
-            if (ex != null) return (null, vcontext);
+            if (this._CheckSupportedExtensions)
+            {
+                root._ValidateExtensions(vcontext.GetContext());
+                var ex = vcontext.Errors.FirstOrDefault();
+                if (ex != null) return (null, vcontext);
+            }
+
+            // we must do a basic validation before resolving external dependencies
+
+            if (true)
+            {
+                root.ValidateReferences(vcontext.GetContext());
+                var ex = vcontext.Errors.FirstOrDefault();
+                if (ex != null) return (null, vcontext);
+            }
 
 
             // resolve external dependencies
             // resolve external dependencies
 
 
@@ -290,7 +308,7 @@ namespace SharpGLTF.IO
             if (this.Validation != VALIDATIONMODE.Skip)
             if (this.Validation != VALIDATIONMODE.Skip)
             {
             {
                 root.ValidateContent(vcontext.GetContext());
                 root.ValidateContent(vcontext.GetContext());
-                ex = vcontext.Errors.FirstOrDefault();
+                var ex = vcontext.Errors.FirstOrDefault();
                 if (ex != null) return (null, vcontext);
                 if (ex != null) return (null, vcontext);
             }
             }
 
 

+ 8 - 1
src/SharpGLTF.Core/README.md

@@ -18,9 +18,16 @@ represent the bulk of the low level API to access glTF2 documents.
 
 
 It also contains the main entry point Object that represents a glTF2 model: `ModelRoot`
 It also contains the main entry point Object that represents a glTF2 model: `ModelRoot`
 
 
-
 [Additional info](Schema2/README.md)
 [Additional info](Schema2/README.md)
 
 
+##### .Runtime
+
+Contains classes and types that can help evaluating a model.
+
+Model evaluation can be useful for these tasks:
+- Dumping a raw list of triangles of the whole scene, in their final positions.
+- Rendering the model on a graphics engine.
+
 ##### .Memory
 ##### .Memory
 
 
 glTF2 stores structured arrays as encoded byte buffers that are not easy to read directly.
 glTF2 stores structured arrays as encoded byte buffers that are not easy to read directly.

+ 7 - 7
src/SharpGLTF.Core/Runtime/README.md

@@ -10,7 +10,7 @@ var model = SharpGLTF.Schema2.ModelRoot.Load("model.gltf");
 ```
 ```
 
 
 Now, lets say you have an __AwesomeEngine__ which defines an __AwesomeMesh__ that
 Now, lets say you have an __AwesomeEngine__ which defines an __AwesomeMesh__ that
-is the equivalent of a __glTF Mesh__, so for each glTF Mesh we find in Model.LogicalMeshes,
+is the equivalent of a __glTF Mesh__, so for each _logical_ glTF Mesh we find in Model.LogicalMeshes,
 we create the equivalent AwesomeMesh:
 we create the equivalent AwesomeMesh:
 ```c#
 ```c#
 var gpuMeshes = new AwesomeMesh[model.LogicalMeshes.Count];
 var gpuMeshes = new AwesomeMesh[model.LogicalMeshes.Count];
@@ -53,18 +53,18 @@ Finally, we render the instances like this:
 ```c#
 ```c#
 void RenderInstance(SharpGLTF.Runtime.SceneInstance modelInstance, Matrix4x4 modelMatrix)
 void RenderInstance(SharpGLTF.Runtime.SceneInstance modelInstance, Matrix4x4 modelMatrix)
 {
 {
-    foreach(var drawable in modelInstance.DrawableReferences)
+    foreach(var drawable in modelInstance.DrawableInstances)
     {
     {
-        var gpuMesh = gpuMeshes[drawable.Item1];
+        var gpuMesh = gpuMeshes[drawable.Template.LogicalMeshIndex];
 
 
-        if (drawable.Item2 is SharpGLTF.Transforms.StaticTransform statXform)
+        if (drawable.Transform is SharpGLTF.Transforms.RigidTransform statXform)
         {
         {
-            AwesomeEngine.DrawMesh(gpuMesh, modelMatrix, statXform.WorldMatrix);
+            AwesomeEngine.DrawRigidMesh(gpuMesh, modelMatrix, statXform.WorldMatrix);
         }
         }
 
 
-        if (drawable.Item2 is SharpGLTF.Transforms.SkinTransform skinXform)
+        if (drawable.Transform is SharpGLTF.Transforms.SkinnedLogicalMeshIndexTransform skinXform)
         {
         {
-            AwesomeEngine.DrawMesh(gpuMesh, modelMatrix, skinXform.SkinMatrices);
+            AwesomeEngine.DrawSkinnedMesh(gpuMesh, modelMatrix, skinXform.SkinMatrices);
         }
         }
     }
     }
 }
 }

+ 1 - 1
src/SharpGLTF.Core/Schema2/gltf.AccessorSparse.cs

@@ -23,7 +23,7 @@ namespace SharpGLTF.Schema2
 
 
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().ConcatItems(_indices, _values);
+            return base.GetLogicalChildren().ConcatElements(_indices, _values);
         }
         }
 
 
         internal AccessorSparse(BufferView indices, int indicesOffset, IndexEncodingType indicesEncoding, BufferView values, int valuesOffset, int count)
         internal AccessorSparse(BufferView indices, int indicesOffset, IndexEncodingType indicesEncoding, BufferView values, int valuesOffset, int count)

+ 1 - 1
src/SharpGLTF.Core/Schema2/gltf.Accessors.cs

@@ -109,7 +109,7 @@ namespace SharpGLTF.Schema2
 
 
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().ConcatItems(_sparse);
+            return base.GetLogicalChildren().ConcatElements(_sparse);
         }
         }
 
 
         public void UpdateBounds()
         public void UpdateBounds()

+ 1 - 1
src/SharpGLTF.Core/Schema2/gltf.Camera.cs

@@ -27,7 +27,7 @@ namespace SharpGLTF.Schema2
 
 
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().ConcatItems(_orthographic, _perspective);
+            return base.GetLogicalChildren().ConcatElements(_orthographic, _perspective);
         }
         }
 
 
         internal ICamera GetCamera()
         internal ICamera GetCamera()

+ 26 - 22
src/SharpGLTF.Core/Schema2/gltf.ExtensionsFactory.cs

@@ -102,21 +102,12 @@ namespace SharpGLTF.Schema2
     {
     {
         #region properties
         #region properties
 
 
-        public bool MeshQuantizationAllowed { get; private set; }
+        public bool MeshQuantizationAllowed => this._extensionsRequired.Contains("KHR_mesh_quantization");
 
 
         #endregion
         #endregion
 
 
         #region API
         #region API
 
 
-        /// <summary>
-        /// Immediatelly called after deserialization, it enables <see cref="MeshQuantizationAllowed"/>
-        /// to prevent validators to throw errors
-        /// </summary>
-        private void _FindMeshQuantizationExtension()
-        {
-            MeshQuantizationAllowed = this._extensionsRequired.Contains("KHR_mesh_quantization");
-        }
-
         internal void UpdateExtensionsSupport()
         internal void UpdateExtensionsSupport()
         {
         {
             var used = RetrieveUsedExtensions();
             var used = RetrieveUsedExtensions();
@@ -125,12 +116,12 @@ namespace SharpGLTF.Schema2
             this._extensionsUsed.Clear();
             this._extensionsUsed.Clear();
             this._extensionsUsed.AddRange(used);
             this._extensionsUsed.AddRange(used);
 
 
-            _SetRequiredExtension("KHR_mesh_quantization", MeshQuantizationAllowed);
+            _SetExtensionUsage("KHR_mesh_quantization", this._extensionsUsed.Contains("KHR_mesh_quantization"), true);
         }
         }
 
 
-        private void _SetRequiredExtension(string extension, bool enabled)
+        private void _SetExtensionUsage(string extension, bool used, bool required)
         {
         {
-            if (!enabled)
+            if (!used)
             {
             {
                 this._extensionsUsed.Remove(extension);
                 this._extensionsUsed.Remove(extension);
                 this._extensionsRequired.Remove(extension);
                 this._extensionsRequired.Remove(extension);
@@ -138,20 +129,15 @@ namespace SharpGLTF.Schema2
             }
             }
 
 
             if (!this._extensionsUsed.Contains(extension)) this._extensionsUsed.Add(extension);
             if (!this._extensionsUsed.Contains(extension)) this._extensionsUsed.Add(extension);
-            if (!this._extensionsRequired.Contains(extension)) this._extensionsRequired.Add(extension);
-        }
-
-        internal IEnumerable<ExtraProperties> GetLogicalChildrenFlattened()
-        {
-            return GetLogicalChildren()
-                .SelectMany(item => ExtraProperties.Flatten(item)
-                .ToList());
+            if (required && !this._extensionsRequired.Contains(extension)) this._extensionsRequired.Add(extension);
         }
         }
 
 
         internal IEnumerable<string> RetrieveUsedExtensions()
         internal IEnumerable<string> RetrieveUsedExtensions()
         {
         {
             // retrieve ALL the property based objects of the whole model.
             // retrieve ALL the property based objects of the whole model.
-            var allObjects = new[] { this }.Concat(GetLogicalChildrenFlattened());
+            var allObjects = new[] { this }
+                .Concat(GetLogicalChildrenFlattened())
+                .ToList();
 
 
             // check all the extensions used by each object
             // check all the extensions used by each object
             var used = new HashSet<string>();
             var used = new HashSet<string>();
@@ -172,6 +158,11 @@ namespace SharpGLTF.Schema2
                 used.Add(unk.Name);
                 used.Add(unk.Name);
             }
             }
 
 
+            // search for special cases
+
+            var isQuantized = MeshPrimitive.CheckAttributesQuantizationRequired(this);
+            if (isQuantized) used.Add("KHR_mesh_quantization");
+
             return used;
             return used;
         }
         }
 
 
@@ -185,6 +176,19 @@ namespace SharpGLTF.Schema2
             this._extensionsUsed.Add(id);
             this._extensionsUsed.Add(id);
         }
         }
 
 
+        internal void _ValidateExtensions(Validation.ValidationContext validate)
+        {
+            foreach (var iex in this.IncompatibleExtensions)
+            {
+                validate._LinkThrow("Extensions", iex);
+            }
+
+            foreach (var ext in RetrieveUsedExtensions())
+            {
+                if (!this._extensionsUsed.Contains(ext)) validate._LinkThrow("Extensions", ext);
+            }
+        }
+
         #endregion
         #endregion
     }
     }
 }
 }

+ 1 - 1
src/SharpGLTF.Core/Schema2/gltf.Material.cs

@@ -60,7 +60,7 @@ namespace SharpGLTF.Schema2
 
 
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().ConcatItems(_normalTexture, _emissiveTexture, _occlusionTexture, _pbrMetallicRoughness);
+            return base.GetLogicalChildren().ConcatElements(_normalTexture, _emissiveTexture, _occlusionTexture, _pbrMetallicRoughness);
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 5 - 5
src/SharpGLTF.Core/Schema2/gltf.MaterialsFactory.cs

@@ -169,7 +169,7 @@ namespace SharpGLTF.Schema2
     {
     {
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().ConcatItems(_baseColorTexture, _metallicRoughnessTexture);
+            return base.GetLogicalChildren().ConcatElements(_baseColorTexture, _metallicRoughnessTexture);
         }
         }
 
 
         private TextureInfo _GetBaseTexture(bool create)
         private TextureInfo _GetBaseTexture(bool create)
@@ -242,7 +242,7 @@ namespace SharpGLTF.Schema2
 
 
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().ConcatItems(_diffuseTexture, _specularGlossinessTexture);
+            return base.GetLogicalChildren().ConcatElements(_diffuseTexture, _specularGlossinessTexture);
         }
         }
 
 
         private TextureInfo _GetDiffuseTexture(bool create)
         private TextureInfo _GetDiffuseTexture(bool create)
@@ -313,7 +313,7 @@ namespace SharpGLTF.Schema2
 
 
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().ConcatItems(_clearcoatTexture, _clearcoatRoughnessTexture, _clearcoatNormalTexture);
+            return base.GetLogicalChildren().ConcatElements(_clearcoatTexture, _clearcoatRoughnessTexture, _clearcoatNormalTexture);
         }
         }
 
 
         private TextureInfo _GetClearCoatTexture(bool create)
         private TextureInfo _GetClearCoatTexture(bool create)
@@ -373,7 +373,7 @@ namespace SharpGLTF.Schema2
 
 
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().ConcatItems(_transmissionTexture);
+            return base.GetLogicalChildren().ConcatElements(_transmissionTexture);
         }
         }
 
 
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         public IEnumerable<MaterialChannel> GetChannels(Material material)
@@ -403,7 +403,7 @@ namespace SharpGLTF.Schema2
 
 
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().ConcatItems(_sheenColorTexture, _sheenRoughnessTexture);
+            return base.GetLogicalChildren().ConcatElements(_sheenColorTexture, _sheenRoughnessTexture);
         }
         }
 
 
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         public IEnumerable<MaterialChannel> GetChannels(Material material)

+ 41 - 0
src/SharpGLTF.Core/Schema2/gltf.MeshPrimitive.cs

@@ -256,6 +256,47 @@ namespace SharpGLTF.Schema2
 
 
         #region validation
         #region validation
 
 
+        internal static bool CheckAttributesQuantizationRequired(ModelRoot root)
+        {
+            return root
+                .LogicalMeshes
+                .SelectMany(item => item.Primitives)
+                .Any(prim => prim.CheckAttributesQuantizationRequired());
+        }
+
+        private bool CheckAttributesQuantizationRequired()
+        {
+            bool _checkAccessors(IReadOnlyDictionary<string, Accessor> accessors)
+            {
+                foreach (var va in accessors)
+                {
+                    if (va.Value.Encoding == EncodingType.FLOAT) continue;
+
+                    if (va.Key == "POSITION") return true;
+                    if (va.Key == "NORMAL") return true;
+                    if (va.Key == "TANGENT") return true;
+
+                    if (va.Value.Encoding == EncodingType.UNSIGNED_BYTE) continue;
+                    if (va.Value.Encoding == EncodingType.UNSIGNED_SHORT) continue;
+
+                    if (va.Key.StartsWith("TEXCOORD_")) return true;
+                }
+
+                return false;
+            }
+
+            if (_checkAccessors(this.VertexAccessors)) return true;
+
+            for (int midx = 0; midx < this.MorphTargetsCount; ++midx)
+            {
+                var mt = this.GetMorphTargetAccessors(midx);
+
+                if (_checkAccessors(mt)) return true;
+            }
+
+            return false;
+        }
+
         protected override void OnValidateReferences(Validation.ValidationContext validate)
         protected override void OnValidateReferences(Validation.ValidationContext validate)
         {
         {
             base.OnValidateReferences(validate);
             base.OnValidateReferences(validate);

+ 8 - 10
src/SharpGLTF.Core/Schema2/gltf.Root.cs

@@ -49,7 +49,7 @@ namespace SharpGLTF.Schema2
         /// <returns>A new <see cref="ModelRoot"/> instance.</returns>
         /// <returns>A new <see cref="ModelRoot"/> instance.</returns>
         /// <remarks>
         /// <remarks>
         /// Deep cloning is performed as a brute force operation; by serializing
         /// Deep cloning is performed as a brute force operation; by serializing
-        /// the whole model to GLTF into memory, and then deserializing it back.
+        /// the whole model to GLTF into memory, and then deserializing it back to DOM.
         /// </remarks>
         /// </remarks>
         public ModelRoot DeepClone()
         public ModelRoot DeepClone()
         {
         {
@@ -67,7 +67,7 @@ namespace SharpGLTF.Schema2
 
 
             // restore the model from the temporary storage
             // restore the model from the temporary storage
 
 
-            var rcontext = IO.ReadContext.CreateFromDictionary(dict);
+            var rcontext = IO.ReadContext.CreateFromDictionary(dict, wcontext._UpdateSupportedExtensions);
             rcontext.Validation = Validation.ValidationMode.Skip;
             rcontext.Validation = Validation.ValidationMode.Skip;
             var cloned = rcontext._ReadFromDictionary("deepclone.gltf");
             var cloned = rcontext._ReadFromDictionary("deepclone.gltf");
 
 
@@ -121,7 +121,7 @@ namespace SharpGLTF.Schema2
         {
         {
             var containers = base.GetLogicalChildren();
             var containers = base.GetLogicalChildren();
 
 
-            containers = containers.ConcatItems(this.Asset);
+            containers = containers.ConcatElements(this.Asset);
             containers = containers.Concat(this.LogicalAccessors);
             containers = containers.Concat(this.LogicalAccessors);
             containers = containers.Concat(this.LogicalAnimations);
             containers = containers.Concat(this.LogicalAnimations);
             containers = containers.Concat(this.LogicalBuffers);
             containers = containers.Concat(this.LogicalBuffers);
@@ -139,6 +139,11 @@ namespace SharpGLTF.Schema2
             return containers;
             return containers;
         }
         }
 
 
+        internal IEnumerable<ExtraProperties> GetLogicalChildrenFlattened()
+        {
+            return GetLogicalChildren().SelectMany(item => Flatten(item));
+        }
+
         #endregion
         #endregion
 
 
         #region Visual Tree
         #region Visual Tree
@@ -172,13 +177,6 @@ namespace SharpGLTF.Schema2
 
 
             Asset.ValidateReferences(validate);
             Asset.ValidateReferences(validate);
 
 
-            // check incompatible extensions
-
-            foreach (var iex in this.IncompatibleExtensions)
-            {
-                validate._LinkThrow("Extensions", iex);
-            }
-
             base.OnValidateReferences(validate);
             base.OnValidateReferences(validate);
 
 
             Node._ValidateParentHierarchy(this.LogicalNodes, validate);
             Node._ValidateParentHierarchy(this.LogicalNodes, validate);

+ 1 - 1
src/SharpGLTF.Core/Schema2/gltf.Serialization.Read.cs

@@ -209,7 +209,7 @@ namespace SharpGLTF.Schema2
 
 
         internal void OnDeserializationCompleted()
         internal void OnDeserializationCompleted()
         {
         {
-            _FindMeshQuantizationExtension();
+            
         }
         }
 
 
         internal void _ResolveSatelliteDependencies(IO.ReadContext context)
         internal void _ResolveSatelliteDependencies(IO.ReadContext context)

+ 1 - 2
src/SharpGLTF.Core/SharpGLTF.Core.csproj

@@ -35,8 +35,7 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Update="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.1" />
-    <PackageReference Update="Microsoft.CodeQuality.Analyzers" Version="3.3.1" />
+    <None Include="..\..\.editorconfig" Link=".editorconfig" />
   </ItemGroup>  
   </ItemGroup>  
 
 
 </Project>
 </Project>

+ 12 - 3
src/SharpGLTF.Toolkit/Schema2/AnimationExtensions.cs

@@ -30,7 +30,10 @@ namespace SharpGLTF.Schema2
                 if (degree == 1) animation.CreateScaleChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 1) animation.CreateScaleChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 3) animation.CreateScaleChannel(node, curve.ToSplineCurve());
                 if (degree == 3) animation.CreateScaleChannel(node, curve.ToSplineCurve());
             }
             }
-            else throw new ArgumentException("Must implement IConvertibleCurve<Vector3>", nameof(sampler));
+            else
+            {
+                throw new ArgumentException("Must implement IConvertibleCurve<Vector3>", nameof(sampler));
+            }
 
 
             return node;
             return node;
         }
         }
@@ -48,7 +51,10 @@ namespace SharpGLTF.Schema2
                 if (degree == 1) animation.CreateTranslationChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 1) animation.CreateTranslationChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 3) animation.CreateTranslationChannel(node, curve.ToSplineCurve());
                 if (degree == 3) animation.CreateTranslationChannel(node, curve.ToSplineCurve());
             }
             }
-            else throw new ArgumentException("Must implement IConvertibleCurve<Vector3>", nameof(sampler));
+            else
+            {
+                throw new ArgumentException("Must implement IConvertibleCurve<Vector3>", nameof(sampler));
+            }
 
 
             return node;
             return node;
         }
         }
@@ -85,7 +91,10 @@ namespace SharpGLTF.Schema2
                 if (degree == 1) animation.CreateRotationChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 1) animation.CreateRotationChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 3) animation.CreateRotationChannel(node, curve.ToSplineCurve());
                 if (degree == 3) animation.CreateRotationChannel(node, curve.ToSplineCurve());
             }
             }
-            else throw new ArgumentException("Must implement IConvertibleCurve<Quaternion>", nameof(sampler));
+            else
+            {
+                throw new ArgumentException("Must implement IConvertibleCurve<Quaternion>", nameof(sampler));
+            }
 
 
             return node;
             return node;
         }
         }

+ 0 - 5
src/SharpGLTF.Toolkit/SharpGLTF.Toolkit.csproj

@@ -20,11 +20,6 @@
 
 
   <ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\SharpGLTF.Core\SharpGLTF.Core.csproj" />
     <ProjectReference Include="..\SharpGLTF.Core\SharpGLTF.Core.csproj" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <PackageReference Update="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.1" />
-    <PackageReference Update="Microsoft.CodeQuality.Analyzers" Version="3.3.1" />
   </ItemGroup>  
   </ItemGroup>  
   
   
 </Project>
 </Project>

+ 44 - 5
tests/SharpGLTF.NUnit/TestFiles.cs

@@ -58,7 +58,7 @@ namespace SharpGLTF
 
 
         private static readonly string _SchemaDir;
         private static readonly string _SchemaDir;
         private static readonly string _ValidationDir;
         private static readonly string _ValidationDir;
-        private static readonly string _SampleModelsDir;
+        internal static readonly string _SampleModelsDir;
 
 
         private static readonly string _PollyModelsDir;
         private static readonly string _PollyModelsDir;
         private static readonly string _UniVRMModelsDir;
         private static readonly string _UniVRMModelsDir;
@@ -131,12 +131,13 @@ namespace SharpGLTF
         {
         {
             _Check();
             _Check();
 
 
-            var files = GetModelPathsInDirectory(_SampleModelsDir, "2.0");
+            var entries = KhronosSampleModel.Load();
 
 
-            return files
-                .OrderBy(item => item)
-                .Where(item => !item.Contains("\\glTF-Draco\\"))
+            var files = entries
+                .SelectMany(item => item.GetPaths(_SampleModelsDir, "2.0"))
                 .ToList();
                 .ToList();
+
+            return files;            
         }
         }
 
 
         public static IReadOnlyList<string> GetKhronosValidationPaths()
         public static IReadOnlyList<string> GetKhronosValidationPaths()
@@ -244,4 +245,42 @@ namespace SharpGLTF
 
 
         #endregion
         #endregion
     }
     }
+
+    [System.Diagnostics.DebuggerDisplay("{Name}")]
+    class KhronosSampleModel
+    {
+        public static KhronosSampleModel[] Load()
+        {
+            var path = System.IO.Path.Combine(TestFiles._SampleModelsDir, "2.0", "model-index.json");
+            var text = System.IO.File.ReadAllText(path);
+            return Read(text);
+        }
+
+        public static KhronosSampleModel[] Read(string json)
+        {
+            var opts = new System.Text.Json.JsonSerializerOptions
+            {
+                PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase,
+                PropertyNameCaseInsensitive = true
+            };
+
+            return System.Text.Json.JsonSerializer.Deserialize<KhronosSampleModel[]>(json, opts);
+        }
+
+        public string Name { get; set; }
+        public string Screenshot { get; set; }
+        public Dictionary<string, string> Variants { get; set; } = new Dictionary<string, string>();
+
+        public IEnumerable<string> GetPaths(params string[] basePath)
+        {
+            var rootPath = System.IO.Path.Combine(basePath);
+
+            foreach(var variant in Variants)
+            {
+                if (variant.Key == "glTF-Draco") continue; // draco is not supported by SharpGLTF
+
+                yield return System.IO.Path.Combine(rootPath, Name, variant.Key, variant.Value);
+            }
+        }
+    }
 }
 }

+ 2 - 2
tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadGeneratedTests.cs

@@ -36,7 +36,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
 
 
             foreach (var filePath in files)
             foreach (var filePath in files)
             {
             {
-                // System.Diagnostics.Debug.Assert(!filePath.EndsWith("Compatibility_05.gltf"));
+                // System.Diagnostics.Debug.Assert(!filePath.EndsWith("Buffer_Interleaved_03.gltf"));
 
 
                 var gltfJson = filePath.EndsWith(".gltf") ? System.IO.File.ReadAllText(filePath) : string.Empty;
                 var gltfJson = filePath.EndsWith(".gltf") ? System.IO.File.ReadAllText(filePath) : string.Empty;
 
 
@@ -71,7 +71,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
                     else
                     else
                     {
                     {
                         TestContext.WriteLine($"{filePath.ToShortDisplayPath()} 🙂👍");
                         TestContext.WriteLine($"{filePath.ToShortDisplayPath()} 🙂👍");
-                        TestContext.WriteLine($"   Exception: {ex.Message}");
+                        TestContext.WriteLine($"   Expected Exception: {ex.Message}");
                     }                    
                     }                    
                 }
                 }
 
 

+ 1 - 0
tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadSampleTests.cs

@@ -95,6 +95,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
         [TestCase("\\glTF-IBL\\")]
         [TestCase("\\glTF-IBL\\")]
         [TestCase("\\glTF-Binary\\")]
         [TestCase("\\glTF-Binary\\")]
         [TestCase("\\glTF-Embedded\\")]
         [TestCase("\\glTF-Embedded\\")]
+        [TestCase("\\glTF-Quantized\\")]
         [TestCase("\\glTF-pbrSpecularGlossiness\\")]
         [TestCase("\\glTF-pbrSpecularGlossiness\\")]
         public void LoadModelsFromKhronosSamples(string section)
         public void LoadModelsFromKhronosSamples(string section)
         {
         {

+ 1 - 1
tests/SharpGLTF.Tests/SharpGLTF.Core.Tests.csproj

@@ -26,7 +26,7 @@
       <PrivateAssets>all</PrivateAssets>
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
     </PackageReference>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
   </ItemGroup>  
   </ItemGroup>  
 
 
 </Project>
 </Project>

+ 1 - 1
tests/SharpGLTF.Toolkit.Tests/SharpGLTF.Toolkit.Tests.csproj

@@ -26,7 +26,7 @@
       <PrivateAssets>all</PrivateAssets>
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
     </PackageReference>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
   </ItemGroup>  
   </ItemGroup>  
 
 
 </Project>
 </Project>