Răsfoiți Sursa

MeshBuilder with interfaces

Vicente Penades 6 ani în urmă
părinte
comite
0b9b3c33b8

+ 89 - 181
src/SharpGLTF.Toolkit/Geometry/MeshBuilder.cs

@@ -9,10 +9,23 @@ namespace SharpGLTF.Geometry
     using Collections;
     using VertexTypes;
 
+    public interface IMeshBuilder<TMaterial>
+    {
+        string Name { get; set; }
+
+        IReadOnlyCollection<TMaterial> Materials { get; }
+
+        IPrimitiveBuilder UsePrimitive(TMaterial material);
+
+        IPrimitive<TMaterial> GetPrimitive(TMaterial material);
+
+        void Validate();
+    }
+
     /// <summary>
-    /// Represents an utility class to help build mesh primitives by adding triangles
+    /// Represents an utility class to help build meshes by adding primitives associated with a given material.
     /// </summary>
-    /// <typeparam name="TMaterial">The material type used by this <see cref="PrimitiveBuilder{TMaterial, TvP, TvM, JvS}"/> instance.</typeparam>
+    /// <typeparam name="TMaterial">The material type used by this <see cref="PrimitiveBuilder{TMaterial, TvP, TvM, TvS}"/> instance.</typeparam>
     /// <typeparam name="TvP">
     /// The vertex fragment type with Position, Normal and Tangent.
     /// Valid types are:
@@ -28,7 +41,7 @@ namespace SharpGLTF.Geometry
     /// <see cref="VertexTexture1"/>,
     /// <see cref="VertexColor1Texture1"/>.
     /// </typeparam>
-    /// <typeparam name="JvS">
+    /// <typeparam name="TvS">
     /// The vertex fragment type with Skin Joint Weights.
     /// Valid types are:
     /// <see cref="VertexEmpty"/>,
@@ -37,162 +50,82 @@ namespace SharpGLTF.Geometry
     /// <see cref="VertexJoints16x4"/>,
     /// <see cref="VertexJoints16x8"/>.
     /// </typeparam>
-    public class PrimitiveBuilder<TMaterial, TvP, TvM, JvS>
+    public class MeshBuilder<TMaterial, TvP, TvM, TvS> : IMeshBuilder<TMaterial>
         where TvP : struct, IVertexPosition
         where TvM : struct, IVertexMaterial
-        where JvS : struct, IVertexSkinning
+        where TvS : struct, IVertexSkinning
     {
         #region lifecycle
 
-        internal PrimitiveBuilder(MeshBuilder<TMaterial, TvP, TvM, JvS> mesh, TMaterial material, bool strict)
+        public MeshBuilder(string name = null)
         {
-            this._Scrict = strict;
-            this._Mesh = mesh;
-            this._Material = material;
+            this.Name = name;
         }
 
         #endregion
 
         #region data
 
-        private readonly bool _Scrict;
-
-        private readonly MeshBuilder<TMaterial, TvP, TvM, JvS> _Mesh;
-
-        private readonly TMaterial _Material;
-
-        private readonly VertexList<(TvP, TvM, JvS)> _Vertices = new VertexList<(TvP, TvM, JvS)>();
-        private readonly List<int> _Indices = new List<int>();
+        private readonly Dictionary<TMaterial, PrimitiveBuilder<TMaterial, TvP, TvM, TvS>> _Primitives = new Dictionary<TMaterial, PrimitiveBuilder<TMaterial, TvP, TvM, TvS>>();
 
         #endregion
 
         #region properties
 
-        public MeshBuilder<TMaterial, TvP, TvM, JvS> Mesh => _Mesh;
+        public Boolean StrictMode { get; set; }
 
-        public TMaterial Material => _Material;
+        public string Name { get; set; }
 
-        public IReadOnlyList<(TvP, TvM, JvS)> Vertices => _Vertices;
+        public IReadOnlyCollection<TMaterial> Materials => _Primitives.Keys;
 
-        public IReadOnlyList<int> Indices => _Indices;
+        public IReadOnlyCollection<PrimitiveBuilder<TMaterial, TvP, TvM, TvS>> Primitives => _Primitives.Values;
 
-        public IEnumerable<(int, int, int)> Triangles
-        {
-            get
-            {
-                for (int i = 2; i < _Indices.Count; i += 3)
-                {
-                    yield return (_Indices[i - 2], _Indices[i - 1], _Indices[i]);
-                }
-            }
-        }
+        string IMeshBuilder<TMaterial>.Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+
+        IReadOnlyCollection<TMaterial> IMeshBuilder<TMaterial>.Materials => throw new NotImplementedException();
 
         #endregion
 
         #region API
 
-        public int UseVertex((TvP, TvM, JvS) vertex)
+        private PrimitiveBuilder<TMaterial, TvP, TvM, TvS> _UsePrimitive(TMaterial material)
         {
-            if (_Scrict)
+            if (!_Primitives.TryGetValue(material, out PrimitiveBuilder<TMaterial, TvP, TvM, TvS> primitive))
             {
-                vertex.Item1.Validate();
-                vertex.Item2.Validate();
-                vertex.Item3.Validate();
-            }
-
-            return _Vertices.Use(vertex);
-        }
-
-        public void AddTriangle((TvP, TvM, JvS) a, (TvP, TvM, JvS) b, (TvP, TvM, JvS) c)
-        {
-            var aa = UseVertex(a);
-            var bb = UseVertex(b);
-            var cc = UseVertex(c);
-
-            // check for degenerated triangles:
-            if (aa == bb || aa == cc || bb == cc)
-            {
-                if (_Scrict) throw new ArgumentException($"Invalid triangle {aa} {bb} {cc}");
-                return;
+                primitive = new PrimitiveBuilder<TMaterial, TvP, TvM, TvS>(this, material, StrictMode);
+                _Primitives[material] = primitive;
             }
 
-            _Indices.Add(aa);
-            _Indices.Add(bb);
-            _Indices.Add(cc);
-        }
-
-        public void AddTriangle((TvP, TvM) a, (TvP, TvM) b, (TvP, TvM) c)
-        {
-            AddTriangle((a.Item1, a.Item2, default), (b.Item1, b.Item2, default), (c.Item1, c.Item2, default));
-        }
-
-        public void AddTriangle((TvP, JvS) a, (TvP, JvS) b, (TvP, JvS) c)
-        {
-            AddTriangle((a.Item1, default, a.Item2), (b.Item1, default, b.Item2), (c.Item1, default, c.Item2));
-        }
-
-        public void AddTriangle(TvP a, TvP b, TvP c)
-        {
-            AddTriangle((a, default, default), (b, default, default), (c, default, default));
+            return primitive;
         }
 
-        public void AddPolygon(params (TvP, TvM, JvS)[] points)
-        {
-            for (int i = 2; i < points.Length; ++i)
-            {
-                AddTriangle(points[0], points[i - 1], points[i]);
-            }
-        }
+        public PrimitiveBuilder<TMaterial, TvP, TvM, TvS> UsePrimitive(TMaterial material) { return _UsePrimitive(material); }
 
-        public void AddPolygon(params (TvP, TvM)[] points)
-        {
-            for (int i = 2; i < points.Length; ++i)
-            {
-                AddTriangle(points[0], points[i - 1], points[i]);
-            }
-        }
+        IPrimitiveBuilder IMeshBuilder<TMaterial>.UsePrimitive(TMaterial material) { return _UsePrimitive(material); }
 
-        public void AddPolygon(params (TvP, JvS)[] points)
+        IPrimitive<TMaterial> IMeshBuilder<TMaterial>.GetPrimitive(TMaterial material)
         {
-            for (int i = 2; i < points.Length; ++i)
+            if (_Primitives.TryGetValue(material, out PrimitiveBuilder<TMaterial, TvP, TvM, TvS> primitive))
             {
-                AddTriangle(points[0], points[i - 1], points[i]);
+                return primitive;
             }
-        }
 
-        public void AddPolygon(params TvP[] points)
-        {
-            for (int i = 2; i < points.Length; ++i)
-            {
-                AddTriangle(points[0], points[i - 1], points[i]);
-            }
+            return null;
         }
 
-        public void AddPrimitive(PrimitiveBuilder<TMaterial, TvP, TvM, JvS> primitive, Matrix4x4 transform)
+        public void AddMesh(MeshBuilder<TMaterial, TvP, TvM, TvS> mesh, Matrix4x4 transform)
         {
-            if (primitive == null) throw new ArgumentNullException(nameof(primitive));
-
-            foreach (var t in primitive.Triangles)
+            foreach (var p in mesh.Primitives)
             {
-                var a = primitive.Vertices[t.Item1];
-                var b = primitive.Vertices[t.Item2];
-                var c = primitive.Vertices[t.Item3];
-
-                var aa = a.Item1; aa.Transform(transform); a.Item1 = aa;
-                var bb = b.Item1; bb.Transform(transform); b.Item1 = bb;
-                var cc = c.Item1; cc.Transform(transform); c.Item1 = cc;
-
-                AddTriangle(a, b, c);
+                UsePrimitive(p.Material).AddPrimitive(p, transform);
             }
         }
 
         public void Validate()
         {
-            foreach (var v in _Vertices)
+            foreach (var p in _Primitives.Values)
             {
-                v.Item1.Validate();
-                v.Item2.Validate();
-                v.Item3.Validate();
+                p.Validate();
             }
         }
 
@@ -202,7 +135,6 @@ namespace SharpGLTF.Geometry
     /// <summary>
     /// Represents an utility class to help build meshes by adding primitives associated with a given material.
     /// </summary>
-    /// <typeparam name="TMaterial">The material type used by this <see cref="PrimitiveBuilder{TMaterial, TvP, TvM, JvS}"/> instance.</typeparam>
     /// <typeparam name="TvP">
     /// The vertex fragment type with Position, Normal and Tangent.
     /// Valid types are:
@@ -218,7 +150,7 @@ namespace SharpGLTF.Geometry
     /// <see cref="VertexTexture1"/>,
     /// <see cref="VertexColor1Texture1"/>.
     /// </typeparam>
-    /// <typeparam name="JvS">
+    /// <typeparam name="TvS">
     /// The vertex fragment type with Skin Joint Weights.
     /// Valid types are:
     /// <see cref="VertexEmpty"/>,
@@ -227,79 +159,55 @@ namespace SharpGLTF.Geometry
     /// <see cref="VertexJoints16x4"/>,
     /// <see cref="VertexJoints16x8"/>.
     /// </typeparam>
-    public class MeshBuilder<TMaterial, TvP, TvM, JvS>
+    public class MeshBuilder<TvP, TvM, TvS> : MeshBuilder<Materials.MaterialBuilder, TvP, TvM, TvS>
         where TvP : struct, IVertexPosition
         where TvM : struct, IVertexMaterial
-        where JvS : struct, IVertexSkinning
+        where TvS : struct, IVertexSkinning
     {
-        #region lifecycle
-
         public MeshBuilder(string name = null)
-        {
-            this.Name = name;
-        }
-
-        #endregion
-
-        #region data
-
-        private readonly Dictionary<TMaterial, PrimitiveBuilder<TMaterial, TvP, TvM, JvS>> _Primitives = new Dictionary<TMaterial, PrimitiveBuilder<TMaterial, TvP, TvM, JvS>>();
-
-        #endregion
-
-        #region properties
-
-        public Boolean StrictMode { get; set; }
-
-        public string Name { get; set; }
-
-        public IReadOnlyCollection<PrimitiveBuilder<TMaterial, TvP, TvM, JvS>> Primitives => _Primitives.Values;
-
-        #endregion
-
-        #region API
-
-        public PrimitiveBuilder<TMaterial, TvP, TvM, JvS> UsePrimitive(TMaterial material)
-        {
-            if (!_Primitives.TryGetValue(material, out PrimitiveBuilder<TMaterial, TvP, TvM, JvS> primitive))
-            {
-                primitive = new PrimitiveBuilder<TMaterial, TvP, TvM, JvS>(this, material, StrictMode);
-                _Primitives[material] = primitive;
-            }
-
-            return primitive;
-        }
-
-        public IEnumerable<(int, int, int)> GetTriangles(TMaterial material)
-        {
-            if (_Primitives.TryGetValue(material, out PrimitiveBuilder<TMaterial, TvP, TvM, JvS> primitive)) return primitive.Triangles;
-
-            return Enumerable.Empty<(int, int, int)>();
-        }
-
-        public IReadOnlyList<int> GetIndices(TMaterial material)
-        {
-            if (_Primitives.TryGetValue(material, out PrimitiveBuilder<TMaterial, TvP, TvM, JvS> primitive)) return primitive.Indices;
-
-            return new int[0];
-        }
-
-        public void AddMesh(MeshBuilder<TMaterial, TvP, TvM, JvS> mesh, Matrix4x4 transform)
-        {
-            foreach (var p in mesh.Primitives)
-            {
-                UsePrimitive(p.Material).AddPrimitive(p, transform);
-            }
-        }
+            : base(name) { }
+    }
 
-        public void Validate()
-        {
-            foreach (var p in _Primitives.Values)
-            {
-                p.Validate();
-            }
-        }
+    /// <summary>
+    /// Represents an utility class to help build meshes by adding primitives associated with a given material.
+    /// </summary>
+    /// <typeparam name="TvP">
+    /// The vertex fragment type with Position, Normal and Tangent.
+    /// Valid types are:
+    /// <see cref="VertexPosition"/>,
+    /// <see cref="VertexPositionNormal"/>,
+    /// <see cref="VertexPositionNormalTangent"/>.
+    /// </typeparam>
+    /// <typeparam name="TvM">
+    /// The vertex fragment type with Colors and Texture Coordinates.
+    /// Valid types are:
+    /// <see cref="VertexEmpty"/>,
+    /// <see cref="VertexColor1"/>,
+    /// <see cref="VertexTexture1"/>,
+    /// <see cref="VertexColor1Texture1"/>.
+    /// </typeparam>
+    public class MeshBuilder<TvP, TvM> : MeshBuilder<Materials.MaterialBuilder, TvP, TvM, VertexEmpty>
+        where TvP : struct, IVertexPosition
+        where TvM : struct, IVertexMaterial
+    {
+        public MeshBuilder(string name = null)
+            : base(name) { }
+    }
 
-        #endregion
+    /// <summary>
+    /// Represents an utility class to help build meshes by adding primitives associated with a given material.
+    /// </summary>
+    /// <typeparam name="TvP">
+    /// The vertex fragment type with Position, Normal and Tangent.
+    /// Valid types are:
+    /// <see cref="VertexPosition"/>,
+    /// <see cref="VertexPositionNormal"/>,
+    /// <see cref="VertexPositionNormalTangent"/>.
+    /// </typeparam>
+    public class MeshBuilder<TvP> : MeshBuilder<Materials.MaterialBuilder, TvP, VertexEmpty, VertexEmpty>
+        where TvP : struct, IVertexPosition
+    {
+        public MeshBuilder(string name = null)
+            : base(name) { }
     }
 }

+ 6 - 6
src/SharpGLTF.Toolkit/Geometry/PackedMeshBuilder.cs

@@ -8,7 +8,7 @@ namespace SharpGLTF.Geometry
     using Schema2;
 
     /// <summary>
-    /// Used internally to convert a <see cref="MeshBuilder{TMaterial, TvP, TvM, JvS}"/>
+    /// Used internally to convert a <see cref="MeshBuilder{TMaterial, TvP, TvM, TvS}"/>
     /// to <see cref="Schema2.Mesh"/>.
     /// </summary>
     /// <typeparam name="TMaterial">A material key to split primitives by material.</typeparam>
@@ -17,19 +17,19 @@ namespace SharpGLTF.Geometry
         #region lifecycle
 
         /// <summary>
-        /// Converts a collection of <see cref="MeshBuilder{TMaterial, TvP, TvM, JvS}"/>
+        /// Converts a collection of <see cref="MeshBuilder{TMaterial, TvP, TvM, TvS}"/>
         /// to a collection of <see cref="PackedMeshBuilder{TMaterial}"/>, trying to use
         /// a single vertex buffer and a single index buffer shared by all meshes.
         /// </summary>
         /// <typeparam name="TvP">The vertex fragment type with Position, Normal and Tangent.</typeparam>
         /// <typeparam name="TvM">The vertex fragment type with Colors and Texture Coordinates.</typeparam>
