Bert Temme 1 gadu atpakaļ
vecāks
revīzija
8ca7ed2cf2
34 mainītis faili ar 1033 papildinājumiem un 1494 dzēšanām
  1. 1 0
      examples/InfiniteSkinnedTentacle/InfiniteSkinnedTentacle.csproj
  2. 18 0
      examples/InfiniteSkinnedTentacle/Properties/PublishProfiles/FolderProfile.pubxml
  3. 11 1
      src/SharpGLTF.Core/Diagnostics/DebuggerDisplay.cs
  4. 9 0
      src/SharpGLTF.Core/Memory/MemoryAccessor.cs
  5. 132 43
      src/SharpGLTF.Core/Schema2/gltf.ExtensionsFactory.cs
  6. 5 5
      src/SharpGLTF.Ext.3DTiles/Schema2/Tiles3DExtensions.cs
  7. 4 4
      src/SharpGLTF.Ext.Agi/schema2/AgiExtensions.cs
  8. 8 26
      src/SharpGLTF.Toolkit/Geometry/MeshBuilderToolkit.cs
  9. 2 0
      src/SharpGLTF.Toolkit/Geometry/PrimitiveBuilder.cs
  10. 1 0
      src/SharpGLTF.Toolkit/Geometry/PrimitiveInterfaces.cs
  11. 24 15
      src/SharpGLTF.Toolkit/Geometry/VertexBufferColumns.cs
  12. 17 10
      src/SharpGLTF.Toolkit/Geometry/VertexBuilder.cs
  13. 1 0
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/Attributes.cs
  14. 5 0
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexEmpty.cs
  15. 38 37
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexGeometry.cs
  16. 31 70
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.Permutations.cs
  17. 302 0
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.Permutations.tt
  18. 119 1020
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.cs
  19. 15 0
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexReflection.cs
  20. 25 21
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexSkinning.cs
  21. 31 61
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.Accessors.cs
  22. 0 8
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.Builder.Reflection.cs
  23. 99 0
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.Builder.Reflection.tt
  24. 26 100
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.Builder.cs
  25. 13 12
      src/SharpGLTF.Toolkit/Schema2/MeshExtensions.cs
  26. 35 1
      src/SharpGLTF.Toolkit/SharpGLTF.Toolkit.csproj
  27. 9 9
      tests/SharpGLTF.Cesium.Tests/VertexPointcloud.cs
  28. 7 6
      tests/SharpGLTF.Cesium.Tests/VertexWithFeatureId.cs
  29. 12 10
      tests/SharpGLTF.Cesium.Tests/VertexWithFeatureIds.cs
  30. 2 1
      tests/SharpGLTF.Core.Tests/Validation/InvalidFilesTests.cs
  31. 2 3
      tests/SharpGLTF.NUnit/TestFiles.cs
  32. 23 21
      tests/SharpGLTF.Toolkit.Tests/Geometry/VertexTypes/CustomVertices.cs
  33. 4 3
      tests/SharpGLTF.Trimmed.App/Properties/PublishProfiles/FolderProfile.pubxml
  34. 2 7
      tests/SharpGLTF.Trimmed.App/SharpGLTF.Trimmed.App.csproj

+ 1 - 0
examples/InfiniteSkinnedTentacle/InfiniteSkinnedTentacle.csproj

@@ -3,6 +3,7 @@
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <TargetFramework>net8.0</TargetFramework>
+    <PublishAot>true</PublishAot>
   </PropertyGroup>
 
   <ItemGroup>

+ 18 - 0
examples/InfiniteSkinnedTentacle/Properties/PublishProfiles/FolderProfile.pubxml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+https://go.microsoft.com/fwlink/?LinkID=208121.
+-->
+<Project>
+  <PropertyGroup>
+    <Configuration>Release</Configuration>
+    <Platform>Any CPU</Platform>
+    <PublishDir>bin\Release\net8.0\publish\win-x64\</PublishDir>
+    <PublishProtocol>FileSystem</PublishProtocol>
+    <_TargetId>Folder</_TargetId>
+    <TargetFramework>net8.0</TargetFramework>
+    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
+    <SelfContained>true</SelfContained>
+    <PublishSingleFile>false</PublishSingleFile>
+    <PublishReadyToRun>false</PublishReadyToRun>
+  </PropertyGroup>
+</Project>

+ 11 - 1
src/SharpGLTF.Core/Diagnostics/DebuggerDisplay.cs

@@ -11,6 +11,10 @@ namespace SharpGLTF.Diagnostics
     {
         internal static string GetAttributeShortName(string attributeName)
         {
+            var suffix = string.Empty;
+
+            if (attributeName.EndsWith("DELTA")) { attributeName = attributeName.Substring(0, attributeName.Length - 5); suffix = "Δ"; }
+
             if (attributeName == "POSITION") return "𝐏";
             if (attributeName == "NORMAL") return "𝚴";
             if (attributeName == "TANGENT") return "𝚻";
@@ -18,13 +22,19 @@ namespace SharpGLTF.Diagnostics
             if (attributeName == "COLOR_1") return "𝐂₁";
             if (attributeName == "TEXCOORD_0") return "𝐔𝐕₀";
             if (attributeName == "TEXCOORD_1") return "𝐔𝐕₁";
+            if (attributeName == "TEXCOORD_2") return "𝐔𝐕₂";
+            if (attributeName == "TEXCOORD_3") return "𝐔𝐕₃";
+            if (attributeName == "TEXCOORD_4") return "𝐔𝐕₄";
+            if (attributeName == "TEXCOORD_5") return "𝐔𝐕₅";
+            if (attributeName == "TEXCOORD_6") return "𝐔𝐕₆";
+            if (attributeName == "TEXCOORD_7") return "𝐔𝐕₇";
 
             if (attributeName == "JOINTS_0") return "𝐉₀";
             if (attributeName == "JOINTS_1") return "𝐉₁";
 
             if (attributeName == "WEIGHTS_0") return "𝐖₀";
             if (attributeName == "WEIGHTS_1") return "𝐖₁";
-            return attributeName;
+            return attributeName + suffix;
         }
 
         public static String ToReport(this Memory.MemoryAccessInfo minfo)

+ 9 - 0
src/SharpGLTF.Core/Memory/MemoryAccessor.cs

@@ -205,6 +205,15 @@ namespace SharpGLTF.Memory
             return Math.Max(ByteStride, _GetItemByteLength());
         }
 
