1
0
mirror of synced 2024-09-24 11:38:22 +02:00

Cleanup with new open/save methods. Also add gtx rebuilding.

This commit is contained in:
KillzXGaming 2018-12-04 21:40:03 -05:00
parent 364c9ceeed
commit d96f4dec43
41 changed files with 2161 additions and 892 deletions

View File

@ -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<IFileFormat> formats = new List<IFileFormat>();
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()
{

View File

@ -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<IFileFormat> formats = new List<IFileFormat>();
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<string, ASST> 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
{

View File

@ -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);
}

View File

@ -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;

View File

@ -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<ushort>();
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<ushort>();
List<string> keyList = shapes.Select(o => o.Text).ToList();

View File

@ -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<ushort> 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;

View File

@ -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)

View File

@ -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();

View File

@ -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)
{

View File

@ -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)

View File

@ -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();

View File

@ -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}");

View File

@ -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<UserData>();
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)
{

View File

@ -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<Type> types = new List<Type>();
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<BlockType>(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<byte[]> 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<uint, uint, uint>(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;

View File

@ -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<Type> types = new List<Type>();
return types.ToArray();
}
}
private GTXHeader header;
public List<byte[]> data = new List<byte[]>();
public List<byte[]> mipMaps = new List<byte[]>();
public List<TextureData> textures = new List<TextureData>();
public List<GTXDataBlock> blocks = new List<GTXDataBlock>();
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<byte[]> 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<BlockType>(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<List<byte[]>> mipmaps = new List<List<byte[]>>();
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);
}
}
}
}

View File

@ -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<uint[]> mipSizes = new List<uint[]>();
public int Alignment;
public List<List<byte[]>> mipmaps = new List<List<byte[]>>();
public List<List<byte[]>> blocksCompressed = new List<List<byte[]>>();
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<byte[]> mipmaps = new List<byte[]>();
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<byte[]>() { 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<byte[]> mips = new List<byte[]>();
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);
}

View File

@ -214,7 +214,8 @@ namespace FirstPlugin
public uint[] MipOffsets { get; set; }
public BlockHeader DataBlockHeader { get; set; }
public List<byte[]> mipmaps = new List<byte[]>();
public List<byte[]> compressedBlocks = new List<byte[]>();
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);

View File

@ -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)
{

View File

@ -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();

View File

@ -59,7 +59,7 @@ namespace FirstPlugin
bonesCB.SelectedIndex = 0;
textBoxVertexSkinCount.Text = shape.VertexSkinCount.ToString();
if (BFRES.Instance.IsWiiU)
if (shape.GetResFileU() != null)
{
}

View File

@ -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)
{

Binary file not shown.

View File

@ -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)(() =>
{

View File

@ -0,0 +1,341 @@
namespace FirstPlugin
{
partial class GTXEditor
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

View File

@ -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<Runtime.PictureBoxBG>())
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);
}
}
}

View File

@ -0,0 +1,331 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="pictureBoxCustom1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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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
</value>
</data>
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View File

@ -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<byte[]> DataBlockOutput = new List<byte[]>();
@ -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<uint> mipOffsets = new List<uint>();
List<byte[]> Swizzled = new List<byte[]>();
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<uint, uint> GetCurrentMipSize(uint width, uint height, uint bpp, int CurLevel, bool IsCompressed)

View File

@ -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);

View File

