Browse Source

+optimizations
+docs

Vicente Penades 3 years ago
parent
commit
9bc142b3f4

+ 1 - 1
src/Directory.Build.props

@@ -113,7 +113,7 @@
   <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
     <SignAssembly>true</SignAssembly>
     <DelaySign>false</DelaySign>
-    <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)SharpGLTF.snk</AssemblyOriginatorKeyFile>
+    <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)Shared\SharpGLTF.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
 
   <!-- Source Control =================================================================================== -->

+ 0 - 0
src/SharpGLTF.snk → src/Shared/SharpGLTF.snk


+ 2 - 2
src/Shared/_Extensions.cs

@@ -63,12 +63,12 @@ namespace SharpGLTF
             return v.X._IsFinite() && v.Y._IsFinite() && v.Z._IsFinite();
         }
 
-        internal static bool _IsFinite(this Vector4 v)
+        internal static bool _IsFinite(this in Vector4 v)
         {
             return v.X._IsFinite() && v.Y._IsFinite() && v.Z._IsFinite() && v.W._IsFinite();
         }
 
-        internal static bool _IsFinite(this Matrix4x4 v)
+        internal static bool _IsFinite(this in Matrix4x4 v)
         {
             if (!(v.M11._IsFinite() && v.M12._IsFinite() && v.M13._IsFinite() && v.M14._IsFinite())) return false;
             if (!(v.M21._IsFinite() && v.M22._IsFinite() && v.M23._IsFinite() && v.M24._IsFinite())) return false;

+ 1 - 1
src/SharpGLTF.Core/IO/JsonContent.Impl.cs

@@ -18,7 +18,7 @@ namespace SharpGLTF.IO
         int Count { get; }
     }
 
