mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2024-11-21 20:13:06 +00:00
Update retro formats to support Metroid Prime Remastered
This commit is contained in:
parent
976939bec0
commit
afe7ab3890
13 changed files with 322 additions and 128 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -356,3 +356,4 @@ Toolbox/Lib.zip
|
|||
yuzu-glsl-decompiler
|
||||
AnimSetupPrevious.zip
|
||||
AnimSetupNew.zip
|
||||
Switch_Toolbox_Library/Forms/Editors/UV/UVEditor.cs
|
||||
|
|
|
@ -140,8 +140,10 @@ namespace DKCTF
|
|||
{
|
||||
string guid = texMap.Value.FileID.ToString();
|
||||
if (texFolder.Nodes.ContainsKey(guid) || !Textures.ContainsKey(guid))
|
||||
{
|
||||
Console.WriteLine($"Texture not present in pak file! {mat.Name} {texMap.Key} {guid}");
|
||||
continue;
|
||||
|
||||
}
|
||||
if (Textures[guid].FileFormat == null)
|
||||
Textures[guid].OpenFile();
|
||||
|
||||
|
@ -153,7 +155,7 @@ namespace DKCTF
|
|||
t.Tag = tex;
|
||||
texFolder.Nodes.Add(t);
|
||||
|
||||
if (texMap.Key == "DIFT")
|
||||
if (texMap.Key == "DIFT" || texMap.Key == "BCLR")
|
||||
{
|
||||
tex.Text = guid;
|
||||
|
||||
|
@ -167,6 +169,7 @@ namespace DKCTF
|
|||
|
||||
TreeNode texFolder = new STTextureFolder("Textures");
|
||||
TreeNode skeletonFolder = new STTextureFolder("Skeleton");
|
||||
TreeNode shaderFolder = new STTextureFolder("Materials");
|
||||
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
|
@ -179,11 +182,14 @@ namespace DKCTF
|
|||
Nodes.Add(meshFolder);
|
||||
|
||||
Nodes.Add(texFolder);
|
||||
|
||||
Nodes.Add(skeletonFolder);
|
||||
Nodes.Add(shaderFolder);
|
||||
|
||||
Model = ToGeneric();
|
||||
|
||||
foreach (var mat in ModelData.Materials)
|
||||
shaderFolder.Nodes.Add(new TreeNode(mat.Name + "_" + mat.ID.ToString()));
|
||||
|
||||
foreach (GenericRenderedObject mesh in Model.Objects)
|
||||
{
|
||||
Renderer.Meshes.Add(mesh);
|
||||
|
@ -235,6 +241,7 @@ namespace DKCTF
|
|||
if (tex.Key == "DIFT") type = STGenericMatTexture.TextureType.Diffuse;
|
||||
if (tex.Key == "NMAP") type = STGenericMatTexture.TextureType.Normal;
|
||||
if (tex.Key == "SPCT") type = STGenericMatTexture.TextureType.Specular;
|
||||
if (tex.Key == "BCLR") type = STGenericMatTexture.TextureType.Diffuse;
|
||||
|
||||
genericMaterial.TextureMaps.Add(new STGenericMatTexture()
|
||||
{
|
||||
|
|
|
@ -134,13 +134,16 @@ namespace DKCTF
|
|||
|
||||
Header = new TXTR(stream);
|
||||
|
||||
if (Header.IsSwitch)
|
||||
if (!Header.IsSwitch)
|
||||
PlatformSwizzle = PlatformSwizzle.Platform_WiiU;
|
||||
|
||||
Width = Header.TextureHeader.Width;
|
||||
Height = Header.TextureHeader.Height;
|
||||
MipCount = (uint)Header.MipSizes.Length;
|
||||
Format = FormatList[Header.TextureHeader.Format];
|
||||
|
||||
if (Header.TextureHeader.Type == 3)
|
||||
this.ArrayCount = 6;
|
||||
}
|
||||
|
||||
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>()
|
||||
{
|
||||
{ 12, TEX_FORMAT.R8G8B8A8_UNORM },
|
||||
|
@ -257,11 +248,40 @@ namespace DKCTF
|
|||
{ 32, TEX_FORMAT.R16G16_FLOAT },
|
||||
{ 33, TEX_FORMAT.R8G8_UNORM },
|
||||
|
||||
{ 53, TEX_FORMAT.ASTC_4x4_UNORM },
|
||||
{ 54, TEX_FORMAT.ASTC_5x4_UNORM },
|
||||
{ 55, TEX_FORMAT.ASTC_5x5_UNORM },
|
||||
{ 56, TEX_FORMAT.ASTC_6x5_UNORM },
|
||||
{ 57, TEX_FORMAT.ASTC_6x6_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 },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,19 +42,23 @@ namespace DKCTF
|
|||
/// <summary>
|
||||
/// Gets a vertex list from the provided buffer and descriptor info.
|
||||
/// </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++) {
|
||||
CMDL.CVertex vertex = new CMDL.CVertex();
|
||||
vertices.Add(vertex);
|
||||
for (int i = 0; i < vertexInfo.VertexCount; i++)
|
||||
{
|
||||
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);
|
||||
switch (comp.Type)
|
||||
{
|
||||
|
@ -68,7 +72,7 @@ namespace DKCTF
|
|||
vertex.TexCoord0 = ReadData(reader, comp.Format).Xy;
|
||||
break;
|
||||
case CMDL.EVertexComponent.in_texCoord1:
|
||||
vertex.TexCoord1 = ReadData(reader, comp.Format).Xy;
|
||||
vertex.TexCoord0 = ReadData(reader, comp.Format).Xy;
|
||||
break;
|
||||
case CMDL.EVertexComponent.in_texCoord2:
|
||||
vertex.TexCoord2 = ReadData(reader, comp.Format).Xy;
|
||||
|
@ -89,7 +93,6 @@ namespace DKCTF
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace DKCTF
|
|||
|
||||
public override void Read(FileReader reader)
|
||||
{
|
||||
reader.ReadStruct<CAssetHeader>();
|
||||
var assetHeader = reader.ReadStruct<CAssetHeader>();
|
||||
reader.ReadStruct<SInfo>();
|
||||
//Dumb hack atm
|
||||
bool IsSwitch = false;
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace DKCTF
|
|||
{
|
||||
}
|
||||
|
||||
public override void ReadMetaData(FileReader reader)
|
||||
public override void ReadMetaData(FileReader reader, CFormDescriptor pakVersion)
|
||||
{
|
||||
Meta = new SMetaData();
|
||||
Meta.Unknown = reader.ReadUInt32();
|
||||
|
@ -60,13 +60,12 @@ namespace DKCTF
|
|||
Meta.ReadBufferInfo = IOFileExtension.ReadList<SReadBufferInfo>(reader);
|
||||
Meta.VertexBuffers = 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.GPUOffset);
|
||||
IOFileExtension.WriteList(writer, Meta.ReadBufferInfo);
|
||||
IOFileExtension.WriteList(writer, Meta.VertexBuffers);
|
||||
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++)
|
||||
{
|
||||
var vertexInfo = VertexBuffers[i];
|
||||
|
||||
var buffer = Meta.VertexBuffers[i];
|
||||
//First buffer or specific buffer
|
||||
var info = Meta.ReadBufferInfo[(int)buffer.ReadBufferIndex];
|
||||
//Seek into the buffer region
|
||||
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
|
||||
var data = IOFileExtension.DecompressedBuffer(reader, buffer.CompressedSize, buffer.DecompressedSize, IsSwitch);
|
||||
if (buffer.DecompressedSize != data.Length)
|
||||
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
|
||||
foreach (var mesh in Meshes)
|
||||
{
|
||||
if (mesh.Header.VertexBufferIndex == i)
|
||||
{
|
||||
//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;
|
||||
if (mesh.Header.VertexBufferIndex == j)
|
||||
mesh.SetupVertices(vertices.ToList());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -241,6 +234,8 @@ namespace DKCTF
|
|||
|
||||
private void ReadMaterials(FileReader reader)
|
||||
{
|
||||
if (this.IsMPR)
|
||||
reader.ReadUInt32();
|
||||
uint numMaterials = reader.ReadUInt32();
|
||||
for (int i = 0; i < numMaterials; i++)
|
||||
{
|
||||
|
@ -250,8 +245,26 @@ namespace DKCTF
|
|||
uint size = reader.ReadUInt32();
|
||||
material.Name = reader.ReadString((int)size, true);
|
||||
material.ID = reader.ReadStruct<CObjectId>();
|
||||
material.Type = reader.ReadStruct<Magic>();
|
||||
material.Flags = reader.ReadUInt32();
|
||||
if (this.IsMPR)
|
||||
{
|
||||
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();
|
||||
|
||||
//A list of data types
|
||||
|
@ -304,6 +317,9 @@ namespace DKCTF
|
|||
reader.ReadStruct<STextureUsageInfo>();
|
||||
}
|
||||
break;
|
||||
case "MA4": //Matrix4x4
|
||||
material.Matrices.Add(dtype, reader.ReadSingles(16));
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Unsupported material type {dformat}!");
|
||||
}
|
||||
|
@ -315,10 +331,31 @@ namespace DKCTF
|
|||
{
|
||||
uint numMeshes = reader.ReadUInt32();
|
||||
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()
|
||||
{
|
||||
Header = reader.ReadStruct<CRenderMesh>(),
|
||||
Header = mesh,
|
||||
});
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private void ReadVertexBuffer(FileReader reader)
|
||||
|
@ -334,6 +371,8 @@ namespace DKCTF
|
|||
for (int j = 0; j < numAttributes; j++)
|
||||
vertexBuffer.Components.Add(reader.ReadStruct<SVertexDataComponent>());
|
||||
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, int> Int = 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>();
|
||||
}
|
||||
|
@ -416,16 +456,13 @@ namespace DKCTF
|
|||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public class CRenderMesh
|
||||
{
|
||||
public PrimtiiveType PrimtiiveMode;
|
||||
public ushort MaterialIndex;
|
||||
public byte VertexBufferIndex;
|
||||
public byte IndexBufferIndex;
|
||||
public uint IndexStart;
|
||||
public uint IndexCount;
|
||||
public ushort field_10;
|
||||
public byte field_12;
|
||||
public byte field_13;
|
||||
public byte field_14;
|
||||
public ushort field_C;
|
||||
public ushort field_E; //0x4000
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
|
@ -465,7 +502,7 @@ namespace DKCTF
|
|||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public class SVertexDataComponent
|
||||
{
|
||||
public uint field_0;
|
||||
public uint BufferID;
|
||||
public uint Offset;
|
||||
public uint Stride;
|
||||
public VertexFormat Format;
|
||||
|
|
|
@ -20,11 +20,22 @@ namespace DKCTF
|
|||
|
||||
public FileForm() { }
|
||||
|
||||
public bool IsLittleEndian = false;
|
||||
public bool IsMPR = false;
|
||||
|
||||
public FileForm(Stream stream, bool leaveOpen = false)
|
||||
{
|
||||
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>();
|
||||
Read(reader);
|
||||
AfterLoad();
|
||||
|
@ -61,7 +72,7 @@ namespace DKCTF
|
|||
/// <summary>
|
||||
/// Reads meta data information within the pak archive.
|
||||
/// </summary>
|
||||
public virtual void ReadMetaData(FileReader reader)
|
||||
public virtual void ReadMetaData(FileReader reader, CFormDescriptor pakVersion)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -69,7 +80,7 @@ namespace DKCTF
|
|||
/// <summary>
|
||||
/// Writes meta data information within the pak archive.
|
||||
/// </summary>
|
||||
public virtual void WriteMetaData(FileWriter writer)
|
||||
public virtual void WriteMetaData(FileWriter writer, CFormDescriptor pakVersion)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -87,22 +98,28 @@ namespace DKCTF
|
|||
/// </summary>
|
||||
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")
|
||||
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.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
|
||||
//Seek back to meta data
|
||||
reader.SeekBegin(reader.Position - size);
|
||||
//Read meta data
|
||||
ReadMetaData(reader);
|
||||
CFormDescriptor pakHeader = new CFormDescriptor();
|
||||
pakHeader.VersionA = versionA;
|
||||
pakHeader.VersionB = versionB;
|
||||
|
||||
ReadMetaData(reader, pakHeader);
|
||||
|
||||
return reader.BaseStream.Length - size;
|
||||
}
|
||||
|
@ -111,22 +128,24 @@ namespace DKCTF
|
|||
/// <summary>
|
||||
/// Writes a footer to a file for accessing meta data information outside a .pak archive.
|
||||
/// </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
|
||||
var mem = new MemoryStream();
|
||||
using (var writer = new FileWriter(mem))
|
||||
{
|
||||
writer.SetByteOrder(true);
|
||||
writer.SetByteOrder(!pack.IsLittleEndian);
|
||||
|
||||
reader.SeekBegin(metaOffset);
|
||||
var file = GetFileForm(type);
|
||||
file.ReadMetaData(reader);
|
||||
file.WriteMetaData(writer);
|
||||
file.ReadMetaData(reader, pack.FileHeader);
|
||||
file.WriteMetaData(writer, pack.FileHeader);
|
||||
|
||||
//Write footer header last
|
||||
writer.WriteSignature("META");
|
||||
writer.WriteSignature(type);
|
||||
writer.Write(pack.FileHeader.VersionA);
|
||||
writer.Write(pack.FileHeader.VersionB);
|
||||
writer.Write((uint)(writer.BaseStream.Length + 4)); //size
|
||||
}
|
||||
return mem.ToArray();
|
||||
|
|
|
@ -58,14 +58,12 @@ namespace DKCTF
|
|||
reader.SetByteOrder(true);
|
||||
|
||||
Console.WriteLine($"type {type}");
|
||||
// File.WriteAllBytes($"Buffer{type}.bin", reader.ReadBytes((int)(compSize - 4)));
|
||||
|
||||
var data = reader.ReadBytes((int)compSize - 4);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CompressionType.None:
|
||||
return reader.ReadBytes((int)decompSize);
|
||||
return data;
|
||||
//LZSS with byte, short, and uint types
|
||||
case CompressionType.LZSS_8: return DecompressLZSS(data, 1, decompSize);
|
||||
case CompressionType.LZSS_16: return DecompressLZSS(data, 2, decompSize);
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace DKCTF
|
|||
for (int i = 0; i < numEntries; i++)
|
||||
{
|
||||
DirectoryAssetEntry entry = new DirectoryAssetEntry();
|
||||
entry.Read(reader);
|
||||
entry.Read(reader, this.FileHeader);
|
||||
Assets.Add(entry);
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,8 @@ namespace DKCTF
|
|||
var id = IOFileExtension.ReadID(reader);
|
||||
|
||||
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 long Offset;
|
||||
public long DecompressedSize;
|
||||
public long Size;
|
||||
|
||||
public void Read(FileReader reader)
|
||||
public void Read(FileReader reader, CFormDescriptor header)
|
||||
{
|
||||
Type = reader.ReadString(4, Encoding.ASCII);
|
||||
FileID = IOFileExtension.ReadID(reader);
|
||||
Offset = reader.ReadInt64();
|
||||
Size = reader.ReadInt64();
|
||||
if (header.VersionA >= 1 && header.VersionB >= 1)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ namespace DKCTF
|
|||
|
||||
public uint Unknown { get; set; }
|
||||
|
||||
|
||||
public bool IsSwitch => this.FileHeader.VersionA >= 0x0F;
|
||||
|
||||
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();
|
||||
using (var writer = new FileWriter(mem))
|
||||
using (var reader = new FileReader(fileData))
|
||||
{
|
||||
writer.SetByteOrder(true);
|
||||
reader.SetByteOrder(true);
|
||||
reader.SetByteOrder(!isLittleEndian);
|
||||
writer.SetByteOrder(!isLittleEndian);
|
||||
|
||||
FileHeader = reader.ReadStruct<CFormDescriptor>();
|
||||
ReadMetaFooter(reader);
|
||||
|
||||
//Rewrite header for saving uncompressed file
|
||||
reader.Position = 0;
|
||||
byte[] textureInfo = reader.ReadBytes((int)Meta.GPUOffset + 24);
|
||||
|
||||
long pos = reader.BaseStream.Position - 24;
|
||||
|
||||
var buffer = Meta.BufferInfo[0];
|
||||
reader.Seek(buffer.Offset);
|
||||
List<byte[]> combinedBuffer = new List<byte[]>();
|
||||
|
||||
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(BufferData);
|
||||
writer.Write(textureData);
|
||||
|
||||
using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin))
|
||||
{
|
||||
writer.Write((long)BufferData.Length);
|
||||
using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) {
|
||||
writer.Write((long)textureData.Length);
|
||||
}
|
||||
|
||||
return mem.ToArray();
|
||||
|
@ -84,9 +106,8 @@ namespace DKCTF
|
|||
if (Meta != null)
|
||||
{
|
||||
var buffer = Meta.BufferInfo[0];
|
||||
|
||||
reader.Seek(buffer.Offset);
|
||||
BufferData = IOFileExtension.DecompressedBuffer(reader, buffer.CompressedSize, buffer.DecompressedSize, IsSwitch);
|
||||
reader.SeekBegin(buffer.StartOffset);
|
||||
BufferData = IOFileExtension.DecompressedBuffer(reader, (uint)buffer.CompressedSize, (uint)buffer.DestSize, IsSwitch);
|
||||
}
|
||||
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.Unknown = reader.ReadUInt32();
|
||||
Meta.AllocCategory = reader.ReadUInt32();
|
||||
Meta.GPUOffset = reader.ReadUInt32();
|
||||
Meta.BaseAlignment = reader.ReadUInt32();
|
||||
Meta.GPUDataStart = reader.ReadUInt32();
|
||||
Meta.GPUDataSize = reader.ReadUInt32();
|
||||
Meta.BufferInfo = IOFileExtension.ReadList<SCompressedBufferInfo>(reader);
|
||||
// MPR
|
||||
if (pakVersion.VersionA >= 1 && pakVersion.VersionB >= 1)
|
||||
{
|
||||
reader.ReadUInt32(); //Extra uint in MPR
|
||||
Meta.Unknown = reader.ReadUInt32();
|
||||
Meta.AllocCategory = reader.ReadUInt32();
|
||||
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);
|
||||
writer.Write(Meta.AllocCategory);
|
||||
writer.Write(Meta.GPUOffset);
|
||||
writer.Write(Meta.BaseAlignment);
|
||||
writer.Write(Meta.GPUDataStart);
|
||||
writer.Write(Meta.GPUDataSize);
|
||||
IOFileExtension.WriteList(writer, Meta.BufferInfo);
|
||||
if (pakVersion.VersionA >= 1 && pakVersion.VersionB >= 1)
|
||||
{
|
||||
writer.Write(Meta.Unknown);
|
||||
writer.Write(0);
|
||||
writer.Write(Meta.AllocCategory);
|
||||
writer.Write(Meta.GPUOffset);
|
||||
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)]
|
||||
public class STextureHeader
|
||||
{
|
||||
public uint Type;
|
||||
public uint Type; //1 = 2D 3 = Cubemap
|
||||
public uint Format;
|
||||
public uint Width;
|
||||
public uint Height;
|
||||
|
@ -135,16 +186,38 @@ namespace DKCTF
|
|||
public class SMetaData
|
||||
{
|
||||
public uint Unknown; //4
|
||||
public uint Unknown2;
|
||||
public uint AllocCategory;
|
||||
public uint GPUOffset;
|
||||
public uint BaseAlignment;
|
||||
public uint GPUDataStart;
|
||||
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<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)]
|
||||
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 CompressedSize;
|
||||
|
|
|
@ -58,9 +58,14 @@ namespace DKCTF
|
|||
public Dictionary<string, CHAR> CharFiles = new Dictionary<string, CHAR>();
|
||||
public Dictionary<string, FileEntry> AnimFiles = new Dictionary<string, FileEntry>();
|
||||
|
||||
public PACK PakData;
|
||||
|
||||
internal bool IsMPR;
|
||||
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
PACK pack = new PACK(stream);
|
||||
PakData = pack;
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
files = files.OrderBy(x => x.FileName).ToList();
|
||||
// files = files.OrderBy(x => x.FileName).ToList();
|
||||
}
|
||||
|
||||
Dictionary<string, string> DirectoryLabels = new Dictionary<string, string>()
|
||||
{
|
||||
{ "CHAR", "Characters" },
|
||||
{ "CHPR", "Character Project" },
|
||||
{ "CMDL", "Static Models" },
|
||||
{ "SMDL", "Skinned Models" },
|
||||
{ "TXTR", "Textures" },
|
||||
|
@ -185,14 +191,20 @@ namespace DKCTF
|
|||
|
||||
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)
|
||||
{
|
||||
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")
|
||||
{
|
||||
var txt = new TXTR();
|
||||
return txt.CreateUncompressedFile(Utils.CombineByteArray(Data.ToArray()));
|
||||
return txt.CreateUncompressedFile(Utils.CombineByteArray(Data.ToArray()), ParentArchive.PakData.FileHeader, ParentArchive.PakData.IsMPR);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace Toolbox.Library.Forms
|
|||
{
|
||||
if (genericObjects.Count == 0) return;
|
||||
|
||||
|
||||
foreach (var genericObject in genericObjects)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (displayFaceSize < 3 || genericObject.vertices.Count < 3)
|
||||
|
|
|
@ -202,13 +202,22 @@ namespace Toolbox.Library.Forms
|
|||
{
|
||||
if (meshesCB.SelectedIndex >= 0)
|
||||
{
|
||||
uvViewport1.ActiveObjects.Clear();
|
||||
|
||||
if (Objects.Count > meshesCB.SelectedIndex)
|
||||
uvViewport1.ActiveObjects.Add(Objects[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();
|
||||
Textures.Clear();
|
||||
textureCB.Items.Clear();
|
||||
|
@ -235,6 +244,8 @@ namespace Toolbox.Library.Forms
|
|||
|
||||
if (textureCB.Items.Count > 0)
|
||||
textureCB.SelectedIndex = 0;
|
||||
|
||||
uvViewport1.UpdateViewport();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue