Update retro formats to support Metroid Prime Remastered

This commit is contained in:
KillzXGaming 2023-02-16 17:25:43 -05:00
parent 976939bec0
commit afe7ab3890
13 changed files with 322 additions and 128 deletions

1
.gitignore vendored
View file

@ -356,3 +356,4 @@ Toolbox/Lib.zip
yuzu-glsl-decompiler yuzu-glsl-decompiler
AnimSetupPrevious.zip AnimSetupPrevious.zip
AnimSetupNew.zip AnimSetupNew.zip
Switch_Toolbox_Library/Forms/Editors/UV/UVEditor.cs

View file

@ -140,8 +140,10 @@ namespace DKCTF
{ {
string guid = texMap.Value.FileID.ToString(); string guid = texMap.Value.FileID.ToString();
if (texFolder.Nodes.ContainsKey(guid) || !Textures.ContainsKey(guid)) if (texFolder.Nodes.ContainsKey(guid) || !Textures.ContainsKey(guid))
{
Console.WriteLine($"Texture not present in pak file! {mat.Name} {texMap.Key} {guid}");
continue; continue;
}
if (Textures[guid].FileFormat == null) if (Textures[guid].FileFormat == null)
Textures[guid].OpenFile(); Textures[guid].OpenFile();
@ -153,7 +155,7 @@ namespace DKCTF
t.Tag = tex; t.Tag = tex;
texFolder.Nodes.Add(t); texFolder.Nodes.Add(t);
if (texMap.Key == "DIFT") if (texMap.Key == "DIFT" || texMap.Key == "BCLR")
{ {
tex.Text = guid; tex.Text = guid;
@ -167,6 +169,7 @@ namespace DKCTF
TreeNode texFolder = new STTextureFolder("Textures"); TreeNode texFolder = new STTextureFolder("Textures");
TreeNode skeletonFolder = new STTextureFolder("Skeleton"); TreeNode skeletonFolder = new STTextureFolder("Skeleton");
TreeNode shaderFolder = new STTextureFolder("Materials");
public void Load(System.IO.Stream stream) public void Load(System.IO.Stream stream)
{ {
@ -179,11 +182,14 @@ namespace DKCTF
Nodes.Add(meshFolder); Nodes.Add(meshFolder);
Nodes.Add(texFolder); Nodes.Add(texFolder);
Nodes.Add(skeletonFolder); Nodes.Add(skeletonFolder);
Nodes.Add(shaderFolder);
Model = ToGeneric(); Model = ToGeneric();
foreach (var mat in ModelData.Materials)
shaderFolder.Nodes.Add(new TreeNode(mat.Name + "_" + mat.ID.ToString()));
foreach (GenericRenderedObject mesh in Model.Objects) foreach (GenericRenderedObject mesh in Model.Objects)
{ {
Renderer.Meshes.Add(mesh); Renderer.Meshes.Add(mesh);
@ -235,6 +241,7 @@ namespace DKCTF
if (tex.Key == "DIFT") type = STGenericMatTexture.TextureType.Diffuse; if (tex.Key == "DIFT") type = STGenericMatTexture.TextureType.Diffuse;
if (tex.Key == "NMAP") type = STGenericMatTexture.TextureType.Normal; if (tex.Key == "NMAP") type = STGenericMatTexture.TextureType.Normal;
if (tex.Key == "SPCT") type = STGenericMatTexture.TextureType.Specular; if (tex.Key == "SPCT") type = STGenericMatTexture.TextureType.Specular;
if (tex.Key == "BCLR") type = STGenericMatTexture.TextureType.Diffuse;
genericMaterial.TextureMaps.Add(new STGenericMatTexture() genericMaterial.TextureMaps.Add(new STGenericMatTexture()
{ {

View file

@ -134,13 +134,16 @@ namespace DKCTF
Header = new TXTR(stream); Header = new TXTR(stream);
if (Header.IsSwitch) if (!Header.IsSwitch)
PlatformSwizzle = PlatformSwizzle.Platform_WiiU; PlatformSwizzle = PlatformSwizzle.Platform_WiiU;
Width = Header.TextureHeader.Width; Width = Header.TextureHeader.Width;
Height = Header.TextureHeader.Height; Height = Header.TextureHeader.Height;
MipCount = (uint)Header.MipSizes.Length; MipCount = (uint)Header.MipSizes.Length;
Format = FormatList[Header.TextureHeader.Format]; Format = FormatList[Header.TextureHeader.Format];
if (Header.TextureHeader.Type == 3)
this.ArrayCount = 6;
} }
public void Save(System.IO.Stream stream) public void Save(System.IO.Stream stream)
@ -225,18 +228,6 @@ namespace DKCTF
} }
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class STextureHeader
{
public uint Type;
public uint Format;
public uint Width;
public uint Height;
public uint Depth;
public uint TileMode;
public uint Swizzle;
}
Dictionary<uint, TEX_FORMAT> FormatList = new Dictionary<uint, TEX_FORMAT>() Dictionary<uint, TEX_FORMAT> FormatList = new Dictionary<uint, TEX_FORMAT>()
{ {
{ 12, TEX_FORMAT.R8G8B8A8_UNORM }, { 12, TEX_FORMAT.R8G8B8A8_UNORM },
@ -257,11 +248,40 @@ namespace DKCTF
{ 32, TEX_FORMAT.R16G16_FLOAT }, { 32, TEX_FORMAT.R16G16_FLOAT },
{ 33, TEX_FORMAT.R8G8_UNORM }, { 33, TEX_FORMAT.R8G8_UNORM },
{ 53, TEX_FORMAT.ASTC_4x4_UNORM },
{ 54, TEX_FORMAT.ASTC_5x4_UNORM }, { 54, TEX_FORMAT.ASTC_5x4_UNORM },
{ 55, TEX_FORMAT.ASTC_5x5_UNORM }, { 55, TEX_FORMAT.ASTC_5x5_UNORM },
{ 56, TEX_FORMAT.ASTC_6x5_UNORM }, { 56, TEX_FORMAT.ASTC_6x5_UNORM },
{ 57, TEX_FORMAT.ASTC_6x6_UNORM }, { 57, TEX_FORMAT.ASTC_6x6_UNORM },
{ 58, TEX_FORMAT.ASTC_8x5_UNORM }, { 58, TEX_FORMAT.ASTC_8x5_UNORM },
{ 59, TEX_FORMAT.ASTC_8x6_UNORM },
{ 60, TEX_FORMAT.ASTC_8x8_UNORM },
{ 61, TEX_FORMAT.ASTC_10x5_UNORM },
{ 62, TEX_FORMAT.ASTC_10x6_UNORM},
{ 63, TEX_FORMAT.ASTC_10x8_UNORM},
{ 64, TEX_FORMAT.ASTC_10x10_UNORM},
{ 65, TEX_FORMAT.ASTC_12x10_UNORM},
{ 66, TEX_FORMAT.ASTC_12x12_UNORM},
{ 67, TEX_FORMAT.ASTC_4x4_SRGB},
{ 68, TEX_FORMAT.ASTC_5x4_SRGB },
{ 69, TEX_FORMAT.ASTC_5x5_SRGB },
{ 70, TEX_FORMAT.ASTC_6x5_SRGB },
{ 71, TEX_FORMAT.ASTC_6x6_SRGB },
{ 72, TEX_FORMAT.ASTC_8x5_SRGB },
{ 73, TEX_FORMAT.ASTC_8x6_SRGB },
{ 74, TEX_FORMAT.ASTC_8x8_SRGB},
{ 75, TEX_FORMAT.ASTC_10x5_SRGB },
{ 76, TEX_FORMAT.ASTC_10x6_SRGB},
{ 77, TEX_FORMAT.ASTC_10x8_SRGB},
{ 78, TEX_FORMAT.ASTC_10x10_SRGB},
{ 79, TEX_FORMAT.ASTC_12x10_SRGB},
{ 80, TEX_FORMAT.ASTC_12x12_SRGB},
{ 81, TEX_FORMAT.BC6H_UF16 },
{ 82, TEX_FORMAT.BC6H_SF16 },
{ 83, TEX_FORMAT.BC7_UNORM },
{ 84, TEX_FORMAT.BC7_UNORM_SRGB },
}; };
} }
} }

View file

@ -42,19 +42,23 @@ namespace DKCTF
/// <summary> /// <summary>
/// Gets a vertex list from the provided buffer and descriptor info. /// Gets a vertex list from the provided buffer and descriptor info.
/// </summary> /// </summary>
public static List<CMDL.CVertex> LoadVertexBuffer(byte[] buffer, CMDL.VertexBuffer vertexBuffer, bool isLittleEndian) public static CMDL.CVertex[] LoadVertexBuffer(List<byte[]> buffers, int startIndex, CMDL.VertexBuffer vertexInfo, bool isLittleEndian)
{ {
List<CMDL.CVertex> vertices = new List<CMDL.CVertex>(); var vertices = new CMDL.CVertex[vertexInfo.VertexCount];
using (var reader = new FileReader(buffer)) foreach (var comp in vertexInfo.Components)
{ {
reader.SetByteOrder(!isLittleEndian); //switch is little endianness var buffer = buffers[startIndex + (int)comp.BufferID];
using (var reader = new FileReader(buffer))
{
reader.SetByteOrder(!isLittleEndian); //switch is little endianness
for (int i = 0; i < vertexBuffer.VertexCount; i++) { for (int i = 0; i < vertexInfo.VertexCount; i++)
CMDL.CVertex vertex = new CMDL.CVertex(); {
vertices.Add(vertex); if (vertices[i] == null) vertices[i] = new CMDL.CVertex();
CMDL.CVertex vertex = vertices[i];
foreach (var comp in vertexBuffer.Components) {
reader.SeekBegin(comp.Offset + i * comp.Stride); reader.SeekBegin(comp.Offset + i * comp.Stride);
switch (comp.Type) switch (comp.Type)
{ {
@ -68,7 +72,7 @@ namespace DKCTF
vertex.TexCoord0 = ReadData(reader, comp.Format).Xy; vertex.TexCoord0 = ReadData(reader, comp.Format).Xy;
break; break;
case CMDL.EVertexComponent.in_texCoord1: case CMDL.EVertexComponent.in_texCoord1:
vertex.TexCoord1 = ReadData(reader, comp.Format).Xy; vertex.TexCoord0 = ReadData(reader, comp.Format).Xy;
break; break;
case CMDL.EVertexComponent.in_texCoord2: case CMDL.EVertexComponent.in_texCoord2:
vertex.TexCoord2 = ReadData(reader, comp.Format).Xy; vertex.TexCoord2 = ReadData(reader, comp.Format).Xy;
@ -89,7 +93,6 @@ namespace DKCTF
} }
} }
} }
return vertices; return vertices;
} }

View file

@ -31,7 +31,7 @@ namespace DKCTF
public override void Read(FileReader reader) public override void Read(FileReader reader)
{ {
reader.ReadStruct<CAssetHeader>(); var assetHeader = reader.ReadStruct<CAssetHeader>();
reader.ReadStruct<SInfo>(); reader.ReadStruct<SInfo>();
//Dumb hack atm //Dumb hack atm
bool IsSwitch = false; bool IsSwitch = false;

View file

@ -52,7 +52,7 @@ namespace DKCTF
{ {
} }
public override void ReadMetaData(FileReader reader) public override void ReadMetaData(FileReader reader, CFormDescriptor pakVersion)
{ {
Meta = new SMetaData(); Meta = new SMetaData();
Meta.Unknown = reader.ReadUInt32(); Meta.Unknown = reader.ReadUInt32();
@ -60,13 +60,12 @@ namespace DKCTF
Meta.ReadBufferInfo = IOFileExtension.ReadList<SReadBufferInfo>(reader); Meta.ReadBufferInfo = IOFileExtension.ReadList<SReadBufferInfo>(reader);
Meta.VertexBuffers = IOFileExtension.ReadList<SBufferInfo>(reader); Meta.VertexBuffers = IOFileExtension.ReadList<SBufferInfo>(reader);
Meta.IndexBuffers = IOFileExtension.ReadList<SBufferInfo>(reader); Meta.IndexBuffers = IOFileExtension.ReadList<SBufferInfo>(reader);
Console.WriteLine();
} }
public override void WriteMetaData(FileWriter writer) public override void WriteMetaData(FileWriter writer, CFormDescriptor pakVersion)
{ {
writer.Write(Meta.GPUOffset);
writer.Write(Meta.Unknown); writer.Write(Meta.Unknown);
writer.Write(Meta.GPUOffset);
IOFileExtension.WriteList(writer, Meta.ReadBufferInfo); IOFileExtension.WriteList(writer, Meta.ReadBufferInfo);
IOFileExtension.WriteList(writer, Meta.VertexBuffers); IOFileExtension.WriteList(writer, Meta.VertexBuffers);
IOFileExtension.WriteList(writer, Meta.IndexBuffers); IOFileExtension.WriteList(writer, Meta.IndexBuffers);
@ -130,47 +129,41 @@ namespace DKCTF
} }
} }
} }
//Prepare buffer list
List<byte[]> vertexData = new List<byte[]>();
for (int i = 0; i < Meta.VertexBuffers.Count; i++) for (int i = 0; i < Meta.VertexBuffers.Count; i++)
{ {
var vertexInfo = VertexBuffers[i];
var buffer = Meta.VertexBuffers[i]; var buffer = Meta.VertexBuffers[i];
//First buffer or specific buffer //First buffer or specific buffer
var info = Meta.ReadBufferInfo[(int)buffer.ReadBufferIndex]; var info = Meta.ReadBufferInfo[(int)buffer.ReadBufferIndex];
//Seek into the buffer region //Seek into the buffer region
reader.SeekBegin(info.Offset + buffer.Offset); reader.SeekBegin(info.Offset + buffer.Offset);
using (reader.TemporarySeek(reader.Position, System.IO.SeekOrigin.Begin))
{
reader.SetByteOrder(false);
var type = reader.ReadUInt32();
reader.SetByteOrder(true);
if (type != 13)
{
byte[] b = reader.ReadBytes((int)buffer.CompressedSize - 4);
System.IO.File.WriteAllBytes($"{Toolbox.Library.Runtime.ExecutableDir}\\VBuffer_{type}_{i}_{buffer.DecompressedSize}.bin", b);
}
}
//Decompress //Decompress
var data = IOFileExtension.DecompressedBuffer(reader, buffer.CompressedSize, buffer.DecompressedSize, IsSwitch); var data = IOFileExtension.DecompressedBuffer(reader, buffer.CompressedSize, buffer.DecompressedSize, IsSwitch);
if (buffer.DecompressedSize != data.Length) if (buffer.DecompressedSize != data.Length)
throw new Exception(); throw new Exception();
var vertices = BufferHelper.LoadVertexBuffer(data, vertexInfo,IsSwitch); vertexData.Add(data);
startPos += buffer.CompressedSize;
}
for (int j = 0; j < VertexBuffers.Count; j++)
{
var vertexInfo = VertexBuffers[j];
var bufferID = j * 2;
if (!this.IsMPR)
bufferID = j;
var vertices = BufferHelper.LoadVertexBuffer(vertexData, bufferID, vertexInfo, IsSwitch);
//Read //Read
foreach (var mesh in Meshes) foreach (var mesh in Meshes)
{ if (mesh.Header.VertexBufferIndex == j)
if (mesh.Header.VertexBufferIndex == i) mesh.SetupVertices(vertices.ToList());
{
//Only use the vertices referenced in the indices
//Some meshes use the same big buffer and can add too many unecessary vertices
mesh.SetupVertices(vertices);
}
}
startPos += buffer.CompressedSize;
} }
break; break;
} }
@ -241,6 +234,8 @@ namespace DKCTF
private void ReadMaterials(FileReader reader) private void ReadMaterials(FileReader reader)
{ {
if (this.IsMPR)
reader.ReadUInt32();
uint numMaterials = reader.ReadUInt32(); uint numMaterials = reader.ReadUInt32();
for (int i = 0; i < numMaterials; i++) for (int i = 0; i < numMaterials; i++)
{ {
@ -250,8 +245,26 @@ namespace DKCTF
uint size = reader.ReadUInt32(); uint size = reader.ReadUInt32();
material.Name = reader.ReadString((int)size, true); material.Name = reader.ReadString((int)size, true);
material.ID = reader.ReadStruct<CObjectId>(); material.ID = reader.ReadStruct<CObjectId>();
material.Type = reader.ReadStruct<Magic>(); if (this.IsMPR)
material.Flags = reader.ReadUInt32(); {
reader.ReadBytes(24); //Shader guid and extras?
uint numTypes = reader.ReadByte();
reader.ReadBytes(3);
reader.ReadUInt32s((int)numTypes); //type list, fourcc
uint numDataInts = reader.ReadUInt32();
//A list of data types with extra flags
for (int j = 0; j < numDataInts; j++)
{
var dtype = reader.ReadStruct<Magic>();
var dformat = reader.ReadStruct<Magic>();
reader.ReadUInt16();
}
}
else
reader.ReadBytes(8); //Type, Flags
uint numData = reader.ReadUInt32(); uint numData = reader.ReadUInt32();
//A list of data types //A list of data types
@ -304,6 +317,9 @@ namespace DKCTF
reader.ReadStruct<STextureUsageInfo>(); reader.ReadStruct<STextureUsageInfo>();
} }
break; break;
case "MA4": //Matrix4x4
material.Matrices.Add(dtype, reader.ReadSingles(16));
break;
default: default:
throw new Exception($"Unsupported material type {dformat}!"); throw new Exception($"Unsupported material type {dformat}!");
} }
@ -315,10 +331,31 @@ namespace DKCTF
{ {
uint numMeshes = reader.ReadUInt32(); uint numMeshes = reader.ReadUInt32();
for (int i = 0; i < numMeshes; i++) for (int i = 0; i < numMeshes; i++)
{
var mesh = new CRenderMesh();
if (this.IsMPR)
mesh = reader.ReadStruct<CRenderMesh>();
else
{
uint type = reader.ReadUInt32(); //prim type
mesh.MaterialIndex = reader.ReadUInt16();
mesh.VertexBufferIndex = reader.ReadByte();
mesh.IndexBufferIndex = reader.ReadByte();
mesh.IndexStart = reader.ReadUInt32();
mesh.IndexCount = reader.ReadUInt32();
reader.ReadUInt16(); //0x10
reader.ReadByte(); //0x12
reader.ReadByte(); //0x13
reader.ReadByte(); //flags
}
Meshes.Add(new CMesh() Meshes.Add(new CMesh()
{ {
Header = reader.ReadStruct<CRenderMesh>(), Header = mesh,
}); });
}
Console.WriteLine();
} }
private void ReadVertexBuffer(FileReader reader) private void ReadVertexBuffer(FileReader reader)
@ -334,6 +371,8 @@ namespace DKCTF
for (int j = 0; j < numAttributes; j++) for (int j = 0; j < numAttributes; j++)
vertexBuffer.Components.Add(reader.ReadStruct<SVertexDataComponent>()); vertexBuffer.Components.Add(reader.ReadStruct<SVertexDataComponent>());
VertexBuffers.Add(vertexBuffer); VertexBuffers.Add(vertexBuffer);
if (this.IsMPR)
reader.ReadByte();
} }
} }
@ -381,6 +420,7 @@ namespace DKCTF
public Dictionary<string, float> Scalars = new Dictionary<string, float>(); public Dictionary<string, float> Scalars = new Dictionary<string, float>();
public Dictionary<string, int> Int = new Dictionary<string, int>(); public Dictionary<string, int> Int = new Dictionary<string, int>();
public Dictionary<string, int[]> Int4 = new Dictionary<string, int[]>(); public Dictionary<string, int[]> Int4 = new Dictionary<string, int[]>();
public Dictionary<string, float[]> Matrices = new Dictionary<string, float[]>();
public Dictionary<string, Color4f> Colors = new Dictionary<string, Color4f>(); public Dictionary<string, Color4f> Colors = new Dictionary<string, Color4f>();
} }
@ -416,16 +456,13 @@ namespace DKCTF
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential, Pack = 1)]
public class CRenderMesh public class CRenderMesh
{ {
public PrimtiiveType PrimtiiveMode;
public ushort MaterialIndex; public ushort MaterialIndex;
public byte VertexBufferIndex; public byte VertexBufferIndex;
public byte IndexBufferIndex; public byte IndexBufferIndex;
public uint IndexStart; public uint IndexStart;
public uint IndexCount; public uint IndexCount;
public ushort field_10; public ushort field_C;
public byte field_12; public ushort field_E; //0x4000
public byte field_13;
public byte field_14;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential, Pack = 1)]
@ -465,7 +502,7 @@ namespace DKCTF
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential, Pack = 1)]
public class SVertexDataComponent public class SVertexDataComponent
{ {
public uint field_0; public uint BufferID;
public uint Offset; public uint Offset;
public uint Stride; public uint Stride;
public VertexFormat Format; public VertexFormat Format;

View file

@ -20,11 +20,22 @@ namespace DKCTF
public FileForm() { } public FileForm() { }
public bool IsLittleEndian = false;
public bool IsMPR = false;
public FileForm(Stream stream, bool leaveOpen = false) public FileForm(Stream stream, bool leaveOpen = false)
{ {
using (var reader = new FileReader(stream, leaveOpen)) using (var reader = new FileReader(stream, leaveOpen))
{ {
reader.SetByteOrder(true); //Small "hack" to detect endianness.
using (reader.TemporarySeek(4, SeekOrigin.Begin)) {
//Size is a uint64. If the first 4 bytes are present, file is little endian
IsLittleEndian = reader.ReadUInt32() != 0;
//MPR is only game currently that is little endian
IsMPR = IsLittleEndian;
}
reader.SetByteOrder(!IsLittleEndian);
FileHeader = reader.ReadStruct<CFormDescriptor>(); FileHeader = reader.ReadStruct<CFormDescriptor>();
Read(reader); Read(reader);
AfterLoad(); AfterLoad();
@ -61,7 +72,7 @@ namespace DKCTF
/// <summary> /// <summary>
/// Reads meta data information within the pak archive. /// Reads meta data information within the pak archive.
/// </summary> /// </summary>
public virtual void ReadMetaData(FileReader reader) public virtual void ReadMetaData(FileReader reader, CFormDescriptor pakVersion)
{ {
} }
@ -69,7 +80,7 @@ namespace DKCTF
/// <summary> /// <summary>
/// Writes meta data information within the pak archive. /// Writes meta data information within the pak archive.
/// </summary> /// </summary>
public virtual void WriteMetaData(FileWriter writer) public virtual void WriteMetaData(FileWriter writer, CFormDescriptor pakVersion)
{ {
} }
@ -87,22 +98,28 @@ namespace DKCTF
/// </summary> /// </summary>
public long ReadMetaFooter(FileReader reader) public long ReadMetaFooter(FileReader reader)
{ {
using (reader.TemporarySeek(reader.BaseStream.Length - 12, SeekOrigin.Begin)) using (reader.TemporarySeek(reader.BaseStream.Length - 20, SeekOrigin.Begin))
{ {
if (reader.ReadString(4, Encoding.ASCII) != "META") if (reader.ReadString(4, Encoding.ASCII) != "META")
return reader.BaseStream.Length; return reader.BaseStream.Length;
} }
using (reader.TemporarySeek(reader.BaseStream.Length - 12, SeekOrigin.Begin)) using (reader.TemporarySeek(reader.BaseStream.Length - 20, SeekOrigin.Begin))
{ {
reader.ReadSignature(4, "META"); reader.ReadSignature(4, "META");
reader.ReadString(4); //type of file reader.ReadString(4); //type of file
uint versionA = reader.ReadUInt32(); //pak version A
uint versionB = reader.ReadUInt32(); //pak version B
uint size = reader.ReadUInt32(); //size of meta data uint size = reader.ReadUInt32(); //size of meta data
//Seek back to meta data //Seek back to meta data
reader.SeekBegin(reader.Position - size); reader.SeekBegin(reader.Position - size);
//Read meta data //Read meta data
ReadMetaData(reader); CFormDescriptor pakHeader = new CFormDescriptor();
pakHeader.VersionA = versionA;
pakHeader.VersionB = versionB;
ReadMetaData(reader, pakHeader);
return reader.BaseStream.Length - size; return reader.BaseStream.Length - size;
} }
@ -111,22 +128,24 @@ namespace DKCTF
/// <summary> /// <summary>
/// Writes a footer to a file for accessing meta data information outside a .pak archive. /// Writes a footer to a file for accessing meta data information outside a .pak archive.
/// </summary> /// </summary>
public static byte[] WriteMetaFooter(FileReader reader, uint metaOffset, string type) public static byte[] WriteMetaFooter(FileReader reader, uint metaOffset, string type, PACK pack)
{ {
//Magic + meta offset first //Magic + meta offset first
var mem = new MemoryStream(); var mem = new MemoryStream();
using (var writer = new FileWriter(mem)) using (var writer = new FileWriter(mem))
{ {
writer.SetByteOrder(true); writer.SetByteOrder(!pack.IsLittleEndian);
reader.SeekBegin(metaOffset); reader.SeekBegin(metaOffset);
var file = GetFileForm(type); var file = GetFileForm(type);
file.ReadMetaData(reader); file.ReadMetaData(reader, pack.FileHeader);
file.WriteMetaData(writer); file.WriteMetaData(writer, pack.FileHeader);
//Write footer header last //Write footer header last
writer.WriteSignature("META"); writer.WriteSignature("META");
writer.WriteSignature(type); writer.WriteSignature(type);
writer.Write(pack.FileHeader.VersionA);
writer.Write(pack.FileHeader.VersionB);
writer.Write((uint)(writer.BaseStream.Length + 4)); //size writer.Write((uint)(writer.BaseStream.Length + 4)); //size
} }
return mem.ToArray(); return mem.ToArray();

View file

@ -58,14 +58,12 @@ namespace DKCTF
reader.SetByteOrder(true); reader.SetByteOrder(true);
Console.WriteLine($"type {type}"); Console.WriteLine($"type {type}");
// File.WriteAllBytes($"Buffer{type}.bin", reader.ReadBytes((int)(compSize - 4)));
var data = reader.ReadBytes((int)compSize - 4); var data = reader.ReadBytes((int)compSize - 4);
switch (type) switch (type)
{ {
case CompressionType.None: case CompressionType.None:
return reader.ReadBytes((int)decompSize); return data;
//LZSS with byte, short, and uint types //LZSS with byte, short, and uint types
case CompressionType.LZSS_8: return DecompressLZSS(data, 1, decompSize); case CompressionType.LZSS_8: return DecompressLZSS(data, 1, decompSize);
case CompressionType.LZSS_16: return DecompressLZSS(data, 2, decompSize); case CompressionType.LZSS_16: return DecompressLZSS(data, 2, decompSize);

View file

@ -70,7 +70,7 @@ namespace DKCTF
for (int i = 0; i < numEntries; i++) for (int i = 0; i < numEntries; i++)
{ {
DirectoryAssetEntry entry = new DirectoryAssetEntry(); DirectoryAssetEntry entry = new DirectoryAssetEntry();
entry.Read(reader); entry.Read(reader, this.FileHeader);
Assets.Add(entry); Assets.Add(entry);
} }
} }
@ -85,7 +85,8 @@ namespace DKCTF
var id = IOFileExtension.ReadID(reader); var id = IOFileExtension.ReadID(reader);
uint offset = reader.ReadUInt32(); uint offset = reader.ReadUInt32();
MetaOffsets.Add(id.ToString(), offset); if (!MetaOffsets.ContainsKey(id.ToString()))
MetaOffsets.Add(id.ToString(), offset);
} }
} }
@ -118,14 +119,27 @@ namespace DKCTF
public CObjectId FileID; public CObjectId FileID;
public long Offset; public long Offset;
public long DecompressedSize;
public long Size; public long Size;
public void Read(FileReader reader) public void Read(FileReader reader, CFormDescriptor header)
{ {
Type = reader.ReadString(4, Encoding.ASCII); Type = reader.ReadString(4, Encoding.ASCII);
FileID = IOFileExtension.ReadID(reader); FileID = IOFileExtension.ReadID(reader);
Offset = reader.ReadInt64(); if (header.VersionA >= 1 && header.VersionB >= 1)
Size = reader.ReadInt64(); {
long flag1 = reader.ReadUInt32();
long flag2 = reader.ReadUInt32();
Offset = reader.ReadInt64();
DecompressedSize = reader.ReadInt64();
Size = reader.ReadInt64();
}
else
{
Offset = reader.ReadInt64();
Size = reader.ReadInt64();
DecompressedSize = Size;
}
} }
} }

View file

@ -26,7 +26,6 @@ namespace DKCTF
public uint Unknown { get; set; } public uint Unknown { get; set; }
public bool IsSwitch => this.FileHeader.VersionA >= 0x0F; public bool IsSwitch => this.FileHeader.VersionA >= 0x0F;
public TXTR() { } public TXTR() { }
@ -35,34 +34,57 @@ namespace DKCTF
{ {
} }
public byte[] CreateUncompressedFile(byte[] fileData) public byte[] CreateUncompressedFile(byte[] fileData, CFormDescriptor pakHeader, bool isLittleEndian)
{ {
var mem = new MemoryStream(); var mem = new MemoryStream();
using (var writer = new FileWriter(mem)) using (var writer = new FileWriter(mem))
using (var reader = new FileReader(fileData)) using (var reader = new FileReader(fileData))
{ {
writer.SetByteOrder(true); reader.SetByteOrder(!isLittleEndian);
reader.SetByteOrder(true); writer.SetByteOrder(!isLittleEndian);
FileHeader = reader.ReadStruct<CFormDescriptor>(); FileHeader = reader.ReadStruct<CFormDescriptor>();
ReadMetaFooter(reader); ReadMetaFooter(reader);
//Rewrite header for saving uncompressed file
reader.Position = 0; reader.Position = 0;
byte[] textureInfo = reader.ReadBytes((int)Meta.GPUOffset + 24); byte[] textureInfo = reader.ReadBytes((int)Meta.GPUOffset + 24);
long pos = reader.BaseStream.Position - 24; long pos = reader.BaseStream.Position - 24;
var buffer = Meta.BufferInfo[0]; List<byte[]> combinedBuffer = new List<byte[]>();
reader.Seek(buffer.Offset);
byte[] BufferData = IOFileExtension.DecompressedBuffer(reader, buffer.CompressedSize, buffer.DecompressedSize, IsSwitch); byte[] textureData = new byte[Meta.DecompressedSize];
if (pakHeader.VersionA >= 1 && pakHeader.VersionB >= 1)
{
//Decompress all buffers
foreach (var info in Meta.TextureInfo)
{
var buff = Meta.BufferInfo[info.Index];
//Go to the buffer
reader.SeekBegin(info.StartOffset + buff.StartOffset);
//Decompress the buffer
byte[] BufferData = IOFileExtension.DecompressedBuffer(reader, buff.CompressedSize, buff.DestSize, IsSwitch || isLittleEndian);
combinedBuffer.Add(BufferData);
Array.Copy(BufferData, 0, textureData, (int)buff.DestOffset, (int)buff.DestSize);
}
}
else
{
var buffer = Meta.BufferInfoV1[0];
reader.SeekBegin(Meta.GPUDataStart + buffer.Offset);
textureData = IOFileExtension.DecompressedBuffer(reader, buffer.CompressedSize, buffer.DecompressedSize, IsSwitch);
}
writer.Write(textureInfo); writer.Write(textureInfo);
writer.Write(BufferData); writer.Write(textureData);
using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) {
{ writer.Write((long)textureData.Length);
writer.Write((long)BufferData.Length);
} }
return mem.ToArray(); return mem.ToArray();
@ -84,9 +106,8 @@ namespace DKCTF
if (Meta != null) if (Meta != null)
{ {
var buffer = Meta.BufferInfo[0]; var buffer = Meta.BufferInfo[0];
reader.SeekBegin(buffer.StartOffset);
reader.Seek(buffer.Offset); BufferData = IOFileExtension.DecompressedBuffer(reader, (uint)buffer.CompressedSize, (uint)buffer.DestSize, IsSwitch);
BufferData = IOFileExtension.DecompressedBuffer(reader, buffer.CompressedSize, buffer.DecompressedSize, IsSwitch);
} }
else else
{ {
@ -96,33 +117,63 @@ namespace DKCTF
} }
} }
public override void ReadMetaData(FileReader reader) public override void ReadMetaData(FileReader reader, CFormDescriptor pakVersion)
{ {
Meta = new SMetaData(); Meta = new SMetaData();
Meta.Unknown = reader.ReadUInt32(); // MPR
Meta.AllocCategory = reader.ReadUInt32(); if (pakVersion.VersionA >= 1 && pakVersion.VersionB >= 1)
Meta.GPUOffset = reader.ReadUInt32(); {
Meta.BaseAlignment = reader.ReadUInt32(); reader.ReadUInt32(); //Extra uint in MPR
Meta.GPUDataStart = reader.ReadUInt32(); Meta.Unknown = reader.ReadUInt32();
Meta.GPUDataSize = reader.ReadUInt32(); Meta.AllocCategory = reader.ReadUInt32();
Meta.BufferInfo = IOFileExtension.ReadList<SCompressedBufferInfo>(reader); Meta.GPUOffset = reader.ReadUInt32();
Meta.BaseAlignment = reader.ReadUInt32();
Meta.DecompressedSize = reader.ReadUInt32(); //total decomp size
Meta.TextureInfo = IOFileExtension.ReadList<STextureInfo>(reader);
Meta.BufferInfo = IOFileExtension.ReadList<SCompressedBufferInfo>(reader);
}
else
{
Meta.Unknown = reader.ReadUInt32();
Meta.AllocCategory = reader.ReadUInt32();
Meta.GPUOffset = reader.ReadUInt32();
Meta.BaseAlignment = reader.ReadUInt32();
Meta.GPUDataStart = reader.ReadUInt32();
Meta.GPUDataSize = reader.ReadUInt32();
Meta.BufferInfoV1 = IOFileExtension.ReadList<SCompressedBufferInfoV1>(reader);
}
Console.WriteLine();
} }
public override void WriteMetaData(FileWriter writer) public override void WriteMetaData(FileWriter writer, CFormDescriptor pakVersion)
{ {
writer.Write(Meta.Unknown); if (pakVersion.VersionA >= 1 && pakVersion.VersionB >= 1)
writer.Write(Meta.AllocCategory); {
writer.Write(Meta.GPUOffset); writer.Write(Meta.Unknown);
writer.Write(Meta.BaseAlignment); writer.Write(0);
writer.Write(Meta.GPUDataStart); writer.Write(Meta.AllocCategory);
writer.Write(Meta.GPUDataSize); writer.Write(Meta.GPUOffset);
IOFileExtension.WriteList(writer, Meta.BufferInfo); writer.Write(Meta.BaseAlignment);
writer.Write(Meta.DecompressedSize);
IOFileExtension.WriteList(writer, Meta.TextureInfo);
IOFileExtension.WriteList(writer, Meta.BufferInfo);
}
else
{
writer.Write(Meta.Unknown);
writer.Write(Meta.AllocCategory);
writer.Write(Meta.GPUOffset);
writer.Write(Meta.BaseAlignment);
writer.Write(Meta.GPUDataStart);
writer.Write(Meta.GPUDataSize);
IOFileExtension.WriteList(writer, Meta.BufferInfoV1);
}
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential, Pack = 1)]
public class STextureHeader public class STextureHeader
{ {
public uint Type; public uint Type; //1 = 2D 3 = Cubemap
public uint Format; public uint Format;
public uint Width; public uint Width;
public uint Height; public uint Height;
@ -135,16 +186,38 @@ namespace DKCTF
public class SMetaData public class SMetaData
{ {
public uint Unknown; //4 public uint Unknown; //4
public uint Unknown2;
public uint AllocCategory; public uint AllocCategory;
public uint GPUOffset; public uint GPUOffset;
public uint BaseAlignment;
public uint GPUDataStart; public uint GPUDataStart;
public uint GPUDataSize; public uint GPUDataSize;
public uint BaseAlignment;
public uint DecompressedSize;
public List<STextureInfo> TextureInfo = new List<STextureInfo>();
public List<SCompressedBufferInfo> BufferInfo = new List<SCompressedBufferInfo>(); public List<SCompressedBufferInfo> BufferInfo = new List<SCompressedBufferInfo>();
public List<SCompressedBufferInfoV1> BufferInfoV1 = new List<SCompressedBufferInfoV1>();
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class STextureInfo
{
public byte Index;
public uint StartOffset;
public uint EndOffset;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential, Pack = 1)]
public class SCompressedBufferInfo public class SCompressedBufferInfo
{
public uint Index;
public uint StartOffset;
public uint CompressedSize;
public uint DestOffset;
public uint DestSize;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class SCompressedBufferInfoV1
{ {
public uint DecompressedSize; public uint DecompressedSize;
public uint CompressedSize; public uint CompressedSize;

View file

@ -58,9 +58,14 @@ namespace DKCTF
public Dictionary<string, CHAR> CharFiles = new Dictionary<string, CHAR>(); public Dictionary<string, CHAR> CharFiles = new Dictionary<string, CHAR>();
public Dictionary<string, FileEntry> AnimFiles = new Dictionary<string, FileEntry>(); public Dictionary<string, FileEntry> AnimFiles = new Dictionary<string, FileEntry>();
public PACK PakData;
internal bool IsMPR;
public void Load(System.IO.Stream stream) public void Load(System.IO.Stream stream)
{ {
PACK pack = new PACK(stream); PACK pack = new PACK(stream);
PakData = pack;
for (int i = 0; i < pack.Assets.Count; i++) for (int i = 0; i < pack.Assets.Count; i++)
{ {
@ -124,12 +129,13 @@ namespace DKCTF
if (file.AssetEntry.Type == "ANIM") file.FileName = file.FileName.Replace("exportData", "animations"); if (file.AssetEntry.Type == "ANIM") file.FileName = file.FileName.Replace("exportData", "animations");
} }
} }
files = files.OrderBy(x => x.FileName).ToList(); // files = files.OrderBy(x => x.FileName).ToList();
} }
Dictionary<string, string> DirectoryLabels = new Dictionary<string, string>() Dictionary<string, string> DirectoryLabels = new Dictionary<string, string>()
{ {
{ "CHAR", "Characters" }, { "CHAR", "Characters" },
{ "CHPR", "Character Project" },
{ "CMDL", "Static Models" }, { "CMDL", "Static Models" },
{ "SMDL", "Skinned Models" }, { "SMDL", "Skinned Models" },
{ "TXTR", "Textures" }, { "TXTR", "Textures" },
@ -185,14 +191,20 @@ namespace DKCTF
using (var reader = new FileReader(SubData, true)) using (var reader = new FileReader(SubData, true))
{ {
Data.Add(reader.ReadBytes((int)reader.BaseStream.Length)); var data = reader.ReadBytes((int)reader.BaseStream.Length);
reader.Position = 0;
if (AssetEntry.DecompressedSize != AssetEntry.Size)
data = IOFileExtension.DecompressedBuffer(reader, (uint)AssetEntry.Size, (uint)AssetEntry.DecompressedSize, true);
Data.Add(data);
if (WriteMetaData) if (WriteMetaData)
{ {
using (var r = new FileReader(ArchiveStream, true)) { using (var r = new FileReader(ArchiveStream, true)) {
r.SetByteOrder(true); r.SetByteOrder(!ParentArchive.PakData.IsLittleEndian);
Data.Add(FileForm.WriteMetaFooter(r, (uint)MetaPointer, AssetEntry.Type)); Data.Add(FileForm.WriteMetaFooter(r, (uint)MetaPointer, AssetEntry.Type, ParentArchive.PakData));
} }
} }
} }
@ -200,7 +212,7 @@ namespace DKCTF
if (AssetEntry.Type == "TXTR") if (AssetEntry.Type == "TXTR")
{ {
var txt = new TXTR(); var txt = new TXTR();
return txt.CreateUncompressedFile(Utils.CombineByteArray(Data.ToArray())); return txt.CreateUncompressedFile(Utils.CombineByteArray(Data.ToArray()), ParentArchive.PakData.FileHeader, ParentArchive.PakData.IsMPR);
} }
@ -255,7 +267,7 @@ namespace DKCTF
} }
if (file is CCharacter) if (file is CCharacter)
((CCharacter)file).LoadModels(pak); ((CCharacter)file).LoadModels(pak);
this.FileFormat = file; this.FileFormat = file;
return file; return file;

View file

@ -48,6 +48,7 @@ namespace Toolbox.Library.Forms
{ {
if (genericObjects.Count == 0) return; if (genericObjects.Count == 0) return;
foreach (var genericObject in genericObjects) foreach (var genericObject in genericObjects)
{ {
int divisions = 4; int divisions = 4;
@ -83,8 +84,6 @@ namespace Toolbox.Library.Forms
} }
} }
Console.WriteLine($"displayFaceSize {f.Count} {displayFaceSize} {genericObject.vertices.Count }");
for (int v = 0; v < displayFaceSize; v += 3) for (int v = 0; v < displayFaceSize; v += 3)
{ {
if (displayFaceSize < 3 || genericObject.vertices.Count < 3) if (displayFaceSize < 3 || genericObject.vertices.Count < 3)

View file

@ -202,13 +202,22 @@ namespace Toolbox.Library.Forms
{ {
if (meshesCB.SelectedIndex >= 0) if (meshesCB.SelectedIndex >= 0)
{ {
uvViewport1.ActiveObjects.Clear();
if (Objects.Count > meshesCB.SelectedIndex)
uvViewport1.ActiveObjects.Add(Objects[meshesCB.SelectedIndex]);
ActiveMaterial = Materials[meshesCB.SelectedIndex]; ActiveMaterial = Materials[meshesCB.SelectedIndex];
uvViewport1.ActiveObjects.Clear();
foreach (var obj in Objects)
{
if (obj.GetMaterial() == ActiveMaterial)
uvViewport1.ActiveObjects.Add(obj);
foreach (var p in obj.PolygonGroups)
{
if (p.Material == ActiveMaterial && !uvViewport1.ActiveObjects.Contains(obj))
uvViewport1.ActiveObjects.Add(obj);
}
}
ChannelTextures.Clear(); ChannelTextures.Clear();
Textures.Clear(); Textures.Clear();
textureCB.Items.Clear(); textureCB.Items.Clear();
@ -235,6 +244,8 @@ namespace Toolbox.Library.Forms
if (textureCB.Items.Count > 0) if (textureCB.Items.Count > 0)
textureCB.SelectedIndex = 0; textureCB.SelectedIndex = 0;
uvViewport1.UpdateViewport();
} }
} }