-        /// <typeparam name="JvS">The vertex fragment type with Skin Joint Weights.</typeparam>
-        /// <param name="meshBuilders">A collection of <see cref="MeshBuilder{TMaterial, TvP, TvM, JvS}"/> instances.</param>
+        /// <typeparam name="TvS">The vertex fragment type with Skin Joint Weights.</typeparam>
+        /// <param name="meshBuilders">A collection of <see cref="MeshBuilder{TMaterial, TvP, TvM, TvS}"/> instances.</param>
         /// <returns>A collection of <see cref="PackedMeshBuilder{TMaterial}"/> instances.</returns>
-        internal static IEnumerable<PackedMeshBuilder<TMaterial>> PackMeshes<TvP, TvM, JvS>(IEnumerable<MeshBuilder<TMaterial, TvP, TvM, JvS>> meshBuilders)
+        internal static IEnumerable<PackedMeshBuilder<TMaterial>> PackMeshes<TvP, TvM, TvS>(IEnumerable<MeshBuilder<TMaterial, TvP, TvM, TvS>> meshBuilders)
             where TvP : struct, VertexTypes.IVertexPosition
             where TvM : struct, VertexTypes.IVertexMaterial
-            where JvS : struct, VertexTypes.IVertexSkinning
+            where TvS : struct, VertexTypes.IVertexSkinning
         {
             try
             {

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

@@ -0,0 +1,302 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Linq;
+using System.Numerics;
+
+namespace SharpGLTF.Geometry
+{
+    using Collections;
+    using VertexTypes;
+
+    public interface IPrimitive<TMaterial>
+    {
+        TMaterial Material { get; }
+
+        int VertexCount { get; }
+
+        TvPP GetVertexPosition<TvPP>(int index)
+            where TvPP : struct, IVertexPosition;
+
+        TvMM GetVertexMaterial<TvMM>(int index)
+            where TvMM : struct, IVertexMaterial;
+
+        TvSS GetVertexSkinning<TvSS>(int index)
+            where TvSS : struct, IVertexSkinning;
+
+        IReadOnlyList<int> Indices { get; }
+
+        IEnumerable<(int, int, int)> Triangles { get; }
+    }
+
+    public interface IPrimitiveBuilder
+    {
+        void AddTriangle<TvPP, TvMM, TvSS>
+            (
+            (TvPP, TvMM, TvSS) a,
+            (TvPP, TvMM, TvSS) b,
+            (TvPP, TvMM, TvSS) c
+            )
+            where TvPP : struct, IVertexPosition
+            where TvMM : struct, IVertexMaterial
+            where TvSS : struct, IVertexSkinning;
+    }
+
+    /// <summary>
+    /// Represents an utility class to help build mesh primitives by adding triangles
+    /// </summary>
+    /// <typeparam name="TMaterial">The material type used by this <see cref="PrimitiveBuilder{TMaterial, TvP, TvM, TvS}"/> instance.</typeparam>
+    /// <typeparam name="TvP">
+    /// The vertex fragment type with Position, Normal and Tangent.
+    /// Valid types are:
+    /// <see cref="VertexPosition"/>,
+    /// <see cref="VertexPositionNormal"/>,
+    /// <see cref="VertexPositionNormalTangent"/>.
+    /// </typeparam>
+    /// <typeparam name="TvM">
+    /// The vertex fragment type with Colors and Texture Coordinates.
+    /// Valid types are:
+    /// <see cref="VertexEmpty"/>,
+    /// <see cref="VertexColor1"/>,
+    /// <see cref="VertexTexture1"/>,
+    /// <see cref="VertexColor1Texture1"/>.
+    /// </typeparam>
+    /// <typeparam name="TvS">
+    /// The vertex fragment type with Skin Joint Weights.
+    /// Valid types are:
+    /// <see cref="VertexEmpty"/>,
+    /// <see cref="VertexJoints8x4"/>,
+    /// <see cref="VertexJoints8x8"/>,
+    /// <see cref="VertexJoints16x4"/>,
+    /// <see cref="VertexJoints16x8"/>.
+    /// </typeparam>
+    public class PrimitiveBuilder<TMaterial, TvP, TvM, TvS> : IPrimitiveBuilder, IPrimitive<TMaterial>
+        where TvP : struct, IVertexPosition
+        where TvM : struct, IVertexMaterial
+        where TvS : struct, IVertexSkinning
+    {
+        #region lifecycle
+
+        internal PrimitiveBuilder(MeshBuilder<TMaterial, TvP, TvM, TvS> mesh, TMaterial material, bool strict)
+        {
+            this._Scrict = strict;
+            this._Mesh = mesh;
+            this._Material = material;
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly bool _Scrict;
+
+        private readonly MeshBuilder<TMaterial, TvP, TvM, TvS> _Mesh;
+
+        private readonly TMaterial _Material;
+
+        private readonly VertexList<(TvP, TvM, TvS)> _Vertices = new VertexList<(TvP, TvM, TvS)>();
+        private readonly List<int> _Indices = new List<int>();
+
+        #endregion
+
+        #region properties
+
+        public MeshBuilder<TMaterial, TvP, TvM, TvS> Mesh => _Mesh;
+
+        public TMaterial Material => _Material;
+
+        public int VertexCount => _Vertices.Count;
+
+        public IReadOnlyList<(TvP, TvM, TvS)> Vertices => _Vertices;
+
+        public IReadOnlyList<int> Indices => _Indices;
+
+        public IEnumerable<(int, int, int)> Triangles
+        {
+            get
+            {
+                // TODO: use Schema2.PrimitiveType.TRIANGLES.GetTrianglesIndices()
+
+                for (int i = 2; i < _Indices.Count; i += 3)
+                {
+                    yield return (_Indices[i - 2], _Indices[i - 1], _Indices[i]);
+                }
+            }
+        }
+
+        #endregion
+
+        #region API
+
+        public int UseVertex((TvP, TvM, TvS) vertex)
+        {
+            if (_Scrict)
+            {
+                vertex.Item1.Validate();
+                vertex.Item2.Validate();
+                vertex.Item3.Validate();
+            }
+
+            return _Vertices.Use(vertex);
+        }
+
+        public void AddTriangle((TvP, TvM, TvS) a, (TvP, TvM, TvS) b, (TvP, TvM, TvS) c)
+        {
+            var aa = UseVertex(a);
+            var bb = UseVertex(b);
+            var cc = UseVertex(c);
+
+            // check for degenerated triangles:
+            if (aa == bb || aa == cc || bb == cc)
+            {
+                if (_Scrict) throw new ArgumentException($"Invalid triangle {aa} {bb} {cc}");
+                return;
+            }
+
+            _Indices.Add(aa);
+            _Indices.Add(bb);
+            _Indices.Add(cc);
+        }
+
+        public void AddTriangle((TvP, TvM) a, (TvP, TvM) b, (TvP, TvM) c)
+        {
+            AddTriangle((a.Item1, a.Item2, default), (b.Item1, b.Item2, default), (c.Item1, c.Item2, default));
+        }
+
+        public void AddTriangle((TvP, TvS) a, (TvP, TvS) b, (TvP, TvS) c)
+        {
+            AddTriangle((a.Item1, default, a.Item2), (b.Item1, default, b.Item2), (c.Item1, default, c.Item2));
+        }
+
+        public void AddTriangle(TvP a, TvP b, TvP c)
+        {
+            AddTriangle((a, default, default), (b, default, default), (c, default, default));
+        }
+
+        public void AddPolygon(params (TvP, TvM, TvS)[] points)
+        {
+            for (int i = 2; i < points.Length; ++i)
+            {
+                AddTriangle(points[0], points[i - 1], points[i]);
+            }
+        }
+
+        public void AddPolygon(params (TvP, TvM)[] points)
+        {
+            for (int i = 2; i < points.Length; ++i)
+            {
+                AddTriangle(points[0], points[i - 1], points[i]);
+            }
+        }
+
+        public void AddPolygon(params (TvP, TvS)[] points)
+        {
+            for (int i = 2; i < points.Length; ++i)
+            {
+                AddTriangle(points[0], points[i - 1], points[i]);
+            }
+        }
+
+        public void AddPolygon(params TvP[] points)
+        {
+            for (int i = 2; i < points.Length; ++i)
+            {
+                AddTriangle(points[0], points[i - 1], points[i]);
+            }
+        }
+
+        public void AddPrimitive(PrimitiveBuilder<TMaterial, TvP, TvM, TvS> primitive, Matrix4x4 transform)
+        {
+            if (primitive == null) throw new ArgumentNullException(nameof(primitive));
+
+            foreach (var t in primitive.Triangles)
+            {
+                var a = primitive.Vertices[t.Item1];
+                var b = primitive.Vertices[t.Item2];
+                var c = primitive.Vertices[t.Item3];
+
+                var aa = a.Item1; aa.Transform(transform); a.Item1 = aa;
+                var bb = b.Item1; bb.Transform(transform); b.Item1 = bb;
+                var cc = c.Item1; cc.Transform(transform); c.Item1 = cc;
+
+                AddTriangle(a, b, c);
+            }
+        }
+
+        public void Validate()
+        {
+            foreach (var v in _Vertices)
+            {
+                v.Item1.Validate();
+                v.Item2.Validate();
+                v.Item3.Validate();
+            }
+        }
+
+        public void AddTriangle<TvPP, TvMM, TvSS>((TvPP, TvMM, TvSS) a, (TvPP, TvMM, TvSS) b, (TvPP, TvMM, TvSS) c)
+            where TvPP : struct, IVertexPosition
+            where TvMM : struct, IVertexMaterial
+            where TvSS : struct, IVertexSkinning
+        {
+            var p1 = default(TvP);
+            var p2 = default(TvP);
+            var p3 = default(TvP);
+
+            var m1 = default(TvM);
+            var m2 = default(TvM);
+            var m3 = default(TvM);
+
+            var s1 = default(TvS);
+            var s2 = default(TvS);
+            var s3 = default(TvS);
+
+            p1.AssignFrom(a.Item1);
+            p2.AssignFrom(b.Item1);
+            p3.AssignFrom(c.Item1);
+
+            /*
+            m1.AssignFrom(a.Item2);
+            m2.AssignFrom(b.Item2);
+            m3.AssignFrom(c.Item2);
+
+            s1.AssignFrom(a.Item3);
+            s2.AssignFrom(b.Item3);
+            s3.AssignFrom(c.Item3);
+            */
+
+            AddTriangle((p1, m1, s1), (p2, m2, s2), (p3, m3, s3));
+        }
+
+        public TvPP GetVertexPosition<TvPP>(int index)
+            where TvPP : struct, IVertexPosition
+        {
+            var p = default(TvPP);
+
+            p.AssignFrom(_Vertices[index].Item1);
+
+            return p;
+        }
+
+        public TvMM GetVertexMaterial<TvMM>(int index)
+            where TvMM : struct, IVertexMaterial
+        {
+            var m = default(TvMM);
+
+            // m.AssignFrom(_Vertices[index].Item2);
+
+            return m;
+        }
+
+        public TvSS GetVertexSkinning<TvSS>(int index)
+            where TvSS : struct, IVertexSkinning
+        {
+            var s = default(TvSS);
+
+            // s.AssignFrom(_Vertices[index].Item3);
+
+            return s;
+        }
+
+        #endregion
+    }
+}

+ 0 - 89
src/SharpGLTF.Toolkit/Geometry/StaticMeshBuilder.cs

@@ -1,89 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Numerics;
-using System.Text;
-
-namespace SharpGLTF.Geometry
-{
-    using VertexTypes;
-
-    /// <summary>
-    /// Represents an utility class to help build meshes by adding primitives associated with a given material.
-    /// </summary>
-    /// <typeparam name="TvP">
-    /// The vertex fragment type with Position, Normal and Tangent.
-    /// Valid types are:
-    /// <see cref="VertexPosition"/>,
-    /// <see cref="VertexPositionNormal"/>,
-    /// <see cref="VertexPositionNormalTangent"/>.
-    /// </typeparam>
-    /// <typeparam name="TvM">
-    /// The vertex fragment type with Colors and Texture Coordinates.
-    /// Valid types are:
-    /// <see cref="VertexEmpty"/>,
-    /// <see cref="VertexColor1"/>,
-    /// <see cref="VertexTexture1"/>,
-    /// <see cref="VertexColor1Texture1"/>.
-    /// </typeparam>
-    /// <typeparam name="JvS">
-    /// The vertex fragment type with Skin Joint Weights.
-    /// Valid types are:
-    /// <see cref="VertexEmpty"/>,
-    /// <see cref="VertexJoints8x4"/>,
-    /// <see cref="VertexJoints8x8"/>,
-    /// <see cref="VertexJoints16x4"/>,
-    /// <see cref="VertexJoints16x8"/>.
-    /// </typeparam>
-    public class MeshBuilder<TvP, TvM, JvS> : MeshBuilder<Materials.MaterialBuilder, TvP, TvM, JvS>
-        where TvP : struct, IVertexPosition
-        where TvM : struct, IVertexMaterial
-        where JvS : struct, IVertexSkinning
-    {
-        public MeshBuilder(string name = null)
-            : base(name) { }
-    }
-
-    /// <summary>
-    /// Represents an utility class to help build meshes by adding primitives associated with a given material.
-    /// </summary>
-    /// <typeparam name="TvP">
-    /// The vertex fragment type with Position, Normal and Tangent.
-    /// Valid types are:
-    /// <see cref="VertexPosition"/>,
-    /// <see cref="VertexPositionNormal"/>,
-    /// <see cref="VertexPositionNormalTangent"/>.
-    /// </typeparam>
-    /// <typeparam name="TvM">
-    /// The vertex fragment type with Colors and Texture Coordinates.
-    /// Valid types are:
-    /// <see cref="VertexEmpty"/>,
-    /// <see cref="VertexColor1"/>,
-    /// <see cref="VertexTexture1"/>,
-    /// <see cref="VertexColor1Texture1"/>.
-    /// </typeparam>
-    public class MeshBuilder<TvP, TvM> : MeshBuilder<Materials.MaterialBuilder, TvP, TvM, VertexEmpty>
-        where TvP : struct, IVertexPosition
-        where TvM : struct, IVertexMaterial
-    {
-        public MeshBuilder(string name = null)
-            : base(name) { }
-    }
-
-    /// <summary>
-    /// Represents an utility class to help build meshes by adding primitives associated with a given material.
-    /// </summary>
-    /// <typeparam name="TvP">
-    /// The vertex fragment type with Position, Normal and Tangent.
-    /// Valid types are:
-    /// <see cref="VertexPosition"/>,
-    /// <see cref="VertexPositionNormal"/>,
-    /// <see cref="VertexPositionNormalTangent"/>.
-    /// </typeparam>
-    public class MeshBuilder<TvP> : MeshBuilder<Materials.MaterialBuilder, TvP, VertexEmpty, VertexEmpty>
-        where TvP : struct, IVertexPosition
-    {
-        public MeshBuilder(string name = null)
-            : base(name) { }
-    }
-}

+ 3 - 3
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexColumns.cs

@@ -67,10 +67,10 @@ namespace SharpGLTF.Geometry.VertexTypes
             return cctt;
         }
 
-        public JvS GetJointsFragment<JvS>(int index)
-            where JvS : struct, IVertexSkinning
+        public TvS GetSkinningFragment<TvS>(int index)
+            where TvS : struct, IVertexSkinning
         {
-            var jjjj = default(JvS);
+            var jjjj = default(TvS);
 
             if (Joints0 != null && Weights0 != null) jjjj.SetJoints(0, Joints0[index], Weights0[index]);
             if (Joints1 != null && Weights1 != null) jjjj.SetJoints(1, Joints1[index], Weights1[index]);

+ 12 - 12
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexEmpty.cs

@@ -7,20 +7,20 @@ namespace SharpGLTF.Geometry.VertexTypes
 {
     public struct VertexEmpty : IVertexMaterial, IVertexSkinning
     {
-        void IVertexMaterial.SetColor(int setIndex, Vector4 color)
-        {
-        }
+        public int MaxJoints => 0;
 
-        void IVertexMaterial.SetTexCoord(int setIndex, Vector2 coord)
-        {
-        }
+        void IVertexMaterial.SetColor(int setIndex, Vector4 color) { }
 
-        void IVertexSkinning.SetJoints(int jointSet, Vector4 joints, Vector4 weights)
-        {
-        }
+        void IVertexMaterial.SetTexCoord(int setIndex, Vector2 coord) { }
 
-        public void Validate()
-        {
-        }
+        void IVertexSkinning.SetJoints(int jointSet, Vector4 joints, Vector4 weights) { }
+
+        public void Validate() { }
+
+        public KeyValuePair<int, float> GetJoint(int index) { return default; }
+
+        public void SetJoint(int index, KeyValuePair<int, float> jw) { }
+
+        public void AssignFrom(IVertexSkinning vertex) { }
     }
 }

+ 39 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexPosition.cs

@@ -11,6 +11,12 @@ namespace SharpGLTF.Geometry.VertexTypes
         void SetNormal(Vector3 normal);
         void SetTangent(Vector4 tangent);
 
+        Vector3 GetPosition();
+        Boolean TryGetNormal(out Vector3 normal);
+        Boolean TryGetTangent(out Vector4 tangent);
+
+        void AssignFrom(IVertexPosition vertex);
+
         void Transform(Matrix4x4 xform);
 
         void Validate();
@@ -45,6 +51,14 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         void IVertexPosition.SetTangent(Vector4 tangent) { }
 
+        public Vector3 GetPosition() { return this.Position; }
+
+        public bool TryGetNormal(out Vector3 normal) { normal = default; return false; }
+
+        public bool TryGetTangent(out Vector4 tangent) { tangent = default; return false; }
+
+        public void AssignFrom(IVertexPosition vertex) { this.Position = vertex.GetPosition(); }
+
         public void Transform(Matrix4x4 xform)
         {
             Position = Vector3.Transform(Position, xform);
@@ -85,6 +99,18 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         void IVertexPosition.SetTangent(Vector4 tangent) { }
 
+        public Vector3 GetPosition() { return this.Position; }
+
+        public bool TryGetNormal(out Vector3 normal) { normal = this.Normal; return true; }
+
+        public bool TryGetTangent(out Vector4 tangent) { tangent = default; return false; }
+
+        public void AssignFrom(IVertexPosition vertex)
+        {
+            this.Position = vertex.GetPosition();
+            if (vertex.TryGetNormal(out Vector3 nrm)) this.Normal = nrm;
+        }
+
         public void Transform(Matrix4x4 xform)
         {
             Position = Vector3.Transform(Position, xform);
@@ -125,6 +151,19 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         void IVertexPosition.SetTangent(Vector4 tangent) { this.Tangent = tangent; }
 
+        public Vector3 GetPosition() { return this.Position; }
+
+        public bool TryGetNormal(out Vector3 normal) { normal = this.Normal; return true; }
+
+        public bool TryGetTangent(out Vector4 tangent) { tangent = this.Tangent; return true; }
+
+        public void AssignFrom(IVertexPosition vertex)
+        {
+            this.Position = vertex.GetPosition();
+            if (vertex.TryGetNormal(out Vector3 nrm)) this.Normal = nrm;
+            if (vertex.TryGetTangent(out Vector4 tgt)) this.Tangent = tgt;
+        }
+
         public void Transform(Matrix4x4 xform)
         {
             Position = Vector3.Transform(Position, xform);

+ 159 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexSkinning.cs

@@ -5,10 +5,23 @@ using System.Text;
 
 namespace SharpGLTF.Geometry.VertexTypes
 {
+    using JOINTWEIGHT = KeyValuePair<int, float>;
+
     public interface IVertexSkinning
     {
         void SetJoints(int jointSet, Vector4 joints, Vector4 weights);
 
+        int MaxJoints { get; }
+
+        JOINTWEIGHT GetJoint(int index);
+
+        void SetJoint(int index, JOINTWEIGHT jw);
+
+        void AssignFrom(IVertexSkinning vertex);
+
+        // TODO: validation must ensure that:
+        // - there's some positive weight
+        // - every joint is unique
         void Validate();
     }
 
@@ -41,6 +54,8 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("WEIGHTS_0", Schema2.EncodingType.UNSIGNED_BYTE, true)]
         public Vector4 Weights;
 
+        public int MaxJoints => 4;
+
         #endregion
 
         #region API
@@ -50,6 +65,17 @@ namespace SharpGLTF.Geometry.VertexTypes
             if (jointSet == 0) { this.Joints = joints; this.Weights = weights; }
         }
 
+        public void AssignFrom(IVertexSkinning vertex)
+        {
+            var c = Math.Min(this.MaxJoints, vertex.MaxJoints);
+
+            for (int i = 0; i < c; ++i)
+            {
+                var jw = vertex.GetJoint(i);
+                this.SetJoint(i, jw);
+            }
+        }
+
         public void Validate()
         {
             if (!Joints._IsReal()) throw new NotFiniteNumberException(nameof(Joints));
@@ -58,6 +84,30 @@ namespace SharpGLTF.Geometry.VertexTypes
             if (!Weights._IsReal()) throw new NotFiniteNumberException(nameof(Weights));
         }
 
+        public JOINTWEIGHT GetJoint(int index)
+        {
+            switch (index)
+            {
+                case 0: return new JOINTWEIGHT((int)this.Joints.X, this.Weights.X);
+                case 1: return new JOINTWEIGHT((int)this.Joints.Y, this.Weights.Y);
+                case 2: return new JOINTWEIGHT((int)this.Joints.Z, this.Weights.Z);
+                case 3: return new JOINTWEIGHT((int)this.Joints.W, this.Weights.W);
+                default: throw new ArgumentOutOfRangeException(nameof(index));
+            }
+        }
+
+        public void SetJoint(int index, JOINTWEIGHT jw)
+        {
+            switch (index)
+            {
+                case 0: { this.Joints.X = jw.Key; this.Weights.X = jw.Value; return; }
+                case 1: { this.Joints.Y = jw.Key; this.Weights.Y = jw.Value; return; }
+                case 2: { this.Joints.Z = jw.Key; this.Weights.Z = jw.Value; return; }
+                case 3: { this.Joints.W = jw.Key; this.Weights.W = jw.Value; return; }
+                default: throw new ArgumentOutOfRangeException(nameof(index));
+            }
+        }
+
         #endregion
     }
 
@@ -90,6 +140,8 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("WEIGHTS_0", Schema2.EncodingType.UNSIGNED_BYTE, true)]
         public Vector4 Weights;
 
+        public int MaxJoints => 4;
+
         #endregion
 
         #region API
@@ -107,6 +159,35 @@ namespace SharpGLTF.Geometry.VertexTypes
             if (!Weights._IsReal()) throw new NotFiniteNumberException(nameof(Weights));
         }
 
+        public JOINTWEIGHT GetJoint(int index)
+        {
+            switch (index)
+            {
+                case 0: return new JOINTWEIGHT((int)this.Joints.X, this.Weights.X);
+                case 1: return new JOINTWEIGHT((int)this.Joints.Y, this.Weights.Y);
+                case 2: return new JOINTWEIGHT((int)this.Joints.Z, this.Weights.Z);
+                case 3: return new JOINTWEIGHT((int)this.Joints.W, this.Weights.W);
+                default: throw new ArgumentOutOfRangeException(nameof(index));
+            }
+        }
+
+        public void SetJoint(int index, JOINTWEIGHT jw)
+        {
+            switch (index)
+            {
+                case 0: { this.Joints.X = jw.Key; this.Weights.X = jw.Value; return; }
+                case 1: { this.Joints.Y = jw.Key; this.Weights.Y = jw.Value; return; }
+                case 2: { this.Joints.Z = jw.Key; this.Weights.Z = jw.Value; return; }
+                case 3: { this.Joints.W = jw.Key; this.Weights.W = jw.Value; return; }
+                default: throw new ArgumentOutOfRangeException(nameof(index));
+            }
+        }
+
+        public void AssignFrom(IVertexSkinning vertex)
+        {
+            throw new NotImplementedException();
+        }
+
         #endregion
     }
 
@@ -149,6 +230,8 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("WEIGHTS_1", Schema2.EncodingType.UNSIGNED_BYTE, true)]
         public Vector4 Weights1;
 
+        public int MaxJoints => 8;
+
         #endregion
 
         #region API
@@ -171,6 +254,43 @@ namespace SharpGLTF.Geometry.VertexTypes
             if (!Weights1._IsReal()) throw new NotFiniteNumberException(nameof(Weights1));
         }
 
+        public JOINTWEIGHT GetJoint(int index)
+        {
+            switch (index)
+            {
+                case 0: return new JOINTWEIGHT((int)this.Joints0.X, this.Weights0.X);
+                case 1: return new JOINTWEIGHT((int)this.Joints0.Y, this.Weights0.Y);
+                case 2: return new JOINTWEIGHT((int)this.Joints0.Z, this.Weights0.Z);
+                case 3: return new JOINTWEIGHT((int)this.Joints0.W, this.Weights0.W);
+                case 4: return new JOINTWEIGHT((int)this.Joints1.X, this.Weights1.X);
+                case 5: return new JOINTWEIGHT((int)this.Joints1.Y, this.Weights1.Y);
+                case 6: return new JOINTWEIGHT((int)this.Joints1.Z, this.Weights1.Z);
+                case 7: return new JOINTWEIGHT((int)this.Joints1.W, this.Weights1.W);
+                default: throw new ArgumentOutOfRangeException(nameof(index));
+            }
+        }
+
+        public void SetJoint(int index, JOINTWEIGHT jw)
+        {
+            switch (index)
+            {
+                case 0: { this.Joints0.X = jw.Key; this.Weights0.X = jw.Value; return; }
+                case 1: { this.Joints0.Y = jw.Key; this.Weights0.Y = jw.Value; return; }
+                case 2: { this.Joints0.Z = jw.Key; this.Weights0.Z = jw.Value; return; }
+                case 3: { this.Joints0.W = jw.Key; this.Weights0.W = jw.Value; return; }
+                case 4: { this.Joints1.X = jw.Key; this.Weights1.X = jw.Value; return; }
+                case 5: { this.Joints1.Y = jw.Key; this.Weights1.Y = jw.Value; return; }
+                case 6: { this.Joints1.Z = jw.Key; this.Weights1.Z = jw.Value; return; }
+                case 7: { this.Joints1.W = jw.Key; this.Weights1.W = jw.Value; return; }
+                default: throw new ArgumentOutOfRangeException(nameof(index));
+            }
+        }
+
+        public void AssignFrom(IVertexSkinning vertex)
+        {
+            throw new NotImplementedException();
+        }
+
         #endregion
     }
 
@@ -213,6 +333,8 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("WEIGHTS_1", Schema2.EncodingType.UNSIGNED_BYTE, true)]
         public Vector4 Weights1;
 
+        public int MaxJoints => 8;
+
         #endregion
 
         #region API
@@ -235,6 +357,43 @@ namespace SharpGLTF.Geometry.VertexTypes
             if (!Weights1._IsReal()) throw new NotFiniteNumberException(nameof(Weights1));
         }
 
+        public JOINTWEIGHT GetJoint(int index)
+        {
+            switch (index)
+            {
+                case 0: return new JOINTWEIGHT((int)this.Joints0.X, this.Weights0.X);
+                case 1: return new JOINTWEIGHT((int)this.Joints0.Y, this.Weights0.Y);
+                case 2: return new JOINTWEIGHT((int)this.Joints0.Z, this.Weights0.Z);
+                case 3: return new JOINTWEIGHT((int)this.Joints0.W, this.Weights0.W);
+                case 4: return new JOINTWEIGHT((int)this.Joints1.X, this.Weights1.X);
+                case 5: return new JOINTWEIGHT((int)this.Joints1.Y, this.Weights1.Y);
+                case 6: return new JOINTWEIGHT((int)this.Joints1.Z, this.Weights1.Z);
+                case 7: return new JOINTWEIGHT((int)this.Joints1.W, this.Weights1.W);
+                default: throw new ArgumentOutOfRangeException(nameof(index));
+            }
+        }
+
+        public void SetJoint(int index, JOINTWEIGHT jw)
+        {
+            switch (index)
+            {
+                case 0: { this.Joints0.X = jw.Key; this.Weights0.X = jw.Value; return; }
+                case 1: { this.Joints0.Y = jw.Key; this.Weights0.Y = jw.Value; return; }
+                case 2: { this.Joints0.Z = jw.Key; this.Weights0.Z = jw.Value; return; }
+                case 3: { this.Joints0.W = jw.Key; this.Weights0.W = jw.Value; return; }
+                case 4: { this.Joints1.X = jw.Key; this.Weights1.X = jw.Value; return; }
+                case 5: { this.Joints1.Y = jw.Key; this.Weights1.Y = jw.Value; return; }
+                case 6: { this.Joints1.Z = jw.Key; this.Weights1.Z = jw.Value; return; }
+                case 7: { this.Joints1.W = jw.Key; this.Weights1.W = jw.Value; return; }
+                default: throw new ArgumentOutOfRangeException(nameof(index));
+            }
+        }
+
+        public void AssignFrom(IVertexSkinning vertex)
+        {
+            throw new NotImplementedException();
+        }
+
         #endregion
     }
 }

+ 15 - 15
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.cs

@@ -9,16 +9,16 @@ namespace SharpGLTF.Geometry.VertexTypes
 
     static class VertexUtils
     {
-        public static IEnumerable<MemoryAccessor[]> CreateVertexMemoryAccessors<TvP, TvM, JvS>(this IEnumerable<IReadOnlyList<(TvP, TvM, JvS)>> vertexBlocks)
+        public static IEnumerable<MemoryAccessor[]> CreateVertexMemoryAccessors<TvP, TvM, TvS>(this IEnumerable<IReadOnlyList<(TvP, TvM, TvS)>> vertexBlocks)
             where TvP : struct, IVertexPosition
             where TvM : struct, IVertexMaterial
-            where JvS : struct, IVertexSkinning
+            where TvS : struct, IVertexSkinning
         {
             // total number of vertices
             var totalCount = vertexBlocks.Sum(item => item.Count);
 
             // vertex attributes
-            var attributes = GetVertexAttributes(typeof(TvP), typeof(TvM), typeof(JvS), totalCount);
+            var attributes = GetVertexAttributes(typeof(TvP), typeof(TvM), typeof(TvS), totalCount);
 
             // create master vertex buffer
             int byteStride = attributes[0].ByteStride;
@@ -35,7 +35,7 @@ namespace SharpGLTF.Geometry.VertexTypes
 
                 foreach (var accessor in accessors)
                 {
-                    var columnFunc = GetItemValueFunc<TvP, TvM, JvS>(accessor.Attribute.Name);
+                    var columnFunc = GetItemValueFunc<TvP, TvM, TvS>(accessor.Attribute.Name);
 
                     if (accessor.Attribute.Dimensions == Schema2.DimensionType.SCALAR) accessor.Fill(block.GetScalarColumn(columnFunc));
                     if (accessor.Attribute.Dimensions == Schema2.DimensionType.VEC2) accessor.Fill(block.GetVector2Column(columnFunc));
@@ -139,7 +139,7 @@ namespace SharpGLTF.Geometry.VertexTypes
             return new MemoryAccessInfo(attribute.Name, 0, 0, 0, dimensions.Value, attribute.Encoding, attribute.Normalized);
         }
 
-        private static Func<(TvP, TvM, JvS), Object> GetItemValueFunc<TvP, TvM, JvS>(string attributeName)
+        private static Func<(TvP, TvM, TvS), Object> GetItemValueFunc<TvP, TvM, TvS>(string attributeName)
         {
             var finfo = GetVertexField(typeof(TvP), attributeName);
             if (finfo != null) return vertex => finfo.GetValue(vertex.Item1);
@@ -147,33 +147,33 @@ namespace SharpGLTF.Geometry.VertexTypes
             finfo = GetVertexField(typeof(TvM), attributeName);
             if (finfo != null) return vertex => finfo.GetValue(vertex.Item2);
 
-            finfo = GetVertexField(typeof(JvS), attributeName);
+            finfo = GetVertexField(typeof(TvS), attributeName);
             if (finfo != null) return vertex => finfo.GetValue(vertex.Item3);
 
             throw new NotImplementedException();
         }
 
-        private static Single[] GetScalarColumn<TvP, TvM, JvS>(this IReadOnlyList<(TvP, TvM, JvS)> vertices, Func<(TvP, TvM, JvS), Object> func)
+        private static Single[] GetScalarColumn<TvP, TvM, TvS>(this IReadOnlyList<(TvP, TvM, TvS)> vertices, Func<(TvP, TvM, TvS), Object> func)
         {
-            return GetColumn<TvP, TvM, JvS, Single>(vertices, func);
+            return GetColumn<TvP, TvM, TvS, Single>(vertices, func);
         }
 
-        private static Vector2[] GetVector2Column<TvP, TvM, JvS>(this IReadOnlyList<(TvP, TvM, JvS)> vertices, Func<(TvP, TvM, JvS), Object> func)
+        private static Vector2[] GetVector2Column<TvP, TvM, TvS>(this IReadOnlyList<(TvP, TvM, TvS)> vertices, Func<(TvP, TvM, TvS), Object> func)
         {
-            return GetColumn<TvP, TvM, JvS, Vector2>(vertices, func);
+            return GetColumn<TvP, TvM, TvS, Vector2>(vertices, func);
         }
 
-        private static Vector3[] GetVector3Column<TvP, TvM, JvS>(this IReadOnlyList<(TvP, TvM, JvS)> vertices, Func<(TvP, TvM, JvS), Object> func)
+        private static Vector3[] GetVector3Column<TvP, TvM, TvS>(this IReadOnlyList<(TvP, TvM, TvS)> vertices, Func<(TvP, TvM, TvS), Object> func)
         {
-            return GetColumn<TvP, TvM, JvS, Vector3>(vertices, func);
+            return GetColumn<TvP, TvM, TvS, Vector3>(vertices, func);
         }
 
-        private static Vector4[] GetVector4Column<TvP, TvM, JvS>(this IReadOnlyList<(TvP, TvM, JvS)> vertices, Func<(TvP, TvM, JvS), Object> func)
+        private static Vector4[] GetVector4Column<TvP, TvM, TvS>(this IReadOnlyList<(TvP, TvM, TvS)> vertices, Func<(TvP, TvM, TvS), Object> func)
         {
-            return GetColumn<TvP, TvM, JvS, Vector4>(vertices, func);
+            return GetColumn<TvP, TvM, TvS, Vector4>(vertices, func);
         }
 
-        private static TColumn[] GetColumn<TvP, TvM, JvS, TColumn>(this IReadOnlyList<(TvP, TvM, JvS)> vertices, Func<(TvP, TvM, JvS), Object> func)
+        private static TColumn[] GetColumn<TvP, TvM, TvS, TColumn>(this IReadOnlyList<(TvP, TvM, TvS)> vertices, Func<(TvP, TvM, TvS), Object> func)
         {
             var dst = new TColumn[vertices.Count];
 

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

@@ -12,50 +12,50 @@ namespace SharpGLTF.Schema2
     {
         #region meshes
 
-        public static Mesh CreateMesh<TvP, TvM, JvS>(this ModelRoot root, Geometry.MeshBuilder<Materials.MaterialBuilder, TvP, TvM, JvS> meshBuilder)
+        public static Mesh CreateMesh<TvP, TvM, TvS>(this ModelRoot root, Geometry.MeshBuilder<Materials.MaterialBuilder, TvP, TvM, TvS> meshBuilder)
             where TvP : struct, Geometry.VertexTypes.IVertexPosition
             where TvM : struct, Geometry.VertexTypes.IVertexMaterial
-            where JvS : struct, Geometry.VertexTypes.IVertexSkinning
+            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
         {
             return root.CreateMeshes(meshBuilder).First();
         }
 
-        public static Mesh CreateMesh<TvP, TvM, JvS>(this ModelRoot root, Geometry.MeshBuilder<Material, TvP, TvM, JvS> meshBuilder)
+        public static Mesh CreateMesh<TvP, TvM, TvS>(this ModelRoot root, Geometry.MeshBuilder<Material, TvP, TvM, TvS> meshBuilder)
             where TvP : struct, Geometry.VertexTypes.IVertexPosition
             where TvM : struct, Geometry.VertexTypes.IVertexMaterial
-            where JvS : struct, Geometry.VertexTypes.IVertexSkinning
+            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
         {
             return root.CreateMeshes(meshBuilder).First();
         }
 
-        public static Mesh CreateMesh<TMaterial, TvP, TvM, JvS>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, Geometry.MeshBuilder<TMaterial, TvP, TvM, JvS> meshBuilder)
+        public static Mesh CreateMesh<TMaterial, TvP, TvM, TvS>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, Geometry.MeshBuilder<TMaterial, TvP, TvM, TvS> meshBuilder)
             where TvP : struct, Geometry.VertexTypes.IVertexPosition
             where TvM : struct, Geometry.VertexTypes.IVertexMaterial
-            where JvS : struct, Geometry.VertexTypes.IVertexSkinning
+            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
         {
             return root.CreateMeshes(materialEvaluator, meshBuilder).First();
         }
 
-        public static IReadOnlyList<Mesh> CreateMeshes<TvP, TvM, JvS>(this ModelRoot root, params Geometry.MeshBuilder<Material, TvP, TvM, JvS>[] meshBuilders)
+        public static IReadOnlyList<Mesh> CreateMeshes<TvP, TvM, TvS>(this ModelRoot root, params Geometry.MeshBuilder<Material, TvP, TvM, TvS>[] meshBuilders)
             where TvP : struct, Geometry.VertexTypes.IVertexPosition
             where TvM : struct, Geometry.VertexTypes.IVertexMaterial
-            where JvS : struct, Geometry.VertexTypes.IVertexSkinning
+            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
         {
             return root.CreateMeshes(m => m, meshBuilders);
         }
 
-        public static IReadOnlyList<Mesh> CreateMeshes<TvP, TvM, JvS>(this ModelRoot root, params Geometry.MeshBuilder<Materials.MaterialBuilder, TvP, TvM, JvS>[] meshBuilders)
+        public static IReadOnlyList<Mesh> CreateMeshes<TvP, TvM, TvS>(this ModelRoot root, params Geometry.MeshBuilder<Materials.MaterialBuilder, TvP, TvM, TvS>[] meshBuilders)
             where TvP : struct, Geometry.VertexTypes.IVertexPosition
             where TvM : struct, Geometry.VertexTypes.IVertexMaterial
-            where JvS : struct, Geometry.VertexTypes.IVertexSkinning
+            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
         {
             return root.CreateMeshes(mb => root.CreateMaterial(mb), meshBuilders);
         }
 
-        public static IReadOnlyList<Mesh> CreateMeshes<TMaterial, TvP, TvM, JvS>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, params Geometry.MeshBuilder<TMaterial, TvP, TvM, JvS>[] meshBuilders)
+        public static IReadOnlyList<Mesh> CreateMeshes<TMaterial, TvP, TvM, TvS>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, params Geometry.MeshBuilder<TMaterial, TvP, TvM, TvS>[] meshBuilders)
             where TvP : struct, Geometry.VertexTypes.IVertexPosition
             where TvM : struct, Geometry.VertexTypes.IVertexMaterial
-            where JvS : struct, Geometry.VertexTypes.IVertexSkinning
+            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
         {
             // create a new material for every unique material in the mesh builders.
             var mapMaterials = meshBuilders
@@ -277,20 +277,20 @@ namespace SharpGLTF.Schema2
 
         #region evaluation
 
-        public static IEnumerable<((TvP, TvM, JvS), (TvP, TvM, JvS), (TvP, TvM, JvS), Material)> Triangulate<TvP, TvM, JvS>(this Mesh mesh, Matrix4x4 xform)
+        public static IEnumerable<((TvP, TvM, TvS), (TvP, TvM, TvS), (TvP, TvM, TvS), Material)> Triangulate<TvP, TvM, TvS>(this Mesh mesh, Matrix4x4 xform)
             where TvP : struct, Geometry.VertexTypes.IVertexPosition
             where TvM : struct, Geometry.VertexTypes.IVertexMaterial
-            where JvS : struct, Geometry.VertexTypes.IVertexSkinning
+            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
         {
             var normals = mesh.GetComputedNormals();
 
-            return mesh.Primitives.SelectMany(item => item.Triangulate<TvP, TvM, JvS>(xform, normals));
+            return mesh.Primitives.SelectMany(item => item.Triangulate<TvP, TvM, TvS>(xform, normals));
         }
 
-        public static IEnumerable<((TvP, TvM, JvS), (TvP, TvM, JvS), (TvP, TvM, JvS), Material)> Triangulate<TvP, TvM, JvS>(this MeshPrimitive prim, Matrix4x4 xform, IReadOnlyDictionary<Vector3, Vector3> defaultNormals)
+        public static IEnumerable<((TvP, TvM, TvS), (TvP, TvM, TvS), (TvP, TvM, TvS), Material)> Triangulate<TvP, TvM, TvS>(this MeshPrimitive prim, Matrix4x4 xform, IReadOnlyDictionary<Vector3, Vector3> defaultNormals)
             where TvP : struct, Geometry.VertexTypes.IVertexPosition
             where TvM : struct, Geometry.VertexTypes.IVertexMaterial
-            where JvS : struct, Geometry.VertexTypes.IVertexSkinning
+            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
         {
             var vertices = prim.GetVertexColumns();
             if (vertices.Normals == null && defaultNormals != null) vertices.SetNormals(defaultNormals);
@@ -311,9 +311,9 @@ namespace SharpGLTF.Schema2
                 var bm = vertices.GetMaterialFragment<TvM>(t.Item2);
                 var cm = vertices.GetMaterialFragment<TvM>(t.Item3);
 
-                var aj = vertices.GetJointsFragment<JvS>(t.Item1);
-                var bj = vertices.GetJointsFragment<JvS>(t.Item2);
-                var cj = vertices.GetJointsFragment<JvS>(t.Item3);
+                var aj = vertices.GetSkinningFragment<TvS>(t.Item1);
+                var bj = vertices.GetSkinningFragment<TvS>(t.Item2);
+                var cj = vertices.GetSkinningFragment<TvS>(t.Item3);
 
                 yield return ((ap, am, aj), (bp, bm, bj), (cp, cm, cj), prim.Material);
             }
@@ -391,10 +391,10 @@ namespace SharpGLTF.Schema2
             return posnrm;
         }
 
-        public static void AddMesh<TMaterial, TvP, TvM, JvS>(this Geometry.MeshBuilder<TMaterial, TvP, TvM, JvS> meshBuilder, Mesh srcMesh, Matrix4x4 xform, Func<Material, TMaterial> materialFunc)
+        public static void AddMesh<TMaterial, TvP, TvM, TvS>(this Geometry.MeshBuilder<TMaterial, TvP, TvM, TvS> meshBuilder, Mesh srcMesh, Matrix4x4 xform, Func<Material, TMaterial> materialFunc)
             where TvP : struct, Geometry.VertexTypes.IVertexPosition
             where TvM : struct, Geometry.VertexTypes.IVertexMaterial
-            where JvS : struct, Geometry.VertexTypes.IVertexSkinning
+            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
         {
             var normals = srcMesh.GetComputedNormals();
 
@@ -402,7 +402,7 @@ namespace SharpGLTF.Schema2
             {
                 var dstPrim = meshBuilder.UsePrimitive(materialFunc(srcPrim.Material));
 
-                foreach (var tri in srcPrim.Triangulate<TvP, TvM, JvS>(xform, normals))
+                foreach (var tri in srcPrim.Triangulate<TvP, TvM, TvS>(xform, normals))
                 {
                     dstPrim.AddTriangle(tri.Item1, tri.Item2, tri.Item3);
                 }

+ 9 - 9
src/SharpGLTF.Toolkit/Schema2/SceneExtensions.cs

@@ -87,15 +87,15 @@ namespace SharpGLTF.Schema2
         /// </summary>
         /// <typeparam name="TvP">The vertex fragment type with Position, Normal and Tangent.</typeparam>
         /// <typeparam name="TvM">The vertex fragment type with Colors and Texture Coordinates.</typeparam>
-        /// <typeparam name="JvS">The vertex fragment type with Skin Joint Weights.</typeparam>
+        /// <typeparam name="TvS">The vertex fragment type with Skin Joint Weights.</typeparam>
         /// <param name="scene">A <see cref="Scene"/> instance.</param>
         /// <returns>A collection of triangles in world space.</returns>
-        public static IEnumerable<((TvP, TvM, JvS), (TvP, TvM, JvS), (TvP, TvM, JvS), Material)> Triangulate<TvP, TvM, JvS>(this Scene scene)
+        public static IEnumerable<((TvP, TvM, TvS), (TvP, TvM, TvS), (TvP, TvM, TvS), Material)> Triangulate<TvP, TvM, TvS>(this Scene scene)
             where TvP : struct, Geometry.VertexTypes.IVertexPosition
             where TvM : struct, Geometry.VertexTypes.IVertexMaterial
-            where JvS : struct, Geometry.VertexTypes.IVertexSkinning
+            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
         {
-            return Node.Flatten(scene).SelectMany(item => item.Triangulate<TvP, TvM, JvS>(true));
+            return Node.Flatten(scene).SelectMany(item => item.Triangulate<TvP, TvM, TvS>(true));
         }
 
         /// <summary>
@@ -104,21 +104,21 @@ namespace SharpGLTF.Schema2
         /// </summary>
         /// <typeparam name="TvP">The vertex fragment type with Position, Normal and Tangent.</typeparam>
         /// <typeparam name="TvM">The vertex fragment type with Colors and Texture Coordinates.</typeparam>
-        /// <typeparam name="JvS">The vertex fragment type with Skin Joint Weights.</typeparam>
+        /// <typeparam name="TvS">The vertex fragment type with Skin Joint Weights.</typeparam>
         /// <param name="node">A <see cref="Node"/> instance.</param>
         /// <param name="inWorldSpace">A value indicating whether the returned triangles must be in local (false) or world (true) space.</param>
         /// <returns>A collection of triangles in local or world space.</returns>
-        public static IEnumerable<((TvP, TvM, JvS), (TvP, TvM, JvS), (TvP, TvM, JvS), Material)> Triangulate<TvP, TvM, JvS>(this Node node, bool inWorldSpace)
+        public static IEnumerable<((TvP, TvM, TvS), (TvP, TvM, TvS), (TvP, TvM, TvS), Material)> Triangulate<TvP, TvM, TvS>(this Node node, bool inWorldSpace)
             where TvP : struct, Geometry.VertexTypes.IVertexPosition
             where TvM : struct, Geometry.VertexTypes.IVertexMaterial
-            where JvS : struct, Geometry.VertexTypes.IVertexSkinning
+            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
         {
             var mesh = node.Mesh;
-            if (mesh == null) return Enumerable.Empty<((TvP, TvM, JvS), (TvP, TvM, JvS), (TvP, TvM, JvS), Material)>();
+            if (mesh == null) return Enumerable.Empty<((TvP, TvM, TvS), (TvP, TvM, TvS), (TvP, TvM, TvS), Material)>();
 
             var xform = inWorldSpace ? node.WorldMatrix : Matrix4x4.Identity;
 
-            return mesh.Triangulate<TvP, TvM, JvS>(xform);
+            return mesh.Triangulate<TvP, TvM, TvS>(xform);
         }
 
         #endregion