+        /// <summary>
+        /// Assuming that <paramref name="attributes"/> are sequential and adyacent,
+        /// it modifies the <see cref="ByteOffset"/> of each item of <paramref name="attributes"/> to ensure
+        /// the offsets are sequential.
+        /// </summary>
+        /// <param name="attributes">A list of attributes to fix.</param>
+        /// <param name="byteOffset">The initial byteoffset.</param>
+        /// <param name="itemsCount">the default items count.</param>
+        /// <returns>The byte stride.</returns>
         public static int SetInterleavedInfo(MemoryAccessInfo[] attributes, int byteOffset, int itemsCount)
         {
             Guard.NotNull(attributes, nameof(attributes));

+ 132 - 43
src/SharpGLTF.Core/Schema2/gltf.ExtensionsFactory.cs

@@ -5,6 +5,11 @@ using System.Linq;
 
 using SharpGLTF.IO;
 
+#if NET6_0_OR_GREATER
+using DYNAMICMEMBERS = System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute;
+using DYNAMICTYPES = System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes;
+#endif
+
 namespace SharpGLTF.Schema2
 {
     /// <summary>
@@ -16,6 +21,10 @@ namespace SharpGLTF.Schema2
     /// </remarks>
     public static class ExtensionsFactory
     {
+        #if NET6_0_OR_GREATER
+        private const DYNAMICTYPES DYNAMICCONSTRUCTORS = DYNAMICTYPES.NonPublicConstructors | DYNAMICTYPES.PublicConstructors;
+        #endif
+
         // extensions design inconsistencies:
         // https://github.com/KhronosGroup/glTF/issues/1491
 
@@ -23,37 +32,37 @@ namespace SharpGLTF.Schema2
 
         static ExtensionsFactory()
         {
-            RegisterExtension<ModelRoot, _ModelPunctualLights>("KHR_lights_punctual");
-            RegisterExtension<Node, _NodePunctualLight>("KHR_lights_punctual");
-
-            RegisterExtension<Node, MeshGpuInstancing>("EXT_mesh_gpu_instancing");
-
-            RegisterExtension<Material, MaterialUnlit>("KHR_materials_unlit");
-            RegisterExtension<Material, MaterialSheen>("KHR_materials_sheen");
-            RegisterExtension<Material, MaterialIOR>("KHR_materials_ior");
-            RegisterExtension<Material, MaterialSpecular>("KHR_materials_specular");
-            RegisterExtension<Material, MaterialClearCoat>("KHR_materials_clearcoat");
-            RegisterExtension<Material, MaterialTransmission>("KHR_materials_transmission");
-            RegisterExtension<Material, MaterialVolume>("KHR_materials_volume");
-            RegisterExtension<Material, MaterialEmissiveStrength>("KHR_materials_emissive_strength");
-            RegisterExtension<Material, MaterialPBRSpecularGlossiness>("KHR_materials_pbrSpecularGlossiness");
-            RegisterExtension<Material, MaterialIridescence>("KHR_materials_iridescence");
-
-            RegisterExtension<TextureInfo, TextureTransform>("KHR_texture_transform");
-
-            RegisterExtension<Texture, TextureDDS>("MSFT_texture_dds");
-            RegisterExtension<Texture, TextureWEBP>("EXT_texture_webp");
-            RegisterExtension<Texture, TextureKTX2>("KHR_texture_basisu");
-
-            RegisterExtension<ModelRoot, XmpPackets>("KHR_xmp_json_ld");
-            RegisterExtension<ExtraProperties, XmpPacketReference>("KHR_xmp_json_ld");                        
+            RegisterExtension<ModelRoot, _ModelPunctualLights>("KHR_lights_punctual", p=> new _ModelPunctualLights(p));
+            RegisterExtension<Node, _NodePunctualLight>("KHR_lights_punctual", p=> new _NodePunctualLight(p));
+
+            RegisterExtension<Node, MeshGpuInstancing>("EXT_mesh_gpu_instancing", p=> new MeshGpuInstancing(p));
+
+            RegisterExtension<Material, MaterialUnlit>("KHR_materials_unlit", p => new MaterialUnlit(p));
+            RegisterExtension<Material, MaterialSheen>("KHR_materials_sheen", p => new MaterialSheen(p));
+            RegisterExtension<Material, MaterialIOR>("KHR_materials_ior", p => new MaterialIOR(p));
+            RegisterExtension<Material, MaterialSpecular>("KHR_materials_specular", p => new MaterialSpecular(p));
+            RegisterExtension<Material, MaterialClearCoat>("KHR_materials_clearcoat", p => new MaterialClearCoat(p));
+            RegisterExtension<Material, MaterialTransmission>("KHR_materials_transmission", p => new MaterialTransmission(p));
+            RegisterExtension<Material, MaterialVolume>("KHR_materials_volume", p => new MaterialVolume(p));
+            RegisterExtension<Material, MaterialEmissiveStrength>("KHR_materials_emissive_strength", p => new MaterialEmissiveStrength(p));
+            RegisterExtension<Material, MaterialPBRSpecularGlossiness>("KHR_materials_pbrSpecularGlossiness", p => new MaterialPBRSpecularGlossiness(p));
+            RegisterExtension<Material, MaterialIridescence>("KHR_materials_iridescence", p => new MaterialIridescence(p));
+
+            RegisterExtension<TextureInfo, TextureTransform>("KHR_texture_transform", p => new TextureTransform(p));
+
+            RegisterExtension<Texture, TextureDDS>("MSFT_texture_dds", p => new TextureDDS(p));
+            RegisterExtension<Texture, TextureWEBP>("EXT_texture_webp", p => new TextureWEBP(p));
+            RegisterExtension<Texture, TextureKTX2>("KHR_texture_basisu", p => new TextureKTX2(p));
+
+            RegisterExtension<ModelRoot, XmpPackets>("KHR_xmp_json_ld", p => new XmpPackets(p));
+            RegisterExtension<ExtraProperties, XmpPacketReference>("KHR_xmp_json_ld", p => new XmpPacketReference(p));                        
         }
 
         #endregion
 
         #region data
 
-        private static readonly List<(string Name, Type ParentType, Type ExtType)> _Extensions = new List<(string, Type, Type)>();
+        private static readonly List<ExtensionEntry> _Extensions = new List<ExtensionEntry>();
 
         #endregion
 
@@ -73,7 +82,14 @@ namespace SharpGLTF.Schema2
         /// The <paramref name="persistentName"/> is the value used for serialization<br/>
         /// and it must meet <see href="https://github.com/KhronosGroup/glTF/blob/master/extensions/Prefixes.md">extension naming constraints</see>.
         /// </remarks>
-        public static void RegisterExtension<TParent, TExtension>(string persistentName)
+        [Obsolete("Use RegisterExtension(name, factory) instead.")]
+        public static void RegisterExtension
+            <TParent,
+                #if NET6_0_OR_GREATER
+                [DYNAMICMEMBERS(DYNAMICCONSTRUCTORS)]
+                #endif
+            TExtension>
+            (string persistentName)
             where TParent : JsonSerializable
             where TExtension : JsonSerializable
         {
@@ -82,7 +98,34 @@ namespace SharpGLTF.Schema2
 
             // TODO: check that persistentName has a valid extension name.
 
-            _Extensions.Add( (persistentName, typeof(TParent), typeof(TExtension)) );
+            var ext = ExtensionEntry.Create<TParent,TExtension>(persistentName);
+
+            _Extensions.Add(ext);
+        }
+
+        /// <summary>
+        /// Registers a new extensions to be used globally.
+        /// </summary>
+        /// <typeparam name="TParent">The parent type to which this extension is attached.</typeparam>
+        /// <typeparam name="TExtension">The extension type.</typeparam>
+        /// <param name="persistentName">The extension name.</param>
+        /// <param name="factory">callback used to create instances of type <typeparamref name="TExtension"/>.</param>
+        /// <remarks>
+        /// The <paramref name="persistentName"/> is the value used for serialization<br/>
+        /// and it must meet <see href="https://github.com/KhronosGroup/glTF/blob/master/extensions/Prefixes.md">extension naming constraints</see>.
+        /// </remarks>
+        public static void RegisterExtension<TParent,TExtension>(string persistentName, Func<TParent, JsonSerializable> factory)
+            where TParent : JsonSerializable
+            where TExtension : JsonSerializable
+        {
+            Guard.NotNullOrEmpty(persistentName, nameof(persistentName));
+            Guard.MustBeNull(Identify(typeof(TParent), typeof(TExtension)), $"{nameof(TExtension)} already registered for {nameof(TParent)}");
+
+            // TODO: check that persistentName has a valid extension name.
+
+            var ext = new ExtensionEntry(persistentName, typeof(TParent), typeof(TExtension), p => factory.Invoke((TParent)p));
+
+            _Extensions.Add(ext);
         }
 
         #endregion
@@ -99,22 +142,13 @@ namespace SharpGLTF.Schema2
         {
             var ptype = parent.GetType();
 
-            var (name, parentType, extType) = _Extensions.FirstOrDefault(item => item.Name == extensionName && item.ParentType.IsAssignableFrom(ptype));
-
-            if (name == null) return null;                        
+            var extension = _Extensions.FirstOrDefault(item => item.IsMatch(ptype, extensionName));
 
-            Guard.HasDynamicallyAccessedMembers(extType, true, false, false, false, nameof(extensionName));
+            if (extension.Name == null) return null;
 
-            var instance = Activator.CreateInstance
-                (
-                extType,
-                System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance,
-                null,
-                new Object[] { parent },
-                null
-                );
+            var instance = extension.Factory.Invoke(parent);
 
-            return instance as JsonSerializable;
+            return instance ?? throw new InvalidOperationException($"Could not create an instance of {extensionName}");
         }
 
         /// <summary>
@@ -124,18 +158,73 @@ namespace SharpGLTF.Schema2
         /// <param name="extensionType">The type of the extension object.</param>
         /// <returns>An extension identifier code, like "KHR_texture_transform".</returns>
         /// <remarks>
-        /// Extensions must be registered in advanced using <see cref="RegisterExtension{TParent, TExtension}(string)"/>.
+        /// Extensions must be registered in advanced using <see cref="RegisterExtension{TParent, TExtension}(string, Func{TParent, JsonSerializable})"/>.
         /// </remarks>
         internal static string Identify(Type parentType, Type extensionType)
         {
-            foreach (var (name, baseType, extType) in _Extensions)
+            foreach (var ext in _Extensions)
             {
-                if (baseType.IsAssignableFrom(parentType) && extType == extensionType) return name;
+                if (ext.IsMatch(parentType,extensionType)) return ext.Name;
             }
 
             return null;
         }
 
+        internal readonly struct ExtensionEntry
+        {
+            public static ExtensionEntry Create
+                <
+                TParent,
+                #if NET6_0_OR_GREATER
+                [DYNAMICMEMBERS(DYNAMICCONSTRUCTORS)]
+                #endif
+                TExtension
+                >(string persistentName)
+
+            where TParent : JsonSerializable
+            where TExtension : JsonSerializable
+            {
+                var extType = typeof(TExtension);
+
+                JsonSerializable factory(JsonSerializable parent)
+                {
+                    return Activator.CreateInstance
+                    (
+                        extType,
+                        System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance,
+                        null,
+                        new Object[] { parent },
+                        null
+                    ) as JsonSerializable;
+                }
+
+                return new ExtensionEntry(persistentName, typeof(TParent), extType, factory);
+            }
+
+            public ExtensionEntry(string n, Type p, Type e, Func<JsonSerializable, JsonSerializable> f)
+            {
+                Name= n;
+                ParentType = p;
+                ExtType = e;
+                Factory = f;
+            }
+
+            public readonly string Name;
+            public readonly Type ParentType;
+            public readonly Type ExtType;
+            public readonly Func<JsonSerializable, JsonSerializable> Factory;
+
+            public readonly bool IsMatch(Type parentType, string extensionName)
+            {
+                return this.ParentType.IsAssignableFrom(parentType) && this.Name == extensionName;
+            }
+
+            public readonly bool IsMatch(Type parentType, Type extensionType)
+            {
+                return this.ParentType.IsAssignableFrom(parentType) && this.ExtType == extensionType;
+            }
+        }
+
         #endregion
     }
 

+ 5 - 5
src/SharpGLTF.Ext.3DTiles/Schema2/Tiles3DExtensions.cs

@@ -18,11 +18,11 @@
 
             _3DTilesRegistered = true;
 
-            ExtensionsFactory.RegisterExtension<MeshPrimitive, CesiumPrimitiveOutline>("CESIUM_primitive_outline");
-            ExtensionsFactory.RegisterExtension<Node, MeshExtInstanceFeatures>("EXT_instance_features");
-            ExtensionsFactory.RegisterExtension<MeshPrimitive, MeshExtMeshFeatures>("EXT_mesh_features");
-            ExtensionsFactory.RegisterExtension<ModelRoot, EXTStructuralMetadataRoot>("EXT_structural_metadata");
-            ExtensionsFactory.RegisterExtension<MeshPrimitive, ExtStructuralMetadataMeshPrimitive>("EXT_structural_metadata");
+            ExtensionsFactory.RegisterExtension<MeshPrimitive, CesiumPrimitiveOutline>("CESIUM_primitive_outline", p=> new CesiumPrimitiveOutline(p));
+            ExtensionsFactory.RegisterExtension<Node, MeshExtInstanceFeatures>("EXT_instance_features", p => new MeshExtInstanceFeatures(p));
+            ExtensionsFactory.RegisterExtension<MeshPrimitive, MeshExtMeshFeatures>("EXT_mesh_features", p => new MeshExtMeshFeatures(p));
+            ExtensionsFactory.RegisterExtension<ModelRoot, EXTStructuralMetadataRoot>("EXT_structural_metadata", p => new EXTStructuralMetadataRoot(p));
+            ExtensionsFactory.RegisterExtension<MeshPrimitive, ExtStructuralMetadataMeshPrimitive>("EXT_structural_metadata", p => new ExtStructuralMetadataMeshPrimitive(p));
         }
     }
 }

+ 4 - 4
src/SharpGLTF.Ext.Agi/schema2/AgiExtensions.cs

@@ -22,10 +22,10 @@ namespace SharpGLTF.Schema2
 
             _AgiRegistered = true;
 
-            ExtensionsFactory.RegisterExtension<ModelRoot, AgiRootArticulations>("AGI_articulations");
-            ExtensionsFactory.RegisterExtension<ModelRoot, AgiRootStkMetadata>("AGI_stk_metadata");
-            ExtensionsFactory.RegisterExtension<Node, AgiNodeArticulations>("AGI_articulations");
-            ExtensionsFactory.RegisterExtension<Node, AgiNodeStkMetadata>("AGI_stk_metadata");
+            ExtensionsFactory.RegisterExtension<ModelRoot, AgiRootArticulations>("AGI_articulations", p => new AgiRootArticulations(p));
+            ExtensionsFactory.RegisterExtension<ModelRoot, AgiRootStkMetadata>("AGI_stk_metadata", p => new AgiRootStkMetadata(p));
+            ExtensionsFactory.RegisterExtension<Node, AgiNodeArticulations>("AGI_articulations", p => new AgiNodeArticulations(p));
+            ExtensionsFactory.RegisterExtension<Node, AgiNodeStkMetadata>("AGI_stk_metadata", p => new AgiNodeStkMetadata(p));
         }
     }
 }

+ 8 - 26
src/SharpGLTF.Toolkit/Geometry/MeshBuilderToolkit.cs

@@ -74,7 +74,7 @@ namespace SharpGLTF.Geometry
         void Validate();
     }
 
-    static class MeshBuilderToolkit
+    static partial class MeshBuilderToolkit
     {
         public static VertexBuilder<VertexGeometryDelta, VertexMaterialDelta, VertexEmpty>[] GetMorphTargetVertices(this IPrimitiveMorphTargetReader morphTarget, int vertexCount)
         {
@@ -115,6 +115,7 @@ namespace SharpGLTF.Geometry
 
             return maxIndex < 256 ? Schema2.EncodingType.UNSIGNED_BYTE : Schema2.EncodingType.UNSIGNED_SHORT;
         }
+
         
         public static IMeshBuilder<TMaterial> CreateMeshBuilderFromVertexAttributes
             <
@@ -123,31 +124,12 @@ namespace SharpGLTF.Geometry
             #endif
             TMaterial>(params string[] vertexAttributes)
         {
-            Type meshType = GetMeshBuilderType(typeof(TMaterial), vertexAttributes);
-
-            var mesh = Activator.CreateInstance(meshType, string.Empty);
-
-            return mesh as IMeshBuilder<TMaterial>;
-        }
-        
-        #if NET6_0_OR_GREATER
-        [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
-        #endif
-        public static Type GetMeshBuilderType
-            (
-            #if NET6_0_OR_GREATER
-            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
-            #endif
-            Type materialType, string[] vertexAttributes)
-        {
-            var tvg = VertexUtils.GetVertexGeometryType(vertexAttributes);
-            var tvm = VertexUtils.GetVertexMaterialType(vertexAttributes);
-            var tvs = VertexUtils.GetVertexSkinningType(vertexAttributes);
-
-            var meshType = typeof(MeshBuilder<,,,>);
-
-            return meshType.MakeGenericType(materialType, tvg, tvm, tvs);
-        }
+            return VertexUtils
+                .GetVertexBuilderType(vertexAttributes) // get a vertex factory from attributes
+                .BuilderFactory                         
+                .Invoke()                               // create a single vertex
+                .CreateCompatibleMesh<TMaterial>();     // create a mesh with the given vertex format.
+        }        
 
         public static IReadOnlyDictionary<Vector3, Vector3> CalculateSmoothNormals<TMaterial>(this IMeshBuilder<TMaterial> srcMesh)
         {

+ 2 - 0
src/SharpGLTF.Toolkit/Geometry/PrimitiveBuilder.cs

@@ -111,6 +111,8 @@ namespace SharpGLTF.Geometry
         #endif
         public Type VertexType => typeof(VertexBuilder<TvG, TvM, TvS>);
 
+        public Func<IVertexBuilder> VertexFactory => () => new VertexBuilder<TvG, TvM, TvS>();
+
         /// <summary>
         /// Gets the list of vertices used by this primitive.
         /// </summary>

+ 1 - 0
src/SharpGLTF.Toolkit/Geometry/PrimitiveInterfaces.cs

@@ -79,6 +79,7 @@ namespace SharpGLTF.Geometry
         [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)]
         #endif
         Type VertexType { get; }
+        Func<IVertexBuilder> VertexFactory { get; }
 
         void SetVertexDelta(int morphTargetIndex, int vertexIndex, VertexGeometryDelta geometryDelta, VertexMaterialDelta materialDelta);
 

+ 24 - 15
src/SharpGLTF.Toolkit/Geometry/VertexBufferColumns.cs

@@ -169,10 +169,12 @@ namespace SharpGLTF.Geometry
             this.Positions = _IsolateColumn(this.Positions); // Position, normal and tangent can be modified by morphing and skinning
             this.Normals = _IsolateColumn(this.Normals);
             this.Tangents = _IsolateColumn(this.Tangents);
-            this.Colors0 = _IsolateColumn(this.Colors0);     // colors0,1 and texCoords0,1 can be modified by morphing
+            this.Colors0 = _IsolateColumn(this.Colors0);     // colors0,1 and texCoords 0,1,2,3 can be modified by morphing
             this.Colors1 = _IsolateColumn(this.Colors1);
             this.TexCoords0 = _IsolateColumn(this.TexCoords0);
             this.TexCoords1 = _IsolateColumn(this.TexCoords1);
+            this.TexCoords2 = _IsolateColumn(this.TexCoords2);
+            this.TexCoords3 = _IsolateColumn(this.TexCoords3);
 
             // prepare animation data, if available
 
@@ -185,6 +187,8 @@ namespace SharpGLTF.Geometry
             Vector4[] morphColors1 = null;
             Vector2[] morphTexcrd0 = null;
             Vector2[] morphTexcrd1 = null;
+            Vector2[] morphTexcrd2 = null;
+            Vector2[] morphTexcrd3 = null;
 
             if (_MorphTargets != null)
             {
@@ -195,6 +199,8 @@ namespace SharpGLTF.Geometry
                 if (_MorphTargets.All(item => item.Colors1 != null)) morphColors1 = new Vector4[this.MorphTargets.Count];
                 if (_MorphTargets.All(item => item.TexCoords0 != null)) morphTexcrd0 = new Vector2[this.MorphTargets.Count];
                 if (_MorphTargets.All(item => item.TexCoords1 != null)) morphTexcrd1 = new Vector2[this.MorphTargets.Count];
+                if (_MorphTargets.All(item => item.TexCoords2 != null)) morphTexcrd2 = new Vector2[this.MorphTargets.Count];
+                if (_MorphTargets.All(item => item.TexCoords3 != null)) morphTexcrd3 = new Vector2[this.MorphTargets.Count];
             }
 
             // loop over every vertex
@@ -252,6 +258,18 @@ namespace SharpGLTF.Geometry
                         _FillMorphData(morphTexcrd1, vc => vc.TexCoords1[i]);
                         TexCoords1[i] = morphMaterial.MorphTexCoord(TexCoords1[i], morphTexcrd1);
                     }
