From c7f3e7e63d5aaf1949a8bb3903c657f09133024a Mon Sep 17 00:00:00 2001 From: MeltyPlayer Date: Sat, 4 Nov 2023 17:11:33 -0500 Subject: [PATCH] Simplified how JObj is read by using Schema. --- .../math/matrix/four/Matrix4x4Tests.cs | 10 +- .../Fin/src/math/matrix/four/FinMatrix4x4.cs | 14 +++ .../TyAndruf/output/TyAndruf.glb | Bin 610280 -> 610224 bytes .../TyBField/output/TyBField.glb | Bin 525980 -> 525872 bytes .../TyBancho/output/TyBancho.glb | Bin 56432 -> 56328 bytes .../TyDaisy/output/TyDaisy.glb | Bin 1066424 -> 1066372 bytes .../TyGmCube/output/TyGmCube.glb | Bin 545384 -> 545348 bytes .../TyGwfeld/output/TyGwfeld.glb | Bin 289612 -> 289576 bytes .../Dat/Dat/src/api/DatModelImporter.cs | 33 +++--- .../Formats/Dat/Dat/src/schema/Dat.cs | 106 ++++-------------- .../Dat/Dat/src/schema/DatNodeInterfaces.cs | 4 + .../Formats/Dat/Dat/src/schema/JObj.cs | 29 +++-- .../Modl/src/schema/xml/LevelXmlParser.cs | 2 +- .../Visceral/src/api/GeoModelImporter.cs | 2 +- 14 files changed, 87 insertions(+), 113 deletions(-) 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 6b4afd3adc50e2cbbe7e451f09ecf3b37cc4e506..3664c53d5d69e27f804c495145fb589a25e110ec 100644 GIT binary patch delta 189 zcmaDcUv?ODdUc!Hg%BO!{C(P8F1Kppr=uRpbIp3eJElhBIJN+hOWW*`Q!S%H`hh}pM)spt4|9spOIKw1C* delta 246 zcmdlmU-iX&Ro?WR5H}_U28I{@oD2^dd0TlIxAHQ*DmTkZ%uQ9YQZg_wFmZ7I#RRd?h6~h@YsqIPCOi?UM3JUFe>Y0F;8Hibcm=%cGfS7&z Jo_dZi=K%r7OY8su 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 0bab1d2e11e6542c81e83c29ce74f77c7e263cd1..91448b7356d90b98a64a5eba91573d4db8b3d7e6 100644 GIT binary patch delta 193 zcmbQ!tFWO*fj2!T#Epr8fx&={gQ2F8cPlUBk8p|PjLe*rqSQPkt7sz~V;vJ6QysI| zTAk|YjuDKe)14w1P0)$HNJcwmb0f>?=OY5eftU%1nSq!Eh*^P{ZF^@lyYOlNc4jv= delta 317 zcmdncqcEpefj2!T#Epr8fng3C2g8d--mSchKf-PD5_40PtdtB43=ADzEG(3Cl#(+t zb5e>@^OUTjjdYB4Oms|j%wlVGs+CZbIs=tX4~$?m6+{+xHNY-xf?XJ79~MJkW}8h{ zj%2iDwzM#xo(yCN0vS3=N_lz|i6vArvmF^;MIc{(EygJ@!G5I_3ZX delta 215 zcmZqacHGhJ$eW%M;>N_lz_7zrfZ<9b?^a&MXUSf9iMgptR!Rm22IgiK78Xi6O34|S zIVnY{c}iB%Mmol^wK~;GD2kjdl+eX24S*V_bEGhqFk4!fPp?m5v;{LhrZDPbXKW8m yWsGBL-;&M<#2}g(h*^M`6^Pk@m>q~YfS41Axqz4(h5_n=_n;QpPCC@}#lnf&X;K4wb`^U1qk+Jflj-!I#LzhnerCLm@8Viq7~1!A`C KzhAO@W&i+|5HZOB 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 c67a46965c2660e03ef1339481234230dfa61f61..8591393f636c62bb5a247a0ebb7be4dfaed7d091 100644 GIT binary patch delta 71 zcmX?eO>o6ELB8~y5H}_U1_q667KT6XHu4>LE0CO#nUhkKnx|wHZ4_IpQ$3mWofEUU ak>zBscQ2bw-nW~)X9QxV?I!P;C29c885{!u delta 106 zcmZ2+P4LV$LB8~y5H}_U1_qyO76yg)8~KjBHO@=SO;xf|G5`W+Gb0Nn9i`-q%$$^> x)I24tXrtI#ooXc%C1w^%lOMfxVz#s}pRE4wWi$W#cK-K_K+LqA|2?y04FE72Bi8@` 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