From d96f4dec43e0c0631f1979a64a39a3ace83d6899 Mon Sep 17 00:00:00 2001 From: KillzXGaming Date: Tue, 4 Dec 2018 21:40:03 -0500 Subject: [PATCH] Cleanup with new open/save methods. Also add gtx rebuilding. --- Switch_FileFormatsMain/FileFormats/BARS.cs | 20 +- Switch_FileFormatsMain/FileFormats/BEA.cs | 467 ++++++--------- Switch_FileFormatsMain/FileFormats/BFRES.cs | 45 +- .../FileFormats/BFRES/Bfres Structs/FMAT.cs | 4 +- .../FileFormats/BFRES/Bfres Structs/FMDL.cs | 42 +- .../FileFormats/BFRES/Bfres Structs/FSHP.cs | 40 +- .../FileFormats/BFRES/BfresSwitch.cs | 2 - .../FileFormats/BFRES/BfresWiiU.cs | 25 +- Switch_FileFormatsMain/FileFormats/GFPAK.cs | 29 +- Switch_FileFormatsMain/FileFormats/KCL.cs | 31 +- Switch_FileFormatsMain/FileFormats/SARC.cs | 94 +-- .../FileFormats/Texture/BNTX.cs | 48 +- .../FileFormats/Texture/FTEX.cs | 33 +- .../FileFormats/Texture/GTX.cs | 269 +-------- .../FileFormats/Texture/GTXFile.cs | 562 ++++++++++++++++++ .../FileFormats/Texture/NUTEXB.cs | 64 +- .../FileFormats/Texture/XTX.cs | 41 +- Switch_FileFormatsMain/GL/BFRES_Render.cs | 6 +- .../GUI/BFRES/BfresMaterialEditor.cs | 2 +- .../GUI/BFRES/BfresShapeEditor.cs | 2 +- .../GUI/Texture Selector.cs | 9 +- .../GUI/TextureUI/0x1cda00708.XTEX | Bin 0 -> 89264 bytes .../GUI/TextureUI/BNTXEditor.cs | 4 +- .../GUI/TextureUI/GTXEditor.Designer.cs | 341 +++++++++++ .../GUI/TextureUI/GTXEditor.cs | 175 ++++++ .../GUI/TextureUI/GTXEditor.resx | 331 +++++++++++ .../GUI/TextureUI/GTXImporterSettings.cs | 43 +- .../GUI/TextureUI/TextureImporterSettings.cs | 27 +- .../Switch_FileFormatsMain.csproj | 28 +- Switch_Toolbox/Lib/DirectXTex/wrapper.cpp | 1 + .../Lib/Syroot.NintenTools.NSW.Bntx.dll | Bin 76800 -> 76288 bytes .../Lib/Syroot.NintenTools.NSW.Bntx.pdb | Bin 28372 -> 28324 bytes Switch_Toolbox/MainForm.cs | 14 +- Switch_Toolbox/Switch_Toolbox.csproj | 5 +- .../FileFormats/Assimp/Assimp.cs | 2 +- .../FileFormats/Assimp/AssimpHelper.cs | 46 ++ Switch_Toolbox_Library/FileFormats/DDS.cs | 4 +- .../GUI Custom/BitmapCustom.cs | 9 + .../Helpers/TextureHelper.cs | 2 +- Switch_Toolbox_Library/IO/FileIO.cs | 182 ++++++ .../Switch_Toolbox_Library.csproj | 4 + 41 files changed, 2161 insertions(+), 892 deletions(-) create mode 100644 Switch_FileFormatsMain/FileFormats/Texture/GTXFile.cs create mode 100644 Switch_FileFormatsMain/GUI/TextureUI/0x1cda00708.XTEX create mode 100644 Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.Designer.cs create mode 100644 Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.cs create mode 100644 Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.resx diff --git a/Switch_FileFormatsMain/FileFormats/BARS.cs b/Switch_FileFormatsMain/FileFormats/BARS.cs index 92629443..f207bfcc 100644 --- a/Switch_FileFormatsMain/FileFormats/BARS.cs +++ b/Switch_FileFormatsMain/FileFormats/BARS.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; -using Switch_Toolbox; using System.Windows.Forms; using Switch_Toolbox.Library; +using Switch_Toolbox.Library.IO; using BarsLib; using WeifenLuo.WinFormsUI.Docking; using VGAudio.Formats; @@ -190,10 +190,28 @@ namespace FirstPlugin Nodes[1].Nodes.Add(node); } + + ContextMenu = new ContextMenu(); + MenuItem save = new MenuItem("Save"); + ContextMenu.MenuItems.Add(save); + save.Click += Save; } public void Unload() { + } + private void Save(object sender, EventArgs args) + { + List formats = new List(); + + SaveFileDialog sfd = new SaveFileDialog(); + sfd.Filter = Utils.GetAllFilters(formats); + sfd.FileName = FileName; + + if (sfd.ShowDialog() == DialogResult.OK) + { + STFileSaver.SaveFileFormat(this, sfd.FileName); + } } public byte[] Save() { diff --git a/Switch_FileFormatsMain/FileFormats/BEA.cs b/Switch_FileFormatsMain/FileFormats/BEA.cs index a031c739..8a279f29 100644 --- a/Switch_FileFormatsMain/FileFormats/BEA.cs +++ b/Switch_FileFormatsMain/FileFormats/BEA.cs @@ -8,7 +8,6 @@ using System.Windows.Forms; using Switch_Toolbox.Library; using System.IO; using BezelEngineArchive_Lib; -using ZstdNet; using Switch_Toolbox.Library.IO; using Switch_Toolbox.Library.Forms; @@ -79,23 +78,23 @@ namespace FirstPlugin bea.FileName = file; bea.Load(); - foreach (var asset in beaFile.FileList.Values) + foreach (FileEntry asset in bea.Nodes) { - if (Path.GetExtension(asset.FileName) == ".lua") + if (Path.GetExtension(asset.FullName) == ".lua") { try { - if (!String.IsNullOrWhiteSpace(Path.GetDirectoryName($"{folderPath}/{beaFile.Name}/{asset.FileName}"))) + if (!String.IsNullOrWhiteSpace(Path.GetDirectoryName($"{folderPath}/{bea.Name}/{asset.FullName}"))) { - if (!File.Exists(asset.FileName)) + if (!File.Exists(asset.FullName)) { - if (!Directory.Exists($"{folderPath}/{beaFile.Name}/{asset.FileName}")) + if (!Directory.Exists($"{folderPath}/{bea.Name}/{asset.FullName}")) { - Directory.CreateDirectory(Path.GetDirectoryName($"{folderPath}/{beaFile.Name}/{asset.FileName}")); + Directory.CreateDirectory(Path.GetDirectoryName($"{folderPath}/{bea.Name}/{asset.FullName}")); } } } - File.WriteAllBytes($"{folderPath}/{beaFile.Name}/{asset.FileName}", GetASSTData(asset.FileName)); + File.WriteAllBytes($"{folderPath}/{bea.Name}/{asset.FullName}", GetASSTData(asset)); } catch { @@ -121,6 +120,17 @@ namespace FirstPlugin beaFile = new BezelEngineArchive(new MemoryStream(Data)); FillTreeNodes(this, beaFile.FileList); + + ContextMenu = new ContextMenu(); + MenuItem save = new MenuItem("Save"); + ContextMenu.MenuItems.Add(save); + save.Click += Save; + MenuItem previewFiles = new MenuItem("Preview Window"); + ContextMenu.MenuItems.Add(previewFiles); + previewFiles.Click += PreviewWindow; + MenuItem exportAll = new MenuItem("Export All"); + ContextMenu.MenuItems.Add(exportAll); + exportAll.Click += ExportAll; } public void Unload() { @@ -137,207 +147,156 @@ namespace FirstPlugin yield return child; } } + private void Save(object sender, EventArgs args) + { + Cursor.Current = Cursors.WaitCursor; + List formats = new List(); + formats.Add(this); + + SaveFileDialog sfd = new SaveFileDialog(); + sfd.Filter = Utils.GetAllFilters(formats); + sfd.FileName = FileName; + + if (sfd.ShowDialog() == DialogResult.OK) + { + STFileSaver.SaveFileFormat(this, sfd.FileName); + } + GC.Collect(); + } public byte[] Save() { + beaFile.FileList.Clear(); + beaFile.FileDictionary.Clear(); + foreach (TreeNode node in Collect(Nodes)) { - if (node is FileEntry) + if (node is TreeNodeFile && node != this) { - Console.WriteLine(node); - if (((FileEntry)node).FileHandle != null) + IFileFormat fileFormat = (IFileFormat)node; + if (fileFormat != null) { - Console.WriteLine("Saving FileHandle"); - SaveFileEntryData((FileEntry)node); + byte[] uncomrompressedData = fileFormat.Data; + + //Save any active files in the editor if supported + if (fileFormat.CanSave) + uncomrompressedData = fileFormat.Save(); + + //Create a new asset entry + ASST asset = new ASST(); + asset.unk = 2; + asset.unk2 = 2; + asset.UncompressedSize = uncomrompressedData.LongLength; + + if (fileFormat.FileIsCompressed) + asset.FileData = STLibraryCompression.ZSTD.Compress(uncomrompressedData); + else + asset.FileData = fileFormat.Data; + + asset.FileName = fileFormat.FilePath; + beaFile.FileList.Add(fileFormat.FilePath, asset); + beaFile.FileDictionary.Add(fileFormat.FilePath); } } + else if (node is FileEntry) + { + ASST asset = new ASST(); + asset.unk = ((FileEntry)node).unk1; + asset.unk2 = ((FileEntry)node).unk2; + asset.FileName = ((FileEntry)node).FullName; + asset.FileData = ((FileEntry)node).data; + byte[] uncomp = GetASSTData((FileEntry)node); + asset.UncompressedSize = uncomp.Length; + beaFile.FileList.Add(asset.FileName, asset); + beaFile.FileDictionary.Add(asset.FileName); + } } MemoryStream mem = new MemoryStream(); beaFile.Save(mem); return mem.ToArray(); } - - - public class RootNode : TreeNodeFile + private void ExportAll(object sender, EventArgs args) { - public RootNode(string n, IFileFormat format) - { - Text = n; + FolderSelectDialog fsd = new FolderSelectDialog(); - ContextMenu = new ContextMenu(); - MenuItem previewFiles = new MenuItem("Preview Window"); - ContextMenu.MenuItems.Add(previewFiles); - previewFiles.Click += PreviewWindow; - MenuItem exportAll = new MenuItem("Export All"); - ContextMenu.MenuItems.Add(exportAll); - exportAll.Click += ExportAll; + if (fsd.ShowDialog() == DialogResult.OK) + { + progressBar = new ProgressBarWindow(); + progressBar.Task = "Extracing Files..."; + progressBar.Refresh(); + progressBar.Value = 0; + progressBar.StartPosition = FormStartPosition.CenterScreen; + progressBar.Show(); + + ExportAll(fsd.SelectedPath, progressBar); } - public override void OnClick(TreeView treeview) + } + private void ExportAll(string Folder, ProgressBarWindow progressBar) + { + int Curfile = 0; + foreach (FileEntry asst in Nodes) { + int value = (Curfile * 100) / beaFile.FileList.Count; + progressBar.Value = value; + progressBar.Refresh(); - } - private void ExportAll(object sender, EventArgs args) - { - FolderSelectDialog fsd = new FolderSelectDialog(); - - if (fsd.ShowDialog() == DialogResult.OK) + try { - progressBar = new ProgressBarWindow(); - progressBar.Task = "Extracing Files..."; - progressBar.Refresh(); - progressBar.Value = 0; - progressBar.StartPosition = FormStartPosition.CenterScreen; - progressBar.Show(); - - ExportAll(fsd.SelectedPath, progressBar); - } - } - private void ExportAll(string Folder, ProgressBarWindow progressBar) - { - - int Curfile = 0; - foreach (ASST asst in beaFile.FileList.Values) - { - int value = (Curfile * 100) / beaFile.FileList.Count; - progressBar.Value = value; - progressBar.Refresh(); - - try + if (!String.IsNullOrWhiteSpace(Path.GetDirectoryName($"{Folder}/{beaFile.Name}/{asst.FullName}"))) { - if (!String.IsNullOrWhiteSpace(Path.GetDirectoryName($"{Folder}/{beaFile.Name}/{asst.FileName}"))) + if (!File.Exists(asst.FullName)) { - if (!File.Exists(asst.FileName)) + if (!Directory.Exists($"{Folder}/{beaFile.Name}/{asst.FullName}")) { - if (!Directory.Exists($"{Folder}/{beaFile.Name}/{asst.FileName}")) - { - Directory.CreateDirectory(Path.GetDirectoryName($"{Folder}/{beaFile.Name}/{asst.FileName}")); - } - } - } - File.WriteAllBytes($"{Folder}/{beaFile.Name}/{asst.FileName}", GetASSTData(asst.FileName)); - } - catch - { - - } - - Curfile++; - if (value == 99) - value = 100; - progressBar.Value = value; - progressBar.Refresh(); - } - } - private void CallRecursive(TreeView treeView) - { - // Print each node recursively. - TreeNodeCollection nodes = treeView.Nodes; - foreach (TreeNode n in nodes) - { - PrintRecursive(n); - } - } - private void PrintRecursive(TreeNode treeNode) - { - if (treeNode is FileEntry) - { - FileEntry file = (FileEntry)treeNode; - - if (file.ImageKey == "bntx") - OpenFile(file.Name, GetASSTData(file.FullName), TreeView); - - if (file.ImageKey == "bntx") - Console.WriteLine(file.Name); - // if (file.ImageKey == "bfres") - // OpenFile(file.Name, GetASSTData(file.FullName), TreeView); - } - - // Print each node recursively. - foreach (TreeNode tn in treeNode.Nodes) - { - PrintRecursive(tn); - } - } - - public void PreviewWindow(object sender, EventArgs args) - { - PreviewFormatList previewFormatList = new PreviewFormatList(); - - if (previewFormatList.ShowDialog() == DialogResult.OK) - { - CallRecursive(TreeView); - Console.WriteLine("Loaded files"); - Console.WriteLine(PluginRuntime.bntxContainers.Count); - PreviewEditor previewWindow = new PreviewEditor(); - previewWindow.Show(); - } - } - - public void OpenFile(string FileName, byte[] data, TreeView treeView, bool Compressed = false, CompressionType CompType = CompressionType.None) - { - - FileReader f = new FileReader(data); - string Magic = f.ReadMagic(0, 4); - string Magic2 = f.ReadMagic(0, 2); - - //Determine if the file is compressed or not - if (Magic == "Yaz0") - { - data = EveryFileExplorer.YAZ0.Decompress(data); - OpenFile(FileName, data, treeView, true, CompressionType.Yaz0); - return; - } - if (Magic == "ZLIB") - { - data = FileReader.InflateZLIB(f.getSection(64, data.Length - 64)); - OpenFile(FileName, data, treeView, true, CompressionType.Zlib); - return; - } - - f.Dispose(); - f.Close(); - - IFileFormat[] SupportedFormats = FileManager.GetFileFormats(); - - foreach (IFileFormat format in SupportedFormats) - { - if (format.Magic == Magic || format.Magic == Magic2) - { - format.CompressionType = CompType; - format.FileIsCompressed = Compressed; - format.Data = data; - format.FileName = Path.GetFileName(FileName); - format.Load(); - format.FilePath = FileName; - - if (format is TreeNode) - { - ((TreeNode)format).Text = Text; - ((TreeNode)format).ImageKey = ImageKey; - ((TreeNode)format).SelectedImageKey = SelectedImageKey; - - Nodes.Add(((TreeNode)format)); - } - } - if (format.Magic == String.Empty) //Load by extension if magic isn't defined - { - foreach (string ext in format.Extension) - { - if (ext.Remove(0, 1) == Path.GetExtension(FileName)) - { - format.Load(); + Directory.CreateDirectory(Path.GetDirectoryName($"{Folder}/{beaFile.Name}/{asst.FullName}")); } } } + File.WriteAllBytes($"{Folder}/{beaFile.Name}/{asst.FullName}", GetASSTData(asst)); + } + catch + { + } - SupportedFormats = null; - data = null; - GC.Collect(); - GC.WaitForPendingFinalizers(); + Curfile++; + if (value == 99) + value = 100; + progressBar.Value = value; + progressBar.Refresh(); + } + } + private void CallRecursive(TreeView treeView) + { + // Print each node recursively. + TreeNodeCollection nodes = treeView.Nodes; + foreach (TreeNode n in nodes) + { + PrintRecursive(n); + } + } + private void PrintRecursive(TreeNode treeNode) + { + // Print each node recursively. + foreach (TreeNode tn in treeNode.Nodes) + { + PrintRecursive(tn); } } + public void PreviewWindow(object sender, EventArgs args) + { + PreviewFormatList previewFormatList = new PreviewFormatList(); + + if (previewFormatList.ShowDialog() == DialogResult.OK) + { + CallRecursive(TreeView); + Console.WriteLine("Loaded files"); + Console.WriteLine(PluginRuntime.bntxContainers.Count); + PreviewEditor previewWindow = new PreviewEditor(); + previewWindow.Show(); + } + } public bool Compressed; public class FolderEntry : TreeNode { @@ -371,6 +330,10 @@ namespace FirstPlugin public string FullName; public IFileFormat FileHandle; //Load file instance to save later if possible + public byte[] data; + public ushort unk1; + public ushort unk2; + public bool IsCompressed; private void Export(object sender, EventArgs args) { @@ -381,7 +344,7 @@ namespace FirstPlugin if (sfd.ShowDialog() == DialogResult.OK) { - File.WriteAllBytes(sfd.FileName, GetASSTData(FullName)); + File.WriteAllBytes(sfd.FileName, GetASSTData(this)); } } @@ -394,77 +357,18 @@ namespace FirstPlugin if (ofd.ShowDialog() == DialogResult.OK) { - SetASST(File.ReadAllBytes(ofd.FileName), FullName); + SetASST(this, File.ReadAllBytes(ofd.FileName)); } } - public override void OnClick(TreeView treeView) + public override void OnDoubleMouseClick(TreeView treeview) { - if (beaFile != null) + if (GetASSTData(this) != null) { - if (GetASSTData(FullName) != null) - OpenFile(Name, GetASSTData(FullName), treeView); - } - } + TreeNode node = STFileLoader.GetNodeFileFormat(FullName, GetASSTData(this), true, "", this, IsCompressed, CompressionType.Zstb); - public void OpenFile(string FileName, byte[] data, TreeView treeView, bool Compressed = false, CompressionType CompType = CompressionType.None) - { - - FileReader f = new FileReader(data); - string Magic = f.ReadMagic(0, 4); - string Magic2 = f.ReadMagic(0, 2); - - //Determine if the file is compressed or not - if (Magic == "Yaz0") - { - data = EveryFileExplorer.YAZ0.Decompress(data); - OpenFile(FileName, data, treeView, true, CompressionType.Yaz0); - return; - } - if (Magic == "ZLIB") - { - data = FileReader.InflateZLIB(f.getSection(64, data.Length - 64)); - OpenFile(FileName, data, treeView, true, CompressionType.Zlib); - return; - } - - f.Dispose(); - f.Close(); - - IFileFormat[] SupportedFormats = FileManager.GetFileFormats(); - - foreach (IFileFormat format in SupportedFormats) - { - if (format.Magic == Magic || format.Magic == Magic2) - { - FileHandle = format; - - format.CompressionType = CompType; - format.FileIsCompressed = Compressed; - format.Data = data; - format.FileName = Path.GetFileName(FileName); - format.Load(); - format.FilePath = FileName; - - if (format is TreeNode) - { - ((TreeNode)format).Text = Text; - ((TreeNode)format).ImageKey = ImageKey; - ((TreeNode)format).SelectedImageKey = SelectedImageKey; - - Nodes.Add(((TreeNode)format)); - } - } - if (format.Magic == String.Empty) //Load by extension if magic isn't defined - { - foreach (string ext in format.Extension) - { - if (ext.Remove(0, 1) == Path.GetExtension(FileName)) - { - format.Load(); - } - } - } + if (node != null) + ReplaceNode(this.Parent, this, node); } } } @@ -476,58 +380,19 @@ namespace FirstPlugin node.Nodes.Insert(index, NewNode); } - public static byte[] GetASSTData(string path) + public static byte[] GetASSTData(FileEntry entry) { - if (beaFile.FileList.ContainsKey(path)) - { - if (beaFile.FileList[path].UncompressedSize == beaFile.FileList[path].FileData.Length) - { - return beaFile.FileList[path].FileData; - } - else - { - using (var decompressor = new Decompressor()) - { - return decompressor.Unwrap(beaFile.FileList[path].FileData); - } - } - - } - return null; + if (entry.IsCompressed) + return STLibraryCompression.ZSTD.Decompress(entry.data); + else + return entry.data; } - public static void SetASST(byte[] data, string path) + public static void SetASST(FileEntry fileEntry, byte[] data) { - if (beaFile.FileList.ContainsKey(path)) - { - ASST asst = beaFile.FileList[path]; - Console.WriteLine(path + " A match!"); - - asst.UncompressedSize = data.Length; - - if (asst.IsCompressed) - { - using (var compressor = new Compressor()) - { - asst.FileData = compressor.Wrap(data); - } - } - else - { - asst.FileData = data; - } - } - } - - private void SaveFileEntryData(FileEntry entry) - { - IFileFormat file = entry.FileHandle; - if (beaFile.FileList.ContainsKey(entry.FullName)) - { - if (file.CanSave) - { - SetASST(file.Save(), entry.FullName); - } - } + if (fileEntry.IsCompressed) + fileEntry.data = STLibraryCompression.ZSTD.Compress(data); + else + fileEntry.data = data; } void FillTreeNodes(TreeNode root, Dictionary files) @@ -561,7 +426,7 @@ namespace FirstPlugin var temp = new TreeNode(parentName, 0, 0); if (rootIndex == roots.Length - 1) - temp = SetupFileEntry(node.Value.FileData, parentName, node.Value.FileName, node.Value.IsCompressed); + temp = SetupFileEntry(node.Value,parentName, node.Value.FileName, node.Value.IsCompressed); else temp = SetupFolderEntry(temp); @@ -608,21 +473,25 @@ namespace FirstPlugin return finalList; } - public FileEntry SetupFileEntry(byte[] data, string name, string fullName, bool IsCompressed) + public FileEntry SetupFileEntry(ASST asset,string name, string fullName, bool IsCompressed) { FileEntry fileEntry = new FileEntry(); fileEntry.FullName = fullName; fileEntry.Name = name; fileEntry.Text = name; + fileEntry.unk1 = asset.unk; + fileEntry.unk2 = asset.unk2; + fileEntry.IsCompressed = IsCompressed; + fileEntry.data = asset.FileData; + //Now check magic + //Todo clean this part up + byte[] data = asset.FileData; if (IsCompressed) { try { - using (var decompressor = new Decompressor()) - { - data = decompressor.Unwrap(data); - } + data = STLibraryCompression.ZSTD.Decompress(asset.FileData); } catch { diff --git a/Switch_FileFormatsMain/FileFormats/BFRES.cs b/Switch_FileFormatsMain/FileFormats/BFRES.cs index 41328163..88c01d46 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES.cs @@ -16,9 +16,6 @@ namespace FirstPlugin { public class BFRES : TreeNodeFile, IFileFormat { - private static BFRES _instance; - public static BFRES Instance { get { return _instance == null ? _instance = new BFRES() : _instance; } } - public bool CanSave { get; set; } = false; public bool FileIsEdited { get; set; } = false; public bool FileIsCompressed { get; set; } = false; @@ -43,15 +40,12 @@ namespace FirstPlugin public bool UseEditMenu { get; set; } = false; public int Alignment { get; set; } = 0; public string FilePath { get; set; } - private bool isWiiU; public bool IsWiiU { get { if (Data == null) return false; - if (isWiiU) - return true; using (FileReader reader = new FileReader(new MemoryStream(Data))) { @@ -317,8 +311,7 @@ namespace FirstPlugin if (sfd.ShowDialog() == DialogResult.OK) { - Cursor.Current = Cursors.WaitCursor; - SaveCompressFile(Save(), sfd.FileName, Alignment); + STFileSaver.SaveFileFormat(this, sfd.FileName, Alignment); } } private void Rename(object sender, EventArgs args) @@ -442,32 +435,6 @@ namespace FirstPlugin fbnvFolder.Nodes.Add(boneVis); } } - private void SaveCompressFile(byte[] data, string FileName, int Alignment = 0, bool EnableDialog = true) - { - if (EnableDialog && CompressionType != CompressionType.None) - { - DialogResult save = MessageBox.Show($"Compress file as {CompressionType}?", "File Save", MessageBoxButtons.YesNo); - - if (save == DialogResult.Yes) - { - switch (CompressionType) - { - case CompressionType.Yaz0: - data = EveryFileExplorer.YAZ0.Compress(data, Runtime.Yaz0CompressionLevel, (uint)Alignment); - break; - case CompressionType.Lz4f: - data = STLibraryCompression.Type_LZ4F.Compress(data); - break; - case CompressionType.Lz4: - break; - } - } - } - File.WriteAllBytes(FileName, data); - MessageBox.Show($"File has been saved to {FileName}"); - Cursor.Current = Cursors.Default; - } - private void SaveSwitch(MemoryStream mem) { var resFile = BFRESRender.ResFileNode.resFile; @@ -531,7 +498,7 @@ namespace FirstPlugin // resFileU.SceneAnims.Clear(); // resFileU.ShapeAnims.Clear(); // resFileU.BoneVisibilityAnims.Clear(); - // resFileU.Textures.Clear(); + resFileU.Textures.Clear(); int CurMdl = 0; @@ -540,6 +507,14 @@ namespace FirstPlugin foreach (FMDL model in Nodes["FMDL"].Nodes) resFileU.Models.Add(model.Text, BfresWiiU.SetModel(model)); } + if (Nodes.ContainsKey("FTEX")) + { + foreach (FTEX tex in Nodes["FTEX"].Nodes) + resFileU.Textures.Add(tex.Text, tex.texture); + } + else + throw new Exception("Failed to find textures"); + ErrorCheck(); resFileU.Save(mem); } diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMAT.cs b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMAT.cs index de334a3b..f4a666f4 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMAT.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMAT.cs @@ -143,7 +143,7 @@ namespace Bfres.Structs if (sfd.ShowDialog() == DialogResult.OK) { - if (BFRES.Instance.IsWiiU) + if (GetResFileU() != null) MaterialU.Export(sfd.FileName, GetResFileU()); else Material.Export(sfd.FileName, GetResFile()); @@ -156,7 +156,7 @@ namespace Bfres.Structs if (ofd.ShowDialog() == DialogResult.OK) { - if (BFRES.Instance.IsWiiU) + if (GetResFileU() != null) { MaterialU.Import(ofd.FileName, GetResFileU()); MaterialU.Name = Text; diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMDL.cs b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMDL.cs index 04e1e62a..60bc9278 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMDL.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMDL.cs @@ -81,6 +81,14 @@ namespace Bfres.Structs return ((BFRES)Parent.Parent).BFRESRender.models; } + public bool IsWiiU + { + get + { + return GetResFileU() != null; + } + } + public FMDL() { @@ -121,7 +129,7 @@ namespace Bfres.Structs if (HasNormals) shp.SmoothNormals(); - shp.SaveVertexBuffer(); + shp.SaveVertexBuffer(IsWiiU); } UpdateVertexData(); Cursor.Current = Cursors.Default; @@ -135,7 +143,7 @@ namespace Bfres.Structs if (HasNormals) shp.CalculateNormals(); - shp.SaveVertexBuffer(); + shp.SaveVertexBuffer(IsWiiU); } UpdateVertexData(); Cursor.Current = Cursors.Default; @@ -196,7 +204,7 @@ namespace Bfres.Structs } shp.CalculateTangentBitangent(); - shp.SaveVertexBuffer(); + shp.SaveVertexBuffer(IsWiiU); } UpdateVertexData(); @@ -356,6 +364,8 @@ namespace Bfres.Structs //Function addes shapes, vertices and meshes public void AddOjects(string FileName, bool Replace = true) { + bool IsWiiU = (GetResFileU() != null); + int MatStartIndex = materials.Count; string ext = System.IO.Path.GetExtension(FileName); ext = ext.ToLower(); @@ -442,8 +452,8 @@ namespace Bfres.Structs shape.CreateIndexList(obj, this); shape.VertexSkinCount = obj.GetMaxSkinInfluenceCount(); shape.ApplyImportSettings(csvsettings, GetMaterial(shape.MaterialIndex)); - shape.SaveShape(); - shape.SaveVertexBuffer(); + shape.SaveShape(IsWiiU); + shape.SaveVertexBuffer(IsWiiU); shape.BoneIndices = new List(); Nodes["FshpFolder"].Nodes.Add(shape); @@ -472,7 +482,7 @@ namespace Bfres.Structs } Cursor.Current = Cursors.WaitCursor; - if (!BFRES.Instance.IsWiiU && Replace) + if (Replace) { materials.Clear(); Nodes["FmatFolder"].Nodes.Clear(); @@ -483,18 +493,18 @@ namespace Bfres.Structs FMAT fmat = new FMAT(); if (settings.ExternalMaterialPath != string.Empty) { - if (!BFRES.Instance.IsWiiU) - { - fmat.Material = new Material(); - fmat.Material.Import(settings.ExternalMaterialPath); - fmat.ReadMaterial(fmat.Material); - } - else + if (GetResFileU() != null) { fmat.MaterialU = new ResU.Material(); fmat.MaterialU.Import(settings.ExternalMaterialPath, GetResFileU()); BfresWiiU.ReadMaterial(fmat, fmat.MaterialU); } + else + { + fmat.Material = new Material(); + fmat.Material.Import(settings.ExternalMaterialPath); + fmat.ReadMaterial(fmat.Material); + } } fmat.Text = mat.Text; @@ -583,7 +593,7 @@ namespace Bfres.Structs materials.Add(fmat.Text, fmat); Nodes["FmatFolder"].Nodes.Add(fmat); - if (BFRES.Instance.IsWiiU) + if (GetResFileU() != null) { fmat.MaterialU.Name = Text; fmat.SetMaterial(fmat.MaterialU); @@ -612,8 +622,8 @@ namespace Bfres.Structs shape.CreateBoneList(obj, this); shape.CreateIndexList(obj, this); shape.ApplyImportSettings(settings, GetMaterial(shape.MaterialIndex)); - shape.SaveShape(); - shape.SaveVertexBuffer(); + shape.SaveShape(IsWiiU); + shape.SaveVertexBuffer(IsWiiU); shape.BoneIndices = new List(); List keyList = shapes.Select(o => o.Text).ToList(); diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FSHP.cs b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FSHP.cs index a9c74d49..c7cec228 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FSHP.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FSHP.cs @@ -92,6 +92,14 @@ namespace Bfres.Structs } public class FSHP : STGenericObject { + public bool IsWiiU + { + get + { + return GetResFileU() != null; + } + } + public FSHP() { Checked = true; @@ -188,7 +196,7 @@ namespace Bfres.Structs { Cursor.Current = Cursors.WaitCursor; SmoothNormals(); - SaveVertexBuffer(); + SaveVertexBuffer(IsWiiU); UpdateVertexData(); Cursor.Current = Cursors.Default; } @@ -196,7 +204,7 @@ namespace Bfres.Structs { Cursor.Current = Cursors.WaitCursor; CalculateNormals(); - SaveVertexBuffer(); + SaveVertexBuffer(IsWiiU); UpdateVertexData(); Cursor.Current = Cursors.Default; } @@ -279,8 +287,6 @@ namespace Bfres.Structs param.ValueFloat = new float[] { 1, 1, 1, 1 }; break; case "gsys_bake_st0": - param.ValueFloat = new float[] { 1, 1, 0, 0 }; - break; case "gsys_bake_st1": param.ValueFloat = new float[] { 1, 1, 0, 0 }; break; @@ -346,7 +352,7 @@ namespace Bfres.Structs } CalculateTangentBitangent(); - SaveVertexBuffer(); + SaveVertexBuffer(IsWiiU); UpdateVertexData(); Cursor.Current = Cursors.Default; } @@ -371,7 +377,7 @@ namespace Bfres.Structs } FlipUvsVertical(); - SaveVertexBuffer(); + SaveVertexBuffer(IsWiiU); UpdateVertexData(); } public void FlipUvsHorizontal(object sender, EventArgs args) @@ -383,7 +389,7 @@ namespace Bfres.Structs } FlipUvsHorizontal(); - SaveVertexBuffer(); + SaveVertexBuffer(IsWiiU); UpdateVertexData(); } public void ExportMaterials(object sender, EventArgs args) @@ -445,6 +451,8 @@ namespace Bfres.Structs } public void Replace(object sender, EventArgs args) { + bool IsWiiU = (GetResFileU() != null); + OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "Supported Formats|*.bfobj;*.fbx;*.dae; *.obj;|" + "Bfres Object (shape/vertices) |*.bfobj|" + @@ -494,8 +502,8 @@ namespace Bfres.Structs vertexAttributes = settings.CreateNewAttributes(); lodMeshes = obj.lodMeshes; CreateNewBoundingBoxes(); - SaveShape(); - SaveVertexBuffer(); + SaveShape(IsWiiU); + SaveVertexBuffer(IsWiiU); Cursor.Current = Cursors.Default; } } @@ -609,7 +617,7 @@ namespace Bfres.Structs private void UpdateShaderAssignAttributes(FMAT material) { - material.shaderassign.samplers.Clear(); + material.shaderassign.attributes.Clear(); foreach (VertexAttribute att in vertexAttributes) { material.shaderassign.attributes.Add(att.Name, att.Name); @@ -656,12 +664,12 @@ namespace Bfres.Structs return (ResUGX2.GX2AttribFormat)System.Enum.Parse(typeof(ResUGX2.GX2AttribFormat), type.ToString()); } } - public void SaveShape() + public void SaveShape(bool IsWiiU) { - if (!BFRES.Instance.IsWiiU) - Shape = BfresSwitch.SaveShape(this); - else + if (IsWiiU) ShapeU = BfresWiiU.SaveShape(this); + else + Shape = BfresSwitch.SaveShape(this); } public IList GetIndices() { @@ -683,9 +691,9 @@ namespace Bfres.Structs else return Vector3.TransformNormal(position, trans); } - public void SaveVertexBuffer() + public void SaveVertexBuffer(bool IsWiiU) { - if (BFRES.Instance.IsWiiU) + if (IsWiiU) { BfresWiiU.SaveVertexBuffer(this); return; diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/BfresSwitch.cs b/Switch_FileFormatsMain/FileFormats/BFRES/BfresSwitch.cs index da248650..12de6173 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/BfresSwitch.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/BfresSwitch.cs @@ -53,8 +53,6 @@ namespace FirstPlugin SetMaterial(mat, mat.Material); model.Materials.Add(mat.Material); } - - return model; } public static void Read(BFRESRender renderer, ResFile resFile, TreeNode ResFileNode) diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/BfresWiiU.cs b/Switch_FileFormatsMain/FileFormats/BFRES/BfresWiiU.cs index e77b5212..6194f784 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/BfresWiiU.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/BfresWiiU.cs @@ -35,11 +35,6 @@ namespace FirstPlugin foreach (var shape in duplicates) shape.Text += i++; - foreach (FMAT mat in fmdl.materials.Values) - { - SetMaterial(mat, mat.MaterialU); - model.Materials.Add(mat.Text, mat.MaterialU); - } foreach (FSHP shape in fmdl.shapes) { BFRES.CheckMissingTextures(shape); @@ -52,6 +47,12 @@ namespace FirstPlugin BFRES.SetShaderAssignAttributes(shape.GetMaterial().shaderassign, shape); } + + foreach (FMAT mat in fmdl.materials.Values) + { + SetMaterial(mat, mat.MaterialU); + model.Materials.Add(mat.Text, mat.MaterialU); + } return model; } public static void Read(BFRESRender renderer, ResFile resFile, TreeNode ResFileNode) @@ -377,6 +378,11 @@ namespace FirstPlugin m.ReadShaderParams(mat); m.MaterialU = mat; m.ReadTextureRefs(mat); + m.ReadRenderState(mat.RenderState); + } + public static void ReadRenderState(this FMAT m, RenderState renderState) + { + } public static void ReadTextureRefs(this FMAT m, Material mat) { @@ -399,6 +405,14 @@ namespace FirstPlugin texture.wrapModeW = (int)mat.Samplers[id].TexSampler.ClampZ; mat.Samplers.TryGetKey(mat.Samplers[id], out texture.SamplerName); + if (mat.Samplers[id].TexSampler.MinFilter == GX2TexXYFilterType.Bilinear) + { + texture.magFilter = 0; + } + if (mat.Samplers[id].TexSampler.MagFilter == GX2TexXYFilterType.Bilinear) + { + + } if (Runtime.activeGame == Runtime.ActiveGame.MK8D) { if (texture.SamplerName == "_a0") @@ -727,6 +741,7 @@ namespace FirstPlugin foreach (var att in shd.attributes) mat.ShaderAssign.AttribAssigns.Add(att.Key, att.Value); } + public static Shape SaveShape(FSHP fshp) { Shape ShapeU = new Shape(); diff --git a/Switch_FileFormatsMain/FileFormats/GFPAK.cs b/Switch_FileFormatsMain/FileFormats/GFPAK.cs index 3858e7a3..f8c45e18 100644 --- a/Switch_FileFormatsMain/FileFormats/GFPAK.cs +++ b/Switch_FileFormatsMain/FileFormats/GFPAK.cs @@ -74,23 +74,9 @@ namespace FirstPlugin if (sfd.ShowDialog() == DialogResult.OK) { - Cursor.Current = Cursors.WaitCursor; - SaveCompressFile(Save(), sfd.FileName, IFileInfo.Alignment); + STFileSaver.SaveFileFormat(this, sfd.FileName, IFileInfo.Alignment); } } - private void SaveCompressFile(byte[] data, string FileName, int Alignment = 0, bool EnableDialog = true) - { - if (EnableDialog) - { - DialogResult save = MessageBox.Show("Compress file?", "File Save", MessageBoxButtons.YesNo); - - if (save == DialogResult.Yes) - data = EveryFileExplorer.YAZ0.Compress(data, 3, (uint)Alignment); - } - File.WriteAllBytes(FileName, data); - MessageBox.Show($"File has been saved to {FileName}"); - Cursor.Current = Cursors.Default; - } private void PreviewWindow(object sender, EventArgs args) { @@ -114,19 +100,6 @@ namespace FirstPlugin } private void PrintRecursive(TreeNode treeNode) { - if (treeNode is FileEntry) - { - FileEntry file = (FileEntry)treeNode; - - if (file.ImageKey == "bntx") - OpenFile(file.Name, file.data, file); - - if (file.ImageKey == "bntx") - Console.WriteLine(file.Name); - // if (file.ImageKey == "bfres") - // OpenFile(file.Name, GetASSTData(file.FullName), TreeView); - } - // Print each node recursively. foreach (TreeNode tn in treeNode.Nodes) { diff --git a/Switch_FileFormatsMain/FileFormats/KCL.cs b/Switch_FileFormatsMain/FileFormats/KCL.cs index eef6e7dc..b4bd5034 100644 --- a/Switch_FileFormatsMain/FileFormats/KCL.cs +++ b/Switch_FileFormatsMain/FileFormats/KCL.cs @@ -69,33 +69,6 @@ namespace FirstPlugin { return Data; } - - private static void SaveCompressFile(byte[] data, string FileName, CompressionType CompressionType, int Alignment = 0, bool EnableDialog = true) - { - if (EnableDialog && CompressionType != CompressionType.None) - { - DialogResult save = MessageBox.Show($"Compress file as {CompressionType}?", "File Save", MessageBoxButtons.YesNo); - - if (save == DialogResult.Yes) - { - switch (CompressionType) - { - case CompressionType.Yaz0: - data = EveryFileExplorer.YAZ0.Compress(data, Runtime.Yaz0CompressionLevel, (uint)Alignment); - break; - case CompressionType.Lz4f: - data = STLibraryCompression.Type_LZ4F.Compress(data); - break; - case CompressionType.Lz4: - break; - } - } - } - File.WriteAllBytes(FileName, data); - MessageBox.Show($"File has been saved to {FileName}"); - Cursor.Current = Cursors.Default; - } - public enum GameSet : ushort { MarioOdyssey = 0x0, @@ -165,9 +138,7 @@ namespace FirstPlugin if (sfd.ShowDialog() == DialogResult.OK) { - - int Alignment = IFileInfo.Alignment; - SaveCompressFile(Save(), sfd.FileName, CompressionType, Alignment); + STFileSaver.SaveFileFormat(this, sfd.FileName, IFileInfo.Alignment); } } public void Export(object sender, EventArgs args) diff --git a/Switch_FileFormatsMain/FileFormats/SARC.cs b/Switch_FileFormatsMain/FileFormats/SARC.cs index 19e25790..bedd0c77 100644 --- a/Switch_FileFormatsMain/FileFormats/SARC.cs +++ b/Switch_FileFormatsMain/FileFormats/SARC.cs @@ -106,10 +106,10 @@ namespace FirstPlugin Console.WriteLine("Saving " + node); SaveFileEntryData((SarcEntry)node); } - if (node is TreeNodeFile && node != this) + else if (node is TreeNodeFile && node != this) { IFileFormat fileFormat = (IFileFormat)node; - if (fileFormat != null && fileFormat.IFileInfo.ArchiveHash == SarcHash) + if (fileFormat != null && fileFormat.IFileInfo != null && fileFormat.IFileInfo.ArchiveHash == SarcHash) { sarcData.Files.Add(SetSarcPath(node, this), STLibraryCompression.CompressFile(fileFormat.Save(), fileFormat)); @@ -168,23 +168,9 @@ namespace FirstPlugin if (sfd.ShowDialog() == DialogResult.OK) { - Cursor.Current = Cursors.WaitCursor; - SaveCompressFile(Save(), sfd.FileName, IFileInfo.Alignment); + STFileSaver.SaveFileFormat(this, sfd.FileName, IFileInfo.Alignment); } } - private void SaveCompressFile(byte[] data, string FileName, int Alignment = 0, bool EnableDialog = true) - { - if (EnableDialog) - { - DialogResult save = MessageBox.Show("Compress file?", "File Save", MessageBoxButtons.YesNo); - - if (save == DialogResult.Yes) - data = EveryFileExplorer.YAZ0.Compress(data, 3, (uint)Alignment); - } - File.WriteAllBytes(FileName, data); - MessageBox.Show($"File has been saved to {FileName}"); - Cursor.Current = Cursors.Default; - } private void CallRecursive(TreeView treeView) { // Print each node recursively. @@ -243,7 +229,10 @@ namespace FirstPlugin } public override void OnDoubleMouseClick(TreeView treeView) { - ReplaceNode(this.Parent, this, OpenFile(Name, Data, this)); + TreeNode node = STFileLoader.GetNodeFileFormat(FullName, Data, true, sarcHash, this); + + if (node != null) + ReplaceNode(this.Parent, this, node); } private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) @@ -368,75 +357,6 @@ namespace FirstPlugin return finalList; } - public static TreeNode OpenFile(string FileName, byte[] data, SarcEntry sarcEntry, bool Compressed = false, CompressionType CompType = 0) - { - Cursor.Current = Cursors.WaitCursor; - FileReader fileReader = new FileReader(data); - string Magic4 = fileReader.ReadMagic(0, 4); - string Magic2 = fileReader.ReadMagic(0, 2); - if (Magic4 == "Yaz0") - { - data = EveryFileExplorer.YAZ0.Decompress(data); - return OpenFile(FileName, data, sarcEntry, true, (CompressionType)1); - } - if (Magic4 == "ZLIB") - { - data = FileReader.InflateZLIB(fileReader.getSection(64, data.Length - 64)); - return OpenFile(FileName, data, sarcEntry, true, (CompressionType)2); - } - fileReader.Dispose(); - fileReader.Close(); - foreach (IFileFormat fileFormat in FileManager.GetFileFormats()) - { - if (fileFormat.Magic == Magic4 || fileFormat.Magic == Magic2) - { - fileFormat.CompressionType = CompType; - fileFormat.FileIsCompressed = Compressed; - fileFormat.Data = data; - fileFormat.Load(); - fileFormat.FileName = Path.GetFileName(FileName); - fileFormat.FilePath = FileName; - fileFormat.IFileInfo = new IFileInfo(); - fileFormat.IFileInfo.ArchiveHash = sarcEntry.sarcHash; - fileFormat.IFileInfo.InArchive = true; - - if (fileFormat is TreeNode) - { - ((TreeNode)fileFormat).Text = sarcEntry.Text; - ((TreeNode)fileFormat).ImageKey = sarcEntry.ImageKey; - ((TreeNode)fileFormat).SelectedImageKey = sarcEntry.SelectedImageKey; - return (TreeNode)fileFormat; - } - } - if (fileFormat.Magic == string.Empty) - { - foreach (string str3 in fileFormat.Extension) - { - if (str3.Remove(0, 1) == Path.GetExtension(FileName)) - { - fileFormat.Data = data; - fileFormat.Load(); - fileFormat.FileName = Path.GetFileName(FileName); - fileFormat.FilePath = FileName; - fileFormat.IFileInfo = new IFileInfo(); - fileFormat.IFileInfo.ArchiveHash = sarcEntry.sarcHash; - fileFormat.IFileInfo.InArchive = true; - - if (fileFormat is TreeNode) - { - ((TreeNode)fileFormat).Text = sarcEntry.Text; - ((TreeNode)fileFormat).ImageKey = sarcEntry.ImageKey; - ((TreeNode)fileFormat).SelectedImageKey = sarcEntry.SelectedImageKey; - return (TreeNode)fileFormat; - } - } - } - } - } - return (TreeNode)null; - } - - public SarcEntry SetupFileEntry(byte[] data, string name, string fullName, string SarchHash) { SarcEntry sarcEntry = new SarcEntry(); diff --git a/Switch_FileFormatsMain/FileFormats/Texture/BNTX.cs b/Switch_FileFormatsMain/FileFormats/Texture/BNTX.cs index 5fcde481..fb22d840 100644 --- a/Switch_FileFormatsMain/FileFormats/Texture/BNTX.cs +++ b/Switch_FileFormatsMain/FileFormats/Texture/BNTX.cs @@ -687,7 +687,7 @@ namespace FirstPlugin if (sfd.ShowDialog() == DialogResult.OK) { - File.WriteAllBytes(sfd.FileName, Save()); + STFileSaver.SaveFileFormat(this, sfd.FileName); } } } @@ -836,13 +836,37 @@ namespace FirstPlugin return DDSCompressor.DecompressBC5(data, (int)Width, (int)Height, true); byte[] d = null; - if (IsCompressedFormat(Format)) - d = DDSCompressor.DecompressBlock(data, (int)Width, (int)Height, GetCompressedDXGI_FORMAT(Format)); - else if (IsAtscFormat(Format)) - d = null; - else - d = DDSCompressor.DecodePixelBlock(data, (int)Width, (int)Height, GetUncompressedDXGI_FORMAT(Format)); - + + try + { + if (IsCompressedFormat(Format)) + d = DDSCompressor.DecompressBlock(data, (int)Width, (int)Height, GetCompressedDXGI_FORMAT(Format)); + else if (IsAtscFormat(Format)) + d = null; + else + d = DDSCompressor.DecodePixelBlock(data, (int)Width, (int)Height, GetUncompressedDXGI_FORMAT(Format)); + } + catch + { + if (Format == SurfaceFormat.BC1_UNORM) + return DDSCompressor.DecompressBC1(data, (int)Width, (int)Height, false); + else if (Format == SurfaceFormat.BC1_SRGB) + return DDSCompressor.DecompressBC1(data, (int)Width, (int)Height, true); + else if (Format == SurfaceFormat.BC3_SRGB) + return DDSCompressor.DecompressBC3(data, (int)Width, (int)Height, false); + else if (Format == SurfaceFormat.BC3_UNORM) + return DDSCompressor.DecompressBC3(data, (int)Width, (int)Height, true); + else if (Format == SurfaceFormat.BC4_UNORM) + return DDSCompressor.DecompressBC4(data, (int)Width, (int)Height, false); + else if (Format == SurfaceFormat.BC4_SNORM) + return DDSCompressor.DecompressBC4(data, (int)Width, (int)Height, true); + else if (Format == SurfaceFormat.BC5_UNORM) + return DDSCompressor.DecompressBC5(data, (int)Width, (int)Height, false); + else + return null; + } + + if (d != null) { decomp = BitmapExtension.GetBitmap(d, (int)Width, (int)Height); @@ -882,11 +906,11 @@ namespace FirstPlugin switch (Format) { case SurfaceFormat.BC1_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM; - case SurfaceFormat.BC1_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM_SRGB; + case SurfaceFormat.BC1_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM; case SurfaceFormat.BC2_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM; - case SurfaceFormat.BC2_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM_SRGB; + case SurfaceFormat.BC2_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM; case SurfaceFormat.BC3_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM; - case SurfaceFormat.BC3_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM_SRGB; + case SurfaceFormat.BC3_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM; case SurfaceFormat.BC4_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM; case SurfaceFormat.BC4_SNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_SNORM; case SurfaceFormat.BC5_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM; @@ -894,7 +918,7 @@ namespace FirstPlugin case SurfaceFormat.BC6_UFLOAT: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC6H_UF16; case SurfaceFormat.BC6_FLOAT: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC6H_SF16; case SurfaceFormat.BC7_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM; - case SurfaceFormat.BC7_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB; + case SurfaceFormat.BC7_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM; case SurfaceFormat.Invalid: throw new Exception("Invalid Format"); default: throw new Exception($"Cannot convert format {Format}"); diff --git a/Switch_FileFormatsMain/FileFormats/Texture/FTEX.cs b/Switch_FileFormatsMain/FileFormats/Texture/FTEX.cs index c8c2a7f9..70756267 100644 --- a/Switch_FileFormatsMain/FileFormats/Texture/FTEX.cs +++ b/Switch_FileFormatsMain/FileFormats/Texture/FTEX.cs @@ -22,7 +22,7 @@ namespace FirstPlugin public FTEXContainer() { Text = "Textures"; - Name = "FTEXCONT"; + Name = "FTEX"; ContextMenu = new ContextMenu(); MenuItem importTex = new MenuItem("Import"); @@ -44,9 +44,6 @@ namespace FirstPlugin { } - public override void OnClick(TreeView treeview) - { - } public void RemoveTexture(FTEX textureData) { Nodes.Remove(textureData); @@ -299,19 +296,27 @@ namespace FirstPlugin tex.Dim = (GX2SurfaceDim)surf.dim; tex.Use = (GX2SurfaceUse)surf.use; tex.TileMode = (GX2TileMode)surf.tileMode; - tex.Swizzle = (uint)surf.swizzle; - tex.Pitch = (uint)surf.pitch; - tex.Depth = (uint)surf.depth; - tex.MipCount = (uint)surf.numMips; - tex.MipOffsets = surf.mipOffset; - tex.Height = (uint)surf.height; - tex.Width = (uint)surf.width; - tex.Regs = new uint[0]; + tex.Swizzle = surf.swizzle; + tex.Pitch = surf.pitch; + tex.Depth = surf.depth; + tex.MipCount = surf.numMips; + + tex.MipOffsets = new uint[13]; + for (int i = 0; i < 13; i++) + { + if (i < surf.mipOffset.Length) + tex.MipOffsets[i] = surf.mipOffset[i]; + } + tex.Height = surf.height; + tex.Width = surf.width; + tex.Regs = new uint[5]; + tex.ArrayLength = 1; var channels = SetChannelsByFormat((GX2SurfaceFormat)surf.format); tex.CompSelR = channels[0]; tex.CompSelG = channels[1]; tex.CompSelB = channels[2]; tex.CompSelA = channels[3]; + tex.UserData = new ResDict(); return tex; } private void Rename(object sender, EventArgs args) @@ -357,6 +362,8 @@ namespace FirstPlugin SelectedImageKey = "Texture"; Text = tex.Name; + texture = tex; + renderedTex = new RenderableTex(); renderedTex.width = (int)tex.Width; renderedTex.height = (int)tex.Height; @@ -400,6 +407,8 @@ namespace FirstPlugin renderedTex.mipmaps.Add(mips); renderedTex.data = renderedTex.mipmaps[0][0]; + + LoadOpenGLTexture(); } public static GX2CompSel[] SetChannelsByFormat(GX2SurfaceFormat Format) { diff --git a/Switch_FileFormatsMain/FileFormats/Texture/GTX.cs b/Switch_FileFormatsMain/FileFormats/Texture/GTX.cs index 1aae594c..0fbb7c97 100644 --- a/Switch_FileFormatsMain/FileFormats/Texture/GTX.cs +++ b/Switch_FileFormatsMain/FileFormats/Texture/GTX.cs @@ -1,181 +1,28 @@ using System; using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Text; -using Switch_Toolbox.Library; -using Switch_Toolbox.Library.IO; -using System.Windows.Forms; namespace FirstPlugin { - public enum BlockType : uint - { - Invalid = 0x00, - EndOfFile = 0x01, - AlignData = 0x02, - VertexShaderHeader = 0x03, - VertexShaderProgram = 0x05, - PixelShaderHeader = 0x06, - PixelShaderProgram = 0x07, - GeometryShaderHeader = 0x08, - GeometryShaderProgram = 0x09, - } - - public class GTXFile : TreeNode, IFileFormat - { - public bool CanSave { get; set; } = false; - public bool FileIsEdited { get; set; } = false; - public bool FileIsCompressed { get; set; } = false; - public string[] Description { get; set; } = new string[] { "GTX" }; - public string[] Extension { get; set; } = new string[] { "*.gtx" }; - public string Magic { get; set; } = "Gfx2 "; - public CompressionType CompressionType { get; set; } = CompressionType.None; - public byte[] Data { get; set; } - public string FileName { get; set; } - public bool IsActive { get; set; } = false; - public bool UseEditMenu { get; set; } = false; - public string FilePath { get; set; } - public IFileInfo IFileInfo { get; set; } - - public Type[] Types - { - get - { - List types = new List(); - return types.ToArray(); - } - } - private GTXHeader header; - private GTXDataBlock block; - - public void Load() - { - CanSave = true; - - ReadGx2(new FileReader(Data)); - - - ContextMenu = new ContextMenu(); - MenuItem save = new MenuItem("Save"); - ContextMenu.MenuItems.Add(save); - save.Click += Save; - } - private void Save(object sender, EventArgs args) - { - Save(); - } - private void ReadGx2(FileReader reader) - { - header = new GTXHeader(); - header.Read(reader); - - } - public void Unload() - { - - } - public byte[] Save() - { - System.IO.MemoryStream mem = new System.IO.MemoryStream(); - return mem.ToArray(); - } - public class GTXHeader - { - public uint MajorVersion; - public uint MinorVersion; - public uint GpuVersion; - public uint AlignMode; - - public void Read(FileReader reader) - { - string Signature = reader.ReadString(4, Encoding.ASCII); - if (Signature != "Gfx2") - throw new Exception($"Invalid signature {Signature}! Expected Gfx2."); - - uint HeaderSize = reader.ReadUInt32(); - MajorVersion = reader.ReadUInt32(); - MinorVersion = reader.ReadUInt32(); - GpuVersion = reader.ReadUInt32(); - AlignMode = reader.ReadUInt32(); - } - public void Write(FileWriter writer) - { - writer.WriteSignature("Gfx2"); - writer.Write(MajorVersion); - writer.Write(MinorVersion); - writer.Write(GpuVersion); - writer.Write(AlignMode); - } - } - public class GTXDataBlock - { - public uint HeaderSize; - public uint MajorVersion; - public uint MinorVersion; - public BlockType BlockType; - public uint Identifier; - public uint index; - public uint DataSize; - - public void Read(FileReader reader, GTXHeader header) - { - string Signature = reader.ReadString(4, Encoding.ASCII); - if (Signature != "BLK") - throw new Exception($"Invalid signature {Signature}! Expected BLK."); - - HeaderSize = reader.ReadUInt32(); - MajorVersion = reader.ReadUInt32(); //Must be 0x01 for 6.x.x - MinorVersion = reader.ReadUInt32(); //Must be 0x00 for 6.x.x - BlockType = reader.ReadEnum(false); - DataSize = reader.ReadUInt32(); - Identifier = reader.ReadUInt32(); - index = reader.ReadUInt32(); - } - public void Write(FileWriter writer) - { - writer.WriteSignature("BLK"); - writer.Write(HeaderSize); - writer.Write(MajorVersion); - writer.Write(MinorVersion); - writer.Write(BlockType, true); - writer.Write(DataSize); - writer.Write(Identifier); - writer.Write(index); - } - } - public class TextureInfo - { - - public void Read(FileReader reader) - { - - } - public void Write(FileWriter writer) - { - - } - } - } - - public class GTX { //Some enums and parts from https://github.com/jam1garner/Smash-Forge/blob/master/Smash%20Forge/Filetypes/Textures/GTX.cs //Todo. Add swizzling back - public struct GX2Surface + public class GX2Surface { public uint dim; public uint width; public uint height; public uint depth; public uint numMips; + public uint firstSlice; + public uint numSlices; public uint format; public uint aa; public uint use; public int resourceFlags; public uint imageSize; public uint imagePtr; - public int pMem; + public int MemPtr; public uint mipSize; public uint mipPtr; public uint tileMode; @@ -183,15 +30,18 @@ namespace FirstPlugin public uint alignment; public uint pitch; public uint bpp; + public uint imageCount; + public uint firstMip; public byte[] data; public byte[] mipData; public uint[] mipOffset; + public byte[] compSel; + public uint[] texRegs; }; public static int m_configFlags = 4; - public static int ADDR_OK = 0; public static uint expPitch = 0; public static uint expHeight = 0; @@ -579,6 +429,27 @@ namespace FirstPlugin public static List Decode(GX2Surface tex) { + Console.WriteLine(""); + Console.WriteLine("// ----- GX2Surface Decode Info ----- "); + Console.WriteLine(" dim = " + tex.dim); + Console.WriteLine(" width = " + tex.width); + Console.WriteLine(" height = " + tex.height); + Console.WriteLine(" depth = " + tex.depth); + Console.WriteLine(" numMips = " + tex.numMips); + Console.WriteLine(" format = " + tex.format); + Console.WriteLine(" aa = " + tex.aa); + Console.WriteLine(" use = " + tex.use); + Console.WriteLine(" imageSize = " + tex.imageSize); + Console.WriteLine(" mipSize = " + tex.mipSize); + Console.WriteLine(" tileMode = " + tex.tileMode); + Console.WriteLine(" swizzle = " + tex.swizzle); + Console.WriteLine(" alignment = " + tex.alignment); + Console.WriteLine(" pitch = " + tex.pitch); + Console.WriteLine(" bits per pixel = " + (tex.bpp << 3)); + Console.WriteLine(" bytes per pixel = " + tex.bpp); + Console.WriteLine(" data size = " + tex.data.Length); + Console.WriteLine(" realSize = " + tex.imageSize); + uint blkWidth, blkHeight; if (IsFormatBCN((GX2SurfaceFormat)tex.format)) { @@ -594,7 +465,6 @@ namespace FirstPlugin byte[] data = tex.data; var surfInfo = getSurfaceInfo((GX2SurfaceFormat)tex.format, tex.width, tex.height, tex.depth, (uint)tex.dim, (uint)tex.tileMode, (uint)tex.aa, 0); - Debug(surfInfo); uint bpp = TegraX1Swizzle.DIV_ROUND_UP(surfInfo.bpp, 8); if (surfInfo.depth != 1) @@ -616,7 +486,7 @@ namespace FirstPlugin mipOffset -= (uint)surfInfo.surfSize; surfInfo = getSurfaceInfo((GX2SurfaceFormat)tex.format, tex.width, tex.height, tex.depth, (uint)tex.dim, (uint)tex.tileMode, (uint)tex.aa, mipLevel); - data = new byte[surfInfo.surfSize + mipOffset]; + data = new byte[surfInfo.surfSize]; Array.Copy(tex.mipData, mipOffset, data, 0, surfInfo.surfSize); } byte[] deswizzled = deswizzle(width_, height_, surfInfo.height, (uint)tex.format, @@ -634,24 +504,10 @@ namespace FirstPlugin /*--------------------------------------- * - * Code ported from AboodXD's GTX Extractor https://github.com/aboood40091/GTX-Extractor/blob/master/gtx_extract.py - * - * With help by Aelan! + * Code ported from AboodXD's GTX Extractorhttps://github.com/aboood40091/GTX-Extractor/blob/f586dde90bd4a262421a4a565c1556d0079a748e/addrlib/addrlib_cy.pyx * *---------------------------------------*/ - /*var s_textureFormats[] = { - // internalFormat, gxFormat, glFormat, fourCC, nutFormat, name, bpp, compressed - { FORMAT_RGBA_8888, GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM, GL_RGBA8, 0x00000000, 0x11, "RGBA_8888", 0x20, 0 }, - { FORMAT_ABGR_8888, GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM, GL_RGBA8, 0x00000000, 0x0E, "ABGR_8888 (WIP)", 0x20, 0 }, - { FORMAT_DXT1, GX2_SURFACE_FORMAT_T_BC1_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0x31545844, 0x00, "DXT1", 0x40, 1 }, - { FORMAT_DXT3, GX2_SURFACE_FORMAT_T_BC2_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0x33545844, 0x01, "DXT3", 0x80, 1 }, - { FORMAT_DXT5, GX2_SURFACE_FORMAT_T_BC3_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0x35545844, 0x02, "DXT5", 0x80, 1 }, - { FORMAT_ATI1, GX2_SURFACE_FORMAT_T_BC4_UNORM, GL_COMPRESSED_RED_RGTC1, 0x31495441, 0x15, "ATI1", 0x40, 1 }, - { FORMAT_ATI2, GX2_SURFACE_FORMAT_T_BC5_UNORM, GL_COMPRESSED_RG_RGTC2, 0x32495441, 0x16, "ATI2", 0x80, 1 }, - { FORMAT_INVALID, GX2_SURFACE_FORMAT_INVALID, 0, 0xFFFFFFFF, 0x00, nullptr, 0x00, 0 } - };*/ - public static bool IsFormatBCN(GX2SurfaceFormat Format) { switch (Format) @@ -686,19 +542,6 @@ namespace FirstPlugin private static byte[] swizzleSurf(uint width, uint height, uint height_, uint format, uint tileMode, uint swizzle_, uint pitch, uint bitsPerPixel, byte[] data, int swizzle) { - Console.WriteLine("swizzling level...."); - Console.WriteLine("---------------------------"); - Console.WriteLine("width " + width); - Console.WriteLine("height " + height); - Console.WriteLine("height_ " + height_); - Console.WriteLine("format " + format); - Console.WriteLine("tileMode " + tileMode); - Console.WriteLine("swizzle_ " + swizzle_); - Console.WriteLine("pitch " + pitch); - Console.WriteLine("bitsPerPixel " + bitsPerPixel); - Console.WriteLine("swizzle " + swizzle); - Console.WriteLine("---------------------------"); - uint bytesPerPixel = bitsPerPixel / 8; byte[] result = new byte[data.Length]; @@ -1809,11 +1652,6 @@ namespace FirstPlugin if (padDims == 0) padDims = 3; - Console.WriteLine("padDims " + padDims); - Console.WriteLine("pitchAlign " + pitchAlign); - - - if ((pitchAlign & (pitchAlign - 1)) == 0) expPitch = powTwoAlign(expPitch, pitchAlign); else @@ -1826,10 +1664,6 @@ namespace FirstPlugin if (padDims > 1) expHeight = powTwoAlign(expHeight, heightAlign); - Console.WriteLine("expPitch " + expPitch); - Console.WriteLine("expHeight " + expHeight); - Console.WriteLine("expNumSlices " + expNumSlices); - if (padDims > 2 || thickness > 1) { if (isCube != 0) @@ -1838,10 +1672,6 @@ namespace FirstPlugin if (thickness > 1) expNumSlices = powTwoAlign(expNumSlices, sliceAlign); } - Console.WriteLine("expPitch " + expPitch); - Console.WriteLine("expHeight " + expHeight); - Console.WriteLine("expNumSlices " + expNumSlices); - return new Tuple(expPitch, expHeight, expNumSlices); } @@ -1885,9 +1715,6 @@ namespace FirstPlugin microTileThickness = 1; } } - Console.WriteLine($"baseTileMode {baseTileMode}"); - Console.WriteLine($"tileMode {tileMode}"); - if (tileMode == baseTileMode || mipLevel == 0 || isThickMacroTiled((AddrTileMode)baseTileMode) == 0 @@ -1907,29 +1734,9 @@ namespace FirstPlugin bankSwappedWidth = computeSurfaceBankSwappedWidth((AddrTileMode)tileMode, bpp, pitch, numSamples); - Console.WriteLine("---------------------"); - Console.WriteLine(baseAlign); - Console.WriteLine(pitchAlign); - Console.WriteLine(heightAlign); - Console.WriteLine(macroWidth); - Console.WriteLine(macroHeight); - Console.WriteLine(bankSwappedWidth); - Console.WriteLine("---------------------"); - if (bankSwappedWidth > pitchAlign) pitchAlign = bankSwappedWidth; - Console.WriteLine("padDimensions"); - Console.WriteLine(tileMode); - Console.WriteLine(padDims); - Console.WriteLine((flags.value >> 4) & 1); - Console.WriteLine((flags.value >> 7) & 1); - Console.WriteLine(pitchAlign); - Console.WriteLine(heightAlign); - Console.WriteLine(microTileThickness); - Console.WriteLine("---------------------"); - Console.WriteLine("expPitch " + expPitch); - var padDimens = padDimensions( tileMode, padDims, @@ -1943,14 +1750,6 @@ namespace FirstPlugin expHeight = padDimens.Item2; expNumSlices = padDimens.Item3; - Console.WriteLine(expPitch); - Console.WriteLine(expHeight); - Console.WriteLine(expNumSlices); - Console.WriteLine(bpp); - Console.WriteLine(numSamples); - - Console.WriteLine("---------------------"); - pPitchOut = expPitch; pHeightOut = expHeight; pNumSlicesOut = expNumSlices; @@ -2041,12 +1840,6 @@ namespace FirstPlugin pHeightOut = expHeight; pNumSlicesOut = expNumSlices; pSurfSize = (expHeight * expPitch * expNumSlices * bpp * numSamples + 7) / 8; - Console.WriteLine($"expHeight {expHeight}"); - Console.WriteLine($"expPitch {expPitch}"); - Console.WriteLine($"expNumSlices {expNumSlices}"); - Console.WriteLine($"bpp {bpp}"); - Console.WriteLine($"numSamples {numSamples}"); - Console.WriteLine($"bpp {bpp}"); pTileModeOut = expTileMode; pBaseAlign = baseAlign; diff --git a/Switch_FileFormatsMain/FileFormats/Texture/GTXFile.cs b/Switch_FileFormatsMain/FileFormats/Texture/GTXFile.cs new file mode 100644 index 00000000..1844253c --- /dev/null +++ b/Switch_FileFormatsMain/FileFormats/Texture/GTXFile.cs @@ -0,0 +1,562 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Text; +using System.Threading.Tasks; +using Switch_Toolbox.Library.IO; +using Switch_Toolbox.Library; +using System.Windows.Forms; +using OpenTK.Graphics.OpenGL; + +namespace FirstPlugin +{ + public enum BlockType : uint + { + Invalid = 0x00, + EndOfFile = 0x01, + AlignData = 0x02, + VertexShaderHeader = 0x03, + VertexShaderProgram = 0x05, + PixelShaderHeader = 0x06, + PixelShaderProgram = 0x07, + GeometryShaderHeader = 0x08, + GeometryShaderProgram = 0x09, + GeometryShaderProgram2 = 0x10, + ImageInfo = 0x11, + ImageData = 0x12, + MipData = 0x13, + ComputeShaderHeader = 0x14, + ComputeShader = 0x15, + UserBlock = 0x16, + } + + public class GTXFile : TreeNode, IFileFormat + { + public bool CanSave { get; set; } = false; + public bool FileIsEdited { get; set; } = false; + public bool FileIsCompressed { get; set; } = false; + public string[] Description { get; set; } = new string[] { "GTX" }; + public string[] Extension { get; set; } = new string[] { "*.gtx" }; + public string Magic { get; set; } = "Gfx2 "; + public CompressionType CompressionType { get; set; } = CompressionType.None; + public byte[] Data { get; set; } + public string FileName { get; set; } + public bool IsActive { get; set; } = false; + public bool UseEditMenu { get; set; } = false; + public string FilePath { get; set; } + public IFileInfo IFileInfo { get; set; } + + public Type[] Types + { + get + { + List types = new List(); + return types.ToArray(); + } + } + private GTXHeader header; + + public List data = new List(); + public List mipMaps = new List(); + public List textures = new List(); + + public List blocks = new List(); + + public void Load() + { + CanSave = true; + Text = FileName; + + ReadGx2(new FileReader(Data)); + + ContextMenu = new ContextMenu(); + MenuItem save = new MenuItem("Save"); + ContextMenu.MenuItems.Add(save); + save.Click += Save; + } + private void Save(object sender, EventArgs args) + { + SaveFileDialog sfd = new SaveFileDialog(); + sfd.DefaultExt = "gtx"; + sfd.Filter = "Supported Formats|*.gtx;"; + sfd.FileName = FileName; + + if (sfd.ShowDialog() == DialogResult.OK) + { + STFileSaver.SaveFileFormat(this, sfd.FileName); + } + } + public void Unload() + { + } + public byte[] Save() + { + System.IO.MemoryStream mem = new System.IO.MemoryStream(); + using (FileWriter writer = new FileWriter(mem)) + { + writer.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; + + header.Write(writer); + writer.Seek(header.HeaderSize, System.IO.SeekOrigin.Begin); + foreach (var block in blocks) + block.Write(writer); + } + return mem.ToArray(); + } + private void ReadGx2(FileReader reader) + { + reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; + + header = new GTXHeader(); + header.Read(reader); + + Console.WriteLine("header size " + header.HeaderSize); + + uint surfBlockType; + uint dataBlockType; + uint mipBlockType; + + if (header.MajorVersion == 6) + { + surfBlockType = 0x0A; + dataBlockType = 0x0B; + mipBlockType = 0x0C; + } + else if (header.MajorVersion == 7) + { + surfBlockType = 0x0B; + dataBlockType = 0x0C; + mipBlockType = 0x0D; + } + else + throw new Exception($"Unsupported GTX version {header.MajorVersion}"); + + if (header.GpuVersion != 2) + throw new Exception($"Unsupported GPU version {header.GpuVersion}"); + + reader.Position = header.HeaderSize; + + bool blockB = false; + bool blockC = false; + + uint ImageInfo = 0; + uint images = 0; + + while (reader.Position < reader.BaseStream.Length) + { + GTXDataBlock block = new GTXDataBlock(); + block.Read(reader); + blocks.Add(block); + + //Here we use "if" instead of "case" statements as types vary between versions + if ((uint)block.BlockType == surfBlockType) + { + ImageInfo += 1; + blockB = true; + + var surface = new SurfaceInfoParse(); + surface.Read(new FileReader(block.data)); + + if (surface.numMips > 14) + throw new Exception($"Invalid number of mip maps {surface.numMips}!"); + + TextureData textureData = new TextureData(); + textureData.surface = surface; + textureData.Text = "Texture" + ImageInfo; + Nodes.Add(textureData); + textures.Add(textureData); + } + else if ((uint)block.BlockType == dataBlockType) + { + images += 1; + blockC = true; + + data.Add(block.data); + } + else if ((uint)block.BlockType == mipBlockType) + { + mipMaps.Add(block.data); + } + } + if (textures.Count != data.Count) + throw new Exception($"Bad size! {textures.Count} {data.Count}"); + + int curTex = 0; + int curMip = 0; + foreach (var node in Nodes) + { + TextureData tex = (TextureData)node; + tex.surface.data = data[curTex]; + tex.surface.bpp = GTX.surfaceGetBitsPerPixel(tex.surface.format) >> 3; + + Console.WriteLine(); + + if (tex.surface.numMips > 1 ) + tex.surface.mipData = mipMaps[curMip++]; + else + tex.surface.mipData = new byte[0]; + + Console.WriteLine(""); + Console.WriteLine("// ----- GX2Surface Info ----- "); + Console.WriteLine(" dim = " + tex.surface.dim); + Console.WriteLine(" width = " + tex.surface.width); + Console.WriteLine(" height = " + tex.surface.height); + Console.WriteLine(" depth = " + tex.surface.depth); + Console.WriteLine(" numMips = " + tex.surface.numMips); + Console.WriteLine(" format = " + tex.surface.format); + Console.WriteLine(" aa = " + tex.surface.aa); + Console.WriteLine(" use = " + tex.surface.use); + Console.WriteLine(" imageSize = " + tex.surface.imageSize); + Console.WriteLine(" mipSize = " + tex.surface.mipSize); + Console.WriteLine(" tileMode = " + tex.surface.tileMode); + Console.WriteLine(" swizzle = " + tex.surface.swizzle); + Console.WriteLine(" alignment = " + tex.surface.alignment); + Console.WriteLine(" pitch = " + tex.surface.pitch); + Console.WriteLine(" bits per pixel = " + (tex.surface.bpp << 3)); + Console.WriteLine(" bytes per pixel = " + tex.surface.bpp); + Console.WriteLine(" data size = " + tex.surface.data.Length); + Console.WriteLine(" mip size = " + tex.surface.mipData.Length); + Console.WriteLine(" realSize = " + tex.surface.imageSize); + + List mips = GTX.Decode(tex.surface); + tex.renderedTex.mipmaps.Add(mips); + tex.renderedTex.width = (int)tex.surface.width; + tex.renderedTex.height = (int)tex.surface.height; + + curTex++; + } + } + public class GTXHeader + { + readonly string Magic = "Gfx2"; + public uint HeaderSize; + public uint MajorVersion; + public uint MinorVersion; + public uint GpuVersion; + public uint AlignMode; + + public void Read(FileReader reader) + { + string Signature = reader.ReadString(4, Encoding.ASCII); + if (Signature != Magic) + throw new Exception($"Invalid signature {Signature}! Expected Gfx2."); + + HeaderSize = reader.ReadUInt32(); + MajorVersion = reader.ReadUInt32(); + MinorVersion = reader.ReadUInt32(); + GpuVersion = reader.ReadUInt32(); + AlignMode = reader.ReadUInt32(); + } + public void Write(FileWriter writer) + { + writer.WriteSignature(Magic); + writer.Write(HeaderSize); + writer.Write(MajorVersion); + writer.Write(MinorVersion); + writer.Write(GpuVersion); + writer.Write(AlignMode); + } + } + public class GTXDataBlock + { + readonly string Magic = "BLK{"; + public uint HeaderSize; + public uint MajorVersion; + public uint MinorVersion; + public BlockType BlockType; + public uint Identifier; + public uint index; + public uint DataSize; + public byte[] data; + + public void Read(FileReader reader) + { + long blockStart = reader.Position; + + string Signature = reader.ReadString(4, Encoding.ASCII); + if (Signature != Magic) + throw new Exception($"Invalid signature {Signature}! Expected BLK."); + + HeaderSize = reader.ReadUInt32(); + MajorVersion = reader.ReadUInt32(); //Must be 0x01 for 6.x.x + MinorVersion = reader.ReadUInt32(); //Must be 0x00 for 6.x.x + BlockType = reader.ReadEnum(false); + DataSize = reader.ReadUInt32(); + Identifier = reader.ReadUInt32(); + index = reader.ReadUInt32(); + + reader.Seek(blockStart + HeaderSize, System.IO.SeekOrigin.Begin); + data = reader.ReadBytes((int)DataSize); + System.IO.File.WriteAllBytes($"block {BlockType}.bin", data); + } + public void Write(FileWriter writer) + { + long blockStart = writer.Position; + + writer.WriteSignature(Magic); + writer.Write(HeaderSize); + writer.Write(MajorVersion); + writer.Write(MinorVersion); + writer.Write(BlockType, false); + writer.Write(DataSize); + writer.Write(Identifier); + writer.Write(index); + writer.Seek(blockStart + HeaderSize, System.IO.SeekOrigin.Begin); + + writer.Write(data); + } + } + public class TextureData : TreeNodeCustom + { + public SurfaceInfoParse surface; + public RenderableTex renderedTex = new RenderableTex(); + + public TextureData() + { + ImageKey = "Texture"; + SelectedImageKey = "Texture"; + + ContextMenu = new ContextMenu(); + MenuItem export = new MenuItem("Export"); + ContextMenu.MenuItems.Add(export); + export.Click += Export; + MenuItem replace = new MenuItem("Replace"); + ContextMenu.MenuItems.Add(replace); + replace.Click += Replace; + MenuItem remove = new MenuItem("Remove"); + ContextMenu.MenuItems.Add(remove); + remove.Click += Remove; + } + private void Remove(object sender, EventArgs args) + { + ((GTXFile)Parent).Nodes.Remove(this); + } + private void Export(object sender, EventArgs args) + { + SaveFileDialog sfd = new SaveFileDialog(); + sfd.FileName = Text; + sfd.DefaultExt = "bftex"; + sfd.Filter = "Supported Formats|*.bftex;*.dds; *.png;*.tga;*.jpg;*.tiff|" + + "Binary Texture |*.bftex|" + + "Microsoft DDS |*.dds|" + + "Portable Network Graphics |*.png|" + + "Joint Photographic Experts Group |*.jpg|" + + "Bitmap Image |*.bmp|" + + "Tagged Image File Format |*.tiff|" + + "All files(*.*)|*.*"; + + if (sfd.ShowDialog() == DialogResult.OK) + { + Export(sfd.FileName); + } + } + public void Export(string FileName, bool ExportSurfaceLevel = false, + bool ExportMipMapLevel = false, int SurfaceLevel = 0, int MipLevel = 0) + { + string ext = System.IO.Path.GetExtension(FileName); + ext = ext.ToLower(); + + switch (ext) + { + case ".dds": + SaveDDS(FileName); + break; + default: + SaveBitMap(FileName); + break; + } + } + internal void SaveBitMap(string FileName, int SurfaceLevel = 0, int MipLevel = 0) + { + Bitmap bitMap = DisplayTexture(MipLevel, SurfaceLevel); + + bitMap.Save(FileName); + } + internal void SaveDDS(string FileName) + { + DDS dds = new DDS(); + dds.header = new DDS.Header(); + dds.header.width = (uint)renderedTex.width; + dds.header.height = (uint)renderedTex.width; + dds.header.mipmapCount = (uint)renderedTex.mipmaps[0].Count; + + dds.header.pitchOrLinearSize = (uint)renderedTex.mipmaps[0][0].Length; + + + + dds.Save(dds, FileName, renderedTex.mipmaps); + } + private void Replace(object sender, EventArgs args) + { + OpenFileDialog ofd = new OpenFileDialog(); + ofd.Filter = "Supported Formats|*.dds; *.png;*.tga;*.jpg;*.tiff|" + + "Microsoft DDS |*.dds|" + + "Portable Network Graphics |*.png|" + + "Joint Photographic Experts Group |*.jpg|" + + "Bitmap Image |*.bmp|" + + "Tagged Image File Format |*.tiff|" + + "All files(*.*)|*.*"; + + ofd.Multiselect = false; + if (ofd.ShowDialog() == DialogResult.OK) + { + Replace(ofd.FileName); + } + } + public void Replace(string FileName) + { + string ext = System.IO.Path.GetExtension(FileName); + ext = ext.ToLower(); + + GTXImporterSettings setting = new GTXImporterSettings(); + GTXTextureImporter importer = new GTXTextureImporter(); + + switch (ext) + { + case ".dds": + setting.LoadDDS(FileName, null); + break; + default: + setting.LoadBitMap(FileName); + importer.LoadSetting(setting); + break; + } + + if (importer.ShowDialog() == DialogResult.OK) + { + Cursor.Current = Cursors.WaitCursor; + + if (setting.GenerateMipmaps) + { + setting.DataBlockOutput.Clear(); + setting.DataBlockOutput.Add(setting.GenerateMips()); + } + + if (setting.DataBlockOutput != null) + { + var surface = setting.CreateGx2Texture(setting.DataBlockOutput[0]); + + } + else + { + MessageBox.Show("Something went wrong???"); + } + UpdateEditor(); + } + } + public class RenderableTex + { + public int width, height; + public int display; + public PixelInternalFormat pixelInternalFormat; + public PixelFormat pixelFormat; + public PixelType pixelType = PixelType.UnsignedByte; + public int mipMapCount; + public List> mipmaps = new List>(); + public byte[] data; + + public class Surface + { + + } + } + + public override void OnClick(TreeView treeView) + { + UpdateEditor(); + } + + public void UpdateEditor() + { + if (Viewport.Instance.gL_ControlModern1.Visible == false) + PluginRuntime.FSHPDockState = WeifenLuo.WinFormsUI.Docking.DockState.Document; + + GTXEditor docked = (GTXEditor)LibraryGUI.Instance.GetContentDocked(new GTXEditor()); + if (docked == null) + { + docked = new GTXEditor(); + LibraryGUI.Instance.LoadDockContent(docked, PluginRuntime.FSHPDockState); + } + docked.Text = Text; + docked.Dock = DockStyle.Fill; + docked.LoadPicture(DisplayTexture()); + docked.LoadProperty(this); + } + + public Bitmap DisplayTexture(int DisplayMipIndex = 0, int ArrayIndex = 0) + { + if (renderedTex.mipmaps.Count <= 0) + { + throw new Exception("No texture data found"); + } + + uint width = (uint)Math.Max(1, renderedTex.width >> DisplayMipIndex); + uint height = (uint)Math.Max(1, renderedTex.height >> DisplayMipIndex); + + byte[] data = renderedTex.mipmaps[ArrayIndex][DisplayMipIndex]; + + return FTEX.DecodeBlock(data, width, height, (Syroot.NintenTools.Bfres.GX2.GX2SurfaceFormat)surface.format); + } + } + public class SurfaceInfoParse : GTX.GX2Surface + { + + public void Read(FileReader reader) + { + reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; + + dim = reader.ReadUInt32(); + width = reader.ReadUInt32(); + height = reader.ReadUInt32(); + depth = reader.ReadUInt32(); + numMips = reader.ReadUInt32(); + format = reader.ReadUInt32(); + aa = reader.ReadUInt32(); + use = reader.ReadUInt32(); + imageSize = reader.ReadUInt32(); + imagePtr = reader.ReadUInt32(); + mipSize = reader.ReadUInt32(); + mipPtr = reader.ReadUInt32(); + tileMode = reader.ReadUInt32(); + swizzle = reader.ReadUInt32(); + alignment = reader.ReadUInt32(); + pitch = reader.ReadUInt32(); + mipOffset = reader.ReadUInt32s(13); + firstMip = reader.ReadUInt32(); + imageCount = reader.ReadUInt32(); + firstSlice = reader.ReadUInt32(); + numSlices = reader.ReadUInt32(); + compSel = reader.ReadBytes(4); + texRegs = reader.ReadUInt32s(5); + } + public void Write(FileWriter writer) + { + writer.Write(dim); + writer.Write(width); + writer.Write(height); + writer.Write(depth); + writer.Write(numMips); + writer.Write(format); + writer.Write(aa); + writer.Write(use); + writer.Write(imageSize); + writer.Write(imagePtr); + writer.Write(mipSize); + writer.Write(mipPtr); + writer.Write(tileMode); + writer.Write(swizzle); + writer.Write(alignment); + writer.Write(pitch); + writer.Write(mipOffset); + writer.Write(firstMip); + writer.Write(imageCount); + writer.Write(firstSlice); + writer.Write(numSlices); + writer.Write(compSel); + writer.Write(texRegs); + } + } + } + + +} diff --git a/Switch_FileFormatsMain/FileFormats/Texture/NUTEXB.cs b/Switch_FileFormatsMain/FileFormats/Texture/NUTEXB.cs index 53a5aa1e..ffa8b135 100644 --- a/Switch_FileFormatsMain/FileFormats/Texture/NUTEXB.cs +++ b/Switch_FileFormatsMain/FileFormats/Texture/NUTEXB.cs @@ -156,7 +156,6 @@ namespace FirstPlugin { Console.WriteLine("Something went wrong??"); } - texture.blocksCompressed.Clear(); texture.mipmaps.Clear(); @@ -177,7 +176,7 @@ namespace FirstPlugin public List mipSizes = new List(); public int Alignment; public List> mipmaps = new List>(); - public List> blocksCompressed = new List>(); + public byte[] ImageData; bool IsSwizzled = true; public string ArcOffset; //Temp for exporting in batch @@ -200,7 +199,7 @@ namespace FirstPlugin var bntxFile = new BNTX(); var tex = new TextureData(); tex.Replace(ofd.FileName); - blocksCompressed = tex.Texture.TextureData; + ImageData = tex.Texture.TextureData[0][0]; mipmaps = tex.mipmaps; Width = tex.Texture.Width; Height = tex.Texture.Height; @@ -236,8 +235,7 @@ namespace FirstPlugin if (sfd.ShowDialog() == DialogResult.OK) { - Cursor.Current = Cursors.WaitCursor; - System.IO.File.WriteAllBytes(sfd.FileName, Save()); + STFileSaver.SaveFileFormat(this, sfd.FileName); } } public void Export(string FileName, bool ExportSurfaceLevel = false, @@ -318,39 +316,17 @@ namespace FirstPlugin //Seek to next one reader.Seek(mipPos + 0x40, System.IO.SeekOrigin.Begin); } - - reader.Seek(0, System.IO.SeekOrigin.Begin); - for (int arrayLevel = 1; arrayLevel < ArrayCount + 1; arrayLevel++) - { - List mipmaps = new List(); + ImageData = reader.ReadBytes(imagesize); - for (int mipLevel = 0; mipLevel < mipCount; mipLevel++) - { - //Get the size from the size array - int size = (int)mipSizes[arrayLevel - 1][mipLevel]; - - //Align the size - if (mipLevel == 0) - if (size % Alignment != 0) size = size + (Alignment - (size % Alignment)); - - mipmaps.Add(reader.ReadBytes(imagesize)); - break; - } - blocksCompressed.Add(mipmaps); - //Seek the next array - reader.Seek(imagesize / (int)ArrayCount, System.IO.SeekOrigin.Begin); - } LoadTexture(); } public void Write(FileWriter writer) { - int arrayCount = blocksCompressed.Count; + int arrayCount = mipSizes.Count; + + writer.Write(ImageData); //Write textue block first - foreach (var array in blocksCompressed) - { - writer.Write(array[0]); //Write textue block first - } long headerStart = writer.Position; foreach (var mips in mipSizes) { @@ -371,10 +347,10 @@ namespace FirstPlugin writer.Write((byte)unk); writer.Seek(2); //padding writer.Write(unk2); - writer.Write(blocksCompressed[0].Count); + writer.Write(mipSizes.Count); writer.Write(Alignment); writer.Write(arrayCount); - writer.Write(blocksCompressed[0][0].Length * arrayCount); + writer.Write(ImageData.Length); writer.WriteSignature(" XET"); writer.Write(131073); @@ -392,7 +368,7 @@ namespace FirstPlugin if (IsSwizzled) LoadTexture(); else - mipmaps.Add(blocksCompressed[ArrayIndex]); + mipmaps.Add(new List() { ImageData }); if (mipmaps[0].Count <= 0) { @@ -504,13 +480,21 @@ namespace FirstPlugin uint bpp = bpps((byte)Format); - for (int arrayLevel = 0; arrayLevel < blocksCompressed.Count; arrayLevel++) + for (int arrayLevel = 0; arrayLevel < mipSizes.Count; arrayLevel++) { int blockHeightShift = 0; + uint mipOffset = 0; List mips = new List(); - for (int mipLevel = 0; mipLevel < blocksCompressed[arrayLevel].Count; mipLevel++) + for (int mipLevel = 0; mipLevel < mipSizes[arrayLevel].Length; mipLevel++) { + //Get the size from the size array + int MipSize = (int)mipSizes[arrayLevel][mipLevel]; + + //Align the size + if (mipLevel == 0) + if (MipSize % Alignment != 0) MipSize = MipSize + (Alignment - (MipSize % Alignment)); + uint width = (uint)Math.Max(1, Width >> mipLevel); uint height = (uint)Math.Max(1, Height >> mipLevel); @@ -519,14 +503,14 @@ namespace FirstPlugin if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight) blockHeightShift += 1; - Console.WriteLine($"{blk_dim.ToString("x")} {bpp} {width} {height} {linesPerBlockHeight} {blkWidth} {blkHeight} {size} { blocksCompressed[arrayLevel][mipLevel].Length}"); + Console.WriteLine($"{blk_dim.ToString("x")} {bpp} {width} {height} {linesPerBlockHeight} {blkWidth} {blkHeight} {size} { ImageData.Length}"); try { - byte[] result = TegraX1Swizzle.deswizzle(width, height, blkWidth, blkHeight, target, bpp, tileMode, (int)Math.Max(0, BlockHeightLog2 - blockHeightShift), blocksCompressed[arrayLevel][mipLevel]); + byte[] result = TegraX1Swizzle.deswizzle(width, height, blkWidth, blkHeight, target, bpp, tileMode, (int)Math.Max(0, BlockHeightLog2 - blockHeightShift), ImageData); //Create a copy and use that to remove uneeded data byte[] result_ = new byte[size]; - Array.Copy(result, 0, result_, 0, size); + Array.Copy(result, mipOffset, result_, 0, size); mips.Add(result_); } @@ -537,6 +521,8 @@ namespace FirstPlugin BadSwizzle = true; break; } + mipOffset += (uint)MipSize; + break; } mipmaps.Add(mips); } diff --git a/Switch_FileFormatsMain/FileFormats/Texture/XTX.cs b/Switch_FileFormatsMain/FileFormats/Texture/XTX.cs index 8ca5ec3f..50070ec9 100644 --- a/Switch_FileFormatsMain/FileFormats/Texture/XTX.cs +++ b/Switch_FileFormatsMain/FileFormats/Texture/XTX.cs @@ -214,7 +214,8 @@ namespace FirstPlugin public uint[] MipOffsets { get; set; } public BlockHeader DataBlockHeader { get; set; } public List mipmaps = new List(); - public List compressedBlocks = new List(); + public byte[] ImageData; + public void Read(FileReader reader) { @@ -240,24 +241,12 @@ namespace FirstPlugin DataBlockHeader.Read(reader); reader.Seek(DataBlockOff + DataBlockHeader.DataOffset, SeekOrigin.Begin); - // data = reader.ReadBytes((int)DataBlockHeader.DataSize); long datastart = reader.Position; + ImageData = reader.ReadBytes((int)DataSize); - Console.WriteLine(DataBlockHeader.DataSize); - for (int i = 0; i < MipCount; i++) - { - int size = (int)((int)DataBlockHeader.DataSize - MipOffsets[i]); - Console.WriteLine(size); + if (ImageData.Length == 0) + throw new System.Exception("Empty data size!"); - using (reader.TemporarySeek(datastart + MipOffsets[i], System.IO.SeekOrigin.Begin)) - { - compressedBlocks.Add(reader.ReadBytes(size)); - } - if (compressedBlocks[i].Length == 0) - throw new System.Exception("Empty mip size!"); - - break; //Only first mip level works? - } reader.Seek(DataBlockOff + DataBlockHeader.DataOffset + (long)DataBlockHeader.DataSize, SeekOrigin.Begin); BlockHeader EndBlockHeader = new BlockHeader(); EndBlockHeader.Read(reader); @@ -353,20 +342,36 @@ namespace FirstPlugin uint bpp = XTXFormats.bpps((uint)Format); int blockHeightShift = 0; - for (int mipLevel = 0; mipLevel < compressedBlocks.Count; mipLevel++) + for (int mipLevel = 0; mipLevel < MipOffsets.Length; mipLevel++) { + uint width = (uint)Math.Max(1, Width >> mipLevel); uint height = (uint)Math.Max(1, Height >> mipLevel); // uint size = width * height * bpp; uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp; + byte[] Output = new byte[size]; + + uint mipOffset; + if (mipLevel != 0) + { + mipOffset = (MipOffsets[mipLevel - 1]); + if (mipLevel == 1) + mipOffset -= (uint)size; + + Array.Copy(ImageData, mipOffset, Output, 0, size); + } + else + Output = ImageData; + + byte[] output = new byte[size]; Console.WriteLine(mipLevel + " " + size); if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight) blockHeightShift += 1; - byte[] result = TegraX1Swizzle.deswizzle(width, height, blkWidth, blkHeight, (int)Target, bpp, (uint)TileMode, (int)Math.Max(0, BlockHeightLog2 - blockHeightShift), compressedBlocks[mipLevel]); + byte[] result = TegraX1Swizzle.deswizzle(width, height, blkWidth, blkHeight, (int)Target, bpp, (uint)TileMode, (int)Math.Max(0, BlockHeightLog2 - blockHeightShift), Output); //Create a copy and use that to remove uneeded data byte[] result_ = new byte[size]; Array.Copy(result, 0, result_, 0, size); diff --git a/Switch_FileFormatsMain/GL/BFRES_Render.cs b/Switch_FileFormatsMain/GL/BFRES_Render.cs index 2bc440b4..09e82fd8 100644 --- a/Switch_FileFormatsMain/GL/BFRES_Render.cs +++ b/Switch_FileFormatsMain/GL/BFRES_Render.cs @@ -295,15 +295,15 @@ namespace FirstPlugin // Bind the texture and create the uniform if the material has the right textures. if (hasTex) { - GL.Uniform1(shader.GetUniformLocation(name), BindTexture(mattex)); + GL.Uniform1(shader.GetUniformLocation(name), BindTexture(mattex, mat.GetResFileU() != null)); } } - public static int BindTexture(MatTexture tex) + public static int BindTexture(MatTexture tex, bool IsWiiU) { GL.ActiveTexture(TextureUnit.Texture0 + tex.hash + 1); GL.BindTexture(TextureTarget.Texture2D, RenderTools.defaultTex.Id); - if (BFRES.Instance.IsWiiU) + if (IsWiiU) { foreach (var ftexContainer in PluginRuntime.ftexContainers) { diff --git a/Switch_FileFormatsMain/GUI/BFRES/BfresMaterialEditor.cs b/Switch_FileFormatsMain/GUI/BFRES/BfresMaterialEditor.cs index 2e0eed89..7afea5bd 100644 --- a/Switch_FileFormatsMain/GUI/BFRES/BfresMaterialEditor.cs +++ b/Switch_FileFormatsMain/GUI/BFRES/BfresMaterialEditor.cs @@ -312,7 +312,7 @@ namespace FirstPlugin Console.WriteLine("click"); int index = textureRefListView.SelectedIndices[0]; Texture_Selector tex = new Texture_Selector(); - tex.LoadTexture(); + tex.LoadTexture(material.GetResFileU() != null); if (tex.ShowDialog() == DialogResult.OK) { material.textures[index].Name = tex.GetSelectedTexture(); diff --git a/Switch_FileFormatsMain/GUI/BFRES/BfresShapeEditor.cs b/Switch_FileFormatsMain/GUI/BFRES/BfresShapeEditor.cs index 4fc3664e..443c24a4 100644 --- a/Switch_FileFormatsMain/GUI/BFRES/BfresShapeEditor.cs +++ b/Switch_FileFormatsMain/GUI/BFRES/BfresShapeEditor.cs @@ -59,7 +59,7 @@ namespace FirstPlugin bonesCB.SelectedIndex = 0; textBoxVertexSkinCount.Text = shape.VertexSkinCount.ToString(); - if (BFRES.Instance.IsWiiU) + if (shape.GetResFileU() != null) { } diff --git a/Switch_FileFormatsMain/GUI/Texture Selector.cs b/Switch_FileFormatsMain/GUI/Texture Selector.cs index 1c15b718..85860fce 100644 --- a/Switch_FileFormatsMain/GUI/Texture Selector.cs +++ b/Switch_FileFormatsMain/GUI/Texture Selector.cs @@ -18,9 +18,12 @@ namespace FirstPlugin InitializeComponent(); } - public void LoadTexture() + bool IsWIiiU = false; + public void LoadTexture(bool isWiiU) { - if (BFRES.Instance.IsWiiU) + IsWIiiU = isWiiU; + + if (IsWIiiU) { foreach (FTEXContainer ftexcont in PluginRuntime.ftexContainers) { @@ -54,7 +57,7 @@ namespace FirstPlugin if (listView1.SelectedItems.Count > 0) { string TexName = listView1.SelectedItems[0].Text; - if (BFRES.Instance.IsWiiU) + if (IsWIiiU) { foreach (FTEXContainer ftexcont in PluginRuntime.ftexContainers) { diff --git a/Switch_FileFormatsMain/GUI/TextureUI/0x1cda00708.XTEX b/Switch_FileFormatsMain/GUI/TextureUI/0x1cda00708.XTEX new file mode 100644 index 0000000000000000000000000000000000000000..04732a1c0149d60382764b6c6a1c3c3c1f332863 GIT binary patch literal 89264 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 literal 0 HcmV?d00001 diff --git a/Switch_FileFormatsMain/GUI/TextureUI/BNTXEditor.cs b/Switch_FileFormatsMain/GUI/TextureUI/BNTXEditor.cs index d8667485..c1197b15 100644 --- a/Switch_FileFormatsMain/GUI/TextureUI/BNTXEditor.cs +++ b/Switch_FileFormatsMain/GUI/TextureUI/BNTXEditor.cs @@ -49,8 +49,8 @@ namespace FirstPlugin } private void LoadImage() { - if (Thread != null && Thread.IsAlive) - Thread.Abort(); + // if (Thread != null && Thread.IsAlive) + // Thread.Abort(); Thread = new Thread((ThreadStart)(() => { diff --git a/Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.Designer.cs b/Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.Designer.cs new file mode 100644 index 00000000..6544ca98 --- /dev/null +++ b/Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.Designer.cs @@ -0,0 +1,341 @@ +namespace FirstPlugin +{ + partial class GTXEditor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BNTXEditor)); + this.panel1 = new System.Windows.Forms.Panel(); + this.propertyGrid1 = new System.Windows.Forms.PropertyGrid(); + this.splitter1 = new System.Windows.Forms.Splitter(); + this.panel2 = new System.Windows.Forms.Panel(); + this.panel4 = new System.Windows.Forms.Panel(); + this.pictureBoxCustom1 = new Switch_Toolbox.Library.Forms.PictureBoxCustom(); + this.panel3 = new System.Windows.Forms.Panel(); + this.imageBGComboBox = new System.Windows.Forms.ComboBox(); + this.label1 = new System.Windows.Forms.Label(); + this.texSizeMipsLabel = new System.Windows.Forms.Label(); + this.mipLevelCounterLabel = new System.Windows.Forms.Label(); + this.BtnMipsRight = new System.Windows.Forms.Button(); + this.BtmMipsLeft = new System.Windows.Forms.Button(); + this.button1 = new System.Windows.Forms.Button(); + this.label5 = new System.Windows.Forms.Label(); + this.arrayLevelCounterLabel = new System.Windows.Forms.Label(); + this.btnRightArray = new System.Windows.Forms.Button(); + this.btnLeftArray = new System.Windows.Forms.Button(); + this.btnEdit = new System.Windows.Forms.Button(); + this.panel1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.panel4.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxCustom1)).BeginInit(); + this.panel3.SuspendLayout(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.panel1.Controls.Add(this.propertyGrid1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Top; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(593, 296); + this.panel1.TabIndex = 1; + // + // propertyGrid1 + // + this.propertyGrid1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.propertyGrid1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40))))); + this.propertyGrid1.CategoryForeColor = System.Drawing.Color.WhiteSmoke; + this.propertyGrid1.CategorySplitterColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.propertyGrid1.CommandsActiveLinkColor = System.Drawing.Color.Red; + this.propertyGrid1.CommandsBorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(50)))), ((int)(((byte)(50))))); + this.propertyGrid1.CommandsDisabledLinkColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(50)))), ((int)(((byte)(50))))); + this.propertyGrid1.CommandsForeColor = System.Drawing.Color.White; + this.propertyGrid1.DisabledItemForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.propertyGrid1.HelpBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40))))); + this.propertyGrid1.HelpBorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(45))))); + this.propertyGrid1.HelpForeColor = System.Drawing.Color.White; + this.propertyGrid1.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.propertyGrid1.Location = new System.Drawing.Point(0, 0); + this.propertyGrid1.Name = "propertyGrid1"; + this.propertyGrid1.SelectedItemWithFocusForeColor = System.Drawing.Color.Silver; + this.propertyGrid1.Size = new System.Drawing.Size(593, 299); + this.propertyGrid1.TabIndex = 2; + this.propertyGrid1.ToolbarVisible = false; + this.propertyGrid1.ViewBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40))))); + this.propertyGrid1.ViewBorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.propertyGrid1.ViewForeColor = System.Drawing.Color.White; + this.propertyGrid1.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.propertyGrid1_PropertyValueChanged); + // + // splitter1 + // + this.splitter1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.splitter1.Dock = System.Windows.Forms.DockStyle.Top; + this.splitter1.Location = new System.Drawing.Point(0, 296); + this.splitter1.Name = "splitter1"; + this.splitter1.Size = new System.Drawing.Size(593, 3); + this.splitter1.TabIndex = 2; + this.splitter1.TabStop = false; + // + // panel2 + // + this.panel2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.panel2.Controls.Add(this.panel4); + this.panel2.Controls.Add(this.panel3); + this.panel2.Controls.Add(this.button1); + this.panel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel2.Location = new System.Drawing.Point(0, 299); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(593, 297); + this.panel2.TabIndex = 3; + // + // panel4 + // + this.panel4.Controls.Add(this.pictureBoxCustom1); + this.panel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel4.Location = new System.Drawing.Point(0, 80); + this.panel4.Name = "panel4"; + this.panel4.Size = new System.Drawing.Size(593, 217); + this.panel4.TabIndex = 4; + // + // pictureBoxCustom1 + // + this.pictureBoxCustom1.BackColor = System.Drawing.Color.Transparent; + this.pictureBoxCustom1.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pictureBoxCustom1.BackgroundImage"))); + this.pictureBoxCustom1.Dock = System.Windows.Forms.DockStyle.Fill; + this.pictureBoxCustom1.Location = new System.Drawing.Point(0, 0); + this.pictureBoxCustom1.Name = "pictureBoxCustom1"; + this.pictureBoxCustom1.Size = new System.Drawing.Size(593, 217); + this.pictureBoxCustom1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.pictureBoxCustom1.TabIndex = 0; + this.pictureBoxCustom1.TabStop = false; + // + // panel3 + // + this.panel3.Controls.Add(this.btnEdit); + this.panel3.Controls.Add(this.label5); + this.panel3.Controls.Add(this.arrayLevelCounterLabel); + this.panel3.Controls.Add(this.btnRightArray); + this.panel3.Controls.Add(this.btnLeftArray); + this.panel3.Controls.Add(this.imageBGComboBox); + this.panel3.Controls.Add(this.label1); + this.panel3.Controls.Add(this.texSizeMipsLabel); + this.panel3.Controls.Add(this.mipLevelCounterLabel); + this.panel3.Controls.Add(this.BtnMipsRight); + this.panel3.Controls.Add(this.BtmMipsLeft); + this.panel3.Dock = System.Windows.Forms.DockStyle.Top; + this.panel3.Location = new System.Drawing.Point(0, 25); + this.panel3.Name = "panel3"; + this.panel3.Size = new System.Drawing.Size(593, 55); + this.panel3.TabIndex = 2; + // + // imageBGComboBox + // + this.imageBGComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.imageBGComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.imageBGComboBox.FormattingEnabled = true; + this.imageBGComboBox.Location = new System.Drawing.Point(215, 7); + this.imageBGComboBox.Name = "imageBGComboBox"; + this.imageBGComboBox.Size = new System.Drawing.Size(121, 21); + this.imageBGComboBox.TabIndex = 5; + this.imageBGComboBox.SelectedIndexChanged += new System.EventHandler(this.imageBGComboBox_SelectedIndexChanged); + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.label1.AutoSize = true; + this.label1.ForeColor = System.Drawing.Color.White; + this.label1.Location = new System.Drawing.Point(342, 7); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(67, 13); + this.label1.TabIndex = 4; + this.label1.Text = "Mip Counter:"; + // + // texSizeMipsLabel + // + this.texSizeMipsLabel.AutoSize = true; + this.texSizeMipsLabel.ForeColor = System.Drawing.Color.White; + this.texSizeMipsLabel.Location = new System.Drawing.Point(127, 34); + this.texSizeMipsLabel.Name = "texSizeMipsLabel"; + this.texSizeMipsLabel.Size = new System.Drawing.Size(42, 13); + this.texSizeMipsLabel.TabIndex = 3; + this.texSizeMipsLabel.Text = "00 / 00"; + // + // mipLevelCounterLabel + // + this.mipLevelCounterLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.mipLevelCounterLabel.AutoSize = true; + this.mipLevelCounterLabel.ForeColor = System.Drawing.Color.White; + this.mipLevelCounterLabel.Location = new System.Drawing.Point(415, 7); + this.mipLevelCounterLabel.Name = "mipLevelCounterLabel"; + this.mipLevelCounterLabel.Size = new System.Drawing.Size(42, 13); + this.mipLevelCounterLabel.TabIndex = 2; + this.mipLevelCounterLabel.Text = "00 / 00"; + // + // BtnMipsRight + // + this.BtnMipsRight.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.BtnMipsRight.Location = new System.Drawing.Point(533, 3); + this.BtnMipsRight.Name = "BtnMipsRight"; + this.BtnMipsRight.Size = new System.Drawing.Size(57, 21); + this.BtnMipsRight.TabIndex = 1; + this.BtnMipsRight.Text = ">"; + this.BtnMipsRight.UseVisualStyleBackColor = true; + this.BtnMipsRight.Click += new System.EventHandler(this.BtnMipsRight_Click); + // + // BtmMipsLeft + // + this.BtmMipsLeft.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.BtmMipsLeft.Enabled = false; + this.BtmMipsLeft.Location = new System.Drawing.Point(470, 3); + this.BtmMipsLeft.Name = "BtmMipsLeft"; + this.BtmMipsLeft.Size = new System.Drawing.Size(57, 21); + this.BtmMipsLeft.TabIndex = 0; + this.BtmMipsLeft.Text = "<"; + this.BtmMipsLeft.UseVisualStyleBackColor = true; + this.BtmMipsLeft.Click += new System.EventHandler(this.BtmMipsLeft_Click); + // + // button1 + // + this.button1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.button1.Dock = System.Windows.Forms.DockStyle.Top; + this.button1.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(90)))), ((int)(((byte)(90)))), ((int)(((byte)(90))))); + this.button1.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Gray; + this.button1.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(90)))), ((int)(((byte)(90)))), ((int)(((byte)(90))))); + this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button1.ForeColor = System.Drawing.Color.White; + this.button1.Location = new System.Drawing.Point(0, 0); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(593, 25); + this.button1.TabIndex = 1; + this.button1.Text = "Hide"; + this.button1.UseVisualStyleBackColor = false; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // label5 + // + this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.label5.AutoSize = true; + this.label5.ForeColor = System.Drawing.Color.White; + this.label5.Location = new System.Drawing.Point(342, 30); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(74, 13); + this.label5.TabIndex = 9; + this.label5.Text = "Array Counter:"; + // + // arrayLevelCounterLabel + // + this.arrayLevelCounterLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.arrayLevelCounterLabel.AutoSize = true; + this.arrayLevelCounterLabel.ForeColor = System.Drawing.Color.White; + this.arrayLevelCounterLabel.Location = new System.Drawing.Point(415, 30); + this.arrayLevelCounterLabel.Name = "arrayLevelCounterLabel"; + this.arrayLevelCounterLabel.Size = new System.Drawing.Size(42, 13); + this.arrayLevelCounterLabel.TabIndex = 8; + this.arrayLevelCounterLabel.Text = "00 / 00"; + // + // btnRightArray + // + this.btnRightArray.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnRightArray.Location = new System.Drawing.Point(533, 26); + this.btnRightArray.Name = "btnRightArray"; + this.btnRightArray.Size = new System.Drawing.Size(57, 21); + this.btnRightArray.TabIndex = 7; + this.btnRightArray.Text = ">"; + this.btnRightArray.UseVisualStyleBackColor = true; + this.btnRightArray.Click += new System.EventHandler(this.btnRightArray_Click); + // + // btnLeftArray + // + this.btnLeftArray.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnLeftArray.Enabled = false; + this.btnLeftArray.Location = new System.Drawing.Point(470, 26); + this.btnLeftArray.Name = "btnLeftArray"; + this.btnLeftArray.Size = new System.Drawing.Size(57, 21); + this.btnLeftArray.TabIndex = 6; + this.btnLeftArray.Text = "<"; + this.btnLeftArray.UseVisualStyleBackColor = true; + this.btnLeftArray.Click += new System.EventHandler(this.btnLeftArray_Click); + // + // btnEdit + // + this.btnEdit.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btnEdit.ForeColor = System.Drawing.Color.White; + this.btnEdit.Location = new System.Drawing.Point(6, 5); + this.btnEdit.Name = "btnEdit"; + this.btnEdit.Size = new System.Drawing.Size(63, 23); + this.btnEdit.TabIndex = 12; + this.btnEdit.Text = "Edit"; + this.btnEdit.UseVisualStyleBackColor = true; + this.btnEdit.Click += new System.EventHandler(this.btnEdit_Click); + // BNTXEditor + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.panel2); + this.Controls.Add(this.splitter1); + this.Controls.Add(this.panel1); + this.Name = "BNTXEditor"; + this.Size = new System.Drawing.Size(593, 596); + this.panel1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel4.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxCustom1)).EndInit(); + this.panel3.ResumeLayout(false); + this.panel3.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Splitter splitter1; + private System.Windows.Forms.Panel panel2; + private Switch_Toolbox.Library.Forms.PictureBoxCustom pictureBoxCustom1; + private System.Windows.Forms.PropertyGrid propertyGrid1; + private System.Windows.Forms.Panel panel4; + private System.Windows.Forms.Panel panel3; + private System.Windows.Forms.Label mipLevelCounterLabel; + private System.Windows.Forms.Button BtnMipsRight; + private System.Windows.Forms.Button BtmMipsLeft; + private System.Windows.Forms.Label texSizeMipsLabel; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.ComboBox imageBGComboBox; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label arrayLevelCounterLabel; + private System.Windows.Forms.Button btnRightArray; + private System.Windows.Forms.Button btnLeftArray; + private System.Windows.Forms.Button btnEdit; + private System.Windows.Forms.ToolStripMenuItem replaceSurfaceLevelToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem exportSurfaceLevelToolStripMenuItem; + } +} diff --git a/Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.cs b/Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.cs new file mode 100644 index 00000000..051be6b7 --- /dev/null +++ b/Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using WeifenLuo.WinFormsUI.Docking; +using Syroot.NintenTools.NSW.Bntx; +using Syroot.NintenTools.NSW.Bntx.GFX; +using Switch_Toolbox.Library; + +namespace FirstPlugin +{ + public partial class GTXEditor : UserControl + { + private Thread Thread; + + public GTXEditor() + { + InitializeComponent(); + + foreach (var type in Enum.GetValues(typeof(Runtime.PictureBoxBG)).Cast()) + imageBGComboBox.Items.Add(type); + + imageBGComboBox.SelectedItem = Runtime.pictureBoxStyle; + UpdateBackgroundImage(); + } + public void LoadPicture(Bitmap image) + { + // pictureBoxCustom1.Image = image; + } + + GTXFile.TextureData textureData; + int CurMipDisplayLevel = 0; + int CurArrayDisplayLevel = 0; + public void LoadProperty(GTXFile.TextureData tex) + { + CurMipDisplayLevel = 0; + CurArrayDisplayLevel = 0; + + textureData = tex; + propertyGrid1.PropertySort = PropertySort.Categorized; + UpdateMipDisplay(); + } + private void UpdateMipDisplay() + { + mipLevelCounterLabel.Text = $"{CurMipDisplayLevel} / {textureData.renderedTex.mipmaps[CurArrayDisplayLevel].Count - 1}"; + arrayLevelCounterLabel.Text = $"{CurArrayDisplayLevel} / {textureData.renderedTex.mipmaps.Count - 1}"; + + + if (Thread != null && Thread.IsAlive) + Thread.Abort(); + + Thread = new Thread((ThreadStart)(() => + { + pictureBoxCustom1.Image = Imaging.GetLoadingImage(); + pictureBoxCustom1.Image = textureData.DisplayTexture(CurMipDisplayLevel, CurArrayDisplayLevel); + + // texSizeMipsLabel.Text = $"Width = {pictureBoxCustom1.Image.Width} Height = {pictureBoxCustom1.Image.Height}"; + })); + Thread.Start(); + + + if (CurMipDisplayLevel != textureData.renderedTex.mipmaps[CurArrayDisplayLevel].Count - 1) + BtnMipsRight.Enabled = true; + else + BtnMipsRight.Enabled = false; + + if (CurMipDisplayLevel != 0) + BtmMipsLeft.Enabled = true; + else + BtmMipsLeft.Enabled = false; + + if (CurArrayDisplayLevel != textureData.renderedTex.mipmaps.Count - 1) + btnRightArray.Enabled = true; + else + btnRightArray.Enabled = false; + + if (CurArrayDisplayLevel != 0) + btnLeftArray.Enabled = true; + else + btnLeftArray.Enabled = false; + } + + bool IsHidden = false; + private void button1_Click(object sender, EventArgs e) + { + if (IsHidden) + { + panel1.Visible = true; + IsHidden = false; + button1.Text = "Hide"; + } + else + { + panel1.Visible = false; + IsHidden = true; + button1.Text = "Show"; + } + } + + private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) + { + if (propertyGrid1.SelectedObject != null) + { + Texture tex = (Texture)propertyGrid1.SelectedObject; + textureData.Text = tex.Name; + } + } + + private void BtmMipsLeft_Click(object sender, EventArgs e) + { + if (CurMipDisplayLevel != 0) + CurMipDisplayLevel -= 1; + + UpdateMipDisplay(); + } + + private void BtnMipsRight_Click(object sender, EventArgs e) + { + if (CurMipDisplayLevel != textureData.renderedTex.mipmaps[CurArrayDisplayLevel].Count - 1) + CurMipDisplayLevel += 1; + + UpdateMipDisplay(); + } + + private void btnLeftArray_Click(object sender, EventArgs e) + { + if (CurArrayDisplayLevel != 0) + CurArrayDisplayLevel -= 1; + + UpdateMipDisplay(); + } + + private void btnRightArray_Click(object sender, EventArgs e) + { + if (CurArrayDisplayLevel != textureData.renderedTex.mipmaps.Count - 1) + CurArrayDisplayLevel += 1; + + UpdateMipDisplay(); + } + + + private void UpdateBackgroundImage() + { + switch (Runtime.pictureBoxStyle) + { + case Runtime.PictureBoxBG.Black: + pictureBoxCustom1.BackColor = Color.Black; + pictureBoxCustom1.BackgroundImage = null; + break; + case Runtime.PictureBoxBG.Checkerboard: + pictureBoxCustom1.BackColor = Color.Transparent; + pictureBoxCustom1.BackgroundImage = pictureBoxCustom1.GetCheckerBackground(); + break; + } + } + + private void imageBGComboBox_SelectedIndexChanged(object sender, EventArgs e) + { + Runtime.pictureBoxStyle = (Runtime.PictureBoxBG)imageBGComboBox.SelectedItem; + UpdateBackgroundImage(); + } + + private void btnEdit_Click(object sender, EventArgs e) + { + Button btnSender = (Button)sender; + Point ptLowerLeft = new Point(0, btnSender.Height); + ptLowerLeft = btnSender.PointToScreen(ptLowerLeft); + } + } +} diff --git a/Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.resx b/Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.resx new file mode 100644 index 00000000..3572d1d7 --- /dev/null +++ b/Switch_FileFormatsMain/GUI/TextureUI/GTXEditor.resx @@ -0,0 +1,331 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAACJuGjuAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6 + JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAADAFBMVEXMzMzNzc3Ozs7Pz8/Q0NDR0dHS + 0tLT09PU1NTV1dXW1tbX19fY2NjZ2dna2trb29vc3Nzd3d3e3t7f39/g4ODh4eHi4uLj4+Pk5OTl5eXm + 5ubn5+fo6Ojp6enq6urr6+vs7Ozt7e3u7u7v7+/w8PDx8fHy8vLz8/P09PT19fX29vb39/f4+Pj5+fn6 + +vr7+/v8/Pz9/f3+/v7///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDTbOhAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGXRF + 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 + + + + 17, 17 + + \ No newline at end of file diff --git a/Switch_FileFormatsMain/GUI/TextureUI/GTXImporterSettings.cs b/Switch_FileFormatsMain/GUI/TextureUI/GTXImporterSettings.cs index 9dbf947d..13f0b5a8 100644 --- a/Switch_FileFormatsMain/GUI/TextureUI/GTXImporterSettings.cs +++ b/Switch_FileFormatsMain/GUI/TextureUI/GTXImporterSettings.cs @@ -16,7 +16,6 @@ namespace FirstPlugin public uint TexWidth; public uint TexHeight; public uint MipCount; - public uint bpp; public uint Depth = 1; public uint arrayLength = 1; public List DataBlockOutput = new List(); @@ -194,8 +193,9 @@ namespace FirstPlugin uint pitch = surfOut.pitch; uint mipSize = 0; uint dataSize = (uint)imageData.Length; + uint bpp = GTX.surfaceGetBitsPerPixel((uint)Format) >> 3; - if (imageData.Length <= 0) + if (dataSize <= 0) throw new Exception($"Image is empty!!"); if (surfOut.depth != 1) @@ -228,30 +228,36 @@ namespace FirstPlugin List mipOffsets = new List(); List Swizzled = new List(); - byte[] data; for (int mipLevel = 0; mipLevel < MipCount; mipLevel++) { var result = TextureHelper.GetCurrentMipSize(TexWidth, TexHeight, blkWidth, blkHeight, bpp, mipLevel); + uint offset = result.Item1; uint size = result.Item2; - byte[] data_ = Utils.SubArray(imageData, offset, size); + Console.WriteLine("Swizzle Size " + size); + Console.WriteLine("Swizzle offset " + offset); + Console.WriteLine("bpp " + bpp); + Console.WriteLine("TexWidth " + TexWidth); + Console.WriteLine("TexHeight " + TexHeight); + Console.WriteLine("blkWidth " + blkWidth); + Console.WriteLine("blkHeight " + blkHeight); + Console.WriteLine("mipLevel " + mipLevel); + + byte[] data_ = new byte[size]; + Array.Copy(imageData, offset, data_,0, size); uint width_ = Math.Max(1, TexWidth >> mipLevel); uint height_ = Math.Max(1, TexHeight >> mipLevel); - if (mipLevel != 0) { surfOut = GTX.getSurfaceInfo(Format, TexWidth, TexHeight, 1, 1, tileMode, 0, mipLevel); if (mipLevel == 1) - { - if (mipLevel == 1) - mipOffsets.Add(imageSize); - else - mipOffsets.Add(mipSize); - } + mipOffsets.Add(imageSize); + else + mipOffsets.Add(mipSize); } data_ = Utils.CombineByteArray(data_, new byte[surfOut.surfSize - size]); @@ -260,10 +266,11 @@ namespace FirstPlugin if (mipLevel != 0) mipSize += (uint)(surfOut.surfSize + dataAlignBytes.Length); - Swizzled.Add(Utils.CombineByteArray(dataAlignBytes, GTX.swizzle(width_, height_, surfOut.height, (uint)Format, surfOut.tileMode, s, - surfOut.pitch, surfOut.bpp, data_))); + byte[] SwizzledData = GTX.swizzle(width_, height_, surfOut.height, (uint)Format, surfOut.tileMode, s, + surfOut.pitch, surfOut.bpp, data_); + + Swizzled.Add(dataAlignBytes.Concat(SwizzledData).ToArray()); } - File.WriteAllBytes("NewSwizzle.bin",Swizzled[0]); compSel[0] = GX2CompSel.ChannelR; compSel[1] = GX2CompSel.ChannelG; @@ -275,12 +282,13 @@ namespace FirstPlugin surf.width = TexWidth; surf.height = TexHeight; surf.depth = 1; + surf.use = 1; surf.dim = (uint)SurfaceDim; - surf.bpp = GTX.surfaceGetBitsPerPixel((uint)Format >> 3); surf.tileMode = tileMode; surf.swizzle = s; surf.resourceFlags = 0; - surf.pitch = surfOut.pitch; + surf.pitch = pitch; + surf.bpp = bpp; surf.format = (uint)Format; surf.numMips = MipCount; surf.aa = (uint)AAMode; @@ -295,10 +303,12 @@ namespace FirstPlugin for (int mipLevel = 1; mipLevel < Swizzled.Count; mipLevel++) { mips.Add(Swizzled[mipLevel]); + Console.WriteLine(Swizzled[mipLevel].Length); } surf.mipData = Utils.CombineByteArray(mips.ToArray()); mips.Clear(); + Console.WriteLine(""); Console.WriteLine("// ----- GX2Surface Info ----- "); Console.WriteLine(" dim = 1"); @@ -326,7 +336,6 @@ namespace FirstPlugin Console.WriteLine(" bytes per pixel = " + surf.bpp); Console.WriteLine(" realSize = " + imageData.Length); - return surf; } private static Tuple GetCurrentMipSize(uint width, uint height, uint bpp, int CurLevel, bool IsCompressed) diff --git a/Switch_FileFormatsMain/GUI/TextureUI/TextureImporterSettings.cs b/Switch_FileFormatsMain/GUI/TextureUI/TextureImporterSettings.cs index 1e16332a..3901e926 100644 --- a/Switch_FileFormatsMain/GUI/TextureUI/TextureImporterSettings.cs +++ b/Switch_FileFormatsMain/GUI/TextureUI/TextureImporterSettings.cs @@ -54,47 +54,50 @@ namespace FirstPlugin public bool IsSRGB = true; public bool GenerateMipmaps = false; //If bitmap and count more that 1 then geenrate - private SurfaceFormat LoadDDSFormat(string fourCC, DDS dds = null, bool IsSRGB = false) + private SurfaceFormat LoadDDSFormat(uint fourCC, DDS dds = null, bool IsSRGB = false) { bool IsDX10 = false; switch (fourCC) { - case "DXT1": + case DDS.FOURCC_DXT1: if (IsSRGB) return SurfaceFormat.BC1_SRGB; else return SurfaceFormat.BC1_UNORM; - case "DXT3": + case DDS.FOURCC_DXT3: if (IsSRGB) return SurfaceFormat.BC2_SRGB; else return SurfaceFormat.BC2_UNORM; - case "DXT5": + case DDS.FOURCC_DXT5: if (IsSRGB) return SurfaceFormat.BC3_SRGB; else return SurfaceFormat.BC3_UNORM; - case "BC4U": + case DDS.FOURCC_BC4U: return SurfaceFormat.BC4_UNORM; - case "BC4S": + case DDS.FOURCC_BC4S: return SurfaceFormat.BC4_SNORM; - case "ATI1": + case DDS.FOURCC_ATI1: return SurfaceFormat.BC4_UNORM; - case "ATI2": + case DDS.FOURCC_ATI2: return SurfaceFormat.BC5_UNORM; - case "BC5U": + case DDS.FOURCC_BC5U: return SurfaceFormat.BC5_UNORM; - case "BC5S": + case DDS.FOURCC_BC5S: return SurfaceFormat.BC5_SNORM; - case "DX10": + case DDS.FOURCC_DX10: IsDX10 = true; break; default: return SurfaceFormat.R8_G8_B8_A8_SRGB; } + Console.WriteLine(IsDX10); if (IsDX10) { + Console.WriteLine(dds.DX10header.DXGI_Format); + switch (dds.DX10header.DXGI_Format) { case DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM: @@ -145,7 +148,7 @@ namespace FirstPlugin DataBlockOutput.Add(dds.bdata); - Format = LoadDDSFormat(dds.header.ddspf.fourCC.ToString(), dds, IsSRGB); + Format = LoadDDSFormat(dds.header.ddspf.fourCC, dds, IsSRGB); Texture tex = FromBitMap(DataBlockOutput[0], this); diff --git a/Switch_FileFormatsMain/Switch_FileFormatsMain.csproj b/Switch_FileFormatsMain/Switch_FileFormatsMain.csproj index 178d8739..1a29677a 100644 --- a/Switch_FileFormatsMain/Switch_FileFormatsMain.csproj +++ b/Switch_FileFormatsMain/Switch_FileFormatsMain.csproj @@ -42,12 +42,15 @@ ..\Switch_Toolbox\Lib\BarsLibrary.dll + False ..\Switch_Toolbox\Lib\BezelEngineArchive_Lib.dll + False ..\Switch_Toolbox\Lib\ByamlExt.dll + False ..\Switch_Toolbox\Lib\Costura.dll @@ -55,10 +58,12 @@ ..\Switch_Toolbox\Lib\EditorCoreCommon.dll + False False ..\Switch_Toolbox\Lib\KCLExt.dll + False @@ -80,6 +85,7 @@ ..\Switch_Toolbox\Lib\SARCExt.dll + False ..\Switch_Toolbox\Lib\SFGraphics.dll @@ -91,18 +97,23 @@ ..\Switch_Toolbox\Lib\Syroot.BinaryData.dll + False ..\Switch_Toolbox\Lib\Syroot.Maths.dll + False ..\Switch_Toolbox\Lib\Syroot.NintenTools.Bfres.dll + False ..\Switch_Toolbox\Lib\Syroot.NintenTools.NSW.Bfres.dll + False ..\Switch_Toolbox\Lib\Syroot.NintenTools.NSW.Bntx.dll + False @@ -132,9 +143,6 @@ ..\packages\DockPanelSuite.3.0.4\lib\net40\WeifenLuo.WinFormsUI.Docking.dll False - - ..\Switch_Toolbox\Lib\ZstdNet.dll - @@ -171,6 +179,7 @@ + @@ -267,6 +276,12 @@ BfresShapeEditor.cs + + UserControl + + + GTXEditor.cs + Form @@ -431,6 +446,9 @@ BfresShapeEditor.cs + + GTXEditor.cs + GTXTextureImporter.cs @@ -500,6 +518,7 @@ {96820047-2a39-4e5a-bfa4-e84fff5c66cf} Switch_Toolbox_Library + False @@ -531,6 +550,7 @@ 0 aximp False + False {6BF52A50-394A-11D3-B153-00C04F79FAA6} @@ -539,7 +559,7 @@ 0 tlbimp False - True + False diff --git a/Switch_Toolbox/Lib/DirectXTex/wrapper.cpp b/Switch_Toolbox/Lib/DirectXTex/wrapper.cpp index f147edf8..4453602d 100644 --- a/Switch_Toolbox/Lib/DirectXTex/wrapper.cpp +++ b/Switch_Toolbox/Lib/DirectXTex/wrapper.cpp @@ -24,6 +24,7 @@ #include #include "DirectXTex.h" +#define _WIN32_WINNT 0x0600 using namespace System; using namespace System::IO; diff --git a/Switch_Toolbox/Lib/Syroot.NintenTools.NSW.Bntx.dll b/Switch_Toolbox/Lib/Syroot.NintenTools.NSW.Bntx.dll index 546c2aa6dec165072ceba6999b7e4180ae2e96fd..711fd6637e6bf9cb9ae846e1525312a7a307d9e4 100644 GIT binary patch literal 76288 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 UW%1u~8{A(^DE`&gUr-ACf14W(W&i*H literal 76800 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 diff --git a/Switch_Toolbox/Lib/Syroot.NintenTools.NSW.Bntx.pdb b/Switch_Toolbox/Lib/Syroot.NintenTools.NSW.Bntx.pdb index 5d1f7a47605a3dbafa660cc7a9d0e49c1cf37944..af37cf450a387a0e32e14f5449551c25ce748085 100644 GIT binary patch delta 9908 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 GL;V*=K5KRW delta 9983 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 AtpET3 diff --git a/Switch_Toolbox/MainForm.cs b/Switch_Toolbox/MainForm.cs index 924d4ff6..b9158068 100644 --- a/Switch_Toolbox/MainForm.cs +++ b/Switch_Toolbox/MainForm.cs @@ -11,10 +11,10 @@ using Switch_Toolbox.Library.Forms; using WeifenLuo.WinFormsUI.Docking; using Switch_Toolbox.Library; using Smash_Forge.Rendering; -using Switch_Toolbox_Library; using Switch_Toolbox.Library.IO; using System.Net; + namespace Switch_Toolbox { public partial class MainForm : Form @@ -35,7 +35,6 @@ namespace Switch_Toolbox public MainForm() { InitializeComponent(); - new DiscordPresence().Initialize(); ShaderTools.executableDir = executableDir; @@ -237,10 +236,15 @@ namespace Switch_Toolbox SaveRecentFile(FileName); FileReader f = new FileReader(data); + + uint Identifier = f.ReadUInt32(); + f.Seek(0, SeekOrigin.Begin); + string Magic = f.ReadMagic(0, 4); string Magic2 = f.ReadMagic(0, 2); string Magic3 = f.ReadMagic((int)f.BaseStream.Length - 7, 3); + //Determine if the file is compressed or not if (Magic == "Yaz0") { @@ -248,6 +252,12 @@ namespace Switch_Toolbox OpenFile(FileName, data, true, CompressionType.Yaz0); return; } + if (Identifier == 0x28B52FFD || Identifier == 0xFD2FB528) + { + data = STLibraryCompression.ZSTD.Decompress(f.getSection(0, data.Length)); + OpenFile(FileName, data, true, CompressionType.Zstb); + return; + } if (Magic == "ZLIB") { data = FileReader.InflateZLIB(f.getSection(64, data.Length - 64)); diff --git a/Switch_Toolbox/Switch_Toolbox.csproj b/Switch_Toolbox/Switch_Toolbox.csproj index 7824f874..7d5fd328 100644 --- a/Switch_Toolbox/Switch_Toolbox.csproj +++ b/Switch_Toolbox/Switch_Toolbox.csproj @@ -53,9 +53,6 @@ ..\packages\CsvHelper.8.0.0-beta01\lib\net45\CsvHelper.dll False - - Lib\DiscordRPC.dll - ..\..\..\..\Documents\Visual Studio 2017\Projects\WindowsFormsApp2\WindowsFormsApp2\Lib\EditorCoreCommon.dll False @@ -405,4 +402,4 @@ - + \ No newline at end of file diff --git a/Switch_Toolbox_Library/FileFormats/Assimp/Assimp.cs b/Switch_Toolbox_Library/FileFormats/Assimp/Assimp.cs index 3731251b..03669882 100644 --- a/Switch_Toolbox_Library/FileFormats/Assimp/Assimp.cs +++ b/Switch_Toolbox_Library/FileFormats/Assimp/Assimp.cs @@ -77,7 +77,7 @@ PostProcessSteps.CalculateTangentSpace | PostProcessSteps.GenerateNormals); objects.Add(CreateGenericObject(scene.Meshes[index], index, worldTK)); foreach (Node child in parent.Children) - BuildNode(child, ref rootTransform); + BuildNode(child, ref world); } public void LoadMeshes() { diff --git a/Switch_Toolbox_Library/FileFormats/Assimp/AssimpHelper.cs b/Switch_Toolbox_Library/FileFormats/Assimp/AssimpHelper.cs index a9d93e14..9a2e3b32 100644 --- a/Switch_Toolbox_Library/FileFormats/Assimp/AssimpHelper.cs +++ b/Switch_Toolbox_Library/FileFormats/Assimp/AssimpHelper.cs @@ -16,6 +16,26 @@ namespace Switch_Toolbox.Library input.A2, input.B2, input.C2, input.D2, input.A3, input.B3, input.C3, input.D3, input.A4, input.B4, input.C4, input.D4); + + /* return new OpenTK.Matrix4() + { + M11 = input.A1, + M12 = input.A2, + M13 = input.A3, + M14 = input.A4, + M21 = input.B1, + M22 = input.B2, + M23 = input.B3, + M24 = input.B4, + M31 = input.C1, + M32 = input.C2, + M33 = input.C3, + M34 = input.C4, + M41 = input.D1, + M42 = input.D2, + M43 = input.D3, + M44 = input.D4 + };*/ } public static OpenTK.Quaternion TKQuaternion(Assimp.Quaternion rot) { @@ -27,6 +47,32 @@ namespace Switch_Toolbox.Library return quat; } + public static Matrix4x4 AssimpFromTKMatrix(Matrix4 tkMatrix) + { + Matrix4x4 m = new Matrix4x4(); + m.A1 = tkMatrix.M11; + m.A2 = tkMatrix.M12; + m.A3 = tkMatrix.M13; + m.A4 = tkMatrix.M14; + + m.B1 = tkMatrix.M21; + m.B2 = tkMatrix.M22; + m.B3 = tkMatrix.M23; + m.B4 = tkMatrix.M24; + + m.C1 = tkMatrix.M31; + m.C2 = tkMatrix.M32; + m.C3 = tkMatrix.M33; + m.C4 = tkMatrix.M34; + + m.D1 = tkMatrix.M41; + m.D2 = tkMatrix.M42; + m.D3 = tkMatrix.M43; + m.D4 = tkMatrix.M44; + + return m; + } + public static Vector3 ToEulerAngles(Assimp.Quaternion q) { float PI = (float)Math.PI; diff --git a/Switch_Toolbox_Library/FileFormats/DDS.cs b/Switch_Toolbox_Library/FileFormats/DDS.cs index 1fbe308c..30372d2b 100644 --- a/Switch_Toolbox_Library/FileFormats/DDS.cs +++ b/Switch_Toolbox_Library/FileFormats/DDS.cs @@ -25,7 +25,9 @@ namespace Switch_Toolbox.Library public const uint FOURCC_DXT5 = 0x35545844; public const uint FOURCC_ATI1 = 0x31495441; public const uint FOURCC_BC4U = 0x55344342; + public const uint FOURCC_BC4S = 0x53344342; public const uint FOURCC_BC5U = 0x55354342; + public const uint FOURCC_BC5S = 0x53354342; public const uint FOURCC_DX10 = 0x30315844; public const uint FOURCC_ATI2 = 0x32495441; @@ -369,7 +371,7 @@ namespace Switch_Toolbox.Library imageSize = header.width * header.height * getFormatSize(header.ddspf.fourCC); reader.TemporarySeek((int)(4 + header.size + DX10HeaderSize), SeekOrigin.Begin); - bdata = reader.ReadBytes((int)imageSize); + bdata = reader.ReadBytes((int)(reader.BaseStream.Length - reader.Position)); reader.Dispose(); reader.Close(); diff --git a/Switch_Toolbox_Library/GUI Custom/BitmapCustom.cs b/Switch_Toolbox_Library/GUI Custom/BitmapCustom.cs index 3c8a3926..6d413390 100644 --- a/Switch_Toolbox_Library/GUI Custom/BitmapCustom.cs +++ b/Switch_Toolbox_Library/GUI Custom/BitmapCustom.cs @@ -50,6 +50,15 @@ namespace Switch_Toolbox.Library return Img; } + private static void ConvertBgraToRgba(byte[] bytes) + { + for (int i = 0; i < bytes.Length; i += 4) + { + var temp = bytes[i]; + bytes[i] = bytes[i + 2]; + bytes[i + 2] = temp; + } + } public class ColorSwapFilter { private ColorSwapType swapType = ColorSwapType.FixDDS; diff --git a/Switch_Toolbox_Library/Helpers/TextureHelper.cs b/Switch_Toolbox_Library/Helpers/TextureHelper.cs index f2cda4ce..6abdbe4e 100644 --- a/Switch_Toolbox_Library/Helpers/TextureHelper.cs +++ b/Switch_Toolbox_Library/Helpers/TextureHelper.cs @@ -8,7 +8,7 @@ namespace Switch_Toolbox.Library { public class TextureHelper { - public static Tuple GetCurrentMipSize(uint width, uint height, uint blkHeight, uint blkWidth, uint bpp, int CurLevel) + public static Tuple GetCurrentMipSize(uint width, uint height, uint blkWidth, uint blkHeight, uint bpp, int CurLevel) { uint offset = 0; uint width_ = 0; diff --git a/Switch_Toolbox_Library/IO/FileIO.cs b/Switch_Toolbox_Library/IO/FileIO.cs index 9975052f..f3b5b1fe 100644 --- a/Switch_Toolbox_Library/IO/FileIO.cs +++ b/Switch_Toolbox_Library/IO/FileIO.cs @@ -8,9 +8,165 @@ using System.IO; using System.IO.Compression; using OpenTK; using K4os.Compression.LZ4.Streams; +using System.Windows.Forms; namespace Switch_Toolbox.Library.IO { + public class STFileSaver + { + ///

+ /// Saves the as a file from the given + /// + /// The format instance of the file being saved + /// The name of the file + /// The Alignment used for compression. Used for Yaz0 compression type. + /// Toggle for showing compression dialog + /// + public static void SaveFileFormat(IFileFormat FileFormat, string FileName, int Alignment = 0, bool EnableDialog = true) + { + Cursor.Current = Cursors.WaitCursor; + + byte[] data = FileFormat.Save(); + if (EnableDialog && FileFormat.FileIsCompressed) + { + DialogResult save = MessageBox.Show($"Compress file with {FileFormat.CompressionType}?", "File Save", MessageBoxButtons.YesNo); + + if (save == DialogResult.Yes) + { + switch (FileFormat.CompressionType) + { + case CompressionType.Yaz0: + data = EveryFileExplorer.YAZ0.Compress(data, Runtime.Yaz0CompressionLevel, (uint)Alignment); + break; + case CompressionType.Zstb: + data = STLibraryCompression.ZSTD.Compress(data); + break; + case CompressionType.Lz4: + data = STLibraryCompression.Type_LZ4.Compress(data); + break; + case CompressionType.Lz4f: + data = STLibraryCompression.Type_LZ4.Compress(data); + break; + case CompressionType.Gzip: + data = STLibraryCompression.GZIP.Compress(data); + break; + default: + MessageBox.Show($"Compression Type {FileFormat.CompressionType} not supported!!"); + break; + } + } + } + File.WriteAllBytes(FileName, data); + MessageBox.Show($"File has been saved to {FileName}"); + Cursor.Current = Cursors.Default; + } + } + public class STFileLoader + { + /// + /// Gets the from a file or byte array. + /// + /// The name of the file + /// The byte array of the data + /// If the file is in an archive so it can be saved back + /// The node being replaced from an archive + /// The unique hash from an archive for saving + /// If the file is being compressed or not + /// The type of being used + /// + public static TreeNodeFile GetNodeFileFormat(string FileName, byte[] data, bool InArchive = false, + string ArchiveHash = "", TreeNode archiveNode = null, bool Compressed = false, CompressionType CompType = 0) + { + IFileFormat format = OpenFileFormat(FileName, data, InArchive, ArchiveHash, archiveNode); + + if (format is TreeNode) + return (TreeNodeFile)format; + else + return null; + } + /// + /// Gets the from a file or byte array. + /// + /// The name of the file + /// The byte array of the data + /// If the file is in an archive so it can be saved back + /// The node being replaced from an archive + /// If the file is being compressed or not + /// The type of being used + /// + public static IFileFormat OpenFileFormat(string FileName, byte[] data, bool InArchive = false, + string ArchiveHash = "", TreeNode archiveNode = null, bool Compressed = false, CompressionType CompType = 0) + { + Cursor.Current = Cursors.WaitCursor; + FileReader fileReader = new FileReader(data); + string Magic4 = fileReader.ReadMagic(0, 4); + string Magic2 = fileReader.ReadMagic(0, 2); + if (Magic4 == "Yaz0") + { + data = EveryFileExplorer.YAZ0.Decompress(data); + return OpenFileFormat(FileName, data, InArchive, ArchiveHash, archiveNode, true, CompressionType.Yaz0); + } + if (Magic4 == "ZLIB") + { + data = FileReader.InflateZLIB(fileReader.getSection(64, data.Length - 64)); + return OpenFileFormat(FileName, data, InArchive, ArchiveHash, archiveNode, true, CompressionType.Zlib); + } + fileReader.Dispose(); + fileReader.Close(); + foreach (IFileFormat fileFormat in FileManager.GetFileFormats()) + { + if (fileFormat.Magic == Magic4 || fileFormat.Magic == Magic2) + { + fileFormat.CompressionType = CompType; + fileFormat.FileIsCompressed = Compressed; + fileFormat.Data = data; + fileFormat.Load(); + fileFormat.FileName = Path.GetFileName(FileName); + fileFormat.FilePath = FileName; + fileFormat.IFileInfo = new IFileInfo(); + fileFormat.IFileInfo.InArchive = InArchive; + fileFormat.IFileInfo.ArchiveHash = ArchiveHash; + fileFormat.FileIsCompressed = Compressed; + if (Compressed) + fileFormat.CompressionType = CompType; + + if (fileFormat is TreeNode) + { + ((TreeNode)fileFormat).Text = archiveNode.Text; + ((TreeNode)fileFormat).ImageKey = archiveNode.ImageKey; + ((TreeNode)fileFormat).SelectedImageKey = archiveNode.SelectedImageKey; + return fileFormat; + } + } + if (fileFormat.Magic == string.Empty) + { + foreach (string str3 in fileFormat.Extension) + { + if (str3.Remove(0, 1) == Path.GetExtension(FileName)) + { + fileFormat.Data = data; + fileFormat.Load(); + fileFormat.FileName = Path.GetFileName(FileName); + fileFormat.FilePath = FileName; + fileFormat.IFileInfo = new IFileInfo(); + fileFormat.IFileInfo.InArchive = true; + fileFormat.IFileInfo.ArchiveHash = ArchiveHash; + + if (fileFormat is TreeNode) + { + ((TreeNode)fileFormat).Text = archiveNode.Text; + ((TreeNode)fileFormat).ImageKey = archiveNode.ImageKey; + ((TreeNode)fileFormat).SelectedImageKey = archiveNode.SelectedImageKey; + return fileFormat; + } + } + } + } + } + return null; + } + } + public class STLibraryCompression { public static byte[] CompressFile(byte[] data, IFileFormat format) @@ -31,6 +187,32 @@ namespace Switch_Toolbox.Library.IO } } + public class ZSTD + { + public static byte[] Decompress(byte[] b) + { + using (var decompressor = new ZstdNet.Decompressor()) + { + return decompressor.Unwrap(b); + } + } + public static byte[] Decompress(byte[] b, int MaxDecompressedSize) + { + using (var decompressor = new ZstdNet.Decompressor()) + { + return decompressor.Unwrap(b, MaxDecompressedSize); + } + } + public static byte[] Compress(byte[] b) + { + using (var compressor = new ZstdNet.Compressor()) + { + return compressor.Wrap(b); + } + } + + } + public class GZIP { public static byte[] Decompress(byte[] b) diff --git a/Switch_Toolbox_Library/Switch_Toolbox_Library.csproj b/Switch_Toolbox_Library/Switch_Toolbox_Library.csproj index 8cad482f..da47a5ba 100644 --- a/Switch_Toolbox_Library/Switch_Toolbox_Library.csproj +++ b/Switch_Toolbox_Library/Switch_Toolbox_Library.csproj @@ -102,6 +102,10 @@ ..\packages\DockPanelSuite.ThemeVS2015.3.0.4\lib\net40\WeifenLuo.WinFormsUI.Docking.ThemeVS2015.dll + + False + ..\Switch_Toolbox\Lib\ZstdNet.dll +