-    struct _JsonStaticUtils
+    static class _JsonStaticUtils
     {
         #region serialization
 

+ 3 - 3
src/SharpGLTF.Core/Transforms/Matrix4x4Double.cs

@@ -341,7 +341,7 @@ namespace SharpGLTF.Transforms
         /// Returns the hash code for this instance.
         /// </summary>
         /// <returns>The hash code.</returns>
-        public override int GetHashCode()
+        public readonly override int GetHashCode()
         {
             unchecked
             {
@@ -385,14 +385,14 @@ namespace SharpGLTF.Transforms
         /// </summary>
         /// <param name="other">The matrix to compare this instance to.</param>
         /// <returns>True if the matrices are equal; False otherwise.</returns>
-        public bool Equals(Matrix4x4Double other) => this == other;
+        public readonly bool Equals(Matrix4x4Double other) => this == other;
 
         /// <summary>
         /// Returns a boolean indicating whether the given Object is equal to this matrix instance.
         /// </summary>
         /// <param name="obj">The Object to compare against.</param>
         /// <returns>True if the Object is equal to this matrix; False otherwise.</returns>
-        public override bool Equals(object obj) => (obj is Matrix4x4Double other) && (this == other);
+        public readonly override bool Equals(object obj) => (obj is Matrix4x4Double other) && (this == other);
 
         #endregion Public Fields
 

+ 1 - 1
src/SharpGLTF.Toolkit/Collections/ValueListSet.cs

@@ -328,7 +328,7 @@ namespace SharpGLTF.Collections
             #endregion
         }
 
-        struct _IndexCollection : IEnumerable<int>
+        readonly struct _IndexCollection : IEnumerable<int>
         {
             public _IndexCollection(ValueListSet<T> source) { _Source = source; }
 

+ 1 - 1
src/SharpGLTF.Toolkit/Geometry/VertexBufferColumns.cs

@@ -456,7 +456,7 @@ namespace SharpGLTF.Geometry
 
         #region nested types
 
-        struct _NormalTangentAgent : VertexNormalsFactory.IMeshPrimitive, VertexTangentsFactory.IMeshPrimitive
+        readonly struct _NormalTangentAgent : VertexNormalsFactory.IMeshPrimitive, VertexTangentsFactory.IMeshPrimitive
         {
             public _NormalTangentAgent(VertexBufferColumns vertices, IEnumerable<(int A, int B, int C)> indices)
             {

+ 51 - 34
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexGeometry.cs

@@ -124,16 +124,21 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         [VertexAttribute("POSITION")]
         public Vector3 Position;
-        public override bool Equals(object obj) { return obj is VertexPosition other && AreEqual(this, other); }
-        public bool Equals(VertexPosition other) { return AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return Position.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexPosition other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexPosition other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexPosition a, in VertexPosition b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexPosition a, in VertexPosition b) { return !AreEqual(a, b); }
         public static bool AreEqual(in VertexPosition a, in VertexPosition b)
         {
             return a.Position == b.Position;
-        }
-
-        public override int GetHashCode() { return Position.GetHashCode(); }
+        }        
 
         #endregion
 
@@ -158,13 +163,13 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector3 GetPosition() { return this.Position; }
+        public readonly Vector3 GetPosition() { return this.Position; }
 
         /// <inheritdoc/>
-        public bool TryGetNormal(out Vector3 normal) { normal = default; return false; }
+        public readonly bool TryGetNormal(out Vector3 normal) { normal = default; return false; }
 
         /// <inheritdoc/>
-        public bool TryGetTangent(out Vector4 tangent) { tangent = default; return false; }
+        public readonly bool TryGetTangent(out Vector4 tangent) { tangent = default; return false; }
 
         /// <inheritdoc/>
         public void ApplyTransform(in Matrix4x4 xform)
@@ -224,16 +229,20 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("NORMAL")]
         public Vector3 Normal;
 
-        public override bool Equals(object obj) { return obj is VertexPositionNormal other && AreEqual(this, other); }
-        public bool Equals(VertexPositionNormal other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return Position.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexPositionNormal other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexPositionNormal other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexPositionNormal a, in VertexPositionNormal b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexPositionNormal a, in VertexPositionNormal b) { return !AreEqual(a, b); }
         public static bool AreEqual(in VertexPositionNormal a, in VertexPositionNormal b)
         {
             return a.Position == b.Position && a.Normal == b.Normal;
-        }
-
-        public override int GetHashCode() { return Position.GetHashCode(); }
+        }        
 
         #endregion
 
@@ -259,13 +268,13 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector3 GetPosition() { return this.Position; }
+        public readonly Vector3 GetPosition() { return this.Position; }
 
         /// <inheritdoc/>
-        public bool TryGetNormal(out Vector3 normal) { normal = this.Normal; return true; }
+        public readonly bool TryGetNormal(out Vector3 normal) { normal = this.Normal; return true; }
 
         /// <inheritdoc/>
-        public bool TryGetTangent(out Vector4 tangent) { tangent = default; return false; }
+        public readonly bool TryGetTangent(out Vector4 tangent) { tangent = default; return false; }
 
         /// <inheritdoc/>
         public void ApplyTransform(in Matrix4x4 xform)
@@ -285,7 +294,7 @@ namespace SharpGLTF.Geometry.VertexTypes
     {
         #region debug
 
-        private string _GetDebuggerDisplay() => VertexUtils._GetDebuggerDisplay(this);
+        private readonly string _GetDebuggerDisplay() => VertexUtils._GetDebuggerDisplay(this);
 
         #endregion
 
@@ -325,16 +334,20 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("TANGENT")]
         public Vector4 Tangent;
 
-        public override bool Equals(object obj) { return obj is VertexPositionNormalTangent other && AreEqual(this, other); }
-        public bool Equals(VertexPositionNormalTangent other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return Position.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexPositionNormalTangent other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexPositionNormalTangent other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexPositionNormalTangent a, in VertexPositionNormalTangent b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexPositionNormalTangent a, in VertexPositionNormalTangent b) { return !AreEqual(a, b); }
         public static bool AreEqual(in VertexPositionNormalTangent a, in VertexPositionNormalTangent b)
         {
             return a.Position == b.Position && a.Normal == b.Normal && a.Tangent == b.Tangent;
-        }
-
-        public override int GetHashCode() { return Position.GetHashCode(); }
+        }        
 
         #endregion
 
@@ -347,7 +360,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         void IVertexGeometry.SetTangent(in Vector4 tangent) { this.Tangent = tangent; }
 
         /// <inheritdoc/>
-        public VertexGeometryDelta Subtract(IVertexGeometry baseValue)
+        public readonly VertexGeometryDelta Subtract(IVertexGeometry baseValue)
         {
             return new VertexGeometryDelta((VertexPositionNormalTangent)baseValue, this);
         }
@@ -361,13 +374,13 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector3 GetPosition() { return this.Position; }
+        public readonly Vector3 GetPosition() { return this.Position; }
 
         /// <inheritdoc/>
-        public bool TryGetNormal(out Vector3 normal) { normal = this.Normal; return true; }
+        public readonly bool TryGetNormal(out Vector3 normal) { normal = this.Normal; return true; }
 
         /// <inheritdoc/>
-        public bool TryGetTangent(out Vector4 tangent) { tangent = this.Tangent; return true; }
+        public readonly bool TryGetTangent(out Vector4 tangent) { tangent = this.Tangent; return true; }
 
         /// <inheritdoc/>
         public void ApplyTransform(in Matrix4x4 xform)
@@ -473,16 +486,20 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("TANGENTDELTA")]
         public Vector3 TangentDelta;
 
