diff --git a/FinModelUtility/Fin/Fin Tests/math/matrix/four/Matrix4x4Tests.cs b/FinModelUtility/Fin/Fin Tests/math/matrix/four/Matrix4x4Tests.cs index 1571facbe..22d005233 100644 --- a/FinModelUtility/Fin/Fin Tests/math/matrix/four/Matrix4x4Tests.cs +++ b/FinModelUtility/Fin/Fin Tests/math/matrix/four/Matrix4x4Tests.cs @@ -1,4 +1,6 @@ -using fin.math.floats; +using System; + +using fin.math.floats; using fin.util.asserts; using NUnit.Framework; @@ -17,7 +19,7 @@ public void TestFloatArrayConstructor() { } } - var mat = new FinMatrix4x4(values); + var mat = new FinMatrix4x4(values.AsSpan()); for (var r = 0; r < FinMatrix4x4.ROW_COUNT; ++r) { for (var c = 0; c < FinMatrix4x4.COLUMN_COUNT; ++c) { @@ -36,7 +38,7 @@ public void TestDoubleArrayConstructor() { } } - var mat = new FinMatrix4x4(values); + var mat = new FinMatrix4x4(values.AsSpan()); for (var r = 0; r < FinMatrix4x4.ROW_COUNT; ++r) { for (var c = 0; c < FinMatrix4x4.COLUMN_COUNT; ++c) { @@ -55,7 +57,7 @@ public void TestCopyConstructor() { } } - var first = new FinMatrix4x4(values); + var first = new FinMatrix4x4(values.AsSpan()); var second = new FinMatrix4x4(first); for (var r = 0; r < FinMatrix4x4.ROW_COUNT; ++r) { diff --git a/FinModelUtility/Fin/Fin/src/math/matrix/four/FinMatrix4x4.cs b/FinModelUtility/Fin/Fin/src/math/matrix/four/FinMatrix4x4.cs index 45218e407..9577d5c04 100644 --- a/FinModelUtility/Fin/Fin/src/math/matrix/four/FinMatrix4x4.cs +++ b/FinModelUtility/Fin/Fin/src/math/matrix/four/FinMatrix4x4.cs @@ -41,6 +41,20 @@ public FinMatrix4x4(IReadOnlyList data) { } } + public FinMatrix4x4(ReadOnlySpan data) { + Asserts.Equal(CELL_COUNT, data.Length); + for (var i = 0; i < CELL_COUNT; ++i) { + this[i] = data[i]; + } + } + + public FinMatrix4x4(ReadOnlySpan data) { + Asserts.Equal(CELL_COUNT, data.Length); + for (var i = 0; i < CELL_COUNT; ++i) { + this[i] = (float) data[i]; + } + } + public FinMatrix4x4(IReadOnlyFinMatrix4x4 other) => this.CopyFrom(other); public FinMatrix4x4(SystemMatrix other) => this.CopyFrom(other); 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 6b4afd3ad..3664c53d5 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 0bab1d2e1..91448b735 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 312ad9527..600479792 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 252df4cbb..92bd16467 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 25cef2553..fa7363d66 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 c67a46965..8591393f6 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/Dat/Dat/src/api/DatModelImporter.cs b/FinModelUtility/Formats/Dat/Dat/src/api/DatModelImporter.cs index 731b2d854..8409f7aa8 100644 --- a/FinModelUtility/Formats/Dat/Dat/src/api/DatModelImporter.cs +++ b/FinModelUtility/Formats/Dat/Dat/src/api/DatModelImporter.cs @@ -35,35 +35,42 @@ public unsafe IModel ImportModel(DatModelFileBundle modelFileBundle) { var jObjByOffset = dat.JObjByOffset; var finBoneByJObj = new Dictionary(); var boneWeightsByJObj = new Dictionary(); + var inverseBindMatrixByJObj = + new Dictionary(); var boneQueue = new Queue<(IBone finParentBone, JObj datBone)>(); foreach (var datRootBone in dat.RootJObjs) { boneQueue.Enqueue((finModel.Skeleton.Root, datRootBone)); } + Span inverseBindMatrixBuffer = stackalloc float[4 * 4]; while (boneQueue.Count > 0) { var (finParentBone, jObj) = boneQueue.Dequeue(); - var datBoneData = jObj.Data; - var finBone = - finParentBone.AddChild(datBoneData.Position.X, - datBoneData.Position.Y, - datBoneData.Position.Z) + finParentBone.AddChild(jObj.Position.X, + jObj.Position.Y, + jObj.Position.Z) .SetLocalRotationRadians( - datBoneData.RotationRadians.X, - datBoneData.RotationRadians.Y, - datBoneData.RotationRadians.Z) + jObj.RotationRadians.X, + jObj.RotationRadians.Y, + jObj.RotationRadians.Z) .SetLocalScale( - datBoneData.Scale.X, - datBoneData.Scale.Y, - datBoneData.Scale.Z); + jObj.Scale.X, + jObj.Scale.Y, + jObj.Scale.Z); finBone.Name = jObj.Name; finBoneByJObj[jObj] = finBone; boneWeightsByJObj[jObj] = finSkin.GetOrCreateBoneWeights(VertexSpace.BONE, finBone); - foreach (var datChildBone in jObj.Children) { + var inverseBindMatrixValues = jObj.InverseBindMatrixValues; + inverseBindMatrixValues.CopyTo(inverseBindMatrixBuffer); + inverseBindMatrixBuffer[15] = 1; + inverseBindMatrixByJObj[jObj] = + new FinMatrix4x4(inverseBindMatrixBuffer).TransposeInPlace(); + + foreach (var datChildBone in jObj.GetChildren()) { boneQueue.Enqueue((finBone, datChildBone)); } } @@ -304,7 +311,7 @@ public unsafe IModel ImportModel(DatModelFileBundle modelFileBundle) { jObjByOffset[pObjWeight.JObjOffset]; return new BoneWeight( finBoneByJObj[jObj], - jObj.InverseBindMatrix, + inverseBindMatrixByJObj[jObj], pObjWeight.Weight ); }) diff --git a/FinModelUtility/Formats/Dat/Dat/src/schema/Dat.cs b/FinModelUtility/Formats/Dat/Dat/src/schema/Dat.cs index 06fc3e1bf..78f8a6905 100644 --- a/FinModelUtility/Formats/Dat/Dat/src/schema/Dat.cs +++ b/FinModelUtility/Formats/Dat/Dat/src/schema/Dat.cs @@ -1,4 +1,5 @@ -using fin.math.matrix.four; +using fin.data.queues; +using fin.math.matrix.four; using fin.util.asserts; using fin.util.enumerables; using fin.util.hex; @@ -31,20 +32,13 @@ public class Dat : IBinaryDeserializable { public List RootJObjs { get; } = new(); - private Dictionary jObjByOffset_ = new(); + private readonly Dictionary jObjByOffset_ = new(); public IReadOnlyDictionary JObjByOffset => this.jObjByOffset_; public IEnumerable JObjs => this.RootJObjs.SelectMany( - this.EnumerateSelfAndChildrenWithinJObj_); - - private IEnumerable EnumerateSelfAndChildrenWithinJObj_(JObj jObj) - => jObj.Yield() - .Concat(jObj.Children.SelectMany( - this.EnumerateSelfAndChildrenWithinJObj_)); + DatNodeExtensions.GetSelfAndChildrenAndSiblings); public void Read(IBinaryReader br) { - this.VertexDescriptorValue = (uint) 0; - var fileHeader = br.ReadNew(); Asserts.Equal(br.Length, fileHeader.FileSize); @@ -94,96 +88,40 @@ public void Read(IBinaryReader br) { } this.ReadJObs_(br); - this.ReadDObjs_(br); this.ReadNames_(br); } - private bool AssertNullOrValidPointer_(uint pointer) { - if (pointer == 0) { - return false; - } - - if (!this.validOffsets_.Contains(pointer)) { - ; - } - - Asserts.True(this.validOffsets_.Contains(pointer)); - return true; - } - - public uint VertexDescriptorValue { get; set; } - private void ReadJObs_(IBinaryReader br) { - var jObjQueue = - new Queue<( - RootNode rootNode, - JObj? parentJObj, - uint jObjDataOffset - )>(); - - foreach (var rootNode in this.rootNodes_.Where( - rootNode => rootNode.Type == RootNodeType.JObj)) { - jObjQueue.Enqueue((rootNode, null, rootNode.Data.DataOffset)); - } - br.Position = this.dataBlockOffset_; br.PushLocalSpace(); - this.RootJObjs.Clear(); - while (jObjQueue.Count > 0) { - var (rootNode, parentJObj, jObjDataOffset) = jObjQueue.Dequeue(); - - var jObj = new JObj(); - var jObjData = jObj.Data; + var jObjQueue = new FinTuple2Queue(); - this.jObjByOffset_[jObjDataOffset] = jObj; - jObj.Name = jObjDataOffset.ToHex(); - - if (parentJObj == null) { - this.RootJObjs.Add(jObj); - } else { - parentJObj.Children.Add(jObj); - } - - br.Position = jObjDataOffset; - jObjData.Read(br); - - if (jObjData.InverseBindMatrixOffset != 0) { - br.Position = jObjData.InverseBindMatrixOffset; - - var inverseBindMatrixValues = new float[4 * 4]; - br.ReadSingles(inverseBindMatrixValues.AsSpan(0, 4 * 3)); - inverseBindMatrixValues[15] = 1; - jObj.InverseBindMatrix = - new FinMatrix4x4(inverseBindMatrixValues).TransposeInPlace(); - } + this.RootJObjs.Clear(); + foreach (var rootNode in this.rootNodes_.Where( + rootNode => rootNode.Type == RootNodeType.JObj)) { + var jObjOffset = rootNode.Data.DataOffset; + br.Position = jObjOffset; - var firstChildOffset = jObj.Data.FirstChildBoneOffset; - if (this.AssertNullOrValidPointer_(firstChildOffset)) { - jObjQueue.Enqueue((rootNode, jObj, firstChildOffset)); - } + var jObj = br.ReadNew(); + this.RootJObjs.Add(jObj); - var nextSiblingOffset = jObj.Data.NextSiblingBoneOffset; - if (this.AssertNullOrValidPointer_(nextSiblingOffset)) { - jObjQueue.Enqueue((rootNode, parentJObj, nextSiblingOffset)); - } + jObjQueue.Enqueue((jObjOffset, jObj)); } br.PopLocalSpace(); - } - private void ReadDObjs_(IBinaryReader br) { - br.Position = this.dataBlockOffset_; - br.PushLocalSpace(); + while (jObjQueue.TryDequeue(out var jObjOffset, out var jObj)) { + this.jObjByOffset_[jObjOffset] = jObj; - foreach (var jObj in this.JObjs) { - if (jObj.Data.FirstDObjOffset != 0) { - br.Position = jObj.Data.FirstDObjOffset; - jObj.FirstDObj = br.ReadNew(); + if (jObj.FirstChild != null) { + jObjQueue.Enqueue((jObj.FirstChildBoneOffset, jObj.FirstChild)); } - } - br.PopLocalSpace(); + if (jObj.NextSibling != null) { + jObjQueue.Enqueue((jObj.NextSiblingBoneOffset, jObj.NextSibling)); + } + } } private void ReadNames_(IBinaryReader br) { @@ -191,7 +129,7 @@ private void ReadNames_(IBinaryReader br) { br.PushLocalSpace(); foreach (var jObj in this.JObjs) { - var jObjStringOffset = jObj.Data.StringOffset; + var jObjStringOffset = jObj.StringOffset; if (jObjStringOffset != 0) { br.Position = jObjStringOffset; jObj.Name = br.ReadStringNT(); diff --git a/FinModelUtility/Formats/Dat/Dat/src/schema/DatNodeInterfaces.cs b/FinModelUtility/Formats/Dat/Dat/src/schema/DatNodeInterfaces.cs index a9a20cba0..d88381eca 100644 --- a/FinModelUtility/Formats/Dat/Dat/src/schema/DatNodeInterfaces.cs +++ b/FinModelUtility/Formats/Dat/Dat/src/schema/DatNodeInterfaces.cs @@ -47,5 +47,9 @@ public static IEnumerable GetSelfAndChildrenAndSiblings( } } } + + public static IEnumerable GetChildren(this TNode? root) + where TNode : IDatTreeNode + => root?.FirstChild?.GetSelfAndSiblings() ?? Enumerable.Empty(); } } \ No newline at end of file diff --git a/FinModelUtility/Formats/Dat/Dat/src/schema/JObj.cs b/FinModelUtility/Formats/Dat/Dat/src/schema/JObj.cs index 73810a5d4..7ad2fb83f 100644 --- a/FinModelUtility/Formats/Dat/Dat/src/schema/JObj.cs +++ b/FinModelUtility/Formats/Dat/Dat/src/schema/JObj.cs @@ -3,6 +3,7 @@ using fin.schema.vector; using schema.binary; +using schema.binary.attributes; namespace dat.schema { [Flags] @@ -51,8 +52,11 @@ public enum JObjFlags : uint { ROOT_TEXEDGE = 1 << 30, } + /// + /// Joint object. + /// [BinarySchema] - public partial class JObjData : IBinaryConvertible { + public partial class JObj : IDatTreeNode, IBinaryDeserializable { public uint StringOffset { get; set; } public JObjFlags Flags { get; set; } public uint FirstChildBoneOffset { get; set; } @@ -62,25 +66,30 @@ public partial class JObjData : IBinaryConvertible { public Vector3f Scale { get; } = new(); public Vector3f Position { get; } = new(); public uint InverseBindMatrixOffset { get; set; } + [Unknown] public uint UnknownPointer { get; set; } - } - /// - /// Joint object. - /// - public class JObj { - public JObjData Data { get; } = new(); + [Ignore] public string? Name { get; set; } + [RAtPositionOrNull(nameof(FirstChildBoneOffset))] + public JObj? FirstChild { get; set; } + + [RAtPositionOrNull(nameof(NextSiblingBoneOffset))] + public JObj? NextSibling { get; set; } + + [RAtPositionOrNull(nameof(FirstDObjOffset))] public DObj? FirstDObj { get; set; } - public IEnumerable DObjs => this.FirstDObj.GetSelfAndSiblings(); + [RAtPositionOrNull(nameof(InverseBindMatrixOffset))] + [SequenceLengthSource(4 * 3)] + public float[]? InverseBindMatrixValues { get; set; } - public List Children { get; } = new(); - public IFinMatrix4x4? InverseBindMatrix { get; set; } + [Ignore] + public IEnumerable DObjs => this.FirstDObj.GetSelfAndSiblings(); public override string? ToString() => this.Name; } diff --git a/FinModelUtility/Formats/Modl/Modl/src/schema/xml/LevelXmlParser.cs b/FinModelUtility/Formats/Modl/Modl/src/schema/xml/LevelXmlParser.cs index 10a401084..9faac77d6 100644 --- a/FinModelUtility/Formats/Modl/Modl/src/schema/xml/LevelXmlParser.cs +++ b/FinModelUtility/Formats/Modl/Modl/src/schema/xml/LevelXmlParser.cs @@ -238,7 +238,7 @@ private IDictionary ParseObjectMap_( isUsefulNode = true; node ??= new LevelObject { Id = objId }; - node.Matrix = new FinMatrix4x4(floats); + node.Matrix = new FinMatrix4x4(floats.AsSpan()); } else if (objectType is "cNodeHierarchyResource" && childNameAttribute is "mName") { isUsefulNode = true; diff --git a/FinModelUtility/Formats/Visceral/Visceral/src/api/GeoModelImporter.cs b/FinModelUtility/Formats/Visceral/Visceral/src/api/GeoModelImporter.cs index 850cedcc7..0badbad6e 100644 --- a/FinModelUtility/Formats/Visceral/Visceral/src/api/GeoModelImporter.cs +++ b/FinModelUtility/Formats/Visceral/Visceral/src/api/GeoModelImporter.cs @@ -197,6 +197,6 @@ private void AddGeoFileToModel_( } public IFinMatrix4x4 GetMatrixFromBone_(Matrix4x4f matrix) - => new FinMatrix4x4(matrix.Values).InvertInPlace(); + => new FinMatrix4x4(matrix.Values.AsSpan()).InvertInPlace(); } } \ No newline at end of file