@ -42,12 +42,15 @@
<ItemGroup>
<Reference Include="BarsLibrary">
<HintPath>..\Switch_Toolbox\Lib\BarsLibrary.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="BezelEngineArchive_Lib">
<HintPath>..\Switch_Toolbox\Lib\BezelEngineArchive_Lib.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="ByamlExt">
<HintPath>..\Switch_Toolbox\Lib\ByamlExt.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Costura, Version=3.1.4.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
<HintPath>..\Switch_Toolbox\Lib\Costura.dll</HintPath>
@ -55,10 +58,12 @@
</Reference>
<Reference Include="EditorCoreCommon">
<HintPath>..\Switch_Toolbox\Lib\EditorCoreCommon.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="KCLExt, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Switch_Toolbox\Lib\KCLExt.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="NAudio">
@ -80,6 +85,7 @@
</Reference>
<Reference Include="SARCExt">
<HintPath>..\Switch_Toolbox\Lib\SARCExt.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SFGraphics">
<HintPath>..\Switch_Toolbox\Lib\SFGraphics.dll</HintPath>
@ -91,18 +97,23 @@
</Reference>
<Reference Include="Syroot.BinaryData">
<HintPath>..\Switch_Toolbox\Lib\Syroot.BinaryData.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Syroot.Maths">
<HintPath>..\Switch_Toolbox\Lib\Syroot.Maths.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Syroot.NintenTools.Bfres">
<HintPath>..\Switch_Toolbox\Lib\Syroot.NintenTools.Bfres.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Syroot.NintenTools.NSW.Bfres">
<HintPath>..\Switch_Toolbox\Lib\Syroot.NintenTools.NSW.Bfres.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Syroot.NintenTools.NSW.Bntx">
<HintPath>..\Switch_Toolbox\Lib\Syroot.NintenTools.NSW.Bntx.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -132,9 +143,6 @@
<HintPath>..\packages\DockPanelSuite.3.0.4\lib\net40\WeifenLuo.WinFormsUI.Docking.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="ZstdNet">
<HintPath>..\Switch_Toolbox\Lib\ZstdNet.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Config.cs" />
@ -171,6 +179,7 @@
<Compile Include="FileFormats\Texture\BNTX.cs" />
<Compile Include="FileFormats\Texture\FTEX.cs" />
<Compile Include="FileFormats\Texture\GTX.cs" />
<Compile Include="FileFormats\Texture\GTXFile.cs" />
<Compile Include="FileFormats\Texture\TegraX1Swizzle.cs" />
<Compile Include="FileFormats\Texture\NUTEXB.cs" />
<Compile Include="FileFormats\Texture\TexConv.cs" />
@ -267,6 +276,12 @@
<DependentUpon>BfresShapeEditor.cs</DependentUpon>
</Compile>
<Compile Include="GUI\FormLoader.cs" />
<Compile Include="GUI\TextureUI\GTXEditor.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="GUI\TextureUI\GTXEditor.Designer.cs">
<DependentUpon>GTXEditor.cs</DependentUpon>
</Compile>
<Compile Include="GUI\TextureUI\GTXImporterSettings.cs" />
<Compile Include="GUI\TextureUI\GTXTextureImporter.cs">
<SubType>Form</SubType>
@ -431,6 +446,9 @@
<EmbeddedResource Include="GUI\BFRES\BfresShapeEditor.resx">
<DependentUpon>BfresShapeEditor.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="GUI\TextureUI\GTXEditor.resx">
<DependentUpon>GTXEditor.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="GUI\TextureUI\GTXTextureImporter.resx">
<DependentUpon>GTXTextureImporter.cs</DependentUpon>
</EmbeddedResource>
@ -500,6 +518,7 @@
<ProjectReference Include="..\Switch_Toolbox_Library\Switch_Toolbox_Library.csproj">
<Project>{96820047-2a39-4e5a-bfa4-e84fff5c66cf}</Project>
<Name>Switch_Toolbox_Library</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
@ -531,6 +550,7 @@
<Lcid>0</Lcid>
<WrapperTool>aximp</WrapperTool>
<Isolated>False</Isolated>
<Private>False</Private>
</COMReference>
<COMReference Include="WMPLib">
<Guid>{6BF52A50-394A-11D3-B153-00C04F79FAA6}</Guid>
@ -539,7 +559,7 @@
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>

View File