-        public override bool Equals(object obj) { return obj is VertexGeometryDelta other && AreEqual(this, other); }
-        public bool Equals(VertexGeometryDelta other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return PositionDelta.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexGeometryDelta other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexGeometryDelta other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexGeometryDelta a, in VertexGeometryDelta b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexGeometryDelta a, in VertexGeometryDelta b) { return !AreEqual(a, b); }
         public static bool AreEqual(in VertexGeometryDelta a, in VertexGeometryDelta b)
         {
             return a.PositionDelta == b.PositionDelta && a.NormalDelta == b.NormalDelta && a.TangentDelta == b.TangentDelta;
-        }
-
-        public override int GetHashCode() { return PositionDelta.GetHashCode(); }
+        }        
 
         #endregion
 
@@ -495,13 +512,13 @@ namespace SharpGLTF.Geometry.VertexTypes
         void IVertexGeometry.SetTangent(in Vector4 tangent) { this.TangentDelta = new Vector3(tangent.X, tangent.Y, tangent.Z); }
 
         /// <inheritdoc/>
-        public Vector3 GetPosition() { return this.PositionDelta; }
+        public readonly Vector3 GetPosition() { return this.PositionDelta; }
 
         /// <inheritdoc/>
-        public bool TryGetNormal(out Vector3 normal) { normal = this.NormalDelta; return true; }
+        public readonly bool TryGetNormal(out Vector3 normal) { normal = this.NormalDelta; return true; }
 
         /// <inheritdoc/>
-        public bool TryGetTangent(out Vector4 tangent) { tangent = new Vector4(this.TangentDelta, 0); return true; }
+        public readonly bool TryGetTangent(out Vector4 tangent) { tangent = new Vector4(this.TangentDelta, 0); return true; }
 
         /// <inheritdoc/>
         public void ApplyTransform(in Matrix4x4 xform) { throw new NotSupportedException(); }

+ 121 - 89
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.cs

@@ -121,22 +121,26 @@ namespace SharpGLTF.Geometry.VertexTypes
         public Vector4 Color;
 
         /// <inheritdoc/>
-        public int MaxColors => 1;
+        public readonly int MaxColors => 1;
 
         /// <inheritdoc/>
-        public int MaxTextCoords => 0;
+        public readonly int MaxTextCoords => 0;
 
-        public override bool Equals(object obj) { return obj is VertexColor1 other && AreEqual(this, other); }
-        public bool Equals(VertexColor1 other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return Color.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexColor1 other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexColor1 other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexColor1 a, in VertexColor1 b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexColor1 a, in VertexColor1 b) { return !AreEqual(a, b); }
 
         public static bool AreEqual(in VertexColor1 a, in VertexColor1 b)
         {
             return a.Color == b.Color;
-        }
-
-        public override int GetHashCode() { return Color.GetHashCode(); }
+        }        
 
         #endregion
 
@@ -159,14 +163,14 @@ namespace SharpGLTF.Geometry.VertexTypes
         void IVertexMaterial.SetTexCoord(int setIndex, Vector2 coord) { }
 
         /// <inheritdoc/>
-        public Vector4 GetColor(int index)
+        public readonly Vector4 GetColor(int index)
         {
             if (index != 0) throw new ArgumentOutOfRangeException(nameof(index));
             return Color;
         }
 
         /// <inheritdoc/>
-        public Vector2 GetTexCoord(int index)
+        public readonly Vector2 GetTexCoord(int index)
         {
             throw new NotSupportedException();
         }
@@ -218,22 +222,25 @@ namespace SharpGLTF.Geometry.VertexTypes
         public Vector4 Color1;
 
         /// <inheritdoc/>
-        public int MaxColors => 2;
+        public readonly int MaxColors => 2;
+
+        /// <inheritdoc/>
+        public readonly int MaxTextCoords => 0;
 
         /// <inheritdoc/>
-        public int MaxTextCoords => 0;
+        public readonly override int GetHashCode() { return Color0.GetHashCode() ^ Color1.GetHashCode(); }
 
-        public override bool Equals(object obj) { return obj is VertexColor2 other && AreEqual(this, other); }
-        public bool Equals(VertexColor2 other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexColor2 other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexColor2 other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexColor2 a, in VertexColor2 b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexColor2 a, in VertexColor2 b) { return !AreEqual(a, b); }
-
         public static bool AreEqual(in VertexColor2 a, in VertexColor2 b)
         {
             return a.Color0 == b.Color0 && a.Color1 == b.Color1;
-        }
-
-        public override int GetHashCode() { return Color0.GetHashCode() ^ Color1.GetHashCode(); }
+        }        
 
         #endregion
 
@@ -261,7 +268,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         void IVertexMaterial.SetTexCoord(int setIndex, Vector2 coord) { }
 
         /// <inheritdoc/>
-        public Vector4 GetColor(int index)
+        public readonly Vector4 GetColor(int index)
         {
             if (index == 0) return Color0;
             if (index == 1) return Color1;
@@ -269,7 +276,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector2 GetTexCoord(int index) { throw new NotSupportedException(); }
+        public readonly Vector2 GetTexCoord(int index) { throw new NotSupportedException(); }
 
         #endregion
     }
@@ -313,21 +320,25 @@ namespace SharpGLTF.Geometry.VertexTypes
         public Vector2 TexCoord;
 
         /// <inheritdoc/>
-        public int MaxColors => 0;
+        public readonly int MaxColors => 0;
+
+        /// <inheritdoc/>
+        public readonly int MaxTextCoords => 1;
+
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return TexCoord.GetHashCode(); }
 
         /// <inheritdoc/>
-        public int MaxTextCoords => 1;
+        public readonly override bool Equals(object obj) { return obj is VertexTexture1 other && AreEqual(this, other); }
 
-        public override bool Equals(object obj) { return obj is VertexTexture1 other && AreEqual(this, other); }
-        public bool Equals(VertexTexture1 other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexTexture1 other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexTexture1 a, in VertexTexture1 b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexTexture1 a, in VertexTexture1 b) { return !AreEqual(a, b); }
         public static bool AreEqual(in VertexTexture1 a, in VertexTexture1 b)
         {
             return a.TexCoord == b.TexCoord;
-        }
-
-        public override int GetHashCode() { return TexCoord.GetHashCode(); }
+        }        
 
         #endregion
 
@@ -350,13 +361,13 @@ namespace SharpGLTF.Geometry.VertexTypes
         void IVertexMaterial.SetTexCoord(int setIndex, Vector2 coord) { if (setIndex == 0) this.TexCoord = coord; }
 
         /// <inheritdoc/>
-        public Vector4 GetColor(int index)
+        public readonly Vector4 GetColor(int index)
         {
             throw new NotSupportedException();
         }
 
         /// <inheritdoc/>
-        public Vector2 GetTexCoord(int index)
+        public readonly Vector2 GetTexCoord(int index)
         {
             if (index != 0) throw new ArgumentOutOfRangeException(nameof(index));
             return TexCoord;
@@ -409,21 +420,25 @@ namespace SharpGLTF.Geometry.VertexTypes
         public Vector2 TexCoord1;
 
         /// <inheritdoc/>
-        public int MaxColors => 0;
+        public readonly int MaxColors => 0;
 
         /// <inheritdoc/>
-        public int MaxTextCoords => 2;
+        public readonly int MaxTextCoords => 2;
 
-        public override bool Equals(object obj) { return obj is VertexTexture2 other && AreEqual(this, other); }
-        public bool Equals(VertexTexture2 other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return TexCoord0.GetHashCode() ^ TexCoord1.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexTexture2 other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexTexture2 other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexTexture2 a, in VertexTexture2 b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexTexture2 a, in VertexTexture2 b) { return !AreEqual(a, b); }
         public static bool AreEqual(in VertexTexture2 a, in VertexTexture2 b)
         {
             return a.TexCoord0 == b.TexCoord0 && a.TexCoord1 == b.TexCoord1;
-        }
-
-        public override int GetHashCode() { return TexCoord0.GetHashCode() ^ TexCoord1.GetHashCode(); }
+        }        
 
         #endregion
 
@@ -451,13 +466,13 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector4 GetColor(int index)
+        public readonly Vector4 GetColor(int index)
         {
             throw new NotSupportedException();
         }
 
         /// <inheritdoc/>
-        public Vector2 GetTexCoord(int index)
+        public readonly Vector2 GetTexCoord(int index)
         {
             if (index == 0) return TexCoord0;
             if (index == 1) return TexCoord1;
@@ -511,21 +526,25 @@ namespace SharpGLTF.Geometry.VertexTypes
         public Vector2 TexCoord;
 
         /// <inheritdoc/>
-        public int MaxColors => 1;
+        public readonly int MaxColors => 1;
 
         /// <inheritdoc/>
-        public int MaxTextCoords => 1;
+        public readonly int MaxTextCoords => 1;
 
-        public override bool Equals(object obj) { return obj is VertexColor1Texture1 other && AreEqual(this, other); }
-        public bool Equals(VertexColor1Texture1 other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return TexCoord.GetHashCode() ^ Color.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexColor1Texture1 other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexColor1Texture1 other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexColor1Texture1 a, in VertexColor1Texture1 b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexColor1Texture1 a, in VertexColor1Texture1 b) { return !AreEqual(a, b); }
         public static bool AreEqual(in VertexColor1Texture1 a, in VertexColor1Texture1 b)
         {
             return a.TexCoord == b.TexCoord && a.Color == b.Color;
-        }
-
-        public override int GetHashCode() { return TexCoord.GetHashCode() ^ Color.GetHashCode(); }
+        }        
 
         #endregion
 
@@ -549,14 +568,14 @@ namespace SharpGLTF.Geometry.VertexTypes
         void IVertexMaterial.SetTexCoord(int setIndex, Vector2 coord) { if (setIndex == 0) this.TexCoord = coord; }
 
         /// <inheritdoc/>
-        public Vector4 GetColor(int index)
+        public readonly Vector4 GetColor(int index)
         {
             if (index != 0) throw new ArgumentOutOfRangeException(nameof(index));
             return Color;
         }
 
         /// <inheritdoc/>
-        public Vector2 GetTexCoord(int index)
+        public readonly Vector2 GetTexCoord(int index)
         {
             if (index != 0) throw new ArgumentOutOfRangeException(nameof(index));
             return TexCoord;
@@ -614,21 +633,25 @@ namespace SharpGLTF.Geometry.VertexTypes
         public Vector2 TexCoord1;
 
         /// <inheritdoc/>
-        public int MaxColors => 1;
+        public readonly int MaxColors => 1;
 
         /// <inheritdoc/>
-        public int MaxTextCoords => 2;
+        public readonly int MaxTextCoords => 2;
 
-        public override bool Equals(object obj) { return obj is VertexColor1Texture2 other && AreEqual(this, other); }
-        public bool Equals(VertexColor1Texture2 other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return Color.GetHashCode() ^ TexCoord0.GetHashCode() ^ TexCoord1.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexColor1Texture2 other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexColor1Texture2 other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexColor1Texture2 a, in VertexColor1Texture2 b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexColor1Texture2 a, in VertexColor1Texture2 b) { return !AreEqual(a, b); }
         public static bool AreEqual(in VertexColor1Texture2 a, in VertexColor1Texture2 b)
         {
             return a.Color == b.Color && a.TexCoord0 == b.TexCoord0 && a.TexCoord1 == b.TexCoord1;
-        }
-
-        public override int GetHashCode() { return Color.GetHashCode() ^ TexCoord0.GetHashCode() ^ TexCoord1.GetHashCode(); }
+        }        
 
         #endregion
 
@@ -657,14 +680,14 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector4 GetColor(int index)
+        public readonly Vector4 GetColor(int index)
         {
             if (index != 0) throw new ArgumentOutOfRangeException(nameof(index));
             return Color;
         }
 
         /// <inheritdoc/>
