diff --git a/Penumbra.GameData/Files/MdlFile.Write.cs b/Penumbra.GameData/Files/MdlFile.Write.cs index b4017c52..7db29954 100644 --- a/Penumbra.GameData/Files/MdlFile.Write.cs +++ b/Penumbra.GameData/Files/MdlFile.Write.cs @@ -9,309 +9,277 @@ namespace Penumbra.GameData.Files; public partial class MdlFile { - private static uint Write( BinaryWriter w, string s, long basePos ) + private static uint Write(BinaryWriter w, string s, long basePos) { var currentPos = w.BaseStream.Position; - w.Write( Encoding.UTF8.GetBytes( s ) ); - w.Write( ( byte )0 ); - return ( uint )( currentPos - basePos ); + w.Write(Encoding.UTF8.GetBytes(s)); + w.Write((byte)0); + return (uint)(currentPos - basePos); } - private List< uint > WriteStrings( BinaryWriter w ) + private List WriteStrings(BinaryWriter w) { - var startPos = ( int )w.BaseStream.Position; + var startPos = (int)w.BaseStream.Position; var basePos = startPos + 8; - var count = ( ushort )( Attributes.Length + Bones.Length + Materials.Length + Shapes.Length ); + var count = (ushort)(Attributes.Length + Bones.Length + Materials.Length + Shapes.Length); - w.Write( count ); - w.Seek( basePos, SeekOrigin.Begin ); - var ret = Attributes.Concat( Bones ) - .Concat( Materials ) - .Concat( Shapes.Select( s => s.ShapeName ) ) - .Select( attribute => Write( w, attribute, basePos ) ).ToList(); + w.Write(count); + w.Seek(basePos, SeekOrigin.Begin); + var ret = Attributes.Concat(Bones) + .Concat(Materials) + .Concat(Shapes.Select(s => s.ShapeName)) + .Select(attribute => Write(w, attribute, basePos)).ToList(); - w.Write( ( ushort )0 ); // Seems to always have two additional null-bytes, not padding. - var size = ( int )w.BaseStream.Position - basePos; - w.Seek( startPos + 4, SeekOrigin.Begin ); - w.Write( ( uint )size ); - w.Seek( basePos + size, SeekOrigin.Begin ); + var padding = (w.BaseStream.Position & 0b111) > 0 ? (w.BaseStream.Position & ~0b111) + 8 : w.BaseStream.Position; + for (var i = w.BaseStream.Position; i < padding; ++i) + w.Write((byte)0); + var size = (int)w.BaseStream.Position - basePos; + w.Seek(startPos + 4, SeekOrigin.Begin); + w.Write((uint)size); + w.Seek(basePos + size, SeekOrigin.Begin); return ret; } - private void WriteModelFileHeader( BinaryWriter w, uint runtimeSize ) + private void WriteModelFileHeader(BinaryWriter w, uint runtimeSize) { - w.Write( Version ); - w.Write( StackSize ); - w.Write( runtimeSize ); - w.Write( ( ushort )VertexDeclarations.Length ); - w.Write( ( ushort )Materials.Length ); - w.Write( VertexOffset[ 0 ] > 0 ? VertexOffset[ 0 ] + runtimeSize : 0u ); - w.Write( VertexOffset[ 1 ] > 0 ? VertexOffset[ 1 ] + runtimeSize : 0u ); - w.Write( VertexOffset[ 2 ] > 0 ? VertexOffset[ 2 ] + runtimeSize : 0u ); - w.Write( IndexOffset[ 0 ] > 0 ? IndexOffset[ 0 ] + runtimeSize : 0u ); - w.Write( IndexOffset[ 1 ] > 0 ? IndexOffset[ 1 ] + runtimeSize : 0u ); - w.Write( IndexOffset[ 2 ] > 0 ? IndexOffset[ 2 ] + runtimeSize : 0u ); - w.Write( VertexBufferSize[ 0 ] ); - w.Write( VertexBufferSize[ 1 ] ); - w.Write( VertexBufferSize[ 2 ] ); - w.Write( IndexBufferSize[ 0 ] ); - w.Write( IndexBufferSize[ 1 ] ); - w.Write( IndexBufferSize[ 2 ] ); - w.Write( LodCount ); - w.Write( EnableIndexBufferStreaming ); - w.Write( EnableEdgeGeometry ); - w.Write( ( byte )0 ); // Padding + w.Write(Version); + w.Write(StackSize); + w.Write(runtimeSize); + w.Write((ushort)VertexDeclarations.Length); + w.Write((ushort)Materials.Length); + w.Write(VertexOffset[0] > 0 ? VertexOffset[0] + runtimeSize : 0u); + w.Write(VertexOffset[1] > 0 ? VertexOffset[1] + runtimeSize : 0u); + w.Write(VertexOffset[2] > 0 ? VertexOffset[2] + runtimeSize : 0u); + w.Write(IndexOffset[0] > 0 ? IndexOffset[0] + runtimeSize : 0u); + w.Write(IndexOffset[1] > 0 ? IndexOffset[1] + runtimeSize : 0u); + w.Write(IndexOffset[2] > 0 ? IndexOffset[2] + runtimeSize : 0u); + w.Write(VertexBufferSize[0]); + w.Write(VertexBufferSize[1]); + w.Write(VertexBufferSize[2]); + w.Write(IndexBufferSize[0]); + w.Write(IndexBufferSize[1]); + w.Write(IndexBufferSize[2]); + w.Write(LodCount); + w.Write(EnableIndexBufferStreaming); + w.Write(EnableEdgeGeometry); + w.Write((byte)0); // Padding } - private void WriteModelHeader( BinaryWriter w ) + private void WriteModelHeader(BinaryWriter w) { - w.Write( Radius ); - w.Write( ( ushort )Meshes.Length ); - w.Write( ( ushort )Attributes.Length ); - w.Write( ( ushort )SubMeshes.Length ); - w.Write( ( ushort )Materials.Length ); - w.Write( ( ushort )Bones.Length ); - w.Write( ( ushort )BoneTables.Length ); - w.Write( ( ushort )Shapes.Length ); - w.Write( ( ushort )ShapeMeshes.Length ); - w.Write( ( ushort )ShapeValues.Length ); - w.Write( LodCount ); - w.Write( ( byte )Flags1 ); - w.Write( ( ushort )ElementIds.Length ); - w.Write( ( byte )TerrainShadowMeshes.Length ); - w.Write( ( byte )Flags2 ); - w.Write( ModelClipOutDistance ); - w.Write( ShadowClipOutDistance ); - w.Write( Unknown4 ); - w.Write( ( ushort )TerrainShadowSubMeshes.Length ); - w.Write( Unknown5 ); - w.Write( BgChangeMaterialIndex ); - w.Write( BgCrestChangeMaterialIndex ); - w.Write( Unknown6 ); - w.Write( Unknown7 ); - w.Write( Unknown8 ); - w.Write( Unknown9 ); - w.Write( ( uint )0 ); // 6 byte padding - w.Write( ( ushort )0 ); + w.Write(Radius); + w.Write((ushort)Meshes.Length); + w.Write((ushort)Attributes.Length); + w.Write((ushort)SubMeshes.Length); + w.Write((ushort)Materials.Length); + w.Write((ushort)Bones.Length); + w.Write((ushort)BoneTables.Length); + w.Write((ushort)Shapes.Length); + w.Write((ushort)ShapeMeshes.Length); + w.Write((ushort)ShapeValues.Length); + w.Write(LodCount); + w.Write((byte)Flags1); + w.Write((ushort)ElementIds.Length); + w.Write((byte)TerrainShadowMeshes.Length); + w.Write((byte)Flags2); + w.Write(ModelClipOutDistance); + w.Write(ShadowClipOutDistance); + w.Write(Unknown4); + w.Write((ushort)TerrainShadowSubMeshes.Length); + w.Write(Unknown5); + w.Write(BgChangeMaterialIndex); + w.Write(BgCrestChangeMaterialIndex); + w.Write(Unknown6); + w.Write(Unknown7); + w.Write(Unknown8); + w.Write(Unknown9); + w.Write((uint)0); // 6 byte padding + w.Write((ushort)0); } - private static void Write( BinaryWriter w, in MdlStructs.VertexElement vertex ) + private static void Write(BinaryWriter w, in MdlStructs.VertexElement vertex) { - w.Write( vertex.Stream ); - w.Write( vertex.Offset ); - w.Write( vertex.Type ); - w.Write( vertex.Usage ); - w.Write( vertex.UsageIndex ); - w.Write( ( ushort )0 ); // 3 byte padding - w.Write( ( byte )0 ); + w.Write(vertex.Stream); + w.Write(vertex.Offset); + w.Write(vertex.Type); + w.Write(vertex.Usage); + w.Write(vertex.UsageIndex); + w.Write((ushort)0); // 3 byte padding + w.Write((byte)0); } - private static void Write( BinaryWriter w, in MdlStructs.VertexDeclarationStruct vertexDecl ) + private static void Write(BinaryWriter w, in MdlStructs.VertexDeclarationStruct vertexDecl) { - foreach( var vertex in vertexDecl.VertexElements ) + foreach (var vertex in vertexDecl.VertexElements) + Write(w, vertex); + + Write(w, new MdlStructs.VertexElement() { Stream = 255 }); + w.Seek((int)(NumVertices - 1 - vertexDecl.VertexElements.Length) * 8, SeekOrigin.Current); + } + + private static void Write(BinaryWriter w, in MdlStructs.ElementIdStruct elementId) + { + w.Write(elementId.ElementId); + w.Write(elementId.ParentBoneName); + w.Write(elementId.Translate[0]); + w.Write(elementId.Translate[1]); + w.Write(elementId.Translate[2]); + w.Write(elementId.Rotate[0]); + w.Write(elementId.Rotate[1]); + w.Write(elementId.Rotate[2]); + } + + private static unsafe void Write(BinaryWriter w, in T data) where T : unmanaged + { + fixed (T* ptr = &data) { - Write( w, vertex ); - } - - Write( w, new MdlStructs.VertexElement() { Stream = 255 } ); - w.Seek( ( int )( NumVertices - 1 - vertexDecl.VertexElements.Length ) * 8, SeekOrigin.Current ); - } - - private static void Write( BinaryWriter w, in MdlStructs.ElementIdStruct elementId ) - { - w.Write( elementId.ElementId ); - w.Write( elementId.ParentBoneName ); - w.Write( elementId.Translate[ 0 ] ); - w.Write( elementId.Translate[ 1 ] ); - w.Write( elementId.Translate[ 2 ] ); - w.Write( elementId.Rotate[ 0 ] ); - w.Write( elementId.Rotate[ 1 ] ); - w.Write( elementId.Rotate[ 2 ] ); - } - - private static unsafe void Write< T >( BinaryWriter w, in T data ) where T : unmanaged - { - fixed( T* ptr = &data ) - { - var bytePtr = ( byte* )ptr; - var size = sizeof( T ); - var span = new ReadOnlySpan< byte >( bytePtr, size ); - w.Write( span ); + var bytePtr = (byte*)ptr; + var size = sizeof(T); + var span = new ReadOnlySpan(bytePtr, size); + w.Write(span); } } - private static void Write( BinaryWriter w, MdlStructs.MeshStruct mesh ) + private static void Write(BinaryWriter w, MdlStructs.MeshStruct mesh) { - w.Write( mesh.VertexCount ); - w.Write( ( ushort )0 ); // padding - w.Write( mesh.IndexCount ); - w.Write( mesh.MaterialIndex ); - w.Write( mesh.SubMeshIndex ); - w.Write( mesh.SubMeshCount ); - w.Write( mesh.BoneTableIndex ); - w.Write( mesh.StartIndex ); - w.Write( mesh.VertexBufferOffset[ 0 ] ); - w.Write( mesh.VertexBufferOffset[ 1 ] ); - w.Write( mesh.VertexBufferOffset[ 2 ] ); - w.Write( mesh.VertexBufferStride[ 0 ] ); - w.Write( mesh.VertexBufferStride[ 1 ] ); - w.Write( mesh.VertexBufferStride[ 2 ] ); - w.Write( mesh.VertexStreamCount ); + w.Write(mesh.VertexCount); + w.Write((ushort)0); // padding + w.Write(mesh.IndexCount); + w.Write(mesh.MaterialIndex); + w.Write(mesh.SubMeshIndex); + w.Write(mesh.SubMeshCount); + w.Write(mesh.BoneTableIndex); + w.Write(mesh.StartIndex); + w.Write(mesh.VertexBufferOffset[0]); + w.Write(mesh.VertexBufferOffset[1]); + w.Write(mesh.VertexBufferOffset[2]); + w.Write(mesh.VertexBufferStride[0]); + w.Write(mesh.VertexBufferStride[1]); + w.Write(mesh.VertexBufferStride[2]); + w.Write(mesh.VertexStreamCount); } - private static void Write( BinaryWriter w, MdlStructs.BoneTableStruct bone ) + private static void Write(BinaryWriter w, MdlStructs.BoneTableStruct bone) { - foreach( var index in bone.BoneIndex ) - { - w.Write( index ); - } + foreach (var index in bone.BoneIndex) + w.Write(index); - w.Write( bone.BoneCount ); - w.Write( ( ushort )0 ); // 3 bytes padding - w.Write( ( byte )0 ); + w.Write(bone.BoneCount); + w.Write((ushort)0); // 3 bytes padding + w.Write((byte)0); } - private void Write( BinaryWriter w, int shapeIdx, IReadOnlyList< uint > offsets ) + private void Write(BinaryWriter w, int shapeIdx, IReadOnlyList offsets) { - var shape = Shapes[ shapeIdx ]; - var offset = offsets[ Attributes.Length + Bones.Length + Materials.Length + shapeIdx ]; - w.Write( offset ); - w.Write( shape.ShapeMeshStartIndex[ 0 ] ); - w.Write( shape.ShapeMeshStartIndex[ 1 ] ); - w.Write( shape.ShapeMeshStartIndex[ 2 ] ); - w.Write( shape.ShapeMeshCount[ 0 ] ); - w.Write( shape.ShapeMeshCount[ 1 ] ); - w.Write( shape.ShapeMeshCount[ 2 ] ); + var shape = Shapes[shapeIdx]; + var offset = offsets[Attributes.Length + Bones.Length + Materials.Length + shapeIdx]; + w.Write(offset); + w.Write(shape.ShapeMeshStartIndex[0]); + w.Write(shape.ShapeMeshStartIndex[1]); + w.Write(shape.ShapeMeshStartIndex[2]); + w.Write(shape.ShapeMeshCount[0]); + w.Write(shape.ShapeMeshCount[1]); + w.Write(shape.ShapeMeshCount[2]); } - private static void Write( BinaryWriter w, MdlStructs.BoundingBoxStruct box ) + private static void Write(BinaryWriter w, MdlStructs.BoundingBoxStruct box) { - w.Write( box.Min[ 0 ] ); - w.Write( box.Min[ 1 ] ); - w.Write( box.Min[ 2 ] ); - w.Write( box.Min[ 3 ] ); - w.Write( box.Max[ 0 ] ); - w.Write( box.Max[ 1 ] ); - w.Write( box.Max[ 2 ] ); - w.Write( box.Max[ 3 ] ); + w.Write(box.Min[0]); + w.Write(box.Min[1]); + w.Write(box.Min[2]); + w.Write(box.Min[3]); + w.Write(box.Max[0]); + w.Write(box.Max[1]); + w.Write(box.Max[2]); + w.Write(box.Max[3]); } public byte[] Write() { using var stream = new MemoryStream(); - using( var w = new BinaryWriter( stream ) ) + using (var w = new BinaryWriter(stream)) { // Skip and write this later when we actually know it. - w.Seek( ( int )FileHeaderSize, SeekOrigin.Begin ); + w.Seek((int)FileHeaderSize, SeekOrigin.Begin); - foreach( var vertexDecl in VertexDeclarations ) - { - Write( w, vertexDecl ); - } + foreach (var vertexDecl in VertexDeclarations) + Write(w, vertexDecl); - var offsets = WriteStrings( w ); - WriteModelHeader( w ); + var offsets = WriteStrings(w); + WriteModelHeader(w); - foreach( var elementId in ElementIds ) - { - Write( w, elementId ); - } + foreach (var elementId in ElementIds) + Write(w, elementId); - foreach( var lod in Lods ) - { - Write( w, lod ); - } + foreach (var lod in Lods) + Write(w, lod); - if( Flags2.HasFlag( MdlStructs.ModelFlags2.ExtraLodEnabled ) ) - { - foreach( var extraLod in ExtraLods ) - { - Write( w, extraLod ); - } - } + if (Flags2.HasFlag(MdlStructs.ModelFlags2.ExtraLodEnabled)) + foreach (var extraLod in ExtraLods) + Write(w, extraLod); - foreach( var mesh in Meshes ) - { - Write( w, mesh ); - } + foreach (var mesh in Meshes) + Write(w, mesh); - for( var i = 0; i < Attributes.Length; ++i ) - { - w.Write( offsets[ i ] ); - } + for (var i = 0; i < Attributes.Length; ++i) + w.Write(offsets[i]); - foreach( var terrainShadowMesh in TerrainShadowMeshes ) - { - Write( w, terrainShadowMesh ); - } + foreach (var terrainShadowMesh in TerrainShadowMeshes) + Write(w, terrainShadowMesh); - foreach( var subMesh in SubMeshes ) - { - Write( w, subMesh ); - } + foreach (var subMesh in SubMeshes) + Write(w, subMesh); - foreach( var terrainShadowSubMesh in TerrainShadowSubMeshes ) - { - Write( w, terrainShadowSubMesh ); - } + foreach (var terrainShadowSubMesh in TerrainShadowSubMeshes) + Write(w, terrainShadowSubMesh); - for( var i = 0; i < Materials.Length; ++i ) - { - w.Write( offsets[ Attributes.Length + Bones.Length + i ] ); - } + for (var i = 0; i < Materials.Length; ++i) + w.Write(offsets[Attributes.Length + Bones.Length + i]); - for( var i = 0; i < Bones.Length; ++i ) - { - w.Write( offsets[ Attributes.Length + i ] ); - } + for (var i = 0; i < Bones.Length; ++i) + w.Write(offsets[Attributes.Length + i]); - foreach( var boneTable in BoneTables ) - { - Write( w, boneTable ); - } + foreach (var boneTable in BoneTables) + Write(w, boneTable); - for( var i = 0; i < Shapes.Length; ++i ) - { - Write( w, i, offsets ); - } + for (var i = 0; i < Shapes.Length; ++i) + Write(w, i, offsets); - foreach( var shapeMesh in ShapeMeshes ) - { - Write( w, shapeMesh ); - } + foreach (var shapeMesh in ShapeMeshes) + Write(w, shapeMesh); - foreach( var shapeValue in ShapeValues ) - { - Write( w, shapeValue ); - } + foreach (var shapeValue in ShapeValues) + Write(w, shapeValue); - w.Write( SubMeshBoneMap.Length * 2 ); - foreach( var bone in SubMeshBoneMap ) - { - w.Write( bone ); - } + w.Write(SubMeshBoneMap.Length * 2); + foreach (var bone in SubMeshBoneMap) + w.Write(bone); - w.Write( ( byte )0 ); // number of padding bytes, which is 0 for us. + var pos = w.BaseStream.Position + 1; + var padding = (byte) (pos & 0b111); + if (padding > 0) + padding = (byte) (8 - padding); + w.Write(padding); + for (var i = 0; i < padding; ++i) + w.Write((byte) (0xDEADBEEFF00DCAFEu >> (8 * (7 - i)))); - Write( w, BoundingBoxes ); - Write( w, ModelBoundingBoxes ); - Write( w, WaterBoundingBoxes ); - Write( w, VerticalFogBoundingBoxes ); - foreach( var box in BoneBoundingBoxes ) - { - Write( w, box ); - } - - var totalSize = w.BaseStream.Position; - var runtimeSize = ( uint )( totalSize - StackSize - FileHeaderSize ); - w.Write( RemainingData ); + Write(w, BoundingBoxes); + Write(w, ModelBoundingBoxes); + Write(w, WaterBoundingBoxes); + Write(w, VerticalFogBoundingBoxes); + foreach (var box in BoneBoundingBoxes) + Write(w, box); + + var totalSize = w.BaseStream.Position; + var runtimeSize = (uint)(totalSize - StackSize - FileHeaderSize); + w.Write(RemainingData); // Write header data. - w.Seek( 0, SeekOrigin.Begin ); - WriteModelFileHeader( w, runtimeSize ); + w.Seek(0, SeekOrigin.Begin); + WriteModelFileHeader(w, runtimeSize); } return stream.ToArray(); } -} \ No newline at end of file +} diff --git a/Penumbra.GameData/Files/MdlFile.cs b/Penumbra.GameData/Files/MdlFile.cs index a7d65ee8..6cde07f5 100644 --- a/Penumbra.GameData/Files/MdlFile.cs +++ b/Penumbra.GameData/Files/MdlFile.cs @@ -83,8 +83,8 @@ public partial class MdlFile : IWritable public Shape[] Shapes; // Raw, unparsed data. - public byte[] RemainingData; - + public byte[] RemainingData; + public bool Valid { get; } public MdlFile(byte[] data) @@ -181,6 +181,9 @@ public partial class MdlFile : IWritable for (var i = 0; i < modelHeader.BoneCount; i++) BoneBoundingBoxes[i] = MdlStructs.BoundingBoxStruct.Read(r); + var runtimePadding = header.RuntimeSize + FileHeaderSize + header.StackSize - r.BaseStream.Position; + if (runtimePadding > 0) + r.ReadBytes((int)runtimePadding); RemainingData = r.ReadBytes((int)(r.BaseStream.Length - r.BaseStream.Position)); Valid = true; } diff --git a/Penumbra/UI/Classes/ModEditWindow.Materials.cs b/Penumbra/UI/Classes/ModEditWindow.Materials.cs index 3cc27aac..54330ecb 100644 --- a/Penumbra/UI/Classes/ModEditWindow.Materials.cs +++ b/Penumbra/UI/Classes/ModEditWindow.Materials.cs @@ -215,10 +215,10 @@ public partial class ModEditWindow if( file.AdditionalData.Length > 0 ) { - using var t = ImRaii.TreeNode( "Additional Data" ); + using var t = ImRaii.TreeNode( $"Additional Data (Size: {file.AdditionalData.Length})###AdditionalData" ); if( t ) { - ImRaii.TreeNode( string.Join( ' ', file.AdditionalData.Select( c => $"{c:X2}" ) ), ImGuiTreeNodeFlags.Leaf ).Dispose(); + ImGuiUtil.TextWrapped( string.Join( ' ', file.AdditionalData.Select( c => $"{c:X2}" ) ) ); } } diff --git a/Penumbra/UI/Classes/ModEditWindow.Models.cs b/Penumbra/UI/Classes/ModEditWindow.Models.cs index 5b6ad685..73f2a7dc 100644 --- a/Penumbra/UI/Classes/ModEditWindow.Models.cs +++ b/Penumbra/UI/Classes/ModEditWindow.Models.cs @@ -1,7 +1,10 @@ using ImGuiNET; +using OtterGui; using OtterGui.Raii; using Penumbra.GameData.Files; using Penumbra.String.Classes; +using System.Globalization; +using System.Linq; namespace Penumbra.UI.Classes; @@ -26,6 +29,106 @@ public partial class ModEditWindow } } + ret |= DrawOtherModelDetails( file, disabled ); + return !disabled && ret; } + + private static bool DrawOtherModelDetails( MdlFile file, bool _ ) + { + if( !ImGui.CollapsingHeader( "Further Content" ) ) + { + return false; + } + + using( var table = ImRaii.Table( "##data", 2, ImGuiTableFlags.SizingFixedFit ) ) + { + if( table ) + { + ImGuiUtil.DrawTableColumn( "Version" ); + ImGuiUtil.DrawTableColumn( file.Version.ToString() ); + ImGuiUtil.DrawTableColumn( "Radius" ); + ImGuiUtil.DrawTableColumn( file.Radius.ToString( CultureInfo.InvariantCulture ) ); + ImGuiUtil.DrawTableColumn( "Model Clip Out Distance" ); + ImGuiUtil.DrawTableColumn( file.ModelClipOutDistance.ToString( CultureInfo.InvariantCulture ) ); + ImGuiUtil.DrawTableColumn( "Shadow Clip Out Distance" ); + ImGuiUtil.DrawTableColumn( file.ShadowClipOutDistance.ToString( CultureInfo.InvariantCulture ) ); + ImGuiUtil.DrawTableColumn( "LOD Count" ); + ImGuiUtil.DrawTableColumn( file.LodCount.ToString() ); + ImGuiUtil.DrawTableColumn( "Enable Index Buffer Streaming" ); + ImGuiUtil.DrawTableColumn( file.EnableIndexBufferStreaming.ToString() ); + ImGuiUtil.DrawTableColumn( "Enable Edge Geometry" ); + ImGuiUtil.DrawTableColumn( file.EnableEdgeGeometry.ToString() ); + ImGuiUtil.DrawTableColumn( "Flags 1" ); + ImGuiUtil.DrawTableColumn( file.Flags1.ToString() ); + ImGuiUtil.DrawTableColumn( "Flags 2" ); + ImGuiUtil.DrawTableColumn( file.Flags2.ToString() ); + ImGuiUtil.DrawTableColumn( "Vertex Declarations" ); + ImGuiUtil.DrawTableColumn( file.VertexDeclarations.Length.ToString() ); + ImGuiUtil.DrawTableColumn( "Bone Bounding Boxes" ); + ImGuiUtil.DrawTableColumn( file.BoneBoundingBoxes.Length.ToString() ); + ImGuiUtil.DrawTableColumn( "Bone Tables" ); + ImGuiUtil.DrawTableColumn( file.BoneTables.Length.ToString() ); + ImGuiUtil.DrawTableColumn( "Element IDs" ); + ImGuiUtil.DrawTableColumn( file.ElementIds.Length.ToString() ); + ImGuiUtil.DrawTableColumn( "Extra LoDs" ); + ImGuiUtil.DrawTableColumn( file.ExtraLods.Length.ToString() ); + ImGuiUtil.DrawTableColumn( "Meshes" ); + ImGuiUtil.DrawTableColumn( file.Meshes.Length.ToString() ); + ImGuiUtil.DrawTableColumn( "Shape Meshes" ); + ImGuiUtil.DrawTableColumn( file.ShapeMeshes.Length.ToString() ); + ImGuiUtil.DrawTableColumn( "LoDs" ); + ImGuiUtil.DrawTableColumn( file.Lods.Length.ToString() ); + ImGuiUtil.DrawTableColumn( "Vertex Declarations" ); + ImGuiUtil.DrawTableColumn( file.VertexDeclarations.Length.ToString() ); + ImGuiUtil.DrawTableColumn( "Stack Size" ); + ImGuiUtil.DrawTableColumn( file.StackSize.ToString() ); + } + } + + using( var attributes = ImRaii.TreeNode( "Attributes", ImGuiTreeNodeFlags.DefaultOpen ) ) + { + if( attributes ) + { + foreach( var attribute in file.Attributes ) + { + ImRaii.TreeNode( attribute, ImGuiTreeNodeFlags.Leaf ).Dispose(); + } + } + } + + using( var bones = ImRaii.TreeNode( "Bones", ImGuiTreeNodeFlags.DefaultOpen ) ) + { + if( bones ) + { + foreach( var bone in file.Bones ) + { + ImRaii.TreeNode( bone, ImGuiTreeNodeFlags.Leaf ).Dispose(); + } + } + } + + using( var shapes = ImRaii.TreeNode( "Shapes", ImGuiTreeNodeFlags.DefaultOpen ) ) + { + if( shapes ) + { + foreach( var shape in file.Shapes ) + { + ImRaii.TreeNode( shape.ShapeName, ImGuiTreeNodeFlags.Leaf ).Dispose(); + } + } + } + + if( file.RemainingData.Length > 0 ) + { + using var t = ImRaii.TreeNode( $"Additional Data (Size: {file.RemainingData.Length})###AdditionalData" ); + if( t ) + { + ImGuiUtil.TextWrapped( string.Join( ' ', file.RemainingData.Select( c => $"{c:X2}" ) ) ); + } + } + + return false; + } + } \ No newline at end of file