From 1429a001784f35c389563cea5225f31a3f25d76e Mon Sep 17 00:00:00 2001 From: KillzXGaming Date: Mon, 22 Jul 2019 15:06:49 -0400 Subject: [PATCH] More fixes and additions Archives now use a link list for archive infos and treenodes. Handling replaced treenodes is easier and fixes renaming issues if a file was opened and renamed. More LM2 archive improvements, with more chunk loading. --- .vs/Toolbox/v15/.suo | Bin 508416 -> 526336 bytes .../Archives/LM2/LM2_ChunkTable.cs | 48 ++- .../FileFormats/Archives/LM2/LM2_DICT.cs | 321 ++++++++++-------- .../FileFormats/Archives/LM2/LM2_Enums.cs | 28 ++ .../FileFormats/Archives/LM2/LM2_Model.cs | 120 +++++++ .../FileFormats/Archives/LM2/TexturePOWE.cs | 99 ++++++ .../File_Format_Library.csproj | 3 + File_Format_Library/Main.cs | 1 + .../Editors/Object Editor/ObjectEditorTree.cs | 15 +- Switch_Toolbox_Library/Helpers/TreeHelper.cs | 10 +- Switch_Toolbox_Library/IO/FileReader.cs | 44 +++ .../Interfaces/IArchiveFile.cs | 42 ++- 12 files changed, 539 insertions(+), 192 deletions(-) create mode 100644 File_Format_Library/FileFormats/Archives/LM2/LM2_Enums.cs create mode 100644 File_Format_Library/FileFormats/Archives/LM2/LM2_Model.cs create mode 100644 File_Format_Library/FileFormats/Archives/LM2/TexturePOWE.cs diff --git a/.vs/Toolbox/v15/.suo b/.vs/Toolbox/v15/.suo index 878274dcc71b6ba89c7bb8214b1cad9cc0071b36..70c43e8c4aef1e4c355a0cb7fea9a804639a5d50 100644 GIT binary patch delta 14481 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

