mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
Add some Additional Information to Mdl display, discard some padding when reading mdl files.
This commit is contained in:
parent
36c77034a4
commit
8df4bb0781
4 changed files with 315 additions and 241 deletions
|
|
@ -9,307 +9,275 @@ 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<uint> 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 )
|
||||
{
|
||||
Write( w, vertex );
|
||||
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);
|
||||
}
|
||||
|
||||
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 void Write( BinaryWriter w, in MdlStructs.ElementIdStruct elementId )
|
||||
private static unsafe void Write<T>(BinaryWriter w, in T data) where T : unmanaged
|
||||
{
|
||||
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)
|
||||
{
|
||||
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<byte>(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)
|
||||
{
|
||||
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 void Write( BinaryWriter w, int shapeIdx, IReadOnlyList< uint > offsets )
|
||||
private static void Write(BinaryWriter w, MdlStructs.BoundingBoxStruct box)
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
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 );
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}" ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue