diff --git a/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/GlBufferManager.cs b/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/GlBufferManager.cs index 0fe3a3df3..c4376e822 100644 --- a/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/GlBufferManager.cs +++ b/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/GlBufferManager.cs @@ -1,7 +1,7 @@ using fin.data; using fin.math; -using fin.math.matrix.four; using fin.model; +using fin.model.accessor; using fin.ui.rendering.gl.model; using fin.util.enumerables; using fin.util.linq; diff --git a/FinModelUtility/Fin/Fin/src/data/indexable/IndexableDictionary.cs b/FinModelUtility/Fin/Fin/src/data/indexable/IndexableDictionary.cs index 792ff7108..be1fbee4f 100644 --- a/FinModelUtility/Fin/Fin/src/data/indexable/IndexableDictionary.cs +++ b/FinModelUtility/Fin/Fin/src/data/indexable/IndexableDictionary.cs @@ -1,15 +1,13 @@ using System; -using System.Buffers; using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Runtime.CompilerServices; namespace fin.data.indexable { public interface IReadOnlyIndexableDictionary : IEnumerable where TIndexable : IIndexable { - int Length { get; } - TValue this[int index] { get; } TValue this[TIndexable key] { get; } @@ -17,95 +15,35 @@ public interface IReadOnlyIndexableDictionary bool TryGetValue(TIndexable key, out TValue value); } - public interface IIndexableDictionary : - IReadOnlyIndexableDictionary + public interface IIndexableDictionary + : IReadOnlyIndexableDictionary where TIndexable : IIndexable { void Clear(); new TValue this[int index] { get; set; } new TValue this[TIndexable key] { get; set; } } - public class IndexableDictionary - : IIndexableDictionary where TIndexable : IIndexable { - private static readonly ArrayPool boolPool_ = ArrayPool.Shared; - private static readonly ArrayPool pool_ = ArrayPool.Shared; - - private bool[] hasKeys_ = Array.Empty(); - private TValue[] impl_ = Array.Empty(); + public class IndexableDictionary(int capacity) + : IIndexableDictionary + where TIndexable : IIndexable { + private readonly List<(bool, TValue)> impl_ = new(capacity); public IndexableDictionary() : this(0) { } - public IndexableDictionary(int length) => this.ResizeLength_(length); - - public int Length { get; private set; } - - public void Clear() { - for (var i = 0; i < this.Length; i++) { - hasKeys_[i] = false; - this.impl_[i] = default; - } - - boolPool_.Return(this.hasKeys_); - this.hasKeys_ = Array.Empty(); - - pool_.Return(this.impl_); - this.impl_ = Array.Empty(); - - this.Length = 0; - } - - private void ResizeLength_(int newLength) { - var oldCount = this.Length; - if (oldCount < newLength) { - this.Length = newLength; - - { - var oldImpl = this.hasKeys_; - this.hasKeys_ = boolPool_.Rent(newLength); - - for (var i = 0; i < oldCount; i++) { - this.hasKeys_[i] = oldImpl[i]; - } - - for (var i = oldCount; i < this.hasKeys_.Length; i++) { - this.hasKeys_[i] = false; - } - - if (oldImpl != null) { - boolPool_.Return(oldImpl); - } - } - - { - var oldImpl = this.impl_; - this.impl_ = pool_.Rent(newLength); - - for (var i = 0; i < oldCount; i++) { - this.impl_[i] = oldImpl[i]; - } - - for (var i = oldCount; i < this.impl_.Length; i++) { - this.impl_[i] = default; - } - - if (oldImpl != null) { - pool_.Return(oldImpl); - } - } - } else if (oldCount > newLength) { - throw new NotSupportedException(); - } - } + public void Clear() => this.impl_.Clear(); public TValue this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => impl_[index]; + get => this.impl_[index].Item2; [MethodImpl(MethodImplOptions.AggressiveInlining)] set { - ResizeLength_(Math.Max(this.Length, index + 1)); + this.impl_.EnsureCapacity(index); + + while (this.impl_.Count <= index) { + this.impl_.Add((false, default)); + } - this.impl_[index] = value; - this.hasKeys_[index] = true; + this.impl_[index] = (true, value); } } @@ -117,29 +55,24 @@ public TValue this[TIndexable key] { } public bool TryGetValue(int index, out TValue value) { - if (index >= this.Length) { + if (index >= this.impl_.Count) { value = default!; return false; } - value = this.impl_[index]; - return this.hasKeys_[index]; + (var hasValue, value) = this.impl_[index]; + return hasValue; } public bool TryGetValue(TIndexable key, out TValue value) - => TryGetValue(key.Index, out value); + => this.TryGetValue(key.Index, out value); IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); - public IEnumerator GetEnumerator() { - if (this.impl_ != null) { - for (var i = 0; i < this.Length; i++) { - if (this.hasKeys_[i]) { - yield return this.impl_[i]; - } - } - } - } + public IEnumerator GetEnumerator() + => this.impl_.Where(pair => pair.Item1) + .Select(pair => pair.Item2) + .GetEnumerator(); } } \ No newline at end of file diff --git a/FinModelUtility/Fin/Fin/src/math/BoneTransformManager.cs b/FinModelUtility/Fin/Fin/src/math/BoneTransformManager.cs index 2f2c56c44..0d3afa4af 100644 --- a/FinModelUtility/Fin/Fin/src/math/BoneTransformManager.cs +++ b/FinModelUtility/Fin/Fin/src/math/BoneTransformManager.cs @@ -7,6 +7,7 @@ using fin.math.matrix.four; using fin.math.rotations; using fin.model; +using fin.model.accessor; using fin.ui; namespace fin.math { diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor.cs index 72b18f00a..2aa379242 100644 --- a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor.cs +++ b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor.cs @@ -3,32 +3,7 @@ using fin.color; -namespace fin.model { - public interface IVertexTargeter { - void Target(IReadOnlyVertex vertex); - } - - public interface IVertexAccessor - : IVertexNormalAccessor, - IVertexTangentAccessor, - IVertexColorAccessor, - IVertexUvAccessor { } - - public interface IVertexNormalAccessor : IVertexTargeter, - IReadOnlyNormalVertex { } - - public interface IVertexTangentAccessor : IVertexTargeter, - IReadOnlyTangentVertex { } - - public interface IVertexColorAccessor : IVertexTargeter, - IReadOnlySingleColorVertex, - IReadOnlyMultiColorVertex { } - - public interface IVertexUvAccessor : IVertexTargeter, - IReadOnlySingleUvVertex, - IReadOnlyMultiUvVertex { } - - +namespace fin.model.accessor { /// /// Assumes all vertices are the same, consistent type. /// diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_MultiColorAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_MultiColorAccessor.cs index 366acb6ea..613a433ff 100644 --- a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_MultiColorAccessor.cs +++ b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_MultiColorAccessor.cs @@ -2,7 +2,7 @@ using fin.color; -namespace fin.model { +namespace fin.model.accessor { public partial class ConsistentVertexAccessor { private sealed class MultiColorAccessor : BAccessor, IVertexColorAccessor { private IReadOnlyMultiColorVertex colorVertex_; diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_NullColorAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_NullColorAccessor.cs index 093e7992e..292e3b330 100644 --- a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_NullColorAccessor.cs +++ b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_NullColorAccessor.cs @@ -2,7 +2,7 @@ using fin.color; -namespace fin.model { +namespace fin.model.accessor { public partial class ConsistentVertexAccessor { private sealed class NullColorAccessor : BAccessor, IVertexColorAccessor { diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_SingleColorAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_SingleColorAccessor.cs index 15a1c1a13..fcce41122 100644 --- a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_SingleColorAccessor.cs +++ b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Color_SingleColorAccessor.cs @@ -2,7 +2,7 @@ using fin.color; -namespace fin.model { +namespace fin.model.accessor { public partial class ConsistentVertexAccessor { private sealed class SingleColorAccessor : BAccessor, IVertexColorAccessor { private IReadOnlySingleColorVertex colorVertex_; diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Normal_NormalAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Normal_NormalAccessor.cs index 6bdebd95f..dc6b4d997 100644 --- a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Normal_NormalAccessor.cs +++ b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Normal_NormalAccessor.cs @@ -1,6 +1,6 @@ using System.Runtime.CompilerServices; -namespace fin.model { +namespace fin.model.accessor { public partial class ConsistentVertexAccessor { private sealed class NormalAccessor : BAccessor, IVertexNormalAccessor { private IReadOnlyNormalVertex normalVertex_; diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Normal_NullNormalAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Normal_NullNormalAccessor.cs index c6410f0ba..dd419968b 100644 --- a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Normal_NullNormalAccessor.cs +++ b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Normal_NullNormalAccessor.cs @@ -1,6 +1,6 @@ using System.Runtime.CompilerServices; -namespace fin.model { +namespace fin.model.accessor { public partial class ConsistentVertexAccessor { private sealed class NullNormalAccessor : BAccessor, IVertexNormalAccessor { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Tangent_NullTangentAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Tangent_NullTangentAccessor.cs index cdb35204b..46a59a8a2 100644 --- a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Tangent_NullTangentAccessor.cs +++ b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Tangent_NullTangentAccessor.cs @@ -1,6 +1,6 @@ using System.Runtime.CompilerServices; -namespace fin.model { +namespace fin.model.accessor { public partial class ConsistentVertexAccessor { private sealed class NullTangentAccessor : BAccessor, IVertexTangentAccessor { diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Tangent_TangentAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Tangent_TangentAccessor.cs index c3fb1dd72..7043842c8 100644 --- a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Tangent_TangentAccessor.cs +++ b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Tangent_TangentAccessor.cs @@ -1,6 +1,6 @@ using System.Runtime.CompilerServices; -namespace fin.model { +namespace fin.model.accessor { public partial class ConsistentVertexAccessor { private sealed class TangentAccessor : BAccessor, IVertexTangentAccessor { private IReadOnlyTangentVertex tangentVertex_; diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_MultiUvAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_MultiUvAccessor.cs index 964d9f5ad..99c71b57c 100644 --- a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_MultiUvAccessor.cs +++ b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_MultiUvAccessor.cs @@ -1,6 +1,6 @@ using System.Runtime.CompilerServices; -namespace fin.model { +namespace fin.model.accessor { public partial class ConsistentVertexAccessor { private sealed class MultiUvAccessor : BAccessor, IVertexUvAccessor { private IReadOnlyMultiUvVertex uvVertex_; diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_NullUvAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_NullUvAccessor.cs index 653ff31fc..1fdd810b4 100644 --- a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_NullUvAccessor.cs +++ b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_NullUvAccessor.cs @@ -1,7 +1,7 @@ using System.Runtime.CompilerServices; -namespace fin.model { - public partial class ConsistentVertexAccessor : IVertexAccessor { +namespace fin.model.accessor { + public partial class ConsistentVertexAccessor { private sealed class NullUvAccessor : BAccessor, IVertexUvAccessor { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_SingleUvAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_SingleUvAccessor.cs index b8609c873..84b5c000e 100644 --- a/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_SingleUvAccessor.cs +++ b/FinModelUtility/Fin/Fin/src/model/accessor/ConsistentVertexAccessor_Uv_SingleUvAccessor.cs @@ -1,6 +1,6 @@ using System.Runtime.CompilerServices; -namespace fin.model { +namespace fin.model.accessor { public partial class ConsistentVertexAccessor { private sealed class SingleUvAccessor : BAccessor, IVertexUvAccessor { private IReadOnlySingleUvVertex uvVertex_; diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/MaximalVertexAccessor.cs b/FinModelUtility/Fin/Fin/src/model/accessor/MaximalVertexAccessor.cs new file mode 100644 index 000000000..12a0d2c08 --- /dev/null +++ b/FinModelUtility/Fin/Fin/src/model/accessor/MaximalVertexAccessor.cs @@ -0,0 +1,59 @@ +using System.Runtime.CompilerServices; + +using fin.color; + +namespace fin.model.accessor { + public class MaximalVertexAccessor : IVertexAccessor { + private IReadOnlyVertex currentVertex_; + + public static IVertexAccessor GetAccessorForModel(IModel model) + => new MaximalVertexAccessor(); + + private MaximalVertexAccessor() { } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Target(IReadOnlyVertex vertex) { + this.currentVertex_ = vertex; + } + + public int Index => this.currentVertex_.Index; + + public IBoneWeights? BoneWeights => this.currentVertex_.BoneWeights; + public Position LocalPosition => this.currentVertex_.LocalPosition; + + public Normal? LocalNormal + => (this.currentVertex_ as IReadOnlyNormalVertex)?.LocalNormal; + + public Tangent? LocalTangent + => (this.currentVertex_ as IReadOnlyTangentVertex)?.LocalTangent; + + public int ColorCount + => (this.currentVertex_ as IReadOnlyMultiColorVertex)?.ColorCount ?? + (this.currentVertex_ is IReadOnlySingleColorVertex ? 1 : 0); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public IColor? GetColor() + => (this.currentVertex_ as IReadOnlyMultiColorVertex)?.GetColor(0) ?? + (this.currentVertex_ as IReadOnlySingleColorVertex)?.GetColor(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public IColor? GetColor(int colorIndex) + => (this.currentVertex_ as IReadOnlyMultiColorVertex)?.GetColor( + colorIndex) ?? + (this.currentVertex_ as IReadOnlySingleColorVertex)?.GetColor(); + + public int UvCount + => (this.currentVertex_ as IReadOnlyMultiUvVertex)?.UvCount ?? + (this.currentVertex_ is IReadOnlySingleUvVertex ? 1 : 0); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TexCoord? GetUv() + => (this.currentVertex_ as IReadOnlyMultiUvVertex)?.GetUv(0) ?? + (this.currentVertex_ as IReadOnlySingleUvVertex)?.GetUv(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TexCoord? GetUv(int uvIndex) + => (this.currentVertex_ as IReadOnlyMultiUvVertex)?.GetUv(uvIndex) ?? + (this.currentVertex_ as IReadOnlySingleUvVertex)?.GetUv(); + } +} \ No newline at end of file diff --git a/FinModelUtility/Fin/Fin/src/model/accessor/VertexAccessorInterfaces.cs b/FinModelUtility/Fin/Fin/src/model/accessor/VertexAccessorInterfaces.cs new file mode 100644 index 000000000..14fadef5d --- /dev/null +++ b/FinModelUtility/Fin/Fin/src/model/accessor/VertexAccessorInterfaces.cs @@ -0,0 +1,28 @@ +namespace fin.model.accessor { + public interface IVertexTargeter { + void Target(IReadOnlyVertex vertex); + } + + public interface IVertexAccessor + : IVertexNormalAccessor, + IVertexTangentAccessor, + IVertexColorAccessor, + IVertexUvAccessor { + static abstract IVertexAccessor GetAccessorForModel(IModel model); + } + + public interface IVertexNormalAccessor : IVertexTargeter, + IReadOnlyNormalVertex { } + + public interface IVertexTangentAccessor : IVertexTargeter, + IReadOnlyTangentVertex { } + + public interface IVertexColorAccessor : IVertexTargeter, + IReadOnlySingleColorVertex, + IReadOnlyMultiColorVertex { } + + public interface IVertexUvAccessor : IVertexTargeter, + IReadOnlySingleUvVertex, + IReadOnlyMultiUvVertex { } + +} diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/assimp/indirect/AssimpIndirectUvFixer.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/assimp/indirect/AssimpIndirectUvFixer.cs index 5e869b937..c33c7b418 100644 --- a/FinModelUtility/Fin/Fin/src/model/io/exporters/assimp/indirect/AssimpIndirectUvFixer.cs +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/assimp/indirect/AssimpIndirectUvFixer.cs @@ -4,6 +4,7 @@ using Assimp; using fin.color; +using fin.model.accessor; namespace fin.model.io.exporters.assimp.indirect { public class AssimpIndirectUvFixer { diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfBuilderUtil.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfBuilderUtil.cs new file mode 100644 index 000000000..bdbfdeb3e --- /dev/null +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfBuilderUtil.cs @@ -0,0 +1,41 @@ +using System; + +using SharpGLTF.Geometry.VertexTypes; + +namespace fin.model.io.exporters.gltf { + public static class GltfBuilderUtil { + public static Type GetGeometryType(bool hasNormals, bool hasTangents) + => hasNormals switch { + true when hasTangents => typeof(VertexPositionNormalTangent), + true => typeof(VertexPositionNormal), + _ => typeof(VertexPosition) + }; + + public static Type GetMaterialType(int colorCount, int uvCount) { + if (colorCount >= 2) { + return uvCount switch { + >= 2 => typeof(VertexColor2Texture2), + 1 => typeof(VertexColor2Texture1), + _ => typeof(VertexColor2) + }; + } + + if (uvCount >= 2) { + return colorCount == 1 + ? typeof(VertexColor1Texture2) + : typeof(VertexTexture2); + } + + return colorCount == 1 && uvCount == 1 + ? typeof(VertexColor1Texture1) + : typeof(VertexEmpty); + } + + public static Type GetSkinningType(int weightCount) + => weightCount switch { + > 4 => typeof(VertexJoints8), + > 0 => typeof(VertexJoints4), + _ => typeof(VertexEmpty) + }; + } +} \ No newline at end of file diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfExporter.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfExporter.cs index 64a73d01a..ff3a10a94 100644 --- a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfExporter.cs +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfExporter.cs @@ -57,8 +57,8 @@ public ModelRoot CreateModelRoot(IModel model, float scale) { new GltfMaterialBuilder().GetMaterialBuilders(model.MaterialManager); // Builds meshes. - var meshBuilder = new GltfMeshBuilder { UvIndices = this.UvIndices }; - var gltfMeshes = meshBuilder.BuildAndBindMesh( + var meshBuilder = new GltfSkinBuilder { UvIndices = this.UvIndices }; + var gltfMeshes = meshBuilder.AddSkin( modelRoot, model, scale, @@ -68,16 +68,20 @@ public ModelRoot CreateModelRoot(IModel model, float scale) { .Select( skinNodeAndBone => skinNodeAndBone.Item1) .ToArray(); - foreach (var gltfMesh in gltfMeshes) { + foreach (var (gltfMesh, hasJoints) in gltfMeshes) { // TODO: What causes this to happen??? if (gltfMesh == null) { continue; } - scene.CreateNode() - .WithSkinnedMesh(gltfMesh, - rootNode.WorldMatrix, - joints); + var sceneNode = scene.CreateNode(); + if (hasJoints) { + sceneNode.WithSkinnedMesh(gltfMesh, + rootNode.WorldMatrix, + joints); + } else { + sceneNode.WithMesh(gltfMesh); + } } return modelRoot; diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMeshBuilder.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMeshBuilder.cs deleted file mode 100644 index 22c672e49..000000000 --- a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMeshBuilder.cs +++ /dev/null @@ -1,204 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - -using fin.color; -using fin.data.indexable; -using fin.math; -using fin.util.enumerables; - -using SharpGLTF.Geometry; -using SharpGLTF.Geometry.VertexTypes; -using SharpGLTF.Materials; -using SharpGLTF.Schema2; -using SharpGLTF.Transforms; - -namespace fin.model.io.exporters.gltf { - using VERTEX = - VertexBuilder; - - public class GltfMeshBuilder { - public bool UvIndices { get; set; } - - public IList BuildAndBindMesh( - ModelRoot gltfModel, - IModel model, - float scale, - IDictionary finToTexCoordAndGltfMaterial) { - var skin = model.Skin; - var vertexAccessor = ConsistentVertexAccessor.GetAccessorForModel(model); - - var boneTransformManager = new BoneTransformManager(); - boneTransformManager.CalculateStaticMatricesForManualProjection(model); - - var boneToIndex = model.Skeleton.Skip(1).ToIndexByValueIndexableDictionary(); - - var nullMaterialBuilder = - new MaterialBuilder("null").WithDoubleSide(false) - .WithSpecularGlossiness(); - - var DEFAULT_SKINNING = SparseWeight8.Create((0, 1)); - var skinningByBoneWeights = - new IndexableDictionary(); - - var gltfMeshes = new List(); - foreach (var finMesh in skin.Meshes) { - var gltfMeshBuilder = VERTEX.CreateCompatibleMesh(finMesh.Name); - - foreach (var primitive in finMesh.Primitives) { - MaterialBuilder materialBuilder; - if (primitive.Material != null) { - materialBuilder = - finToTexCoordAndGltfMaterial[primitive.Material]; - } else { - materialBuilder = nullMaterialBuilder; - } - - var points = primitive.Vertices; - var pointsCount = points.Count; - var vertices = new VERTEX[pointsCount]; - - for (var p = 0; p < pointsCount; ++p) { - vertexAccessor.Target(points[p]); - var point = vertexAccessor; - - boneTransformManager.ProjectVertexPositionNormal( - point, - out var outPosition, - out var outNormal); - - var position = - new Vector3(outPosition.X * scale, - outPosition.Y * scale, - outPosition.Z * scale); - // TODO: Don't regenerate the skinning for each vertex, cache this somehow! - var vertexBuilder = VERTEX.Create(position); - - var boneWeights = point.BoneWeights; - if (boneWeights != null) { - if (!skinningByBoneWeights.TryGetValue(boneWeights, - out var skinning)) { - skinningByBoneWeights[boneWeights] = skinning = boneWeights - .Weights.Select( - boneWeight - => (boneToIndex[boneWeight.Bone], - boneWeight.Weight)) - .ToArray(); - } - - vertexBuilder = vertexBuilder.WithSkinning(skinning); - } else { - vertexBuilder = vertexBuilder.WithSkinning(DEFAULT_SKINNING); - } - - if (point.LocalNormal != null) { - var tangent = point.LocalTangent; - - if (tangent == null) { - vertexBuilder = vertexBuilder.WithGeometry( - position, - new Vector3(outNormal.X, outNormal.Y, outNormal.Z)); - } else { - vertexBuilder = vertexBuilder.WithGeometry( - position, - new Vector3(outNormal.X, outNormal.Y, outNormal.Z), - new Vector4(tangent.Value.X, - tangent.Value.Y, - tangent.Value.Z, - tangent.Value.W)); - } - } - - var finColor0 = point.GetColor(0); - var hasColor0 = finColor0 != null; - var assColor0 = hasColor0 - ? GltfMeshBuilder.FinToGltfColor_(finColor0) - : new Vector4(1, 1, 1, 1); - var finColor1 = point.GetColor(1); - var hasColor1 = finColor1 != null; - var assColor1 = hasColor1 - ? GltfMeshBuilder.FinToGltfColor_(finColor1) - : new Vector4(1, 1, 1, 1); - - var hasColor = hasColor0 || hasColor1; - - var hasUvs = vertexAccessor.UvCount > 0; - if (!this.UvIndices) { - if (hasUvs) { - var uv = vertexAccessor.GetUv(); - vertexBuilder = - vertexBuilder.WithMaterial(assColor0, - assColor1, - new Vector2( - uv.Value.U, - uv.Value.V)); - } else if (hasColor) { - vertexBuilder = - vertexBuilder.WithMaterial(assColor0, assColor1); - } - } else { - // Importing the color directly via Assimp doesn't work for some - // reason. - vertexBuilder = - vertexBuilder.WithMaterial(new Vector4(1, 1, 1, 1), - new Vector2( - hasUvs ? point.Index : -1, - hasColor ? point.Index : -1)); - } - - vertices[p] = vertexBuilder; - } - - switch (primitive.Type) { - case PrimitiveType.TRIANGLES: - case PrimitiveType.TRIANGLE_STRIP: - case PrimitiveType.TRIANGLE_FAN: { - var triangles = - gltfMeshBuilder.UsePrimitive(materialBuilder, 3); - - foreach (var (v1, v2, v3) in primitive - .GetOrderedTriangleVertexIndices() - .Select(i => vertices[i]) - .SeparateTriplets()) { - triangles.AddTriangle(v1, v2, v3); - } - - break; - } - case PrimitiveType.QUADS: { - var quads = gltfMeshBuilder.UsePrimitive(materialBuilder); - for (var v = 0; v < pointsCount; v += 4) { - quads.AddQuadrangle(vertices[v + 0], - vertices[v + 1], - vertices[v + 2], - vertices[v + 3]); - } - - break; - } - case PrimitiveType.POINTS: { - var pointPrimitive = - gltfMeshBuilder.UsePrimitive( - materialBuilder, - 1); - for (var v = 0; v < pointsCount; v += 4) { - pointPrimitive.AddPoint(vertices[v]); - } - - break; - } - default: throw new NotSupportedException(); - } - } - - gltfMeshes.Add(gltfModel.CreateMesh(gltfMeshBuilder)); - } - - return gltfMeshes; - } - - private static Vector4 FinToGltfColor_(IColor? color) - => new(color?.Rf ?? 1, color?.Gf ?? 0, color?.Bf ?? 1, color?.Af ?? 1); - } -} \ No newline at end of file diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMeshBuilderUtil.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMeshBuilderUtil.cs new file mode 100644 index 000000000..1afd0044b --- /dev/null +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMeshBuilderUtil.cs @@ -0,0 +1,31 @@ +using System.Linq; + +using SharpGLTF.Geometry; + +using IGltfMeshBuilder + = SharpGLTF.Geometry.IMeshBuilder; + +namespace fin.model.io.exporters.gltf { + public static class GltfMeshBuilderUtil { + private static readonly object?[] meshBuilderParams_ = [null]; + + public static IGltfMeshBuilder CreateMeshBuilder( + bool hasNormals, + bool hasTangents, + int colorCount, + int uvCount, + int weightCount) { + var geometryType + = GltfBuilderUtil.GetGeometryType(hasNormals, hasTangents); + var materialType = GltfBuilderUtil.GetMaterialType(colorCount, uvCount); + var skinningType = GltfBuilderUtil.GetSkinningType(weightCount); + + var meshBuilderType + = typeof(MeshBuilder<,,>).MakeGenericType( + [geometryType, materialType, skinningType]); + + var constructor = meshBuilderType.GetConstructors().Single(); + return (IGltfMeshBuilder) constructor.Invoke(meshBuilderParams_); + } + } +} \ No newline at end of file diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfSkinBuilder.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfSkinBuilder.cs new file mode 100644 index 000000000..e831b65e6 --- /dev/null +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfSkinBuilder.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using fin.data.indexable; +using fin.math; +using fin.model.accessor; +using fin.util.enumerables; + +using SharpGLTF.Geometry; +using SharpGLTF.Materials; +using SharpGLTF.Schema2; + +using IGltfMeshBuilder + = SharpGLTF.Geometry.IMeshBuilder; + +namespace fin.model.io.exporters.gltf { + public class GltfSkinBuilder { + public bool UvIndices { get; set; } + + public IList<(Mesh gltfMesh, bool hasJoints)> AddSkin( + ModelRoot gltfModel, + IModel model, + float scale, + IDictionary finToTexCoordAndGltfMaterial) { + var skin = model.Skin; + + var boneTransformManager = new BoneTransformManager(); + boneTransformManager.CalculateStaticMatricesForManualProjection(model); + + var boneToIndex + = model.Skeleton.Skip(1).ToIndexByValueIndexableDictionary(); + + var nullMaterialBuilder = + new MaterialBuilder("null").WithDoubleSide(false) + .WithSpecularGlossiness(); + + var vertexAccessor = MaximalVertexAccessor.GetAccessorForModel(model); + var vertexMap + = new IndexableDictionary( + skin.Vertices.Count); + + var gltfVertexBuilder = new GltfVertexBuilder(model, boneToIndex); + + var gltfMeshes = new List<(Mesh, bool)>(); + foreach (var finMesh in skin.Meshes) { + bool hasNormals = false; + bool hasTangents = false; + int colorCount = 0; + int uvCount = 0; + int weightCount = 0; + + var verticesInMesh = finMesh.Primitives.SelectMany(p => p.Vertices) + .Distinct() + .ToArray(); + foreach (var finVertex in verticesInMesh) { + vertexAccessor.Target(finVertex); + + hasNormals |= vertexAccessor.LocalNormal != null; + hasTangents |= vertexAccessor.LocalTangent != null; + colorCount = Math.Max(colorCount, vertexAccessor.ColorCount); + uvCount = Math.Max(uvCount, vertexAccessor.UvCount); + weightCount = Math.Max(weightCount, + vertexAccessor.BoneWeights?.Weights.Count ?? + 0); + } + + foreach (var finVertex in verticesInMesh) { + vertexAccessor.Target(finVertex); + + var vertexBuilder = gltfVertexBuilder.CreateVertexBuilder( + boneTransformManager, + vertexAccessor, + scale, + hasNormals, + hasTangents, + colorCount, + uvCount, + weightCount); + + vertexMap[finVertex] = vertexBuilder; + } + + IGltfMeshBuilder gltfMeshBuilder + = GltfMeshBuilderUtil.CreateMeshBuilder(hasNormals, + hasTangents, + colorCount, + uvCount, + weightCount); + gltfMeshBuilder.Name = finMesh.Name; + + foreach (var primitive in finMesh.Primitives) { + MaterialBuilder materialBuilder; + if (primitive.Material != null) { + materialBuilder = + finToTexCoordAndGltfMaterial[primitive.Material]; + } else { + materialBuilder = nullMaterialBuilder; + } + + var points = primitive.Vertices; + var pointsCount = points.Count; + + var vertices = primitive.Vertices.Select(vertex => vertexMap[vertex]) + .ToArray(); + + switch (primitive.Type) { + case PrimitiveType.TRIANGLES: + case PrimitiveType.TRIANGLE_STRIP: + case PrimitiveType.TRIANGLE_FAN: { + var triangles = + gltfMeshBuilder.UsePrimitive(materialBuilder, 3); + + foreach (var (v1, v2, v3) in primitive + .GetOrderedTriangleVertexIndices() + .Select(i => vertices[i]) + .SeparateTriplets()) { + triangles.AddTriangle(v1, v2, v3); + } + + break; + } + case PrimitiveType.QUADS: { + var quads = gltfMeshBuilder.UsePrimitive(materialBuilder); + for (var v = 0; v < pointsCount; v += 4) { + quads.AddQuadrangle(vertices[v + 0], + vertices[v + 1], + vertices[v + 2], + vertices[v + 3]); + } + + break; + } + case PrimitiveType.POINTS: { + var pointPrimitive = + gltfMeshBuilder.UsePrimitive( + materialBuilder, + 1); + for (var v = 0; v < pointsCount; v += 4) { + pointPrimitive.AddPoint(vertices[v]); + } + + break; + } + default: throw new NotSupportedException(); + } + } + + gltfMeshes.Add((gltfModel.CreateMesh(gltfMeshBuilder), + weightCount > 0)); + } + + return gltfMeshes; + } + } +} \ No newline at end of file diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfVertexBuilder.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfVertexBuilder.cs new file mode 100644 index 000000000..bf8136140 --- /dev/null +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfVertexBuilder.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; + +using fin.color; +using fin.data.indexable; +using fin.math; +using fin.model.accessor; + +using SharpGLTF.Geometry; +using SharpGLTF.Geometry.VertexTypes; + +namespace fin.model.io.exporters.gltf { + public class GltfVertexBuilder { + private static readonly (int, float)[] defaultSkinning_ = [(0, 1)]; + + private readonly IndexableDictionary + skinningByBoneWeights_ = new(); + + public GltfVertexBuilder(IModel model, + IIndexableDictionary boneToIndex) { + foreach (var boneWeights in model.Skin.BoneWeights) { + this.skinningByBoneWeights_[boneWeights] = + boneWeights.Weights.Select(boneWeight => ( + boneToIndex[boneWeight.Bone], + boneWeight.Weight)) + .ToArray(); + } + } + + public IVertexBuilder CreateVertexBuilder( + IReadOnlyBoneTransformManager boneTransformManager, + IVertexAccessor vertexAccessor, + float scale, + bool hasNormals, + bool hasTangents, + int colorCount, + int uvCount, + int weightCount) { + var geometryType + = GltfBuilderUtil.GetGeometryType(hasNormals, hasTangents); + var materialType = GltfBuilderUtil.GetMaterialType(colorCount, uvCount); + var skinningType = GltfBuilderUtil.GetSkinningType(weightCount); + + var vertexBuilderType + = typeof(VertexBuilder<,,>).MakeGenericType( + [geometryType, materialType, skinningType]); + + var vertexBuilder + = (IVertexBuilder) Activator.CreateInstance(vertexBuilderType); + + // Geo + { + boneTransformManager.ProjectVertexPositionNormalTangent( + vertexAccessor, + out var outPosition, + out var outNormal, + out var outTangent); + + var position = + new Vector3(outPosition.X * scale, + outPosition.Y * scale, + outPosition.Z * scale); + + if (hasNormals) { + var normal = new Vector3(outNormal.X, outNormal.Y, outNormal.Z); + + if (hasTangents) { + var tangent = new Vector4(outTangent.X, + outTangent.Y, + outTangent.Z, + outTangent.W) / + Math.Abs(outTangent.W); + + vertexBuilder.SetGeometry( + new VertexPositionNormalTangent( + position, + normal, + tangent)); + } else { + vertexBuilder.SetGeometry( + new VertexPositionNormal(position, normal)); + } + } else { + vertexBuilder.SetGeometry(new VertexPosition(position)); + } + } + + // Material + vertexBuilder.SetMaterial( + GetVertexMaterial_(vertexAccessor, colorCount, uvCount)); + + // Skinning + { + var boneWeights = vertexAccessor.BoneWeights; + var skinningArray = boneWeights == null + ? defaultSkinning_ + : this.skinningByBoneWeights_[boneWeights]; + + IVertexSkinning skinning = weightCount switch { + > 4 => new VertexJoints8(skinningArray), + > 0 => new VertexJoints4(skinningArray), + _ => new VertexEmpty() + }; + + vertexBuilder.SetSkinning(skinning); + } + + return vertexBuilder; + } + + private static IVertexMaterial GetVertexMaterial_( + IVertexAccessor vertexAccessor, + int colorCount, + int uvCount) { + var color0 = FinToGltfColor_(vertexAccessor.GetColor(0)); + var color1 = FinToGltfColor_(vertexAccessor.GetColor(1)); + + var uv0 = FinToGltfUv_(vertexAccessor.GetUv(0)); + var uv1 = FinToGltfUv_(vertexAccessor.GetUv(1)); + + if (colorCount >= 2) { + return uvCount switch { + >= 2 => new VertexColor2Texture2(color0, color1, uv0, uv1), + 1 => new VertexColor2Texture1(color0, color1, uv0), + _ => new VertexColor2(color0, color1) + }; + } + + if (uvCount >= 2) { + return colorCount == 1 + ? new VertexColor1Texture2(color0, uv0, uv1) + : new VertexTexture2(uv0, uv1); + } + + return colorCount == 1 && uvCount == 1 + ? new VertexColor1Texture1(color0, uv0) + : new VertexEmpty(); + } + + private static Vector4 FinToGltfColor_(IColor? color) + => new(color?.Rf ?? 1, color?.Gf ?? 1, color?.Bf ?? 1, color?.Af ?? 1); + + private static Vector2 FinToGltfUv_(TexCoord? uv) + => new(uv?.U ?? 0, uv?.V ?? 0); + } +} \ No newline at end of file diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfMeshBuilder.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfMeshBuilder.cs index 8a29bc2e6..9540e9a6e 100644 --- a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfMeshBuilder.cs +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfMeshBuilder.cs @@ -8,6 +8,7 @@ using fin.color; using fin.math; +using fin.model.accessor; using SharpGLTF.Schema2; diff --git a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/bfire/output/Shadowma.glb b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/bfire/output/Shadowma.glb index 7d190fdac..cc7a0a0e4 100644 Binary files a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/bfire/output/Shadowma.glb and b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/bfire/output/Shadowma.glb differ diff --git a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/gel_2p/output/Luigi_2p_gel.glb b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/gel_2p/output/Luigi_2p_gel.glb index 831e52fa7..e50373bd5 100644 Binary files a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/gel_2p/output/Luigi_2p_gel.glb and b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/gel_2p/output/Luigi_2p_gel.glb differ diff --git a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/opdn/output/op_mansion.glb b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/opdn/output/op_mansion.glb index 201a4a366..f06be7eb1 100644 Binary files a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/opdn/output/op_mansion.glb and b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/opdn/output/op_mansion.glb differ diff --git a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/optdemo1/output/GBH_Dr_Oyama.glb b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/optdemo1/output/GBH_Dr_Oyama.glb index 00a04726e..4acc58585 100644 Binary files a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/optdemo1/output/GBH_Dr_Oyama.glb and b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/luigis_mansion_3d/optdemo1/output/GBH_Dr_Oyama.glb differ diff --git a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/majoras_mask_3d/zelda_cow/output/cow.glb b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/majoras_mask_3d/zelda_cow/output/cow.glb index 6c05e5e5f..c959788bc 100644 Binary files a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/majoras_mask_3d/zelda_cow/output/cow.glb and b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/majoras_mask_3d/zelda_cow/output/cow.glb differ diff --git a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/ocarina_of_time_3d/zelda_cow/output/cow.glb b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/ocarina_of_time_3d/zelda_cow/output/cow.glb index 3dcb0c9c6..54c5dd337 100644 Binary files a/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/ocarina_of_time_3d/zelda_cow/output/cow.glb and b/FinModelUtility/Formats/Cmb/Cmb Tests/goldens/cmb/ocarina_of_time_3d/zelda_cow/output/cow.glb differ diff --git a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyAndruf/output/TyAndruf.glb b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyAndruf/output/TyAndruf.glb index 3664c53d5..6d85086b1 100644 Binary files a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyAndruf/output/TyAndruf.glb and b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyAndruf/output/TyAndruf.glb differ diff --git a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyBField/output/TyBField.glb b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyBField/output/TyBField.glb index 91448b735..d2b769d70 100644 Binary files a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyBField/output/TyBField.glb and b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyBField/output/TyBField.glb differ diff --git a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyBancho/output/TyBancho.glb b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyBancho/output/TyBancho.glb index 600479792..eb5142342 100644 Binary files a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyBancho/output/TyBancho.glb and b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyBancho/output/TyBancho.glb differ diff --git a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyDaisy/output/TyDaisy.glb b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyDaisy/output/TyDaisy.glb index 92bd16467..fec11f10a 100644 Binary files a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyDaisy/output/TyDaisy.glb and b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyDaisy/output/TyDaisy.glb differ diff --git a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyGmCube/output/TyGmCube.glb b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyGmCube/output/TyGmCube.glb index fa7363d66..42c35aa14 100644 Binary files a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyGmCube/output/TyGmCube.glb and b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyGmCube/output/TyGmCube.glb differ diff --git a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyGwfeld/output/TyGwfeld.glb b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyGwfeld/output/TyGwfeld.glb index 8591393f6..ee285e0dd 100644 Binary files a/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyGwfeld/output/TyGwfeld.glb and b/FinModelUtility/Formats/Dat/Dat Tests/goldens/super_smash_bros_melee/TyGwfeld/output/TyGwfeld.glb differ diff --git a/FinModelUtility/Formats/Glo/Glo Tests/goldens/at1/output/at1.glb b/FinModelUtility/Formats/Glo/Glo Tests/goldens/at1/output/at1.glb index ea324a106..285f203ad 100644 Binary files a/FinModelUtility/Formats/Glo/Glo Tests/goldens/at1/output/at1.glb and b/FinModelUtility/Formats/Glo/Glo Tests/goldens/at1/output/at1.glb differ diff --git a/FinModelUtility/Formats/Glo/Glo Tests/goldens/chuck/output/CHUCK.glb b/FinModelUtility/Formats/Glo/Glo Tests/goldens/chuck/output/CHUCK.glb index 5614a8ab4..20980d1d3 100644 Binary files a/FinModelUtility/Formats/Glo/Glo Tests/goldens/chuck/output/CHUCK.glb and b/FinModelUtility/Formats/Glo/Glo Tests/goldens/chuck/output/CHUCK.glb differ diff --git a/FinModelUtility/Formats/Glo/Glo Tests/goldens/joff/output/joff.glb b/FinModelUtility/Formats/Glo/Glo Tests/goldens/joff/output/joff.glb index 1536ab06f..f7e2137f5 100644 Binary files a/FinModelUtility/Formats/Glo/Glo Tests/goldens/joff/output/joff.glb and b/FinModelUtility/Formats/Glo/Glo Tests/goldens/joff/output/joff.glb differ diff --git a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/mario_kart_double_dash_babyluigi_course/output/babyluigi_course.glb b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/mario_kart_double_dash_babyluigi_course/output/babyluigi_course.glb index 3bd934254..faad2a679 100644 Binary files a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/mario_kart_double_dash_babyluigi_course/output/babyluigi_course.glb and b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/mario_kart_double_dash_babyluigi_course/output/babyluigi_course.glb differ diff --git a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_Armor/output/enemy.glb b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_Armor/output/enemy.glb index 0b92ba8c6..e3084fb93 100644 Binary files a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_Armor/output/enemy.glb and b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_Armor/output/enemy.glb differ diff --git a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_BigFoot/output/enemy.glb b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_BigFoot/output/enemy.glb index 87e98f7d1..068ab62cf 100644 Binary files a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_BigFoot/output/enemy.glb and b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_BigFoot/output/enemy.glb differ diff --git a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_Chappy/output/enemy.glb b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_Chappy/output/enemy.glb index 3705b6ea4..25219eff8 100644 Binary files a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_Chappy/output/enemy.glb and b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_Chappy/output/enemy.glb differ diff --git a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_flower_red/output/flower_red.glb b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_flower_red/output/flower_red.glb index 73cd13590..2ac5bf2ad 100644 Binary files a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_flower_red/output/flower_red.glb and b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_flower_red/output/flower_red.glb differ diff --git a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_forest/output/model.glb b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_forest/output/model.glb index a5f599212..66647f9c9 100644 Binary files a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_forest/output/model.glb and b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_forest/output/model.glb differ diff --git a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_ufo/output/ufo.glb b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_ufo/output/ufo.glb index 6c0719c4e..31bc7af5c 100644 Binary files a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_ufo/output/ufo.glb and b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/pikmin_2_ufo/output/ufo.glb differ diff --git a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_bianco0_map/output/map.glb b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_bianco0_map/output/map.glb index 824519ff2..5e0277840 100644 Binary files a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_bianco0_map/output/map.glb and b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_bianco0_map/output/map.glb differ diff --git a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_fisha/output/fisha.glb b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_fisha/output/fisha.glb index 7abf054b1..899ff2609 100644 Binary files a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_fisha/output/fisha.glb and b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_fisha/output/fisha.glb differ diff --git a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_kinopio/output/kinopio_body.glb b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_kinopio/output/kinopio_body.glb index 0fb45d9cc..d45afd5b2 100644 Binary files a/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_kinopio/output/kinopio_body.glb and b/FinModelUtility/Formats/JSystem/JSystem Tests/goldens/super_mario_sunshine_kinopio/output/kinopio_body.glb differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/cave/output/cave.glb b/FinModelUtility/Formats/Mod/Mod Tests/goldens/cave/output/cave.glb index fd4274a61..c0833c417 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/cave/output/cave.glb and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/cave/output/cave.glb differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/chappy/output/chappy.glb b/FinModelUtility/Formats/Mod/Mod Tests/goldens/chappy/output/chappy.glb index 06a4d5723..ee36bc248 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/chappy/output/chappy.glb and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/chappy/output/chappy.glb differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/kabekuiC/output/kabekuiC.glb b/FinModelUtility/Formats/Mod/Mod Tests/goldens/kabekuiC/output/kabekuiC.glb index f3d195eb3..c9d39f0ca 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/kabekuiC/output/kabekuiC.glb and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/kabekuiC/output/kabekuiC.glb differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king.glb b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king.glb index 085749685..bbd7e5ae9 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king.glb and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king.glb differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_0.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_0.png index e2a2b7c1b..f2755e9b1 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_0.png and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_0.png differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_1.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_1.png index f2755e9b1..e399b7cac 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_1.png and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_1.png differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_10.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_10.png index cdd517eb8..80a57be90 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_10.png and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_10.png differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_11.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_11.png deleted file mode 100644 index 3026bbc72..000000000 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_11.png and /dev/null differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_12.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_12.png deleted file mode 100644 index 80a57be90..000000000 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_12.png and /dev/null differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_2.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_2.png index e399b7cac..39710323b 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_2.png and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_2.png differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_3.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_3.png index 39710323b..6fd804d44 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_3.png and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_3.png differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_4.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_4.png index 6fd804d44..eedefd1c9 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_4.png and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_4.png differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_5.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_5.png index eedefd1c9..1dfe965f3 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_5.png and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_5.png differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_6.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_6.png index 1dfe965f3..4b5afeb29 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_6.png and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_6.png differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_7.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_7.png index 4b5afeb29..d265740d8 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_7.png and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_7.png differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_8.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_8.png index d265740d8..7070fefaa 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_8.png and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_8.png differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_9.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_9.png index 7070fefaa..3026bbc72 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_9.png and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/king/output/king_9.png differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/kogane/output/kogane.glb b/FinModelUtility/Formats/Mod/Mod Tests/goldens/kogane/output/kogane.glb index 688faca7e..86fac03e6 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/kogane/output/kogane.glb and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/kogane/output/kogane.glb differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/kogane/output/kogane_1.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/kogane/output/kogane.png similarity index 100% rename from FinModelUtility/Formats/Mod/Mod Tests/goldens/kogane/output/kogane_1.png rename to FinModelUtility/Formats/Mod/Mod Tests/goldens/kogane/output/kogane.png diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/kogane/output/kogane_0.png b/FinModelUtility/Formats/Mod/Mod Tests/goldens/kogane/output/kogane_0.png deleted file mode 100644 index 7e382339e..000000000 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/kogane/output/kogane_0.png and /dev/null differ diff --git a/FinModelUtility/Formats/Mod/Mod Tests/goldens/snake/output/snake.glb b/FinModelUtility/Formats/Mod/Mod Tests/goldens/snake/output/snake.glb index 9a8c2ad83..a13c62de8 100644 Binary files a/FinModelUtility/Formats/Mod/Mod Tests/goldens/snake/output/snake.glb and b/FinModelUtility/Formats/Mod/Mod Tests/goldens/snake/output/snake.glb differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/modl/battalion_wars_1/TVET/output/TVET.glb b/FinModelUtility/Formats/Modl/Modl Tests/goldens/modl/battalion_wars_1/TVET/output/TVET.glb index cd1ba9eb0..be74afc0f 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/modl/battalion_wars_1/TVET/output/TVET.glb and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/modl/battalion_wars_1/TVET/output/TVET.glb differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/modl/battalion_wars_2/TVET/output/LG_HI_LOD.glb b/FinModelUtility/Formats/Modl/Modl Tests/goldens/modl/battalion_wars_2/TVET/output/LG_HI_LOD.glb index be98f98a8..43c3a5db6 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/modl/battalion_wars_2/TVET/output/LG_HI_LOD.glb and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/modl/battalion_wars_2/TVET/output/LG_HI_LOD.glb differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus.glb b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus.glb index 807642509..5dce66f60 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus.glb and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus.glb differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_0.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_0.png index d42973ba0..d272c1900 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_0.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_0.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_1.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_1.png index a04d42528..f5abd5c97 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_1.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_1.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_2.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_2.png index f5abd5c97..d42973ba0 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_2.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_2.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_3.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_3.png index d272c1900..496ba9ea9 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_3.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_3.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_4.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_4.png index ce0481c90..a04d42528 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_4.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_4.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_5.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_5.png index 496ba9ea9..ce0481c90 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_5.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Bonus/output/C1_Bonus_5.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet.glb b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet.glb index 073c69b26..22f946696 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet.glb and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet.glb differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_0.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_0.png index 601ab898f..b94399b8e 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_0.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_0.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_2.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_2.png index a04d42528..aafd5f2c8 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_2.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_2.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_4.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_4.png index aafd5f2c8..a04d42528 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_4.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_4.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_5.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_5.png index f5abd5c97..2ed5f422b 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_5.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_5.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_6.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_6.png index b94399b8e..601ab898f 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_6.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_6.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_7.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_7.png index 2ed5f422b..f5abd5c97 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_7.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_1/C1_Gauntlet/output/C1_Gauntlet_7.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1.glb b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1.glb index 1a3a6cd7f..ccae7108f 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1.glb and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1.glb differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_0.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_0.png index abdbdc174..796e25189 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_0.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_0.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_1.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_1.png index 796e25189..bc5524f21 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_1.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_1.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_2.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_2.png index 6a465b4ee..7bb6cacd8 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_2.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_2.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_3.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_3.png index 3c0a8fcbb..abdbdc174 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_3.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_3.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_4.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_4.png index bc5524f21..3c0a8fcbb 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_4.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_4.png differ diff --git a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_5.png b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_5.png index 7bb6cacd8..6a465b4ee 100644 Binary files a/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_5.png and b/FinModelUtility/Formats/Modl/Modl Tests/goldens/out/battalion_wars_2/MP1_L/output/MP1_5.png differ