= zMPaz1cJXh6Q$5sB!QEL1=%IQEy2oG-MUmpXgSCrGeV{xB74&0IH6QXp&U|qFVPKQg z$nBR^Qh-tDf6DR}!=Bm5SLR+coD02BBJtzZ147n&p#OO6CQL+g={Dd0{|%HqjDeER z&^$Uo!bZ6mdQU_bMT^s&d8`m@IqZJ|T@7XWA(Tu~Z$jlVwHnq>QvK}XlC5fQ*q@}f zwwsRaO*EY+OD*Ua-jFp#eGf`fg+&FcRtTG-4kc&oPI~HXmBGH zs=8l{zCg^{p}rcFr>m>TIeR3Td_eVp>uKnd)@kZ-I5J)RQv)mZfr{y95EwAd2}bkb zn_0*d8bk?1%u<6P?K$-_8hEQDxZ^E5o z)!cNTX)XrNIT$Ky1Lj%?+^tTxYxsCB#^*v8w4vnZRN5du<2(^SS79{7DDx^wdg-7V z1lN12tbrCEIu?DkQnd)3-h{JxsK<*`O@_%Xs;`#(cx$vfSIF9q3>h*Jf4I3;EwoSe zCR|vH)`F2P01|R#lnJQ#BStSY1gAiPa&lOR(Jyd!(F3nfFLg7R*Wz+(8Ce2L3NQkr z#M-IPgAYSS_dQ_`Ne|^d7)N#y9x!)1YWI$P8%9^|1{X@vDYLgDA+!Nqu0C+0O!X1_ zGo}-D4%W#YVhUcx5OZ@s633NxC*K%MGXmn@P(8#>7owhoq}P#(F7rIWiLX|1$O;E` zs*Gdu(VjrzN;Sc5z9aA}+BDqtGwLMzJlyE1Zh(MYYNm(?C+uO&{F)lC9XR5{6D!mg zB@u7Z>Z!n@Jt!VW4zslipU*+pYIQe$7LCqjt;WqLcsKH0k)(QP{r6kZje4OQ=}FO> zFyKuLHb>x6naW}AK4iRp#~-Yn+Ux}tZ((Re&0mE*dr`i+17noU&~k%9(Yz;!d}F#j z**f<&8d%OgoDdgU2^j~}C+!&%O2Gmpzefq8tg9j7pn8UUT_-^|ZAnfyE#P@SYX4u&?p2Y{TLf&~9ZS{{ P(=)Z?^t8HWmE8UV2jjx( delta 8644 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 OrOW}uWbBxD*M9*^=P?5S diff --git a/File_Format_Library/FileFormats/Archives/LM2/LM2_ChunkTable.cs b/File_Format_Library/FileFormats/Archives/LM2/LM2_ChunkTable.cs index 1b7b3df9..9cd4ee10 100644 --- a/File_Format_Library/FileFormats/Archives/LM2/LM2_ChunkTable.cs +++ b/File_Format_Library/FileFormats/Archives/LM2/LM2_ChunkTable.cs @@ -5,8 +5,24 @@ using System.Text; using System.Threading.Tasks; using Toolbox.Library.IO; -namespace FirstPlugin +namespace FirstPlugin.LuigisMansion.DarkMoon { + public class ChunkEntry + { + public uint Unknown1; + public uint ChunkOffset; + public DataType ChunkType; + public uint ChunkSubCount; + public uint Unknown3; + } + + public class ChunkSubEntry + { + public SubDataType ChunkType; + public uint ChunkSize; + public uint ChunkOffset; + } + //Table consists of 2 chunk entry lists that define how the .data reads sections public class LM2_ChunkTable { @@ -18,28 +34,6 @@ namespace FirstPlugin public List ChunkEntries = new List(); public List ChunkSubEntries = new List(); - public class ChunkEntry - { - public uint Unknown1; - public uint ChunkOffset; - public uint ChunkType; - public uint ChunkSubCount; - public uint Unknown3; - } - - public class ChunkSubEntry - { - public uint ChunkSize; - public DataType ChunkType; - public uint Unknown; - } - - public enum DataType : uint - { - TextureHeader = 0x0201B501, - TextureData = 0x1701B502, - } - public void Read(FileReader tableReader) { tableReader.SetByteOrder(false); @@ -52,8 +46,8 @@ namespace FirstPlugin entry.Unknown1 = tableReader.ReadUInt32(); //8 entry.ChunkOffset = tableReader.ReadUInt32(); //The chunk offset in the file. Relative to the first chunk position in the file - entry.ChunkType = tableReader.ReadUInt32(); //The type of chunk. 0x8701B5 for example for texture info - entry.ChunkSubCount = tableReader.ReadUInt32(); + entry.ChunkType = tableReader.ReadEnum(false); //The type of chunk. 0x8701B5 for example for texture info + entry.ChunkSubCount = tableReader.ReadUInt32(); //Uncertain about this. 2 for textures (info + block). Some sections however use large numbers. //This increases by 2 each chunk info, however the starting value is not 0 //Note the last entry does not have this @@ -71,9 +65,9 @@ namespace FirstPlugin while (!tableReader.EndOfStream && tableReader.Position <= tableReader.BaseStream.Length - 12) { ChunkSubEntry subEntry = new ChunkSubEntry(); - subEntry.ChunkType = tableReader.ReadEnum(false); //The type of chunk. 0x8701B5 for example for texture info + subEntry.ChunkType = tableReader.ReadEnum(false); //The type of chunk. 0x8701B5 for example for texture info subEntry.ChunkSize = tableReader.ReadUInt32(); - subEntry.Unknown = tableReader.ReadUInt32(); + subEntry.ChunkOffset = tableReader.ReadUInt32(); ChunkSubEntries.Add(subEntry); } } diff --git a/File_Format_Library/FileFormats/Archives/LM2/LM2_DICT.cs b/File_Format_Library/FileFormats/Archives/LM2/LM2_DICT.cs index fa2a58ec..67a5da26 100644 --- a/File_Format_Library/FileFormats/Archives/LM2/LM2_DICT.cs +++ b/File_Format_Library/FileFormats/Archives/LM2/LM2_DICT.cs @@ -10,7 +10,7 @@ using Toolbox.Library.IO; using Toolbox.Library.Forms; using System.Drawing; -namespace FirstPlugin +namespace FirstPlugin.LuigisMansion.DarkMoon { //Parse info based on https://github.com/TheFearsomeDzeraora/LM2L public class LM2_DICT : TreeNodeFile, IFileFormat, IArchiveFile @@ -47,7 +47,7 @@ namespace FirstPlugin } } - public List files = new List(); + public List files = new List(); public IEnumerable Files => files; public void ClearFiles() { files.Clear(); } @@ -55,6 +55,23 @@ namespace FirstPlugin public bool IsCompressed = false; public LM2_ChunkTable ChunkTable; + public List fileEntries = new List(); + + //The click event will load the viewport and any models found in the file if there are any + public override void OnClick(TreeView treeview) + { + if (modelFolder.Nodes.Count != 0) + { + + } + else + { + + } + } + + TreeNode textureFolder = new TreeNode("Textures"); + TreeNode modelFolder = new TreeNode("Models"); public void Load(System.IO.Stream stream) { @@ -71,23 +88,22 @@ namespace FirstPlugin reader.SeekBegin(0x2C); byte[] Unknowns = reader.ReadBytes((int)FileCount); + TreeNode tableNodes = new TreeNode("File Section Entries"); + long FileTablePos = reader.Position; for (int i = 0; i < FileCount; i++) { var file = new FileEntry(this); + file.Text = $"entry {i}"; file.Read(reader); + fileEntries.Add(file); + tableNodes.Nodes.Add(file); - //Skip the file table entries as those are not needed to be loaded - if (file.FileType != 0 && i > 1) - { - file.FileName = $"File {i} (FileType: ({file.FileType}) Unknowns: {file.Unknown2} {file.Unknown3})"; - files.Add(file); - } //The first file stores a chunk layout //The second one seems to be a duplicate? if (i == 0) { - using (var tableReader = new FileReader(file.FileData)) + using (var tableReader = new FileReader(file.GetData())) { ChunkTable = new LM2_ChunkTable(); ChunkTable.Read(tableReader); @@ -97,68 +113,120 @@ namespace FirstPlugin TreeNode list1 = new TreeNode("Entry List 1"); TreeNode list2 = new TreeNode("Entry List 2 "); + debugFolder.Nodes.Add(tableNodes); debugFolder.Nodes.Add(list1); debugFolder.Nodes.Add(list2); foreach (var chunk in ChunkTable.ChunkEntries) { - list1.Nodes.Add($"ChunkType {chunk.ChunkType.ToString("X")} ChunkOffset {chunk.ChunkOffset} Unknown1 {chunk.Unknown1} ChunkSubCount {chunk.ChunkSubCount} Unknown3 {chunk.Unknown3}"); + list1.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkOffset {chunk.ChunkOffset} Unknown1 {chunk.Unknown1} ChunkSubCount {chunk.ChunkSubCount} Unknown3 {chunk.Unknown3}"); } foreach (var chunk in ChunkTable.ChunkSubEntries) { - list2.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkSize {chunk.ChunkSize} Unknown {chunk.Unknown}"); + list2.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkSize {chunk.ChunkSize} Unknown {chunk.ChunkOffset}"); } } } } - //Now go through each file and format and connect the headers and blocks - uint ImageIndex = 0; + //Set an instance of our current data + //Chunks are in order, so you build off of when an instance gets loaded + TexturePOWE currentTexture = new TexturePOWE(); + LM2_Model currentModel = new LM2_Model(); - List Textures = new List(); + //Each part of the file is divided into multiple file/section entries + //The first entry being the chunk table parsed before this + //The second file being a duplicate (sometimes slightly larger than the first) + //The third file stores texture headers, while the fourth one usually has the rest of the main data + //Any additional ones currently are unknown how they work. Some of which have unknown compression aswell - TreeNode textureFolder = new TreeNode("Textures"); + byte[] File002Data = fileEntries[2].GetData(); //Get the third file + byte[] File003Data = fileEntries[3].GetData(); //Get the fourth file - for (int i = 0; i < files.Count; i++) + int chunkId = 0; + uint ImageHeaderIndex = 0; + uint modelIndex = 0; + foreach (var chunk in ChunkTable.ChunkSubEntries) { - if (files[i].FileType == FileEntry.DataType.Texture) - { - if (files[i].Unknown3 == 1) //Info - { - //Read the info - using (var textureReader = new FileReader(files[i].FileData)) - { - int headerIndex = 0; - while (!textureReader.EndOfStream && textureReader.ReadUInt32() == TexturePOWE.Identifier) - { - var texture = new TexturePOWE(); - texture.ImageKey = "texture"; - texture.SelectedImageKey = texture.ImageKey; - texture.Index = ImageIndex; - texture.Read(textureReader); - texture.Text = $"Texture {headerIndex++}"; - textureFolder.Nodes.Add(texture); - Textures.Add(texture); - } - } - } - else //Block - { - uint Offset = 0; - foreach (var tex in Textures) - { - if (tex.Index == ImageIndex) - { - tex.ImageData = Utils.SubArray(files[i].FileData, Offset, tex.ImageSize); - } + var chunkEntry = new ChunkDataEntry(this, chunk); + chunkEntry.DataFile = File003Data; + chunkEntry.FileName = $"Chunk {chunk.ChunkType} {chunkId++}"; + files.Add(chunkEntry); - Offset += tex.ImageSize; + switch (chunk.ChunkType) + { + case SubDataType.TextureHeader: + chunkEntry.DataFile = File002Data; + + //Read the info + using (var textureReader = new FileReader(chunkEntry.FileData)) + { + currentTexture = new TexturePOWE(); + currentTexture.ImageKey = "texture"; + currentTexture.SelectedImageKey = currentTexture.ImageKey; + currentTexture.Index = ImageHeaderIndex; + currentTexture.Read(textureReader); + currentTexture.Text = $"Texture {ImageHeaderIndex}"; + textureFolder.Nodes.Add(currentTexture); + + ImageHeaderIndex++; } - ImageIndex++; - } + break; + case SubDataType.TextureData: + currentTexture.ImageData = chunkEntry.FileData; + break; + case SubDataType.ModelStart: + currentModel.ModelInfo = new LM2_ModelInfo(); + currentModel.Text = $"Model {modelIndex}"; + currentModel.ModelInfo.Data = chunkEntry.FileData; + modelFolder.Nodes.Add(currentModel); + + modelIndex++; + break; + case SubDataType.VertexStartPointers: + using (var vtxPtrReader = new FileReader(chunkEntry.FileData)) + { + while (!vtxPtrReader.EndOfStream) + currentModel.VertexBufferPointers.Add(vtxPtrReader.ReadUInt32()); + } + break; + case SubDataType.SubmeshInfo: + int MeshCount = chunkEntry.FileData.Length / 0x28; + using (var meshReader = new FileReader(chunkEntry.FileData)) + { + for (uint i = 0; i < MeshCount; i++) + { + LM2_Mesh mesh = new LM2_Mesh(); + mesh.Read(meshReader); + currentModel.Meshes.Add(mesh); + } + } + break; + case SubDataType.ModelTransform: + using (var transformReader = new FileReader(chunkEntry.FileData)) + currentModel.Transform = transformReader.ReadMatrix4(); + break; + default: + break; } } + foreach (LM2_Model model in modelFolder.Nodes) + { + for (int i = 0; i < model.VertexBufferPointers.Count; i++) + { + LM2_Mesh mesh = model.Meshes[i]; + + RenderableMeshWrapper genericObj = new RenderableMeshWrapper(); + genericObj.Mesh = mesh; + genericObj.Text = $"Mesh {i}"; + model.Nodes.Add(genericObj); + } + } + + if (modelFolder.Nodes.Count > 0) + Nodes.Add(modelFolder); + if (textureFolder.Nodes.Count > 0) Nodes.Add(textureFolder); } @@ -184,102 +252,16 @@ namespace FirstPlugin return false; } - public class TexturePOWE : STGenericTexture - { - public static readonly uint Identifier = 0xE977D350; - - public uint Index { get; set; } - - public uint ID { get; set; } - public uint ImageSize { get; set; } - public uint ID2 { get; set; } - - public byte[] ImageData { get; set; } - - public void Read(FileReader reader) - { - PlatformSwizzle = PlatformSwizzle.Platform_3DS; - - ID = reader.ReadUInt32(); - ImageSize = reader.ReadUInt32(); - ID2 = reader.ReadUInt32(); - reader.Seek(0x8); - Width = reader.ReadUInt16(); - Height = reader.ReadUInt16(); - reader.Seek(3); - var numMips = reader.ReadByte(); - reader.Seek(0x14); - byte FormatCtr = reader.ReadByte(); - reader.Seek(3); - - MipCount = 1; - Format = CTR_3DS.ConvertPICAToGenericFormat((CTR_3DS.PICASurfaceFormat)FormatCtr); - } - - public override void OnClick(TreeView treeview) - { - ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase)); - if (editor == null) - { - editor = new ImageEditorBase(); - editor.Dock = DockStyle.Fill; - - LibraryGUI.LoadEditor(editor); - } - editor.Text = Text; - editor.LoadProperties(this.GenericProperties); - editor.LoadImage(this); - } - - public override bool CanEdit { get; set; } = false; - - public override void SetImageData(Bitmap bitmap, int ArrayLevel) - { - throw new NotImplementedException(); - } - - public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0) - { - return ImageData; - } - - public override TEX_FORMAT[] SupportedFormats - { - get - { - return new TEX_FORMAT[] - { - TEX_FORMAT.B5G6R5_UNORM, - TEX_FORMAT.R8G8_UNORM, - TEX_FORMAT.B5G5R5A1_UNORM, - TEX_FORMAT.B4G4R4A4_UNORM, - TEX_FORMAT.LA8, - TEX_FORMAT.HIL08, - TEX_FORMAT.L8, - TEX_FORMAT.A8_UNORM, - TEX_FORMAT.LA4, - TEX_FORMAT.A4, - TEX_FORMAT.ETC1_UNORM, - TEX_FORMAT.ETC1_A4, - }; - } - } - } - - public class FileEntry : ArchiveFileInfo + public class ChunkDataEntry : ArchiveFileInfo { + public byte[] DataFile; public LM2_DICT ParentDictionary { get; set; } + public ChunkSubEntry Entry; - public uint Offset; - public uint DecompressedSize; - public uint CompressedSize; - public DataType FileType; - public byte Unknown2; - public byte Unknown3; //Possibly the effect? 0 for image block, 1 for info - - public enum DataType : ushort + public ChunkDataEntry(LM2_DICT dict, ChunkSubEntry entry) { - Texture = 0x80, + ParentDictionary = dict; + Entry = entry; } public override byte[] FileData @@ -291,6 +273,27 @@ namespace FirstPlugin } } + private byte[] GetData( ) + { + using (var reader = new FileReader(DataFile)) + { + reader.SeekBegin(Entry.ChunkOffset); + return reader.ReadBytes((int)Entry.ChunkSize); + } + } + } + + public class FileEntry : TreeNodeFile, IContextMenuNode + { + public LM2_DICT ParentDictionary { get; set; } + + public uint Offset; + public uint DecompressedSize; + public uint CompressedSize; + public ushort Unknown1; + public byte Unknown2; + public byte Unknown3; //Possibly the effect? 0 for image block, 1 for info + public FileEntry(LM2_DICT dict) { ParentDictionary = dict; @@ -301,7 +304,7 @@ namespace FirstPlugin Offset = reader.ReadUInt32(); DecompressedSize = reader.ReadUInt32(); CompressedSize = reader.ReadUInt32(); - FileType = reader.ReadEnum(false); + Unknown1 = reader.ReadUInt16(); Unknown2 = reader.ReadByte(); Unknown3 = reader.ReadByte(); } @@ -319,7 +322,39 @@ namespace FirstPlugin } } - private byte[] GetData() + public ToolStripItem[] GetContextMenuItems() + { + List Items = new List(); + Items.Add(new STToolStipMenuItem("Export Raw Data", null, Export, Keys.Control | Keys.E)); + return Items.ToArray(); + } + + private void Export(object sender, EventArgs args) + { + SaveFileDialog sfd = new SaveFileDialog(); + sfd.FileName = Text; + sfd.Filter = "Raw Data (*.*)|*.*"; + + if (sfd.ShowDialog() == DialogResult.OK) + { + System.IO.File.WriteAllBytes(sfd.FileName, GetData()); + } + } + + public override void OnClick(TreeView treeView) + { + HexEditor editor = (HexEditor)LibraryGUI.GetActiveContent(typeof(HexEditor)); + if (editor == null) + { + editor = new HexEditor(); + LibraryGUI.LoadEditor(editor); + } + editor.Text = Text; + editor.Dock = DockStyle.Fill; + editor.LoadData(GetData()); + } + + public byte[] GetData() { byte[] Data = new byte[DecompressedSize]; diff --git a/File_Format_Library/FileFormats/Archives/LM2/LM2_Enums.cs b/File_Format_Library/FileFormats/Archives/LM2/LM2_Enums.cs new file mode 100644 index 00000000..474a84cd --- /dev/null +++ b/File_Format_Library/FileFormats/Archives/LM2/LM2_Enums.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FirstPlugin.LuigisMansion.DarkMoon +{ + public enum DataType : uint + { + Texture = 0x8701B500, + } + + public enum SubDataType : uint + { + ModelStart = 0x1201B006, + SubmeshInfo = 0x1201B003, //Or polygon groups? + VertexStartPointers = 0x1201B004, + ModelTransform = 0x1301B001, //Matrix4x4. 0x40 in size + MeshBuffers = 0x1301B005, //vertex and index buffer + MaterialName = 0x1201B333, + MeshIndexTable = 0x12017105, + MessageData = 0x12027020, + ShaderData = 0x1401B400, + TextureHeader = 0x0201B501, + TextureData = 0x1701B502, + } +} diff --git a/File_Format_Library/FileFormats/Archives/LM2/LM2_Model.cs b/File_Format_Library/FileFormats/Archives/LM2/LM2_Model.cs new file mode 100644 index 00000000..ccc053d2 --- /dev/null +++ b/File_Format_Library/FileFormats/Archives/LM2/LM2_Model.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Toolbox.Library; +using Toolbox.Library.IO; +using Toolbox.Library.Forms; +using OpenTK; + +namespace FirstPlugin.LuigisMansion.DarkMoon +{ + public class LM2_Model : TreeNodeCustom + { + public LM2_ModelInfo ModelInfo; + public List Meshes = new List(); + public List VertexBufferPointers = new List(); + public Matrix4 Transform { get; set; } + + public override void OnClick(TreeView treeView) + { + STPropertyGrid editor = (STPropertyGrid)LibraryGUI.GetActiveContent(typeof(STPropertyGrid)); + if (editor == null) + { + editor = new STPropertyGrid(); + LibraryGUI.LoadEditor(editor); + } + editor.Text = Text; + editor.Dock = DockStyle.Fill; + editor.LoadProperty(this, OnPropertyChanged); + } + + public void OnPropertyChanged() { } + } + + public class LM2_ModelInfo + { + public byte[] Data; + } + + public class RenderableMeshWrapper : STGenericObject + { + public LM2_Mesh Mesh { get; set; } + + public override void OnClick(TreeView treeView) + { + STPropertyGrid editor = (STPropertyGrid)LibraryGUI.GetActiveContent(typeof(STPropertyGrid)); + if (editor == null) + { + editor = new STPropertyGrid(); + LibraryGUI.LoadEditor(editor); + } + editor.Text = Text; + editor.Dock = DockStyle.Fill; + editor.LoadProperty(Mesh, OnPropertyChanged); + } + + public void OnPropertyChanged() { } + } + + public class LM2_IndexList + { + public short[] UnknownIndices { get; set; } + + public uint Unknown { get; set; } + + public short[] UnknownIndices2 { get; set; } + + public uint[] Unknown2 { get; set; } + + public void Read(FileReader reader) + { + UnknownIndices = reader.ReadInt16s(4); + Unknown = reader.ReadUInt32(); + UnknownIndices2 = reader.ReadInt16s(8); + Unknown2 = reader.ReadUInt32s(6); //Increases by 32 each entry + } + } + + public class LM2_Mesh + { + public uint IndexStartOffset { get; private set; } //relative to buffer start + public ushort IndexCount { get; private set; } //divide by 3 to get face count + public ushort IndexFormat { get; private set; } //0x0 - ushort, 0x8000 - byte + + public ushort BufferStride { get; private set; } + public ushort Unknown { get; private set; } + public ushort Unknown2 { get; private set; } + public ulong DataFormat { get; private set; } + public uint Unknown4 { get; private set; } + public uint Unknown5 { get; private set; } + public uint Unknown6 { get; private set; } + public ushort VertexCount { get; private set; } + public ushort Unknown7 { get; private set; } + public uint HashID { get; private set; } + + public void Read(FileReader reader) + { + IndexStartOffset = reader.ReadUInt32(); + IndexCount = reader.ReadUInt16(); + IndexFormat = reader.ReadUInt16(); + BufferStride = reader.ReadUInt16(); + Unknown = reader.ReadUInt16(); + Unknown2 = reader.ReadUInt16(); + DataFormat = reader.ReadUInt64(); + Unknown4 = reader.ReadUInt32(); + Unknown5 = reader.ReadUInt32(); + Unknown6 = reader.ReadUInt32(); + VertexCount = reader.ReadUInt16(); + Unknown7 = reader.ReadUInt16(); //0x100 + HashID = reader.ReadUInt32(); //0x100 + } + + public class FormatInfo + { + + } + } +} diff --git a/File_Format_Library/FileFormats/Archives/LM2/TexturePOWE.cs b/File_Format_Library/FileFormats/Archives/LM2/TexturePOWE.cs new file mode 100644 index 00000000..16c0d5a1 --- /dev/null +++ b/File_Format_Library/FileFormats/Archives/LM2/TexturePOWE.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Drawing; +using System.Threading.Tasks; +using Toolbox.Library; +using Toolbox.Library.IO; +using Toolbox.Library.Forms; +using System.Windows.Forms; + +namespace FirstPlugin.LuigisMansion.DarkMoon +{ + public class TexturePOWE : STGenericTexture + { + public static readonly uint Identifier = 0xE977D350; + + public uint Index { get; set; } + + public uint ID { get; set; } + public uint ImageSize { get; set; } + public uint ID2 { get; set; } + + public byte[] ImageData { get; set; } + + public void Read(FileReader reader) + { + //Magic and ID not pointed to for sub entries so just skip them for now + // uint magic = reader.ReadUInt32(); + // if (magic != Identifier) + // throw new Exception($"Invalid texture header magic! Expected {Identifier.ToString("x")}. Got {Identifier.ToString("x")}"); + // ID = reader.ReadUInt32(); + + PlatformSwizzle = PlatformSwizzle.Platform_3DS; + + ImageSize = reader.ReadUInt32(); + ID2 = reader.ReadUInt32(); + reader.Seek(0x8); + Width = reader.ReadUInt16(); + Height = reader.ReadUInt16(); + reader.Seek(3); + var numMips = reader.ReadByte(); + reader.Seek(0x14); + byte FormatCtr = reader.ReadByte(); + reader.Seek(3); + + MipCount = 1; + Format = CTR_3DS.ConvertPICAToGenericFormat((CTR_3DS.PICASurfaceFormat)FormatCtr); + } + + public override void OnClick(TreeView treeview) + { + ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase)); + if (editor == null) + { + editor = new ImageEditorBase(); + editor.Dock = DockStyle.Fill; + + LibraryGUI.LoadEditor(editor); + } + editor.Text = Text; + editor.LoadProperties(this.GenericProperties); + editor.LoadImage(this); + } + + public override bool CanEdit { get; set; } = false; + + public override void SetImageData(Bitmap bitmap, int ArrayLevel) + { + throw new NotImplementedException(); + } + + public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0) + { + return ImageData; + } + + public override TEX_FORMAT[] SupportedFormats + { + get + { + return new TEX_FORMAT[] + { + TEX_FORMAT.B5G6R5_UNORM, + TEX_FORMAT.R8G8_UNORM, + TEX_FORMAT.B5G5R5A1_UNORM, + TEX_FORMAT.B4G4R4A4_UNORM, + TEX_FORMAT.LA8, + TEX_FORMAT.HIL08, + TEX_FORMAT.L8, + TEX_FORMAT.A8_UNORM, + TEX_FORMAT.LA4, + TEX_FORMAT.A4, + TEX_FORMAT.ETC1_UNORM, + TEX_FORMAT.ETC1_A4, + }; + } + } + } +} diff --git a/File_Format_Library/File_Format_Library.csproj b/File_Format_Library/File_Format_Library.csproj index 4d8be6a6..a32c79a7 100644 --- a/File_Format_Library/File_Format_Library.csproj +++ b/File_Format_Library/File_Format_Library.csproj @@ -206,6 +206,9 @@ + + + diff --git a/File_Format_Library/Main.cs b/File_Format_Library/Main.cs index 4c52e3cc..1ca155b8 100644 --- a/File_Format_Library/Main.cs +++ b/File_Format_Library/Main.cs @@ -7,6 +7,7 @@ using Toolbox.Library; using Toolbox.Library.Forms; using Toolbox.Library.IO; using FirstPlugin.Forms; +using FirstPlugin.LuigisMansion.DarkMoon; namespace FirstPlugin { diff --git a/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs b/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs index 81774d6c..fc2a7f8b 100644 --- a/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs +++ b/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs @@ -540,8 +540,8 @@ namespace Toolbox.Library.Forms private void treeViewCustom1_DragOver(object sender, DragEventArgs e) { - var file = GetActiveArchive(); - if (file == null || !file.CanReplaceFiles) + var root = GetActiveArchive(); + if (root == null || !root.ArchiveFile.CanReplaceFiles) return; Point pt = treeViewCustom1.PointToClient(new Point(e.X, e.Y)); @@ -557,10 +557,15 @@ namespace Toolbox.Library.Forms // e.Effect = DragDropEffects.None; } - private IArchiveFile GetActiveArchive() + private ArchiveRootNodeWrapper GetActiveArchive() { - if (treeViewCustom1.SelectedNode != null && treeViewCustom1.SelectedNode is ArchiveBase) - return ((ArchiveBase)treeViewCustom1.SelectedNode).ArchiveFile; + var node = treeViewCustom1.SelectedNode; + if (node != null && node is ArchiveRootNodeWrapper) + return (ArchiveRootNodeWrapper)node; + if (node != null && node is ArchiveFileWrapper) + return ((ArchiveFileWrapper)node).RootNode; + if (node != null && node is ArchiveFolderNodeWrapper) + return ((ArchiveFolderNodeWrapper)node).RootNode; return null; } diff --git a/Switch_Toolbox_Library/Helpers/TreeHelper.cs b/Switch_Toolbox_Library/Helpers/TreeHelper.cs index 9435fecf..078cf09e 100644 --- a/Switch_Toolbox_Library/Helpers/TreeHelper.cs +++ b/Switch_Toolbox_Library/Helpers/TreeHelper.cs @@ -183,13 +183,15 @@ namespace Toolbox.Library } - public static void AddFiles(TreeNode parentNode, IArchiveFile archiveFile, string[] Files) + public static void AddFiles(TreeNode parentNode, ArchiveRootNodeWrapper rootNode, string[] Files) { + var archiveFile = rootNode.ArchiveFile; + if (Files == null || Files.Length <= 0 || !archiveFile.CanAddFiles) return; for (int i = 0; i < Files.Length; i++) { - var File = ArchiveFileWrapper.FromPath(Files[i], archiveFile); + var File = ArchiveFileWrapper.FromPath(Files[i], rootNode); string FileName = Path.GetFileName(Files[i]); //Don't add the root file name @@ -209,9 +211,9 @@ namespace Toolbox.Library if (HasAddedFile) { if (parentNode is ArchiveRootNodeWrapper) - ((ArchiveRootNodeWrapper)parentNode).FileNodes.Add(File); + ((ArchiveRootNodeWrapper)parentNode).AddFileNode(File); if (parentNode is ArchiveFolderNodeWrapper) - ((ArchiveRootNodeWrapper)parentNode).FileNodes.Add(File); + ((ArchiveRootNodeWrapper)parentNode).AddFileNode(File); parentNode.Nodes.Add(File); } diff --git a/Switch_Toolbox_Library/IO/FileReader.cs b/Switch_Toolbox_Library/IO/FileReader.cs index e1d46671..9a20aa86 100644 --- a/Switch_Toolbox_Library/IO/FileReader.cs +++ b/Switch_Toolbox_Library/IO/FileReader.cs @@ -147,6 +147,50 @@ namespace Toolbox.Library.IO return new Syroot.IOExtension.Half(ReadUInt16()); } + public Matrix4 ReadMatrix4(bool SwapRows = false) + { + Matrix4 mat4 = new Matrix4(); + if (SwapRows) + { + mat4.M11 = ReadSingle(); + mat4.M21 = ReadSingle(); + mat4.M31 = ReadSingle(); + mat4.M41 = ReadSingle(); + mat4.M12 = ReadSingle(); + mat4.M22 = ReadSingle(); + mat4.M32 = ReadSingle(); + mat4.M42 = ReadSingle(); + mat4.M13 = ReadSingle(); + mat4.M23 = ReadSingle(); + mat4.M33 = ReadSingle(); + mat4.M43 = ReadSingle(); + mat4.M14 = ReadSingle(); + mat4.M24 = ReadSingle(); + mat4.M34 = ReadSingle(); + mat4.M44 = ReadSingle(); + } + else + { + mat4.M11 = ReadSingle(); + mat4.M12 = ReadSingle(); + mat4.M13 = ReadSingle(); + mat4.M14 = ReadSingle(); + mat4.M21 = ReadSingle(); + mat4.M22 = ReadSingle(); + mat4.M23 = ReadSingle(); + mat4.M24 = ReadSingle(); + mat4.M31 = ReadSingle(); + mat4.M32 = ReadSingle(); + mat4.M33 = ReadSingle(); + mat4.M34 = ReadSingle(); + mat4.M41 = ReadSingle(); + mat4.M42 = ReadSingle(); + mat4.M43 = ReadSingle(); + mat4.M44 = ReadSingle(); + } + return mat4; + } + public void SeekBegin(uint Offset) { Seek(Offset, SeekOrigin.Begin); } public void SeekBegin(int Offset) { Seek(Offset, SeekOrigin.Begin); } public void SeekBegin(long Offset) { Seek(Offset, SeekOrigin.Begin); } diff --git a/Switch_Toolbox_Library/Interfaces/IArchiveFile.cs b/Switch_Toolbox_Library/Interfaces/IArchiveFile.cs index 20306fc0..b56818a5 100644 --- a/Switch_Toolbox_Library/Interfaces/IArchiveFile.cs +++ b/Switch_Toolbox_Library/Interfaces/IArchiveFile.cs @@ -183,7 +183,8 @@ namespace Toolbox.Library //Wrapper for the archive file itself public class ArchiveRootNodeWrapper : ArchiveBase, IContextMenuNode { - public List FileNodes = new List(); + //A list that links archive file infos to treenodes of varying types + public List> FileNodes = new List>(); public virtual object PropertyDisplay { get; set; } @@ -195,6 +196,11 @@ namespace Toolbox.Library PropertyDisplay = new GenericArchiveProperties(archiveFile, text); } + public void AddFileNode(ArchiveFileWrapper fileWrapper) + { + FileNodes.Add(Tuple.Create(fileWrapper.ArchiveFileInfo, (TreeNode)fileWrapper)); + } + public ToolStripItem[] GetContextMenuItems() { var ToolStrips = new ToolStripItem[] @@ -232,7 +238,7 @@ namespace Toolbox.Library if (ofd.ShowDialog() == DialogResult.OK) { - TreeHelper.AddFiles(this, ArchiveFile, ofd.FileNames); + TreeHelper.AddFiles(this, this, ofd.FileNames); } } @@ -242,7 +248,9 @@ namespace Toolbox.Library return; for (int i = 0; i < FileNodes.Count; i++) - FileNodes[i].ArchiveFileInfo.FileName = SetFullPath(FileNodes[i], this); + { + FileNodes[i].Item1.FileName = SetFullPath(FileNodes[i].Item2, this); + } } private static string SetFullPath(TreeNode node, TreeNode root) @@ -411,7 +419,7 @@ namespace Toolbox.Library } else if (node is ArchiveFileInfo) { - ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(node.Name, (ArchiveFileInfo)node, archiveFile); + ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(node.Name, (ArchiveFileInfo)node, this); wrapperFile.Name = node.Name; parent.Nodes.Add(wrapperFile); } @@ -468,11 +476,11 @@ namespace Toolbox.Library if (rootIndex == roots.Length - 1) { - ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(parentName, node, archiveFile); + ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(parentName, node, this); wrapperFile.Name = nodeName; parentNode.Nodes.Add(wrapperFile); parentNode = wrapperFile; - FileNodes.Add(wrapperFile); + AddFileNode(wrapperFile); } else { @@ -557,7 +565,7 @@ namespace Toolbox.Library ofd.Multiselect = true; if (ofd.ShowDialog() == DialogResult.OK) { - TreeHelper.AddFiles(this, ArchiveFile, ofd.FileNames); + TreeHelper.AddFiles(this, RootNode, ofd.FileNames); } } @@ -618,11 +626,14 @@ namespace Toolbox.Library //Wrapper for files public class ArchiveFileWrapper : ArchiveBase, IContextMenuNode { + public ArchiveRootNodeWrapper RootNode; + public virtual ArchiveFileInfo ArchiveFileInfo { get; set; } - public ArchiveFileWrapper(string text, ArchiveFileInfo archiveFileInfo, IArchiveFile archiveFile) : base(archiveFile) + public ArchiveFileWrapper(string text, ArchiveFileInfo archiveFileInfo, ArchiveRootNodeWrapper rootNode) : base(rootNode.ArchiveFile) { Text = text; + RootNode = rootNode; // ReloadMenus(archiveFile); ArchiveFileInfo = archiveFileInfo; @@ -705,12 +716,12 @@ namespace Toolbox.Library else return ""; } - public static ArchiveFileWrapper FromPath(string FilePath, IArchiveFile archiveFile) + public static ArchiveFileWrapper FromPath(string FilePath, ArchiveRootNodeWrapper rootNode) { var ArchiveFileInfo = new ArchiveFileInfo(); ArchiveFileInfo.FileName = FilePath; ArchiveFileInfo.FileData = File.ReadAllBytes(FilePath); - return new ArchiveFileWrapper(Path.GetFileName(FilePath), ArchiveFileInfo, archiveFile); + return new ArchiveFileWrapper(Path.GetFileName(FilePath), ArchiveFileInfo, rootNode); } public ToolStripItem[] GetContextMenuItems() @@ -781,12 +792,12 @@ namespace Toolbox.Library OpenFormDialog(file); } else if (file is TreeNode) - ReplaceNode(this.Parent, this, (TreeNode)file); + ReplaceNode(this.Parent, this, (TreeNode)file, RootNode); else if (file is IArchiveFile) { var FileRoot = new ArchiveRootNodeWrapper(file.FileName, (IArchiveFile)file); FileRoot.FillTreeNodes(); - ReplaceNode(this.Parent, this, FileRoot); + ReplaceNode(this.Parent, this, FileRoot, RootNode); } } @@ -847,15 +858,20 @@ namespace Toolbox.Library editor.UpdateEditor(); } - public static void ReplaceNode(TreeNode node, TreeNode replaceNode, TreeNode NewNode) + public static void ReplaceNode(TreeNode node, ArchiveFileWrapper replaceNode, TreeNode NewNode, ArchiveRootNodeWrapper rootNode) { if (NewNode == null) return; + var fileInfo = replaceNode.ArchiveFileInfo; + int index = node.Nodes.IndexOf(replaceNode); node.Nodes.RemoveAt(index); node.Nodes.Insert(index, NewNode); + rootNode.FileNodes.RemoveAt(index); + rootNode.FileNodes.Insert(index, Tuple.Create(fileInfo, NewNode)); + NewNode.ImageKey = replaceNode.ImageKey; NewNode.SelectedImageKey = replaceNode.SelectedImageKey; NewNode.Text = replaceNode.Text;