-        public Vector2 GetTexCoord(int index)
+        public readonly Vector2 GetTexCoord(int index)
         {
             switch (index)
             {
@@ -685,7 +708,7 @@ namespace SharpGLTF.Geometry.VertexTypes
     {
         #region debug
 
-        private string _GetDebuggerDisplay() => VertexUtils._GetDebuggerDisplay(this);
+        private readonly string _GetDebuggerDisplay() => VertexUtils._GetDebuggerDisplay(this);
 
         #endregion
 
@@ -726,29 +749,32 @@ namespace SharpGLTF.Geometry.VertexTypes
         public Vector2 TexCoord;
 
         /// <inheritdoc/>
-        public int MaxColors => 2;
+        public readonly int MaxColors => 2;
+
+        /// <inheritdoc/>
+        public readonly int MaxTextCoords => 1;
+
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return Color0.GetHashCode() ^ Color1.GetHashCode() ^ TexCoord.GetHashCode(); }
 
         /// <inheritdoc/>
-        public int MaxTextCoords => 1;
+        public readonly override bool Equals(object obj) { return obj is VertexColor2Texture1 other && AreEqual(this, other); }
 
-        public override bool Equals(object obj) { return obj is VertexColor2Texture1 other && AreEqual(this, other); }
-        public bool Equals(VertexColor2Texture1 other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexColor2Texture1 other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexColor2Texture1 a, in VertexColor2Texture1 b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexColor2Texture1 a, in VertexColor2Texture1 b) { return !AreEqual(a, b); }
-
         public static bool AreEqual(in VertexColor2Texture1 a, in VertexColor2Texture1 b)
         {
             return a.Color0 == b.Color0 && a.Color1 == b.Color1 && a.TexCoord == b.TexCoord;
-        }
-
-        public override int GetHashCode() { return Color0.GetHashCode() ^ Color1.GetHashCode() ^ TexCoord.GetHashCode(); }
+        }        
 
         #endregion
 
         #region API
 
         /// <inheritdoc/>
-        public VertexMaterialDelta Subtract(IVertexMaterial baseValue)
+        public readonly VertexMaterialDelta Subtract(IVertexMaterial baseValue)
         {
             return new VertexMaterialDelta((VertexColor2Texture1)baseValue, this);
         }
@@ -773,7 +799,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector4 GetColor(int index)
+        public readonly Vector4 GetColor(int index)
         {
             switch (index)
             {
@@ -784,7 +810,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector2 GetTexCoord(int index)
+        public readonly Vector2 GetTexCoord(int index)
         {
             switch (index)
             {
@@ -804,7 +830,7 @@ namespace SharpGLTF.Geometry.VertexTypes
     {
         #region debug
 
-        private string _GetDebuggerDisplay() => VertexUtils._GetDebuggerDisplay(this);
+        private readonly string _GetDebuggerDisplay() => VertexUtils._GetDebuggerDisplay(this);
 
         #endregion
 
@@ -850,29 +876,32 @@ namespace SharpGLTF.Geometry.VertexTypes
         public Vector2 TexCoord1;
 
         /// <inheritdoc/>
-        public int MaxColors => 2;
+        public readonly int MaxColors => 2;
 
         /// <inheritdoc/>
-        public int MaxTextCoords => 2;
+        public readonly int MaxTextCoords => 2;
 
-        public override bool Equals(object obj) { return obj is VertexColor2Texture2 other && AreEqual(this, other); }
-        public bool Equals(VertexColor2Texture2 other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return Color0.GetHashCode() ^ Color1.GetHashCode() ^ TexCoord0.GetHashCode() ^ TexCoord1.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexColor2Texture2 other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexColor2Texture2 other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexColor2Texture2 a, in VertexColor2Texture2 b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexColor2Texture2 a, in VertexColor2Texture2 b) { return !AreEqual(a, b); }
-
         public static bool AreEqual(in VertexColor2Texture2 a, in VertexColor2Texture2 b)
         {
             return a.Color0 == b.Color0 && a.Color1 == b.Color1 && a.TexCoord0 == b.TexCoord0 && a.TexCoord1 == b.TexCoord1;
-        }
-
-        public override int GetHashCode() { return Color0.GetHashCode() ^ Color1.GetHashCode() ^ TexCoord0.GetHashCode() ^ TexCoord1.GetHashCode(); }
+        }        
 
         #endregion
 
         #region API
 
         /// <inheritdoc/>
-        public VertexMaterialDelta Subtract(IVertexMaterial baseValue)
+        public readonly VertexMaterialDelta Subtract(IVertexMaterial baseValue)
         {
             return new VertexMaterialDelta((VertexColor2Texture2)baseValue, this);
         }
@@ -899,7 +928,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector4 GetColor(int index)
+        public readonly Vector4 GetColor(int index)
         {
             switch (index)
             {
@@ -910,7 +939,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector2 GetTexCoord(int index)
+        public readonly Vector2 GetTexCoord(int index)
         {
             switch (index)
             {
@@ -931,7 +960,7 @@ namespace SharpGLTF.Geometry.VertexTypes
     {
         #region debug
 
-        private string _GetDebuggerDisplay() => $"ΔC₀:{Color0Delta} ΔC₁:{Color1Delta} ΔUV₀:{TexCoord0Delta}  ΔUV₁:{TexCoord1Delta}";
+        private readonly string _GetDebuggerDisplay() => $"ΔC₀:{Color0Delta} ΔC₁:{Color1Delta} ΔUV₀:{TexCoord0Delta}  ΔUV₁:{TexCoord1Delta}";
 
         #endregion
 
@@ -1121,24 +1150,27 @@ namespace SharpGLTF.Geometry.VertexTypes
         /// <inheritdoc/>
         public int MaxTextCoords { get; }
 
-        public override bool Equals(object obj) { return obj is VertexMaterialDelta other && AreEqual(this, other); }
-        public bool Equals(VertexMaterialDelta other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return Color0Delta.GetHashCode() ^ Color1Delta.GetHashCode() ^ TexCoord0Delta.GetHashCode() ^ TexCoord1Delta.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexMaterialDelta other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexMaterialDelta other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexMaterialDelta a, in VertexMaterialDelta b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexMaterialDelta a, in VertexMaterialDelta b) { return !AreEqual(a, b); }
-
         public static bool AreEqual(in VertexMaterialDelta a, in VertexMaterialDelta b)
         {
             return a.Color0Delta == b.Color0Delta && a.Color1Delta == b.Color1Delta && a.TexCoord0Delta == b.TexCoord0Delta && a.TexCoord1Delta == b.TexCoord1Delta;
-        }
-
-        public override int GetHashCode() { return Color0Delta.GetHashCode() ^ Color1Delta.GetHashCode() ^ TexCoord0Delta.GetHashCode() ^ TexCoord1Delta.GetHashCode(); }
+        }        
 
         #endregion
 
         #region API
 
         /// <inheritdoc/>
-        public VertexMaterialDelta Subtract(IVertexMaterial baseValue)
+        public readonly VertexMaterialDelta Subtract(IVertexMaterial baseValue)
         {
             return new VertexMaterialDelta((VertexMaterialDelta)baseValue, this);
         }
@@ -1175,7 +1207,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector4 GetColor(int index)
+        public readonly Vector4 GetColor(int index)
         {
             switch (index)
             {
@@ -1186,7 +1218,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         }
 
         /// <inheritdoc/>
-        public Vector2 GetTexCoord(int index)
+        public readonly Vector2 GetTexCoord(int index)
         {
             switch (index)
             {

+ 32 - 22
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexSkinning.cs

@@ -138,8 +138,17 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("WEIGHTS_0")]
         public Vector4 Weights;
 
-        public override bool Equals(object obj) { return obj is VertexJoints4 other && AreEqual(this, other); }
-        public bool Equals(VertexJoints4 other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly int MaxBindings => 4;
+
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return Joints.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexJoints4 other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexJoints4 other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexJoints4 a, in VertexJoints4 b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexJoints4 a, in VertexJoints4 b) { return !AreEqual(a, b); }
         public static bool AreEqual(in VertexJoints4 a, in VertexJoints4 b)
@@ -149,11 +158,7 @@ namespace SharpGLTF.Geometry.VertexTypes
             // to be already sorted by weight, unless filled manually.
 
             return a.Joints == b.Joints && a.Weights == b.Weights;
-        }
-
-        public override int GetHashCode() { return Joints.GetHashCode(); }
-
-        public int MaxBindings => 4;
+        }        
 
         #endregion
 
@@ -173,7 +178,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         #region API
 
         /// <inheritdoc/>
-        public SparseWeight8 GetBindings() { return SparseWeight8.Create(this.Joints, this.Weights); }
+        public readonly SparseWeight8 GetBindings() { return SparseWeight8.Create(this.Joints, this.Weights); }
 
         /// <inheritdoc/>
         public void SetBindings(in SparseWeight8 bindings) { this = new VertexJoints4(bindings); }
@@ -182,7 +187,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         public void SetBindings(params (int Index, float Weight)[] bindings) { this = new VertexJoints4(bindings); }
 
         /// <inheritdoc/>
-        public (int Index, float Weight) GetBinding(int index)
+        public readonly (int Index, float Weight) GetBinding(int index)
         {
             switch (index)
             {
@@ -205,7 +210,7 @@ namespace SharpGLTF.Geometry.VertexTypes
     {
         #region debug
 
-        private string _GetDebuggerDisplay() => VertexUtils._GetDebuggerDisplay(this);
+        private readonly string _GetDebuggerDisplay() => VertexUtils._GetDebuggerDisplay(this);
 
         #endregion
 
@@ -289,8 +294,17 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("WEIGHTS_1")]
         public Vector4 Weights1;
 
-        public override bool Equals(object obj) { return obj is VertexJoints8 other && AreEqual(this, other); }
-        public bool Equals(VertexJoints8 other) { return AreEqual(this, other); }
+        /// <inheritdoc/>
+        public readonly int MaxBindings => 8;
+
+        /// <inheritdoc/>
+        public readonly override int GetHashCode() { return Joints0.GetHashCode(); }
+
+        /// <inheritdoc/>
+        public readonly override bool Equals(object obj) { return obj is VertexJoints8 other && AreEqual(this, other); }
+
+        /// <inheritdoc/>
+        public readonly bool Equals(VertexJoints8 other) { return AreEqual(this, other); }
         public static bool operator ==(in VertexJoints8 a, in VertexJoints8 b) { return AreEqual(a, b); }
         public static bool operator !=(in VertexJoints8 a, in VertexJoints8 b) { return !AreEqual(a, b); }
         public static bool AreEqual(in VertexJoints8 a, in VertexJoints8 b)
@@ -303,29 +317,25 @@ namespace SharpGLTF.Geometry.VertexTypes
                 && a.Weights0 == b.Weights0 && a.Weights1 == b.Weights1;
         }
 
-        public override int GetHashCode() { return Joints0.GetHashCode(); }
-
-        public int MaxBindings => 8;
-
         #endregion
 
         #region properties
 
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
-        Vector4 IVertexSkinning.JointsLow => this.Joints0;
+        readonly Vector4 IVertexSkinning.JointsLow => this.Joints0;
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
-        Vector4 IVertexSkinning.JointsHigh => this.Joints1;
+        readonly Vector4 IVertexSkinning.JointsHigh => this.Joints1;
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
-        Vector4 IVertexSkinning.WeightsLow => this.Weights0;
+        readonly Vector4 IVertexSkinning.WeightsLow => this.Weights0;
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
-        Vector4 IVertexSkinning.WeightsHigh => this.Weights1;
+        readonly Vector4 IVertexSkinning.WeightsHigh => this.Weights1;
 
         #endregion
 
         #region API
 
         /// <inheritdoc/>
-        public SparseWeight8 GetBindings() { return SparseWeight8.CreateUnchecked(this.Joints0, this.Joints1, this.Weights0, this.Weights1); }
+        public readonly SparseWeight8 GetBindings() { return SparseWeight8.CreateUnchecked(this.Joints0, this.Joints1, this.Weights0, this.Weights1); }
 
         /// <inheritdoc/>
         public void SetBindings(in SparseWeight8 weights) { this = new VertexJoints8(weights); }
@@ -334,7 +344,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         public void SetBindings(params (int Index, float Weight)[] bindings) { this = new VertexJoints8(bindings); }
 
         /// <inheritdoc/>
-        public (int Index, float Weight) GetBinding(int index)
+        public readonly (int Index, float Weight) GetBinding(int index)
         {
             switch (index)
             {

+ 17 - 2
src/SharpGLTF.Toolkit/IO/WavefrontWriter.cs

@@ -287,11 +287,26 @@ namespace SharpGLTF.IO
         #region nested types
 
         [System.Diagnostics.DebuggerDisplay("{DiffuseColor} {DiffuseTexture.ToDebuggerDisplay()}")]
-        public struct Material
+        public struct Material : IEquatable<Material>
         {
             public Vector3 DiffuseColor;
             public Vector3 SpecularColor;
-            public Memory.MemoryImage DiffuseTexture;
+            public Memory.MemoryImage DiffuseTexture;            
+
+            public readonly override int GetHashCode()
+            {
+                return DiffuseColor.GetHashCode() ^ SpecularColor.GetHashCode() ^ DiffuseTexture.GetHashCode();
+            }
+
+            public readonly override bool Equals(object obj) { return obj is Material other && this.Equals(other); }
+
+            public readonly bool Equals(Material other)
+            {
+                if (this.DiffuseColor != other.DiffuseColor) return false;
+                if (this.SpecularColor != other.SpecularColor) return false;
+                if (this.DiffuseTexture != other.DiffuseTexture) return false;
+                return true;
+            }
         }
 
         #endregion

+ 13 - 1
src/SharpGLTF.Toolkit/Scenes/TransformChainBuilder.cs

@@ -7,8 +7,10 @@ using TRANSFORM = SharpGLTF.Transforms.AffineTransform;
 
 namespace SharpGLTF.Scenes
 {
-    public struct TransformChainBuilder
+    public readonly struct TransformChainBuilder
     {
+        #region constructors
+
         public static implicit operator TransformChainBuilder(NodeBuilder node)
         {
             return new TransformChainBuilder(node);
@@ -42,10 +44,20 @@ namespace SharpGLTF.Scenes
             _ChildTransform = child;
         }
 
+        #endregion
+
+        #region data
+
         private readonly NodeBuilder _ParentTransform;
         private readonly TRANSFORM? _ChildTransform;
 
+        #endregion
+
+        #region properties
+
         public NodeBuilder Parent => _ParentTransform;
         public TRANSFORM? Child => _ChildTransform;
+
+        #endregion
     }
 }