+
+                    if (this.TexCoords2 != null)
+                    {
+                        _FillMorphData(morphTexcrd2, vc => vc.TexCoords2[i]);
+                        TexCoords1[2] = morphMaterial.MorphTexCoord(TexCoords2[i], morphTexcrd2);
+                    }
+
+                    if (this.TexCoords3 != null)
+                    {
+                        _FillMorphData(morphTexcrd3, vc => vc.TexCoords3[i]);
+                        TexCoords3[2] = morphMaterial.MorphTexCoord(TexCoords3[i], morphTexcrd3);
+                    }
                 }
             }
 
@@ -318,11 +336,8 @@ namespace SharpGLTF.Geometry
         #endregion
 
         #region API - Vertex indexing
-
-        #if NET6_0_OR_GREATER
-        [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)]
-        #endif
-        public Type GetCompatibleVertexType()
+        
+        public (Type BuilderType, Func<IVertexBuilder> BuilderFactory) GetCompatibleVertexType()
         {
             var hasNormals = Normals != null;
             var hasTangents = hasNormals && Tangents != null;
@@ -394,21 +409,15 @@ namespace SharpGLTF.Geometry
             }
 
             return s;
-        }
+        }        
 
-        public IVertexBuilder GetVertex
-            (
-            #if NET6_0_OR_GREATER
-            [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)]
-            #endif
-            Type vertexType,
-            int index)
+        public IVertexBuilder GetVertex(Func<IVertexBuilder> factory, int index)
         {
             var g = GetVertexGeometry<VertexPositionNormalTangent>(index);
             var m = GetVertexMaterial<VertexColor2Texture2>(index);
             var s = GetVertexSkinning<VertexJoints8>(index);
 
-            return new VertexBuilder(g, m, s).ConvertToType(vertexType);
+            return new VertexBuilder(g, m, s).ConvertToType(factory);
         }
 
         public VertexBuilder<TvG, TvM, VertexEmpty> GetVertex<TvG, TvM>(int index)

+ 17 - 10
src/SharpGLTF.Toolkit/Geometry/VertexBuilder.cs

@@ -33,6 +33,9 @@ namespace SharpGLTF.Geometry
         /// </summary>
         /// <param name="skinning">A <see cref="IVertexSkinning"/> set.</param>
         void SetSkinning(IVertexSkinning skinning);
+
+
+        IMeshBuilder<TMaterial> CreateCompatibleMesh<TMaterial>(string name = null);
     }
 
     /// <summary>
@@ -331,6 +334,11 @@ namespace SharpGLTF.Geometry
             return new MeshBuilder<TvG, TvM, TvS>(name);
         }
 
+        IMeshBuilder<TMaterial> IVertexBuilder.CreateCompatibleMesh<TMaterial>(string name)
+        {
+            return new MeshBuilder<TMaterial, TvG, TvM, TvS>(name);
+        }
+
         #pragma warning restore CA1000 // Do not declare static members on generic types
 
         readonly IVertexGeometry IVertexBuilder.GetGeometry() { return this.Geometry; }
@@ -449,7 +457,7 @@ namespace SharpGLTF.Geometry
             v.Skinning.SetBindings(sparse);
 
             return v;
-        }
+        }        
 
         #endregion
     }
@@ -496,17 +504,11 @@ namespace SharpGLTF.Geometry
 
         public void SetMaterial(IVertexMaterial material) { this.Material = material; }
 
-        public void SetSkinning(IVertexSkinning skinning) { this.Skinning = skinning; }
+        public void SetSkinning(IVertexSkinning skinning) { this.Skinning = skinning; }        
 
-        public readonly IVertexBuilder ConvertToType
-            (
-            #if NET6_0_OR_GREATER
-            [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)]
-            #endif
-            Type vertexType
-            )
+        public readonly IVertexBuilder ConvertToType(Func<IVertexBuilder> factory)
         {
-            var v = (IVertexBuilder)Activator.CreateInstance(vertexType);
+            var v = factory.Invoke();
 
             v.SetGeometry(Geometry);
             v.SetMaterial(Material);
@@ -515,6 +517,11 @@ namespace SharpGLTF.Geometry
             return v;
         }
 
+        IMeshBuilder<TMaterial> IVertexBuilder.CreateCompatibleMesh<TMaterial>(string name)
+        {
+            throw new NotImplementedException();
+        }
+
         #endregion
     }
 }

+ 1 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/Attributes.cs

@@ -6,6 +6,7 @@ using System.Text;
 
 namespace SharpGLTF.Geometry.VertexTypes
 {
+    [Obsolete("The usage of this attribute has been removed because it's not AOT friendly. Implement IVertexReflection.GetEncodingAttributes() instead.", true)]
     [AttributeUsageAttribute(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
     public sealed class VertexAttributeAttribute : Attribute
     {

+ 5 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexEmpty.cs

@@ -26,6 +26,11 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         #region data
 
+        IEnumerable<KeyValuePair<string, Memory.AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield break;
+        }
+
         public override int GetHashCode() { return 0; }
         public override bool Equals(object obj) { return obj is VertexEmpty; }
         public bool Equals(VertexEmpty other) { return true; }

+ 38 - 37
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexGeometry.cs

@@ -5,6 +5,8 @@ using System.Numerics;
 using System.Runtime.Serialization;
 using System.Text;
 
+using SharpGLTF.Memory;
+
 namespace SharpGLTF.Geometry.VertexTypes
 {
     /// <summary>
@@ -19,7 +21,7 @@ namespace SharpGLTF.Geometry.VertexTypes
     /// <item><see cref="VertexGeometryDelta"/></item>
     /// </list>
     /// </remarks>
-    public interface IVertexGeometry
+    public interface IVertexGeometry : IVertexReflection
     {
         /// <summary>
         /// Gets the position of the vertex.
@@ -86,10 +88,7 @@ namespace SharpGLTF.Geometry.VertexTypes
 
     /// <summary>
     /// Defines a Vertex attribute with a Position.
-    /// </summary>
-    #if NET6_0_OR_GREATER
-    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields)]
-    #endif
+    /// </summary>    
     [System.Diagnostics.DebuggerDisplay("{_GetDebuggerDisplay(),nq}")]
     public struct VertexPosition : IVertexGeometry, IEquatable<VertexPosition>
     {
@@ -125,10 +124,14 @@ namespace SharpGLTF.Geometry.VertexTypes
         #endregion
 
         #region data
-
-        [VertexAttribute("POSITION")]
+        
         public Vector3 Position;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("POSITION", new AttributeFormat(Schema2.DimensionType.VEC3));
+        }
+
         /// <inheritdoc/>
         public readonly override int GetHashCode() { return Position.GetHashCode(); }
 
@@ -179,17 +182,14 @@ namespace SharpGLTF.Geometry.VertexTypes
         public void ApplyTransform(in Matrix4x4 xform)
         {
             Position = Vector3.Transform(Position, xform);
-        }
+        }        
 
         #endregion
     }
 
     /// <summary>
     /// Defines a Vertex attribute with a Position and a Normal.
-    /// </summary>
-    #if NET6_0_OR_GREATER
-    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields)]
-    #endif
+    /// </summary>    
     [System.Diagnostics.DebuggerDisplay("{_GetDebuggerDisplay(),nq}")]
     public struct VertexPositionNormal : IVertexGeometry, IEquatable<VertexPositionNormal>
     {
@@ -229,13 +229,16 @@ namespace SharpGLTF.Geometry.VertexTypes
         #endregion
 
         #region data
-
-        [VertexAttribute("POSITION")]
+        
         public Vector3 Position;
-
-        [VertexAttribute("NORMAL")]
         public Vector3 Normal;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("POSITION", new AttributeFormat(Schema2.DimensionType.VEC3));
+            yield return new KeyValuePair<string, AttributeFormat>("NORMAL", new AttributeFormat(Schema2.DimensionType.VEC3));
+        }
+
         /// <inheritdoc/>
         public readonly override int GetHashCode() { return Position.GetHashCode(); }
 
@@ -295,10 +298,7 @@ namespace SharpGLTF.Geometry.VertexTypes
 
     /// <summary>
     /// Defines a Vertex attribute with a Position, a Normal and a Tangent.
-    /// </summary>
-    #if NET6_0_OR_GREATER
-    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields)]
-    #endif
+    /// </summary>    
     [System.Diagnostics.DebuggerDisplay("{_GetDebuggerDisplay(),nq}")]
     public struct VertexPositionNormalTangent : IVertexGeometry, IEquatable<VertexPositionNormalTangent>
     {
@@ -334,16 +334,18 @@ namespace SharpGLTF.Geometry.VertexTypes
         #endregion
 
         #region data
-
-        [VertexAttribute("POSITION")]
-        public Vector3 Position;
-
-        [VertexAttribute("NORMAL")]
+        
+        public Vector3 Position;        
         public Vector3 Normal;
-
-        [VertexAttribute("TANGENT")]
         public Vector4 Tangent;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("POSITION", new AttributeFormat(Schema2.DimensionType.VEC3));
+            yield return new KeyValuePair<string, AttributeFormat>("NORMAL", new AttributeFormat(Schema2.DimensionType.VEC3));
+            yield return new KeyValuePair<string, AttributeFormat>("TANGENT", new AttributeFormat(Schema2.DimensionType.VEC4));
+        }
+
         /// <inheritdoc/>
         public readonly override int GetHashCode() { return Position.GetHashCode(); }
 
@@ -408,10 +410,7 @@ namespace SharpGLTF.Geometry.VertexTypes
 
     /// <summary>
     /// Defines a Vertex attribute with a Position, a Normal and a Tangent.
-    /// </summary>
-    #if NET6_0_OR_GREATER
-    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields)]
-    #endif
+    /// </summary>    
     [System.Diagnostics.DebuggerDisplay("{_GetDebuggerDisplay(),nq}")]
     public struct VertexGeometryDelta : IVertexGeometry, IEquatable<VertexGeometryDelta>
     {
@@ -489,16 +488,18 @@ namespace SharpGLTF.Geometry.VertexTypes
         #endregion
 
         #region data
-
-        [VertexAttribute("POSITIONDELTA")]
+        
         public Vector3 PositionDelta;
-
-        [VertexAttribute("NORMALDELTA")]
         public Vector3 NormalDelta;
-
-        [VertexAttribute("TANGENTDELTA")]
         public Vector3 TangentDelta;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("POSITIONDELTA", new AttributeFormat(Schema2.DimensionType.VEC3));
+            yield return new KeyValuePair<string, AttributeFormat>("NORMALDELTA", new AttributeFormat(Schema2.DimensionType.VEC3));
+            yield return new KeyValuePair<string, AttributeFormat>("TANGENTDELTA", new AttributeFormat(Schema2.DimensionType.VEC3));
+        }
+
         /// <inheritdoc/>
         public readonly override int GetHashCode() { return PositionDelta.GetHashCode(); }
 