@ -24,6 +24,7 @@
#include <vcclr.h>
#include "DirectXTex.h"
#define _WIN32_WINNT 0x0600
using namespace System;
using namespace System::IO;

View File

@ -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));

View File

@ -53,9 +53,6 @@
<HintPath>..\packages\CsvHelper.8.0.0-beta01\lib\net45\CsvHelper.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="DiscordRPC">
<HintPath>Lib\DiscordRPC.dll</HintPath>
</Reference>
<Reference Include="EditorCoreCommon">
<HintPath>..\..\..\..\Documents\Visual Studio 2017\Projects\WindowsFormsApp2\WindowsFormsApp2\Lib\EditorCoreCommon.dll</HintPath>
<Private>False</Private>
@ -405,4 +402,4 @@
</Target>
<Import Project="..\packages\Costura.Fody.3.1.4\build\Costura.Fody.targets" Condition="Exists('..\packages\Costura.Fody.3.1.4\build\Costura.Fody.targets')" />
<Import Project="..\packages\AssimpNet.4.1.0\build\AssimpNet.targets" Condition="Exists('..\packages\AssimpNet.4.1.0\build\AssimpNet.targets')" />
</Project>
</Project>

View File

@ -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()
{

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -8,7 +8,7 @@ namespace Switch_Toolbox.Library
{
public class TextureHelper
{
public static Tuple<uint, uint> GetCurrentMipSize(uint width, uint height, uint blkHeight, uint blkWidth, uint bpp, int CurLevel)
public static Tuple<uint, uint> GetCurrentMipSize(uint width, uint height, uint blkWidth, uint blkHeight, uint bpp, int CurLevel)
{
uint offset = 0;
uint width_ = 0;

View File

@ -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
{
/// <summary>
/// Saves the <see cref="IFileFormat"/> as a file from the given <param name="FileName">
/// </summary>
/// <param name="IFileFormat">The format instance of the file being saved</param>
/// <param name="FileName">The name of the file</param>
/// <param name="Alignment">The Alignment used for compression. Used for Yaz0 compression type. </param>
/// <param name="EnableDialog">Toggle for showing compression dialog</param>
/// <returns></returns>
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
{
/// <summary>
/// Gets the <see cref="TreeNodeFile"/> from a file or byte array.
/// </summary>
/// <param name="FileName">The name of the file</param>
/// <param name="data">The byte array of the data</param>
/// <param name="InArchive">If the file is in an archive so it can be saved back</param>
/// <param name="archiveNode">The node being replaced from an archive</param>
/// <param name="ArchiveHash">The unique hash from an archive for saving</param>
/// <param name="Compressed">If the file is being compressed or not</param>
/// <param name="CompType">The type of <see cref="CompressionType"/> being used</param>
/// <returns></returns>
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;
}
/// <summary>
/// Gets the <see cref="IFileFormat"/> from a file or byte array.
/// </summary>
/// <param name="FileName">The name of the file</param>
/// <param name="data">The byte array of the data</param>
/// <param name="InArchive">If the file is in an archive so it can be saved back</param>
/// <param name="archiveNode">The node being replaced from an archive</param>
/// <param name="Compressed">If the file is being compressed or not</param>
/// <param name="CompType">The type of <see cref="CompressionType"/> being used</param>
/// <returns></returns>
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)

View File

@ -102,6 +102,10 @@
<Reference Include="WeifenLuo.WinFormsUI.Docking.ThemeVS2015, Version=3.0.4.0, Culture=neutral, PublicKeyToken=5cded1a1a0a7b481, processorArchitecture=MSIL">
<HintPath>..\packages\DockPanelSuite.ThemeVS2015.3.0.4\lib\net40\WeifenLuo.WinFormsUI.Docking.ThemeVS2015.dll</HintPath>
</Reference>
<Reference Include="ZstdNet, Version=1.3.3.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Switch_Toolbox\Lib\ZstdNet.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Animations\Animation.cs" />