+ 31 - 70
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.Permutations.cs

@@ -1,9 +1,3 @@
-
-
-
-
-
-
 // ------------------------------------------------------------------------------
 // <auto-generated>
 //     This code was generated by a tool.
@@ -25,12 +19,10 @@ using ENCODING = SharpGLTF.Schema2.EncodingType;
 
 
 
-
 namespace SharpGLTF.Geometry.VertexTypes
 {
-    
-    
-    /// <summary>
+        
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -130,8 +122,7 @@ namespace SharpGLTF.Geometry.VertexTypes
      }
 
 
-     
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -239,8 +230,7 @@ namespace SharpGLTF.Geometry.VertexTypes
      }
 
 
-     
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -356,8 +346,7 @@ namespace SharpGLTF.Geometry.VertexTypes
      }
 
 
-     
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -482,8 +471,7 @@ namespace SharpGLTF.Geometry.VertexTypes
 
 
      
-
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -583,8 +571,7 @@ namespace SharpGLTF.Geometry.VertexTypes
      }
 
 
-     
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -692,8 +679,7 @@ namespace SharpGLTF.Geometry.VertexTypes
      }
 
 
-     
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -809,8 +795,7 @@ namespace SharpGLTF.Geometry.VertexTypes
      }
 
 
-     
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -934,8 +919,7 @@ namespace SharpGLTF.Geometry.VertexTypes
      }
 
 
-     
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -1068,8 +1052,7 @@ namespace SharpGLTF.Geometry.VertexTypes
 
 
      
-
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -1177,8 +1160,7 @@ namespace SharpGLTF.Geometry.VertexTypes
      }
 
 
-     
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -1294,8 +1276,7 @@ namespace SharpGLTF.Geometry.VertexTypes
      }
 
 
-     
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -1419,8 +1400,7 @@ namespace SharpGLTF.Geometry.VertexTypes
      }
 
 
-     
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -1552,8 +1532,7 @@ namespace SharpGLTF.Geometry.VertexTypes
      }
 
 
-     
-    /// <summary>
+         /// <summary>
      /// Defines a Vertex attribute with a material Color.
      /// </summary>
      [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
@@ -1694,15 +1673,12 @@ namespace SharpGLTF.Geometry.VertexTypes
 
 
      
-
-    
-
+         
     partial struct VertexMaterialDelta
     {
 
-
-
-internal VertexMaterialDelta(in VertexTexture1 rootVal, in VertexTexture1 morphVal)
+         
+         internal VertexMaterialDelta(in VertexTexture1 rootVal, in VertexTexture1 morphVal)
          {
              MaxColors = 0;
              MaxTextCoords = 1;
@@ -1713,8 +1689,7 @@ internal VertexMaterialDelta(in VertexTexture1 rootVal, in VertexTexture1 morphV
              TexCoord2Delta = Vector2.Zero;
              TexCoord3Delta = Vector2.Zero;
          }
-         
-internal VertexMaterialDelta(in VertexTexture2 rootVal, in VertexTexture2 morphVal)
+         internal VertexMaterialDelta(in VertexTexture2 rootVal, in VertexTexture2 morphVal)
          {
              MaxColors = 0;
              MaxTextCoords = 2;
@@ -1725,8 +1700,7 @@ internal VertexMaterialDelta(in VertexTexture2 rootVal, in VertexTexture2 morphV
              TexCoord2Delta = Vector2.Zero;
              TexCoord3Delta = Vector2.Zero;
          }
-         
-internal VertexMaterialDelta(in VertexTexture3 rootVal, in VertexTexture3 morphVal)
+         internal VertexMaterialDelta(in VertexTexture3 rootVal, in VertexTexture3 morphVal)
          {
              MaxColors = 0;
              MaxTextCoords = 3;
@@ -1737,8 +1711,7 @@ internal VertexMaterialDelta(in VertexTexture3 rootVal, in VertexTexture3 morphV
              TexCoord2Delta = morphVal.TexCoord2 - rootVal.TexCoord2;
              TexCoord3Delta = Vector2.Zero;
          }
-         
-internal VertexMaterialDelta(in VertexTexture4 rootVal, in VertexTexture4 morphVal)
+         internal VertexMaterialDelta(in VertexTexture4 rootVal, in VertexTexture4 morphVal)
          {
              MaxColors = 0;
              MaxTextCoords = 4;
@@ -1750,8 +1723,7 @@ internal VertexMaterialDelta(in VertexTexture4 rootVal, in VertexTexture4 morphV
              TexCoord3Delta = morphVal.TexCoord3 - rootVal.TexCoord3;
          }
          
-
-internal VertexMaterialDelta(in VertexColor1 rootVal, in VertexColor1 morphVal)
+         internal VertexMaterialDelta(in VertexColor1 rootVal, in VertexColor1 morphVal)
          {
              MaxColors = 1;
              MaxTextCoords = 0;
@@ -1762,8 +1734,7 @@ internal VertexMaterialDelta(in VertexColor1 rootVal, in VertexColor1 morphVal)
              TexCoord2Delta = Vector2.Zero;
              TexCoord3Delta = Vector2.Zero;
          }
-         
-internal VertexMaterialDelta(in VertexColor1Texture1 rootVal, in VertexColor1Texture1 morphVal)
+         internal VertexMaterialDelta(in VertexColor1Texture1 rootVal, in VertexColor1Texture1 morphVal)
          {
              MaxColors = 1;
              MaxTextCoords = 1;
@@ -1774,8 +1745,7 @@ internal VertexMaterialDelta(in VertexColor1Texture1 rootVal, in VertexColor1Tex
              TexCoord2Delta = Vector2.Zero;
              TexCoord3Delta = Vector2.Zero;
          }
-         
-internal VertexMaterialDelta(in VertexColor1Texture2 rootVal, in VertexColor1Texture2 morphVal)
+         internal VertexMaterialDelta(in VertexColor1Texture2 rootVal, in VertexColor1Texture2 morphVal)
          {
              MaxColors = 1;
              MaxTextCoords = 2;
@@ -1786,8 +1756,7 @@ internal VertexMaterialDelta(in VertexColor1Texture2 rootVal, in VertexColor1Tex
              TexCoord2Delta = Vector2.Zero;
              TexCoord3Delta = Vector2.Zero;
          }
-         
-internal VertexMaterialDelta(in VertexColor1Texture3 rootVal, in VertexColor1Texture3 morphVal)
+         internal VertexMaterialDelta(in VertexColor1Texture3 rootVal, in VertexColor1Texture3 morphVal)
          {
              MaxColors = 1;
              MaxTextCoords = 3;
@@ -1798,8 +1767,7 @@ internal VertexMaterialDelta(in VertexColor1Texture3 rootVal, in VertexColor1Tex
              TexCoord2Delta = morphVal.TexCoord2 - rootVal.TexCoord2;
              TexCoord3Delta = Vector2.Zero;
          }
-         
-internal VertexMaterialDelta(in VertexColor1Texture4 rootVal, in VertexColor1Texture4 morphVal)
+         internal VertexMaterialDelta(in VertexColor1Texture4 rootVal, in VertexColor1Texture4 morphVal)
          {
              MaxColors = 1;
              MaxTextCoords = 4;
@@ -1811,8 +1779,7 @@ internal VertexMaterialDelta(in VertexColor1Texture4 rootVal, in VertexColor1Tex
              TexCoord3Delta = morphVal.TexCoord3 - rootVal.TexCoord3;
          }
          
-
-internal VertexMaterialDelta(in VertexColor2 rootVal, in VertexColor2 morphVal)
+         internal VertexMaterialDelta(in VertexColor2 rootVal, in VertexColor2 morphVal)
          {
              MaxColors = 2;
              MaxTextCoords = 0;
@@ -1823,8 +1790,7 @@ internal VertexMaterialDelta(in VertexColor2 rootVal, in VertexColor2 morphVal)
              TexCoord2Delta = Vector2.Zero;
              TexCoord3Delta = Vector2.Zero;
          }
-         
-internal VertexMaterialDelta(in VertexColor2Texture1 rootVal, in VertexColor2Texture1 morphVal)
+         internal VertexMaterialDelta(in VertexColor2Texture1 rootVal, in VertexColor2Texture1 morphVal)
          {
              MaxColors = 2;
              MaxTextCoords = 1;
@@ -1835,8 +1801,7 @@ internal VertexMaterialDelta(in VertexColor2Texture1 rootVal, in VertexColor2Tex
              TexCoord2Delta = Vector2.Zero;
              TexCoord3Delta = Vector2.Zero;
          }
-         
-internal VertexMaterialDelta(in VertexColor2Texture2 rootVal, in VertexColor2Texture2 morphVal)
+         internal VertexMaterialDelta(in VertexColor2Texture2 rootVal, in VertexColor2Texture2 morphVal)
          {
              MaxColors = 2;
              MaxTextCoords = 2;
@@ -1847,8 +1812,7 @@ internal VertexMaterialDelta(in VertexColor2Texture2 rootVal, in VertexColor2Tex
              TexCoord2Delta = Vector2.Zero;
              TexCoord3Delta = Vector2.Zero;
          }
-         
-internal VertexMaterialDelta(in VertexColor2Texture3 rootVal, in VertexColor2Texture3 morphVal)
+         internal VertexMaterialDelta(in VertexColor2Texture3 rootVal, in VertexColor2Texture3 morphVal)
          {
              MaxColors = 2;
              MaxTextCoords = 3;
@@ -1859,8 +1823,7 @@ internal VertexMaterialDelta(in VertexColor2Texture3 rootVal, in VertexColor2Tex
              TexCoord2Delta = morphVal.TexCoord2 - rootVal.TexCoord2;
              TexCoord3Delta = Vector2.Zero;
          }
-         
-internal VertexMaterialDelta(in VertexColor2Texture4 rootVal, in VertexColor2Texture4 morphVal)
+         internal VertexMaterialDelta(in VertexColor2Texture4 rootVal, in VertexColor2Texture4 morphVal)
          {
              MaxColors = 2;
              MaxTextCoords = 4;
@@ -1873,8 +1836,6 @@ internal VertexMaterialDelta(in VertexColor2Texture4 rootVal, in VertexColor2Tex
          }
          
 
-
-
     }
 
     

+ 302 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.Permutations.tt

@@ -0,0 +1,302 @@
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ assembly name="System.Core" #>
+<#@ import namespace="System.Linq" #>
+<#@ import namespace="System.Text" #>
+<#@ import namespace="System.Collections.Generic" #>
+<#@ output extension=".cs" #>
+// ------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version: 17.0.0.0
+//  
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+// ------------------------------------------------------------------------------
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
+using System.Text;
+
+using SharpGLTF.Memory;
+
+using ENCODING = SharpGLTF.Schema2.EncodingType;
+
+<#
+
+void WriteVertexMaterialPermutation(int colorCount, int textureCount)
+{
+    string vertexTypeName = "Vertex";
+    if (colorCount > 0) vertexTypeName += $"Color{colorCount}";
+    if (textureCount > 0) vertexTypeName += $"Texture{textureCount}";    
+
+    var colorsSet = new List<string>();    
+    if (colorCount == 1) colorsSet.Add("Color");    
+    else if (colorCount > 1) { for(int i=0; i < colorCount; ++i) colorsSet.Add($"Color{i}"); }    
+
+    var texcrdSet = new List<string>();
+    if (textureCount == 1) texcrdSet.Add("TexCoord");
+    else if (textureCount > 1) { for(int i=0; i < textureCount; ++i) texcrdSet.Add($"TexCoord{i}"); }       
+
+    var currentSet = new List<(string Type, string Arg, string Param)>();
+    foreach(var cset in colorsSet) currentSet.Add(("Vector4", cset.ToLower(), $"{cset}"));
+    foreach(var tset in texcrdSet) currentSet.Add(("Vector2", tset.ToLower(), $"{tset}"));
+
+    var attributeArgs = string.Join(", ", currentSet.Select(item => $"{item.Type} {item.Arg}") );    
+    var attributeParams = string.Join(", ", currentSet.Select(item => item.Param));
+
+    
+    
+    WriteLine("/// <summary>");
+    WriteLine("/// Defines a Vertex attribute with a material Color.");
+    WriteLine("/// </summary>");
+    // WriteLine("#if NET6_0_OR_GREATER");
+    // WriteLine("[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields)]");
+    // WriteLine("#endif");
+    WriteLine("[System.CodeDom.Compiler.GeneratedCodeAttribute(\"Microsoft.VisualStudio.TextTemplating\", \"17.0.0.0\")]");
+    WriteLine("[System.Diagnostics.DebuggerDisplay(\"{_GetDebuggerDisplay(),nq}\")]");
+    WriteLine("[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]");
+
+    WriteLine($"public partial struct {vertexTypeName} : IVertexMaterial, IEquatable<{vertexTypeName}>");   
+    WriteLine("{"); PushIndent("    ");
+
+    // diagnostics
+
+    WriteLine("#region diagnostics"); WriteLine("");
+
+    WriteLine("private readonly string _GetDebuggerDisplay() => VertexUtils._GetDebuggerDisplay(this);");
+
+    WriteLine("#endregion"); WriteLine("");
+
+    // constructors
+
+    WriteLine("#region constructors"); WriteLine("");
+
+    WriteLine($"public {vertexTypeName}({attributeArgs})");      
+    WriteLine("{"); PushIndent("    ");
+    foreach (var item in currentSet) { WriteLine($"{item.Param} = {item.Arg};"); }
+    PopIndent(); WriteLine("}");    
+
+    WriteLine($"public {vertexTypeName}(IVertexMaterial src)");   
+    WriteLine("{"); PushIndent("    ");
+    WriteLine("Guard.NotNull(src, nameof(src));");
+    for (int i=0; i < colorCount; ++i)   { WriteLine($"this.{colorsSet[i]} = {i} < src.MaxColors  ? src.GetColor({i}) : Vector4.One;"); }
+    for (int i=0; i < textureCount; ++i) { WriteLine($"this.{texcrdSet[i]} = {i} < src.MaxTextCoords ? src.GetTexCoord({i}) : Vector2.Zero;"); }
+    PopIndent(); WriteLine("}");
+
+    WriteLine("#endregion"); WriteLine("");
+    
+    // data       
+    
+    WriteLine("#region data"); WriteLine("");
+
+    for(int i=0; i < colorCount; ++i)
+    {
+        // WriteLine($"[VertexAttribute(\"COLOR_{i}\", ENCODING.UNSIGNED_BYTE, true)]");
+        WriteLine($"public Vector4 {colorsSet[i]};");
+        // WriteLine("");
+    }
+
+    for(int i=0; i < textureCount; ++i)
+    {
+        // WriteLine($"[VertexAttribute(\"TEXCOORD_{i}\")]");
+        WriteLine($"public Vector2 {texcrdSet[i]};");
+        // WriteLine("");
+    }
+
+    WriteLine("");
+
+    WriteLine("IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()");
+    WriteLine("{"); PushIndent("    ");
+    for (int i=0; i < colorCount; ++i)   { var name = "COLOR_" + i; WriteLine($"yield return new KeyValuePair<string, AttributeFormat>(\"{name}\", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));"); }
+    for (int i=0; i < textureCount; ++i) { var name = "TEXCOORD_" + i; WriteLine($"yield return new KeyValuePair<string, AttributeFormat>(\"{name}\", new AttributeFormat(Schema2.DimensionType.VEC2));"); }
+    PopIndent(); WriteLine("}");
+
+    WriteLine($"public readonly int MaxColors => {colorCount};");
+    WriteLine("");
+
+    WriteLine($"public readonly int MaxTextCoords => {textureCount};");
+    WriteLine("");
+
+    WriteLine($"public readonly override int GetHashCode()");
+    WriteLine("{"); PushIndent("    ");
+    WriteLine("#if !NETSTANDARD2_0");
+    WriteLine($"return HashCode.Combine({attributeParams});");
+    WriteLine("#else");
+    var hashParams = string.Join("+", currentSet.Select(item => $"{item.Param}.GetHashCode()"));
+    WriteLine($"return {hashParams};");
+    WriteLine("#endif");
+    PopIndent(); WriteLine("}");
+    WriteLine("");
+
+    WriteLine($"public readonly override bool Equals(Object obj) {{ return obj is {vertexTypeName} other ? Equals(other) : false; }}");
+    WriteLine("");
+
+    WriteLine($"public readonly bool Equals({vertexTypeName} other) {{ return AreEqual(this, other); }}");
+    WriteLine("");
+
+    WriteLine($"public static bool operator ==(in {vertexTypeName} a, in {vertexTypeName} b) {{ return AreEqual(a, b); }}");
+    WriteLine("");
+
+    WriteLine($"public static bool operator !=(in {vertexTypeName} a, in {vertexTypeName} b) {{ return !AreEqual(a, b); }}");
+    WriteLine("");
+
+    WriteLine($"public static bool AreEqual(in {vertexTypeName} a, in {vertexTypeName} b)");
+    WriteLine("{"); PushIndent("    ");
+    foreach(var attr in currentSet) { WriteLine($"if (a.{attr.Param} != b.{attr.Param}) return false;"); }    
+    WriteLine("return true;");
+    PopIndent(); WriteLine("}");
+    WriteLine("");
+
+    WriteLine("#endregion"); WriteLine("");
+
+    // API    
+
+    WriteLine("#region API"); WriteLine("");
+
+    WriteLine("public readonly VertexMaterialDelta Subtract(IVertexMaterial baseValue)");
+    WriteLine("{"); PushIndent("    ");
+    WriteLine($"return new VertexMaterialDelta(({vertexTypeName})baseValue, this);");
+    PopIndent(); WriteLine("}");
+
+    WriteLine("public void Add(in VertexMaterialDelta delta)");
+    WriteLine("{"); PushIndent("    ");    
+
+    foreach(var attr in currentSet)    
+    {
+        var src = $"{attr.Param}Delta";
+        if (src == "ColorDelta") src= "Color0Delta";
+        if (src == "TexCoordDelta") src= "TexCoord0Delta";
+        WriteLine($"this.{attr.Param} += delta.{src};");
+    }    
+    PopIndent(); WriteLine("}");
+
+
+    WriteLine("void IVertexMaterial.SetColor(int index, Vector4 color)");
+    WriteLine("{"); PushIndent("    ");
+    for(int i=0; i < colorCount; ++i) { WriteLine($"if (index == {i}) this.{colorsSet[i]} = color;"); }        
+    PopIndent(); WriteLine("}");
+
+    WriteLine("void IVertexMaterial.SetTexCoord(int index, Vector2 coord)");
+    WriteLine("{"); PushIndent("    ");
+    for(int i=0; i < textureCount; ++i) { WriteLine($"if (index == {i}) this.{texcrdSet[i]} = coord;"); }    
+    PopIndent(); WriteLine("}");
+
+    WriteLine("public readonly Vector4 GetColor(int index)");
+    WriteLine("{"); PushIndent("    ");
+    WriteLine("switch (index)");
+    WriteLine("{"); PushIndent("    ");
+    for(int i=0; i < colorCount; ++i) { WriteLine($"case {i}: return this.{colorsSet[i]};"); }        
+    WriteLine("default: throw new ArgumentOutOfRangeException(nameof(index));");
+    PopIndent(); WriteLine("}");
+    PopIndent(); WriteLine("}");
+
+    WriteLine("public readonly Vector2 GetTexCoord(int index)");
+    WriteLine("{"); PushIndent("    ");
+    WriteLine("switch (index)");
+    WriteLine("{"); PushIndent("    ");
+    for(int i=0; i < textureCount; ++i) { WriteLine($"case {i}: return this.{texcrdSet[i]};"); }    
+    WriteLine("default: throw new ArgumentOutOfRangeException(nameof(index));");
+    PopIndent(); WriteLine("}");
+    PopIndent(); WriteLine("}");
+
+    WriteLine("#endregion"); WriteLine("");
+
+    // closing
+
+    PopIndent(); WriteLine("}");
+
+    WriteLine("");
+    WriteLine("");    
+}
+
+void WriteVertexSubtractPermutation(int colorCount, int textureCount)
+{
+    string vertexTypeName = "Vertex";
+    if (colorCount > 0) vertexTypeName += $"Color{colorCount}";
+    if (textureCount > 0) vertexTypeName += $"Texture{textureCount}";  
+    
+    WriteLine($"internal VertexMaterialDelta(in {vertexTypeName} rootVal, in {vertexTypeName} morphVal)");
+    WriteLine("{"); PushIndent("    ");
+
+    
+    colorCount = Math.Min(2,colorCount);
+    textureCount = Math.Min(4,textureCount);
+
+    WriteLine($"MaxColors = {colorCount};");
+    WriteLine($"MaxTextCoords = {textureCount};");
+
+    for(int i=0; i< 2; ++i)
+    {
+        var name = colorCount == 1 ? "Color" : $"Color{i}";
+
+        if (colorCount > i) WriteLine($"Color{i}Delta = morphVal.{name} - rootVal.{name};");
+        else WriteLine($"Color{i}Delta = Vector4.Zero;");    
+    }
+
+    for(int i=0; i < 4; ++i)
+    {
+        var name = textureCount == 1 ? "TexCoord" : $"TexCoord{i}";
+
+        if (textureCount > i) WriteLine($"TexCoord{i}Delta = morphVal.{name} - rootVal.{name};");
+        else WriteLine($"TexCoord{i}Delta = Vector2.Zero;");    
+    }
+
+    PopIndent(); WriteLine("}");
+}
+
+#>
+
+
+namespace SharpGLTF.Geometry.VertexTypes
+{
+    <# PushIndent("     "); #>
+    
+    <# WriteVertexMaterialPermutation(0, 1); #>
+    <# WriteVertexMaterialPermutation(0, 2); #>
+    <# WriteVertexMaterialPermutation(0, 3); #>
+    <# WriteVertexMaterialPermutation(0, 4); #>
+
+    <# WriteVertexMaterialPermutation(1, 0); #>
+    <# WriteVertexMaterialPermutation(1, 1); #>
+    <# WriteVertexMaterialPermutation(1, 2); #>
+    <# WriteVertexMaterialPermutation(1, 3); #>
+    <# WriteVertexMaterialPermutation(1, 4); #>
+
+    <# WriteVertexMaterialPermutation(2, 0); #>
+    <# WriteVertexMaterialPermutation(2, 1); #>
+    <# WriteVertexMaterialPermutation(2, 2); #>
+    <# WriteVertexMaterialPermutation(2, 3); #>
+    <# WriteVertexMaterialPermutation(2, 4); #>
+
+    <# PopIndent(); #>
+
+    partial struct VertexMaterialDelta
+    {
+
+<# PushIndent("         "); #>
+
+<# WriteVertexSubtractPermutation(0, 1); #>
+<# WriteVertexSubtractPermutation(0, 2); #>
+<# WriteVertexSubtractPermutation(0, 3); #>
+<# WriteVertexSubtractPermutation(0, 4); #>
+
+<# WriteVertexSubtractPermutation(1, 0); #>
+<# WriteVertexSubtractPermutation(1, 1); #>
+<# WriteVertexSubtractPermutation(1, 2); #>
+<# WriteVertexSubtractPermutation(1, 3); #>
+<# WriteVertexSubtractPermutation(1, 4); #>
+
+<# WriteVertexSubtractPermutation(2, 0); #>
+<# WriteVertexSubtractPermutation(2, 1); #>
+<# WriteVertexSubtractPermutation(2, 2); #>
+<# WriteVertexSubtractPermutation(2, 3); #>
+<# WriteVertexSubtractPermutation(2, 4); #>
+
+<# ClearIndent(); #>
+
+    }
+
+    
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 119 - 1020
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.cs


+ 15 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexReflection.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SharpGLTF.Geometry.VertexTypes
+{
+    public interface IVertexReflection
+    {
+        /// <summary>
+        /// Gets the information used used to know how to encode the attributes stored in this vertex fragment.
+        /// </summary>
+        /// <returns>A list of attribute-encoding pairs</returns>
+        public IEnumerable<KeyValuePair<string, Memory.AttributeFormat>> GetEncodingAttributes();
+    }
+}

+ 25 - 21
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexSkinning.cs

@@ -3,6 +3,8 @@ using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 using System.Text;
+
+using SharpGLTF.Memory;
 using SharpGLTF.Transforms;
 
 using ENCODING = SharpGLTF.Schema2.EncodingType;
@@ -20,7 +22,7 @@ namespace SharpGLTF.Geometry.VertexTypes
     /// <item><see cref="VertexJoints8"/></item>
     /// </list>
     /// </remarks>
-    public interface IVertexSkinning
+    public interface IVertexSkinning : IVertexReflection
     {
         /// <summary>
         /// Gets the Number of valid joints supported.<br/>Typical values are 0, 4 or 8.
@@ -77,10 +79,7 @@ namespace SharpGLTF.Geometry.VertexTypes
 
     /// <summary>
     /// Defines a Vertex attribute with up to 65535 bone joints and 4 weights.
-    /// </summary>
-    #if NET6_0_OR_GREATER
-    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields)]
-    #endif
+    /// </summary>    
     [System.Diagnostics.DebuggerDisplay("{_GetDebuggerDisplay(),nq}")]
     public struct VertexJoints4 : IVertexSkinning, IEquatable<VertexJoints4>
     {
@@ -128,8 +127,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         /// <remarks>
         /// <para><b>⚠️ AVOID SETTING THIS VALUE DIRECTLY ⚠️</b></para>
         /// Consider using the constructor, or setter methods like<see cref="SetBindings(in SparseWeight8)"/> instead of setting this value directly.
-        /// </remarks>
-        [VertexAttribute("JOINTS_0", ENCODING.UNSIGNED_SHORT, false)]
+        /// </remarks>        
         public Vector4 Joints;
 
         /// <summary>
@@ -138,10 +136,15 @@ namespace SharpGLTF.Geometry.VertexTypes
         /// <remarks>
         /// <para><b>⚠️ AVOID SETTING THIS VALUE DIRECTLY ⚠️</b></para>
         /// Consider using the constructor, or setter methods like <see cref="SetBindings(in SparseWeight8)"/> instead of setting this value directly.
-        /// </remarks>
-        [VertexAttribute("WEIGHTS_0")]
+        /// </remarks>        
         public Vector4 Weights;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("JOINTS_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_SHORT, false));
+            yield return new KeyValuePair<string, AttributeFormat>("WEIGHTS_0", new AttributeFormat(Schema2.DimensionType.VEC4));
+        }
+
         /// <inheritdoc/>
         public readonly int MaxBindings => 4;
 
@@ -208,10 +211,7 @@ namespace SharpGLTF.Geometry.VertexTypes
 
     /// <summary>
     /// Defines a Vertex attribute with up to 65535 bone joints and 8 weights.
-    /// </summary>
-    #if NET6_0_OR_GREATER
-    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields)]
-    #endif
+    /// </summary>    
     [System.Diagnostics.DebuggerDisplay("{_GetDebuggerDisplay(),nq}")]
     public struct VertexJoints8 : IVertexSkinning, IEquatable<VertexJoints8>
     {
@@ -267,8 +267,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         /// <remarks>
         /// <para><b>⚠️ AVOID SETTING THIS VALUE DIRECTLY ⚠️</b></para>
         /// Consider using the constructor, or setter methods like <see cref="SetBindings(in SparseWeight8)"/> instead of setting this value directly.
-        /// </remarks>
-        [VertexAttribute("JOINTS_0", ENCODING.UNSIGNED_SHORT, false)]
+        /// </remarks>        
         public Vector4 Joints0;
 
         /// <summary>
@@ -277,8 +276,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         /// <remarks>
         /// <para><b>⚠️ AVOID SETTING THIS VALUE DIRECTLY ⚠️</b></para>
         /// Consider using the constructor, or setter methods like <see cref="SetBindings(in SparseWeight8)"/> instead of setting this value directly.
-        /// </remarks>
-        [VertexAttribute("JOINTS_1", ENCODING.UNSIGNED_SHORT, false)]
+        /// </remarks>        
         public Vector4 Joints1;
 
         /// <summary>
@@ -287,8 +285,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         /// <remarks>
         /// <para><b>⚠️ AVOID SETTING THESE VALUES DIRECTLY ⚠️</b></para>
         /// Consider using the constructor, or setter methods like <see cref="SetBindings(in SparseWeight8)"/> instead of setting this value directly.
-        /// </remarks>
-        [VertexAttribute("WEIGHTS_0")]
+        /// </remarks>        
         public Vector4 Weights0;
 
         /// <summary>
@@ -297,10 +294,17 @@ namespace SharpGLTF.Geometry.VertexTypes
         /// <remarks>
         /// <para><b>⚠️ AVOID SETTING THESE VALUES DIRECTLY ⚠️</b></para>
         /// Consider using the constructor, or setter methods like <see cref="SetBindings(in SparseWeight8)"/> instead of setting this value directly.
-        /// </remarks>
-        [VertexAttribute("WEIGHTS_1")]
+        /// </remarks>        
         public Vector4 Weights1;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("JOINTS_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_SHORT, false));
+            yield return new KeyValuePair<string, AttributeFormat>("JOINTS_1", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_SHORT, false));
+            yield return new KeyValuePair<string, AttributeFormat>("WEIGHTS_0", new AttributeFormat(Schema2.DimensionType.VEC4));
+            yield return new KeyValuePair<string, AttributeFormat>("WEIGHTS_1", new AttributeFormat(Schema2.DimensionType.VEC4));
+        }
+
         /// <inheritdoc/>
         public readonly int MaxBindings => 8;
 

+ 31 - 61
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.Accessors.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Numerics;
+using System.Runtime.CompilerServices;
 
 using SharpGLTF.Memory;
 
@@ -47,6 +48,7 @@ namespace SharpGLTF.Geometry.VertexTypes
 
             // determine the vertex attributes from the first vertex.
             var attributes = GetVertexAttributes(vertices[0], vertices.Count, vertexEncoding);
+            if (attributes == null || attributes.Length == 0) throw new InvalidOperationException("unable to retrieve attribute information from the vertex");
 
             // create a buffer
             int byteStride = attributes[0].ByteStride;
@@ -99,86 +101,54 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         public static MemoryAccessInfo[] GetVertexAttributes(this IVertexBuilder firstVertex, int vertexCount, PackedEncoding vertexEncoding)
         {
-            var tvg = firstVertex.GetGeometry().GetType();
-            var tvm = firstVertex.GetMaterial().GetType();
-            var tvs = firstVertex.GetSkinning().GetType();
+            var tvg = firstVertex.GetGeometry().GetEncodingAttributes();
+            var tvm = firstVertex.GetMaterial().GetEncodingAttributes();
+            var tvs = firstVertex.GetSkinning().GetEncodingAttributes();
 
-            Guard.HasDynamicallyAccessedMembers(tvg, false, false, false, true, nameof(firstVertex));
-            Guard.HasDynamicallyAccessedMembers(tvm, false, false, false, true, nameof(firstVertex));
-            Guard.HasDynamicallyAccessedMembers(tvs, false, false, false, true, nameof(firstVertex));
+            var attributes = new List<MemoryAccessInfo>();            
 
-            var attributes = new List<MemoryAccessInfo>();
-
-            foreach (var finfo in tvg.GetFields())
-            {
-                var attribute = _GetMemoryAccessInfo(finfo);
-                if (attribute.HasValue) attributes.Add(attribute.Value);
+            foreach (var finfo in tvg)
+            {                
+                attributes.Add(new MemoryAccessInfo(finfo.Key, 0, 0, 0, finfo.Value));
             }
 
-            foreach (var finfo in tvm.GetFields())
+            foreach (var finfo in tvm)
             {
-                var attribute = _GetMemoryAccessInfo(finfo);
-                if (attribute.HasValue)
+                var a = new MemoryAccessInfo(finfo.Key, 0, 0, 0, finfo.Value);
+                
+                if (a.Name.StartsWith("COLOR_", StringComparison.OrdinalIgnoreCase))
                 {
-                    var a = attribute.Value;
-                    if (a.Name.StartsWith("COLOR_", StringComparison.OrdinalIgnoreCase))
+                    if (vertexEncoding.ColorEncoding.HasValue)
                     {
-                        if (vertexEncoding.ColorEncoding.HasValue)
-                        {
-                            a.Encoding = vertexEncoding.ColorEncoding.Value;
-                            a.Normalized = a.Encoding != ENCODING.FLOAT;
-                        }
+                        a.Encoding = vertexEncoding.ColorEncoding.Value;
+                        a.Normalized = a.Encoding != ENCODING.FLOAT;
                     }
-
-                    attributes.Add(a);
                 }
+
+                attributes.Add(a);
             }
 
-            foreach (var finfo in tvs.GetFields())
+            foreach (var finfo in tvs)
             {
-                var attribute = _GetMemoryAccessInfo(finfo);
-                if (attribute.HasValue)
+                var a = new MemoryAccessInfo(finfo.Key, 0, 0, 0, finfo.Value);                
+                
+                if (a.Name.StartsWith("JOINTS_", StringComparison.OrdinalIgnoreCase)) a.Encoding = vertexEncoding.JointsEncoding.Value;
+                if (a.Name.StartsWith("WEIGHTS_", StringComparison.OrdinalIgnoreCase))
                 {
-                    var a = attribute.Value;
-                    if (a.Name.StartsWith("JOINTS_", StringComparison.OrdinalIgnoreCase)) a.Encoding = vertexEncoding.JointsEncoding.Value;
-                    if (a.Name.StartsWith("WEIGHTS_", StringComparison.OrdinalIgnoreCase))
-                    {
-                        a.Encoding = vertexEncoding.WeightsEncoding.Value;
-                        if (a.Encoding != ENCODING.FLOAT) a.Normalized = true;
-                    }
-
-                    attributes.Add(a);
+                    a.Encoding = vertexEncoding.WeightsEncoding.Value;
+                    if (a.Encoding != ENCODING.FLOAT) a.Normalized = true;
                 }
+
+                attributes.Add(a);
+                
             }
 
             var array = attributes.ToArray();
 
-            MemoryAccessInfo.SetInterleavedInfo(array, 0, vertexCount);
+            MemoryAccessInfo.SetInterleavedInfo(array, 0, vertexCount);            
 
             return array;
-        }
-
-        private static MemoryAccessInfo? _GetMemoryAccessInfo(System.Reflection.FieldInfo finfo)
-        {
-            var attribute = finfo.GetCustomAttributes(true)
-                    .OfType<VertexAttributeAttribute>()
-                    .FirstOrDefault();
-
-            if (attribute == null) return null;
-
-            var dimensions = (DIMENSIONS?)null;
-
-            if (finfo.FieldType == typeof(Single)) dimensions = DIMENSIONS.SCALAR;
-            if (finfo.FieldType == typeof(Vector2)) dimensions = DIMENSIONS.VEC2;
-            if (finfo.FieldType == typeof(Vector3)) dimensions = DIMENSIONS.VEC3;
-            if (finfo.FieldType == typeof(Vector4)) dimensions = DIMENSIONS.VEC4;
-            if (finfo.FieldType == typeof(Quaternion)) dimensions = DIMENSIONS.VEC4;
-            if (finfo.FieldType == typeof(Matrix4x4)) dimensions = DIMENSIONS.MAT4;
-
-            if (dimensions == null) throw new ArgumentException($"invalid type {finfo.FieldType}");
-
-            return new MemoryAccessInfo(attribute.Name, 0, 0, 0, dimensions.Value, attribute.Encoding, attribute.Normalized);
-        }
+        }        
 
         private static Converter<IVertexBuilder, Object> _GetVertexBuilderAttributeFunc(string attributeName)
         {
@@ -238,6 +208,6 @@ namespace SharpGLTF.Geometry.VertexTypes
             }
 
             return dst;
-        }
+        }        
     }
 }

+ 0 - 8
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.Builder.Reflection.cs

@@ -1,9 +1,3 @@
-
-
-
-
-
-
 // ------------------------------------------------------------------------------
 // <auto-generated>
 //     This code was generated by a tool.
@@ -23,7 +17,6 @@ using System.Text.Json.Serialization;
 
 
 
-
 namespace SharpGLTF.Geometry.VertexTypes
 {
     partial class VertexUtils
@@ -275,7 +268,6 @@ namespace SharpGLTF.Geometry.VertexTypes
                 default: throw new ArgumentOutOfRangeException(nameof(numJoints));
             }
             throw new NotImplementedException();
-
         }
     }    
 }

+ 99 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.Builder.Reflection.tt

@@ -0,0 +1,99 @@
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ assembly name="System.Core" #>
+<#@ import namespace="System.Linq" #>
+<#@ import namespace="System.Text" #>
+<#@ import namespace="System.Collections.Generic" #>
+<#@ output extension=".cs" #>
+// ------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version: 17.0.0.0
+//  
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+// ------------------------------------------------------------------------------
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+
+<#
+
+void WriteAllVertexTypePermutations(string baseTemplate)
+{
+    WriteLine("switch(numJoints)");
+
+    PushIndent("            ");
+
+    WriteLine("{"); PushIndent("    ");
+
+    for (int __jnt = 0; __jnt <= 8; __jnt += 4)
+    {
+        WriteLine("case " + __jnt + ":");
+        WriteLine("switch(numCols)");
+        WriteLine("{"); PushIndent("    ");
+
+        for(int __col = 0; __col <= 2; ++__col)
+        {
+            WriteLine("case " + __col + ":");
+            WriteLine("switch(numUV)");
+            WriteLine("{"); PushIndent("    ");
+
+            for(int __tex = 0; __tex <= 4; ++__tex)
+            {
+                WriteLine("case " + __tex + ":");
+
+                var matType = "VertexEmpty";
+                var jntType = "VertexEmpty";
+
+                if (__col == 0 && __tex != 0) matType = $"VertexTexture{__tex}";
+                if (__col != 0 && __tex == 0) matType = $"VertexColor{__col}";
+                if (__col != 0 && __tex != 0) matType = $"VertexColor{__col}Texture{__tex}";
+
+                if (__jnt == 4) jntType = "VertexJoints4";
+                if (__jnt == 8) jntType = "VertexJoints8";
+
+                var a = $"{baseTemplate}<VertexPosition,{matType},{jntType}>";
+                var b = $"{baseTemplate}<VertexPositionNormal,{matType},{jntType}>";
+                var c = $"{baseTemplate}<VertexPositionNormalTangent,{matType},{jntType}>";
+
+                PushIndent("    ");
+                WriteLine($"if (!hasNormals) return (typeof({a}), ()=> new {a}() );");
+                WriteLine($"if (!hasTangents) return (typeof({b}), ()=> new {b}() );");
+                WriteLine($"return (typeof({c}), ()=> new {c}() );");                       
+                PopIndent();
+            }
+
+            WriteLine("default: throw new ArgumentOutOfRangeException(nameof(numUV));");
+            PopIndent(); WriteLine("}");                        
+        }
+
+        WriteLine("default: throw new ArgumentOutOfRangeException(nameof(numCols));");
+        PopIndent(); WriteLine("}");                    
+    }
+                
+    WriteLine("default: throw new ArgumentOutOfRangeException(nameof(numJoints));");
+    PopIndent(); WriteLine("}");
+
+    WriteLine("throw new NotImplementedException();");
+
+    PopIndent();    
+}
+
+#>
+
+
+namespace SharpGLTF.Geometry.VertexTypes
+{
+    partial class VertexUtils
+    {            
+        public static (Type BuilderType, Func<IVertexBuilder> BuilderFactory) GetVertexBuilderType(bool hasNormals, bool hasTangents, int numCols, int numUV, int numJoints)
+        {
+            <# WriteAllVertexTypePermutations("VertexBuilder"); #>
+        }
+    }    
+}

+ 26 - 100
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.Builder.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Numerics;
 
@@ -7,111 +6,38 @@ namespace SharpGLTF.Geometry.VertexTypes
 {
     static partial class VertexUtils
     {
-        #if NET6_0_OR_GREATER
-        [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
-        #endif
-        public static Type GetVertexGeometryType(params string[] vertexAttributes)
+        public static (Type BuilderType, Func<IVertexBuilder> BuilderFactory) GetVertexBuilderType(params string[] vertexAttributes)
         {
-            var t = typeof(VertexPosition);
-            if (vertexAttributes.Contains("NORMAL")) t = typeof(VertexPositionNormal);
-            if (vertexAttributes.Contains("TANGENT")) t = typeof(VertexPositionNormalTangent);
-            return t;
-        }
-
-        #if NET6_0_OR_GREATER
-        [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
-        #endif
-        public static Type GetVertexMaterialType(params string[] vertexAttributes)
-        {
-            var colors = vertexAttributes.Contains("COLOR_0") ? 1 : 0;
-            colors = vertexAttributes.Contains("COLOR_1") ? 2 : colors;
-            colors = vertexAttributes.Contains("COLOR_2") ? 3 : colors;
-            colors = vertexAttributes.Contains("COLOR_3") ? 4 : colors;
-
-            var uvcoords = vertexAttributes.Contains("TEXCOORD_0") ? 1 : 0;
-            uvcoords = vertexAttributes.Contains("TEXCOORD_1") ? 2 : uvcoords;
-            uvcoords = vertexAttributes.Contains("TEXCOORD_2") ? 3 : uvcoords;
-            uvcoords = vertexAttributes.Contains("TEXCOORD_3") ? 4 : uvcoords;
-
-            return GetVertexMaterialType(colors, uvcoords);
-        }
-
-        #if NET6_0_OR_GREATER
-        [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
-        #endif
-        public static Type GetVertexMaterialType(int colors, int uvcoords)
-        {
-            if (colors == 0)
-            {
-                if (uvcoords == 0) return typeof(VertexEmpty);
-                if (uvcoords == 1) return typeof(VertexTexture1);
-                if (uvcoords >= 2) return typeof(VertexTexture2);
-            }
-
-            if (colors == 1)
-            {
-                if (uvcoords == 0) return typeof(VertexColor1);
-                if (uvcoords == 1) return typeof(VertexColor1Texture1);
-                if (uvcoords >= 2) return typeof(VertexColor1Texture2);
-            }
-
-            if (colors >= 2)
-            {
-                if (uvcoords == 0) return typeof(VertexColor2);
-                if (uvcoords == 1) return typeof(VertexColor2Texture1);
-                if (uvcoords >= 2) return typeof(VertexColor2Texture2);
-            }
+            var hasNormals = vertexAttributes.Contains("NORMAL");
+            var hasTangents = vertexAttributes.Contains("TANGENT");
+
+            var colors = 0;
+            if (vertexAttributes.Contains("COLOR_0")) colors = Math.Max(colors, 1);
+            if (vertexAttributes.Contains("COLOR_1")) colors = Math.Max(colors, 2);
+            if (vertexAttributes.Contains("COLOR_2")) colors = Math.Max(colors, 3);
+            if (vertexAttributes.Contains("COLOR_3")) colors = Math.Max(colors, 4);
+            if (vertexAttributes.Contains("COLOR_4")) colors = Math.Max(colors, 5);
+            if (vertexAttributes.Contains("COLOR_5")) colors = Math.Max(colors, 6);
+            if (vertexAttributes.Contains("COLOR_6")) colors = Math.Max(colors, 7);
+            if (vertexAttributes.Contains("COLOR_7")) colors = Math.Max(colors, 8);
+
+            var uvcoords = 0;
+            if (vertexAttributes.Contains("TEXCOORD_0")) uvcoords = Math.Max(uvcoords, 1);
+            if (vertexAttributes.Contains("TEXCOORD_1")) uvcoords = Math.Max(uvcoords, 2);
+            if (vertexAttributes.Contains("TEXCOORD_2")) uvcoords = Math.Max(uvcoords, 3);
+            if (vertexAttributes.Contains("TEXCOORD_3")) uvcoords = Math.Max(uvcoords, 4);
+            if (vertexAttributes.Contains("TEXCOORD_4")) uvcoords = Math.Max(uvcoords, 5);
+            if (vertexAttributes.Contains("TEXCOORD_5")) uvcoords = Math.Max(uvcoords, 6);
+            if (vertexAttributes.Contains("TEXCOORD_6")) uvcoords = Math.Max(uvcoords, 7);
+            if (vertexAttributes.Contains("TEXCOORD_7")) uvcoords = Math.Max(uvcoords, 8);
 
-            return typeof(VertexEmpty);
-        }
-
-        #if NET6_0_OR_GREATER
-        [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
-        #endif
-        public static Type GetVertexSkinningType(params string[] vertexAttributes)
-        {
             var joints = vertexAttributes.Contains("JOINTS_0") && vertexAttributes.Contains("WEIGHTS_0") ? 4 : 0;
             joints = vertexAttributes.Contains("JOINTS_1") && vertexAttributes.Contains("WEIGHTS_1") ? 8 : joints;
 
-            if (joints == 4) return typeof(VertexJoints4);
-            if (joints == 8) return typeof(VertexJoints8);
-
-            return typeof(VertexEmpty);
-        }
-
-        #if NET6_0_OR_GREATER
-        [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
-        #endif
-        public static Type GetVertexBuilderType(params string[] vertexAttributes)
-        {
-            var tvg = GetVertexGeometryType(vertexAttributes);
-            var tvm = GetVertexMaterialType(vertexAttributes);
-            var tvs = GetVertexSkinningType(vertexAttributes);
-
-            var vtype = typeof(VertexBuilder<,,>);
+            // WARNING: not all Color x Texture higher values have been defined yet.
 
-            return vtype.MakeGenericType(tvg, tvm, tvs);
-        }
-
-        #if NET6_0_OR_GREATER
-        [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
-        #endif
-        public static Type GetVertexBuilderType(bool hasNormals, bool hasTangents, int numCols, int numUV, int numJoints)
-        {
-            var tvg = typeof(VertexPosition);
-            if (hasNormals) tvg = typeof(VertexPositionNormal);
-            if (hasTangents) tvg = typeof(VertexPositionNormalTangent);
-
-            var tvm = GetVertexMaterialType(numCols, numUV);
-
-            var tvs = typeof(VertexEmpty);
-            if (numJoints == 4) tvs = typeof(VertexJoints4);
-            if (numJoints >= 8) tvs = typeof(VertexJoints8);
-
-            var vtype = typeof(VertexBuilder<,,>);
-
-            return vtype.MakeGenericType(tvg, tvm, tvs);
-        }
+            return GetVertexBuilderType(hasNormals, hasTangents, colors, uvcoords, joints);
+        }        
 
         public static TvP ConvertToGeometry<TvP>(this IVertexGeometry src)
             where TvP : struct, IVertexGeometry

+ 13 - 12
src/SharpGLTF.Toolkit/Schema2/MeshExtensions.cs

@@ -10,6 +10,7 @@ using SharpGLTF.Geometry.VertexTypes;
 
 using MESHXFORM = SharpGLTF.Transforms.IGeometryTransform;
 using JSONEXTRAS = System.Text.Json.Nodes.JsonNode;
+using System.Diagnostics.CodeAnalysis;
 
 namespace SharpGLTF.Schema2
 {
@@ -483,12 +484,12 @@ namespace SharpGLTF.Schema2
             var points = prim.GetPointIndices();
 
             VertexBufferColumns vertices = null;
-            Type vtype = null;
+            Func<IVertexBuilder> vtype = null;
 
             foreach (var xinst in Transforms.InstancingTransform.Evaluate(xform))
             {
                 vertices ??= prim.GetVertexColumns();
-                vtype ??= vertices.GetCompatibleVertexType();
+                vtype ??= vertices.GetCompatibleVertexType().BuilderFactory;
 
                 var xvertices = xinst != null
                     ? vertices.WithTransform(xinst)
@@ -519,7 +520,7 @@ namespace SharpGLTF.Schema2
             if (!lines.Any()) yield break;
 
             var vertices = prim.GetVertexColumns();
-            var vtype = vertices.GetCompatibleVertexType();
+            var vtype = vertices.GetCompatibleVertexType().BuilderFactory;
 
             foreach (var xinst in Transforms.InstancingTransform.Evaluate(xform))
             {
@@ -554,7 +555,7 @@ namespace SharpGLTF.Schema2
             foreach (var xinst in Transforms.InstancingTransform.Evaluate(xform))
             {
                 var xvertices = xinst != null ? vertices.WithTransform(xinst) : vertices;
-                var vtype = vertices.GetCompatibleVertexType();
+                var vtype = vertices.GetCompatibleVertexType().BuilderFactory;
 
                 foreach (var (ta, tb, tc) in triangles)
                 {
@@ -704,7 +705,7 @@ namespace SharpGLTF.Schema2
 
             return srcScene.ToStaticMeshBuilder<Materials.MaterialBuilder, TvG, TvM>(convertMaterial, options, animation, time);
         }
-
+                
         public static IMeshBuilder<Materials.MaterialBuilder> ToMeshBuilder(this Mesh srcMesh)
         {
             if (srcMesh == null) return null;
@@ -811,7 +812,7 @@ namespace SharpGLTF.Schema2
 
             foreach (var srcPoint in srcPrim.GetPointIndices())
             {
-                var vrt = vertices.GetVertex(dstPrim.VertexType, srcPoint);
+                var vrt = vertices.GetVertex(dstPrim.VertexFactory, srcPoint);
 
                 var idx = dstPrim.AddPoint(vrt);
 
@@ -820,8 +821,8 @@ namespace SharpGLTF.Schema2
 
             foreach (var (srcA, srcB) in srcPrim.GetLineIndices())
             {
-                var vrtA = vertices.GetVertex(dstPrim.VertexType, srcA);
-                var vrtB = vertices.GetVertex(dstPrim.VertexType, srcB);
+                var vrtA = vertices.GetVertex(dstPrim.VertexFactory, srcA);
+                var vrtB = vertices.GetVertex(dstPrim.VertexFactory, srcB);
 
                 var (idxA, idxB) = dstPrim.AddLine(vrtA, vrtB);
 
@@ -831,9 +832,9 @@ namespace SharpGLTF.Schema2
 
             foreach (var (srcA, srcB, srcC) in srcPrim.GetTriangleIndices())
             {
-                var vrtA = vertices.GetVertex(dstPrim.VertexType, srcA);
-                var vrtB = vertices.GetVertex(dstPrim.VertexType, srcB);
-                var vrtC = vertices.GetVertex(dstPrim.VertexType, srcC);
+                var vrtA = vertices.GetVertex(dstPrim.VertexFactory, srcA);
+                var vrtB = vertices.GetVertex(dstPrim.VertexFactory, srcB);
+                var vrtC = vertices.GetVertex(dstPrim.VertexFactory, srcC);
 
                 var (idxA, idxB, idxC) = dstPrim.AddTriangle(vrtA, vrtB, vrtC);
 
@@ -850,7 +851,7 @@ namespace SharpGLTF.Schema2
                 {
                     if (kvp.Value < 0) continue;
 
-                    var v = srcTarget.GetVertex(dstPrim.VertexType, kvp.Key);
+                    var v = srcTarget.GetVertex(dstPrim.VertexFactory, kvp.Key);
 
                     dstPrim.SetVertexDelta(tidx, kvp.Value,
                         new VertexGeometryDelta(v.GetGeometry()), new VertexMaterialDelta(v.GetMaterial()));

+ 35 - 1
src/SharpGLTF.Toolkit/SharpGLTF.Toolkit.csproj

@@ -16,6 +16,40 @@
 
   <ItemGroup>
     <ProjectReference Include="..\SharpGLTF.Runtime\SharpGLTF.Runtime.csproj" />
-  </ItemGroup> 
+  </ItemGroup>    
+
+  <ItemGroup>
+    <Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <None Update="Geometry\VertexTypes\VertexUtils.Builder.Reflection.tt">
+      <Generator>TextTemplatingFileGenerator</Generator>
+      <LastGenOutput>VertexUtils.Builder.Reflection.cs</LastGenOutput>
+    </None>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Update="Geometry\VertexTypes\VertexUtils.Builder.Reflection.cs">
+      <DesignTime>True</DesignTime>
+      <AutoGen>True</AutoGen>
+      <DependentUpon>VertexUtils.Builder.Reflection.tt</DependentUpon>
+    </Compile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <None Update="Geometry\VertexTypes\VertexMaterial.Permutations.tt">
+      <Generator>TextTemplatingFileGenerator</Generator>
+      <LastGenOutput>VertexMaterial.Permutations.cs</LastGenOutput>
+    </None>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Update="Geometry\VertexTypes\VertexMaterial.Permutations.cs">
+      <DesignTime>True</DesignTime>
+      <AutoGen>True</AutoGen>
+      <DependentUpon>VertexMaterial.Permutations.tt</DependentUpon>
+    </Compile>
+  </ItemGroup>
 
 </Project>

+ 9 - 9
tests/SharpGLTF.Cesium.Tests/VertexPointcloud.cs

@@ -4,14 +4,11 @@ using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 
 using SharpGLTF.Geometry.VertexTypes;
+using SharpGLTF.Memory;
 using SharpGLTF.Schema2;
 
 namespace SharpGLTF
 {
-    #if NET6_0_OR_GREATER
-        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)]
-    #endif
-
     [System.Diagnostics.DebuggerDisplay("𝐂:{Color} 𝐔𝐕:{TexCoord}")]
     public struct VertexPointcloud : IVertexCustom
     {
@@ -25,15 +22,18 @@ namespace SharpGLTF
         public const string INTENSITYATTRIBUTENAME = "_INTENSITY";
         public const string CLASSIFICATIONATTRIBUTENAME = "_CLASSIFICATION";
 
-        [VertexAttribute("COLOR_0", EncodingType.UNSIGNED_BYTE, true)]
+        
         public Vector4 Color;
-
-        [VertexAttribute(INTENSITYATTRIBUTENAME, EncodingType.FLOAT, false)]
         public float Intensity;
-        
-        [VertexAttribute(CLASSIFICATIONATTRIBUTENAME, EncodingType.FLOAT, false)]
         public float Classification;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_BYTE, true));
+            yield return new KeyValuePair<string, AttributeFormat>(INTENSITYATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));
+            yield return new KeyValuePair<string, AttributeFormat>(CLASSIFICATIONATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));
+        }
+
         public int MaxColors => 1;
 
         public int MaxTextCoords => 0;

+ 7 - 6
tests/SharpGLTF.Cesium.Tests/VertexWithFeatureId.cs

@@ -4,14 +4,11 @@ using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 
 using SharpGLTF.Geometry.VertexTypes;
+using SharpGLTF.Memory;
 using SharpGLTF.Schema2;
 
 namespace SharpGLTF
 {
-
-    #if NET6_0_OR_GREATER
-        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)]
-    #endif
     [System.Diagnostics.DebuggerDisplay("𝐂:{Color} 𝐔𝐕:{TexCoord}")]
     public struct VertexWithFeatureId : IVertexCustom
     {
@@ -26,10 +23,14 @@ namespace SharpGLTF
         }
 
         public const string CUSTOMATTRIBUTENAME = "_FEATURE_ID_0";
-
-        [VertexAttribute(CUSTOMATTRIBUTENAME, EncodingType.FLOAT, false)]
+        
         public float BatchId;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>(CUSTOMATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));            
+        }
+
         public int MaxColors => 0;
 
         public int MaxTextCoords => 0;

+ 12 - 10
tests/SharpGLTF.Cesium.Tests/VertexWithFeatureIds.cs

@@ -4,14 +4,11 @@ using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 
 using SharpGLTF.Geometry.VertexTypes;
+using SharpGLTF.Memory;
 using SharpGLTF.Schema2;
 
 namespace SharpGLTF
-{
-    #if NET6_0_OR_GREATER
-        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)]
-    #endif
-
+{    
     [System.Diagnostics.DebuggerDisplay("𝐂:{Color} 𝐔𝐕:{TexCoord}")]
     public struct VertexWithFeatureIds : IVertexCustom
     {
@@ -23,13 +20,16 @@ namespace SharpGLTF
 
         public const string FEATUREID0ATTRIBUTENAME = "_FEATURE_ID_0";
         public const string FEATUREID1ATTRIBUTENAME = "_FEATURE_ID_1";
-
-        [VertexAttribute(FEATUREID0ATTRIBUTENAME, EncodingType.FLOAT, false)]
-        public float FeatureId0;
-
-        [VertexAttribute(FEATUREID1ATTRIBUTENAME, EncodingType.FLOAT, false)]
+        
+        public float FeatureId0;        
         public float FeatureId1;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>(FEATUREID0ATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));
+            yield return new KeyValuePair<string, AttributeFormat>(FEATUREID1ATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));
+        }
+
         public int MaxColors => 0;
 
         public int MaxTextCoords => 0;
@@ -82,5 +82,7 @@ namespace SharpGLTF
         {
             throw new NotImplementedException();
         }
+
+        
     }
 }

+ 2 - 1
tests/SharpGLTF.Core.Tests/Validation/InvalidFilesTests.cs

@@ -74,8 +74,9 @@ namespace SharpGLTF.Validation
                 // https://github.com/KhronosGroup/glTF-Validator/issues/189
                 if (f.EndsWith("node_weights_override.gltf")) continue;
                 if (f.EndsWith("valid_with_tangent.gltf")) continue;
+                // if (f.EndsWith("custom_property.gltf")) continue;               
 
-                // if (!f.EndsWith("out_of_range.gltf")) continue;
+                if (!f.EndsWith("custom_property.gltf")) continue;
 
                 var gltfJson = f.EndsWith(".gltf") ? System.IO.File.ReadAllText(f) : string.Empty;
                 

+ 2 - 3
tests/SharpGLTF.NUnit/TestFiles.cs

@@ -144,13 +144,12 @@ namespace SharpGLTF
         {
             var skip = new string[]
             {
-                "empty_object.gltf", // need to look further
-                "custom_property.gltf",
+                "empty_object.gltf", // need to look further                
                 "integer_written_as_float.gltf",
                 "unknown_type.gltf",
                 "valid.gltf", // valid just because objects are unused
                 "get_elements_sparse.gltf", // valid just because objects are unused
-                "invalid_elements_float.gltf", // sure, it has invalid floats, but then the accessor is not used.
+                "invalid_elements_float.gltf", // sure, it has invalid floats, but then the accessor is not used by the current scene. But what if the accessor is used externally, or by an unhalded extension?
                 "not_found.gltf", // it fails at a tricky time
                 "non_relative_uri.gltf", // absolute path pointing to a http which is not supported.
                 "unrecognized_format.gltf", // might require to dig into the image

+ 23 - 21
tests/SharpGLTF.Toolkit.Tests/Geometry/VertexTypes/CustomVertices.cs

@@ -4,11 +4,11 @@ using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 using System.Text;
 
+using SharpGLTF.Memory;
+using SharpGLTF.Schema2;
+
 namespace SharpGLTF.Geometry.VertexTypes
-{
-    #if NET6_0_OR_GREATER
-    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)]
-    #endif
+{    
     [System.Diagnostics.DebuggerDisplay("𝐂:{Color} 𝐔𝐕:{TexCoord} {CustomId}")]
     public struct VertexColor1Texture1Custom1 : IVertexCustom
     {
@@ -48,16 +48,18 @@ namespace SharpGLTF.Geometry.VertexTypes
         #region data
 
         public const string CUSTOMATTRIBUTENAME = "_CUSTOM_0";
-
-        [VertexAttribute(CUSTOMATTRIBUTENAME, Schema2.EncodingType.FLOAT, false)]
-        public Single CustomId;
-
-        [VertexAttribute("COLOR_0", Schema2.EncodingType.UNSIGNED_BYTE, true)]
-        public Vector4 Color;
-
-        [VertexAttribute("TEXCOORD_0")]
+        
+        public Single CustomId;        
+        public Vector4 Color;        
         public Vector2 TexCoord;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {            
+            yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_BYTE, true));
+            yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(DimensionType.VEC2));
+            yield return new KeyValuePair<string, AttributeFormat>(CUSTOMATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));
+        }
+
         public int MaxColors => 1;
 
         public int MaxTextCoords => 1;
@@ -124,10 +126,7 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         #endregion
     }
-
-    #if NET6_0_OR_GREATER
-    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)]
-    #endif
+    
     [System.Diagnostics.DebuggerDisplay("{CustomId0} {CustomId1}")]
     public struct VertexCustom2 : IVertexCustom
     {
@@ -167,12 +166,15 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         public const string CUSTOMATTRIBUTENAME0 = "_CUSTOM_0";
         public const string CUSTOMATTRIBUTENAME1 = "_CUSTOM_1";
+        
+        public Single CustomId0;        
+        public Vector4 CustomId1;
 
-        [VertexAttribute(CUSTOMATTRIBUTENAME0, Schema2.EncodingType.FLOAT, false)]
-        public Single CustomId0;
-
-        [VertexAttribute(CUSTOMATTRIBUTENAME1, Schema2.EncodingType.UNSIGNED_BYTE, true)]
-        public Vector4 CustomId1;        
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {            
+            yield return new KeyValuePair<string, AttributeFormat>(CUSTOMATTRIBUTENAME0, new AttributeFormat(DimensionType.SCALAR, EncodingType.FLOAT, false));
+            yield return new KeyValuePair<string, AttributeFormat>(CUSTOMATTRIBUTENAME1, new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_BYTE, true));
+        }
 
         public int MaxColors => 0;
 

+ 4 - 3
tests/SharpGLTF.Trimmed.App/Properties/PublishProfiles/FolderProfile.pubxml

@@ -6,12 +6,13 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
   <PropertyGroup>
     <Configuration>Release</Configuration>
     <Platform>Any CPU</Platform>
-    <PublishDir>bin\publish\</PublishDir>
+    <PublishDir>bin\Release\net8.0\publish\win-x64\</PublishDir>
     <PublishProtocol>FileSystem</PublishProtocol>
-    <TargetFramework>net7.0</TargetFramework>
+    <_TargetId>Folder</_TargetId>
+    <TargetFramework>net8.0</TargetFramework>
     <RuntimeIdentifier>win-x64</RuntimeIdentifier>
     <SelfContained>true</SelfContained>
-    <PublishSingleFile>true</PublishSingleFile>
+    <PublishSingleFile>false</PublishSingleFile>
     <PublishReadyToRun>false</PublishReadyToRun>
   </PropertyGroup>
 </Project>

+ 2 - 7
tests/SharpGLTF.Trimmed.App/SharpGLTF.Trimmed.App.csproj

@@ -2,13 +2,8 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net8.0</TargetFramework>    
-  </PropertyGroup>  
-
-  <PropertyGroup>
-    <PublishTrimmed>true</PublishTrimmed>
-    <!-- Prevent warnings from unused code in dependencies -->
-    <TrimmerDefaultAction>link</TrimmerDefaultAction>
+    <TargetFramework>net8.0</TargetFramework>
+    <PublishAot>true</PublishAot>
     <RootNamespace>SharpGLTF</RootNamespace>
   </PropertyGroup>
 

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels