From f51dd17f94d00c7cf08f73ef88f0c2a64054de71 Mon Sep 17 00:00:00 2001 From: KillzXGaming Date: Tue, 27 Nov 2018 21:21:31 -0500 Subject: [PATCH] Many improvements and new formats. Add in nutexb file format. While not finished, it can preview and export them. Batch exporting for nuteb (tools menu). Rework GTX code. This is WIP and not finished. Add XTX code. Unifnished atm. Add saving for wii u and include fmat exporting. Proper error handling for assimp and texture swizzling. --- Switch_FileFormatsMain/FileFormats/BFRES.cs | 89 +- .../FileFormats/BFRES/Bfres Structs/FMAT.cs | 24 +- .../FileFormats/BFRES/Bfres Structs/FMDL.cs | 222 +- .../FileFormats/BFRES/Bfres Structs/FSCN.cs | 8 +- .../BFRES/Bfres Structs/ResourceFile.cs | 35 +- .../FileFormats/BFRES/BfresSwitch.cs | 12 +- .../FileFormats/BFRES/BfresWiiU.cs | 35 + .../FileFormats/Texture/BNTX.cs | 137 +- .../FileFormats/Texture/FTEX.cs | 9 +- .../FileFormats/Texture/GTX.cs | 784 ++- .../FileFormats/Texture/NUTEXB.cs | 470 ++ .../FileFormats/Texture/XTX.cs | 333 +- .../GUI/BFRES/BfresMaterialEditor.cs | 8 +- .../GUI/NuTexEditor.Designer.cs | 353 + Switch_FileFormatsMain/GUI/NuTexEditor.cs | 207 + Switch_FileFormatsMain/GUI/NuTexEditor.resx | 331 + .../GUI/TexturePatternEditor.Designer.cs | 129 + .../GUI/TexturePatternEditor.cs | 25 + .../GUI/TexturePatternEditor.resx | 120 + Switch_FileFormatsMain/Main.cs | 2 +- .../Switch_FileFormatsMain.csproj | 19 + .../Lib/Syroot.NintenTools.Bfres.dll | Bin 184832 -> 191488 bytes .../Lib/Syroot.NintenTools.Bfres.pdb | Bin 0 -> 78120 bytes .../Lib/Syroot.NintenTools.Bfres.xml | 5730 +++++++++++++++++ Switch_Toolbox/MainForm.cs | 3 +- Switch_Toolbox/Program.cs | 1 - Switch_Toolbox/Switch_Toolbox.csproj | 3 - .../FileFormats/Assimp/Assimp.cs | 22 +- Switch_Toolbox_Library/FileFormats/DDS.cs | 3 - 29 files changed, 8719 insertions(+), 395 deletions(-) create mode 100644 Switch_FileFormatsMain/FileFormats/Texture/NUTEXB.cs create mode 100644 Switch_FileFormatsMain/GUI/NuTexEditor.Designer.cs create mode 100644 Switch_FileFormatsMain/GUI/NuTexEditor.cs create mode 100644 Switch_FileFormatsMain/GUI/NuTexEditor.resx create mode 100644 Switch_FileFormatsMain/GUI/TexturePatternEditor.Designer.cs create mode 100644 Switch_FileFormatsMain/GUI/TexturePatternEditor.cs create mode 100644 Switch_FileFormatsMain/GUI/TexturePatternEditor.resx create mode 100644 Switch_Toolbox/Lib/Syroot.NintenTools.Bfres.pdb create mode 100644 Switch_Toolbox/Lib/Syroot.NintenTools.Bfres.xml diff --git a/Switch_FileFormatsMain/FileFormats/BFRES.cs b/Switch_FileFormatsMain/FileFormats/BFRES.cs index 7f31a0ad..154a5266 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES.cs @@ -153,6 +153,12 @@ namespace FirstPlugin resFile.SceneAnims.Clear(); resFile.ShapeAnims.Clear(); resFile.BoneVisibilityAnims.Clear(); + resFile.ModelDict.Clear(); + resFile.SkeletalAnimDict.Clear(); + resFile.MaterialAnimDict.Clear(); + resFile.SceneAnimDict.Clear(); + resFile.ShapeAnimDict.Clear(); + resFile.BoneVisibilityAnimDict.Clear(); int CurMdl = 0; @@ -195,39 +201,22 @@ namespace FirstPlugin private void SaveWiiU(MemoryStream mem) { var resFileU = bfres.ResFileNode.resFileU; + resFileU.Models.Clear(); + // resFileU.SkeletalAnims.Clear(); + // resFileU.SceneAnims.Clear(); + // resFileU.ShapeAnims.Clear(); + // resFileU.BoneVisibilityAnims.Clear(); + // resFileU.Textures.Clear(); - resFileU.Save(mem); int CurMdl = 0; - foreach (FMDL model in bfres.models) + if (EditorRoot.Nodes.ContainsKey("FMDL")) { - resFileU.Models[CurMdl].Shapes.Clear(); - resFileU.Models[CurMdl].VertexBuffers.Clear(); - resFileU.Models[CurMdl].Materials.Clear(); - - int i = 0; - var duplicates = model.shapes.GroupBy(c => c.Text).Where(g => g.Skip(1).Any()).SelectMany(c => c); - foreach (var shape in duplicates) - shape.Text += i++; - - foreach (FSHP shape in model.shapes) - { - CheckMissingTextures(shape); - BfresWiiU.SetShape(shape, shape.ShapeU); - - resFileU.Models[CurMdl].Shapes.Add(shape.Text, shape.ShapeU); - resFileU.Models[CurMdl].VertexBuffers.Add(shape.VertexBufferU); - shape.ShapeU.VertexBufferIndex = (ushort)(resFileU.Models[CurMdl].VertexBuffers.Count - 1); - - SetShaderAssignAttributes(shape.GetMaterial().shaderassign, shape); - } - foreach (FMAT mat in model.materials.Values) - { - BfresWiiU.SetMaterial(mat, mat.MaterialU); - resFileU.Models[CurMdl].Materials.Add(mat.Text, mat.MaterialU); - } - CurMdl++; + foreach (FMDL model in EditorRoot.Nodes["FMDL"].Nodes) + resFileU.Models.Add(model.Text, BfresWiiU.SetModel(model)); } + ErrorCheck(); + resFileU.Save(mem); } public static void SetShaderAssignAttributes(FMAT.ShaderAssign shd, FSHP shape) @@ -299,20 +288,44 @@ namespace FirstPlugin { foreach (FSHP shp in model.shapes) { - Syroot.NintenTools.NSW.Bfres.VertexBuffer vtx = shp.VertexBuffer; - Syroot.NintenTools.NSW.Bfres.Material mat = shp.GetMaterial().Material; - Syroot.NintenTools.NSW.Bfres.ShaderAssign shdr = mat.ShaderAssign; + if (!IsWiiU) + { + Syroot.NintenTools.NSW.Bfres.VertexBuffer vtx = shp.VertexBuffer; + Syroot.NintenTools.NSW.Bfres.Material mat = shp.GetMaterial().Material; + Syroot.NintenTools.NSW.Bfres.ShaderAssign shdr = mat.ShaderAssign; - for (int att = 0; att < vtx.Attributes.Count; att++) - { - if (!shdr.AttribAssigns.Contains(vtx.Attributes[att].Name)) - MessageBox.Show($"Error! Attribute {vtx.Attributes[att].Name} is unlinked!"); + for (int att = 0; att < vtx.Attributes.Count; att++) + { + if (!shdr.AttribAssigns.Contains(vtx.Attributes[att].Name)) + MessageBox.Show($"Error! Attribute {vtx.Attributes[att].Name} is unlinked!"); + } + for (int att = 0; att < mat.TextureRefs.Count; att++) + { + if (!shdr.SamplerAssigns.Contains(mat.SamplerDict.GetKey(att))) //mat.SamplerDict[att] + MessageBox.Show($"Error! Sampler {mat.SamplerDict.GetKey(att)} is unlinked!"); + } } - for (int att = 0; att < mat.TextureRefs.Count; att++) + else { - if (!shdr.SamplerAssigns.Contains(mat.SamplerDict.GetKey(att))) //mat.SamplerDict[att] - MessageBox.Show($"Error! Sampler {mat.SamplerDict.GetKey(att)} is unlinked!"); + Syroot.NintenTools.Bfres.VertexBuffer vtx = shp.VertexBufferU; + Syroot.NintenTools.Bfres.Material mat = shp.GetMaterial().MaterialU; + Syroot.NintenTools.Bfres.ShaderAssign shdr = mat.ShaderAssign; + + for (int att = 0; att < vtx.Attributes.Count; att++) + { + if (!shdr.AttribAssigns.ContainsKey(vtx.Attributes[att].Name)) + MessageBox.Show($"Error! Attribute {vtx.Attributes[att].Name} is unlinked!"); + } + for (int att = 0; att < mat.TextureRefs.Count; att++) + { + string samp = ""; + mat.Samplers.TryGetKey(mat.Samplers[att], out samp); + if (!shdr.SamplerAssigns.ContainsKey(samp)) //mat.SamplerDict[att] + MessageBox.Show($"Error! Sampler {samp} is unlinked!"); + } } + + } } // ErrorList errorList = new ErrorList(); diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMAT.cs b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMAT.cs index 84a9e0df..38d7a69f 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMAT.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMAT.cs @@ -100,6 +100,9 @@ namespace Bfres.Structs public void SetActiveGame() { + Runtime.activeGame = Runtime.ActiveGame.SMO; + return; + string ShaderName = shaderassign.ShaderArchive; string ShaderModel = shaderassign.ShaderModel; @@ -140,7 +143,10 @@ namespace Bfres.Structs if (sfd.ShowDialog() == DialogResult.OK) { - Material.Export(sfd.FileName, GetResFile()); + if (BFRES.IsWiiU) + MaterialU.Export(sfd.FileName, GetResFileU()); + else + Material.Export(sfd.FileName, GetResFile()); } } private void Replace(object sender, EventArgs args) @@ -150,10 +156,18 @@ namespace Bfres.Structs if (ofd.ShowDialog() == DialogResult.OK) { - Material.Import(ofd.FileName); - Material.Name = Text; - - BfresSwitch.ReadMaterial(this, Material); + if (BFRES.IsWiiU) + { + MaterialU.Import(ofd.FileName, GetResFileU()); + MaterialU.Name = Text; + BfresWiiU.ReadMaterial(this, MaterialU); + } + else + { + Material.Import(ofd.FileName); + Material.Name = Text; + BfresSwitch.ReadMaterial(this, Material); + } } } diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMDL.cs b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMDL.cs index 96189abc..4808fb3b 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMDL.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMDL.cs @@ -356,13 +356,6 @@ namespace Bfres.Structs //Function addes shapes, vertices and meshes public void AddOjects(string FileName, bool Replace = true) { - if (Replace) - { - shapes.Clear(); - - Nodes["FshpFolder"].Nodes.Clear(); - } - int MatStartIndex = materials.Count; string ext = System.IO.Path.GetExtension(FileName); ext = ext.ToLower(); @@ -372,6 +365,12 @@ namespace Bfres.Structs case ".bfobj": Cursor.Current = Cursors.WaitCursor; + if (Replace) + { + shapes.Clear(); + Nodes["FshpFolder"].Nodes.Clear(); + } + Shape shpS = new Shape(); VertexBuffer vertexBuffer = new VertexBuffer(); shpS.Import(FileName, vertexBuffer); @@ -385,12 +384,17 @@ namespace Bfres.Structs break; case ".bfmdl": Cursor.Current = Cursors.WaitCursor; - shapes.Clear(); + + if (Replace) + { + shapes.Clear(); + Nodes["FshpFolder"].Nodes.Clear(); + } + Model mdl = new Model(); mdl.Import(FileName, GetResFile()); mdl.Name = Text; shapes.Clear(); - Nodes["FshpFolder"].Nodes.Clear(); foreach (Shape shp in mdl.Shapes) { FSHP shape = new FSHP(); @@ -415,6 +419,12 @@ namespace Bfres.Structs csvsettings.SetModelAttributes(csvModel.objects[0]); if (csvsettings.ShowDialog() == DialogResult.OK) { + if (Replace) + { + shapes.Clear(); + Nodes["FshpFolder"].Nodes.Clear(); + } + Cursor.Current = Cursors.WaitCursor; foreach (STGenericObject obj in csvModel.objects) @@ -452,13 +462,15 @@ namespace Bfres.Structs return; } BfresModelImportSettings settings = new BfresModelImportSettings(); - - if (BFRES.IsWiiU) - settings.DisableMaterialEdits(); - settings.SetModelAttributes(assimp.objects[0]); if (settings.ShowDialog() == DialogResult.OK) { + if (Replace) + { + shapes.Clear(); + Nodes["FshpFolder"].Nodes.Clear(); + } + Cursor.Current = Cursors.WaitCursor; if (!BFRES.IsWiiU && Replace) { @@ -466,109 +478,124 @@ namespace Bfres.Structs Nodes["FmatFolder"].Nodes.Clear(); MatStartIndex = 0; } - - if (!BFRES.IsWiiU) + foreach (STGenericMaterial mat in assimp.materials) { - foreach (STGenericMaterial mat in assimp.materials) + FMAT fmat = new FMAT(); + if (settings.ExternalMaterialPath != string.Empty) { - FMAT fmat = new FMAT(); - fmat.Material = new Material(); - if (settings.ExternalMaterialPath != string.Empty) + if (!BFRES.IsWiiU) { + fmat.Material = new Material(); fmat.Material.Import(settings.ExternalMaterialPath); fmat.ReadMaterial(fmat.Material); } + else + { + fmat.MaterialU = new ResU.Material(); + fmat.MaterialU.Import(settings.ExternalMaterialPath, GetResFileU()); + BfresWiiU.ReadMaterial(fmat, fmat.MaterialU); + } + } - fmat.Text = mat.Text; - //Setup placeholder textures - //Note we can't add/remove samplers so we must fill these slots + fmat.Text = mat.Text; + //Setup placeholder textures + //Note we can't add/remove samplers so we must fill these slots + foreach (var t in fmat.textures) + { + t.wrapModeS = 0; + t.wrapModeT = 0; + + switch (t.Type) + { + case STGenericMatTexture.TextureType.Diffuse: + t.Name = "Basic_Alb"; + break; + case STGenericMatTexture.TextureType.Emission: + t.Name = "Basic_Emm"; + break; + case STGenericMatTexture.TextureType.Normal: + t.Name = "Basic_Nrm"; + break; + case STGenericMatTexture.TextureType.Specular: + t.Name = "Basic_Spm"; + break; + case STGenericMatTexture.TextureType.SphereMap: + t.Name = "Basic_Sphere"; + break; + case STGenericMatTexture.TextureType.Metalness: + t.Name = "Basic_Mtl"; + break; + case STGenericMatTexture.TextureType.Roughness: + t.Name = "Basic_Rgh"; + break; + case STGenericMatTexture.TextureType.MRA: + t.Name = "Basic_MRA"; + break; + case STGenericMatTexture.TextureType.Shadow: + t.Name = "Basic_Bake_st0"; + break; + case STGenericMatTexture.TextureType.Light: + t.Name = "Basic_Bake_st1"; + break; + } + } + + if (PluginRuntime.bntxContainers.Count > 0) + { + foreach (var node in Parent.Parent.Nodes["EXT"].Nodes) + { + if (node is BinaryTextureContainer) + { + var bntx = (BinaryTextureContainer)node; + + bntx.ImportBasicTextures("Basic_Alb"); + bntx.ImportBasicTextures("Basic_Nrm"); + bntx.ImportBasicTextures("Basic_Spm"); + bntx.ImportBasicTextures("Basic_Sphere"); + bntx.ImportBasicTextures("Basic_Mtl"); + bntx.ImportBasicTextures("Basic_Rgh"); + bntx.ImportBasicTextures("Basic_MRA"); + bntx.ImportBasicTextures("Basic_Bake_st0"); + bntx.ImportBasicTextures("Basic_Bake_st1"); + bntx.ImportBasicTextures("Basic_Emm"); + } + } + } + + foreach (var tex in mat.TextureMaps) + { foreach (var t in fmat.textures) { - t.wrapModeS = 0; - t.wrapModeT = 0; - - switch (t.Type) + if (t.Type == tex.Type) { - case STGenericMatTexture.TextureType.Diffuse: - t.Name = "Basic_Alb"; - break; - case STGenericMatTexture.TextureType.Emission: - t.Name = "Basic_Emm"; - break; - case STGenericMatTexture.TextureType.Normal: - t.Name = "Basic_Nrm"; - break; - case STGenericMatTexture.TextureType.Specular: - t.Name = "Basic_Spm"; - break; - case STGenericMatTexture.TextureType.SphereMap: - t.Name = "Basic_Sphere"; - break; - case STGenericMatTexture.TextureType.Metalness: - t.Name = "Basic_Mtl"; - break; - case STGenericMatTexture.TextureType.Roughness: - t.Name = "Basic_Rgh"; - break; - case STGenericMatTexture.TextureType.MRA: - t.Name = "Basic_MRA"; - break; - case STGenericMatTexture.TextureType.Shadow: - t.Name = "Basic_Bake_st0"; - break; - case STGenericMatTexture.TextureType.Light: - t.Name = "Basic_Bake_st1"; - break; + t.Name = tex.Name; + t.wrapModeS = tex.wrapModeS; + t.wrapModeT = tex.wrapModeT; + t.wrapModeW = tex.wrapModeW; + t.Type = tex.Type; } } + } - if (PluginRuntime.bntxContainers.Count > 0) - { - foreach (var node in Parent.Parent.Nodes["EXT"].Nodes) - { - if (node is BinaryTextureContainer) - { - var bntx = (BinaryTextureContainer)node; + List keyList = new List(materials.Keys); + fmat.Text = Utils.RenameDuplicateString(keyList, fmat.Text); - bntx.ImportBasicTextures("Basic_Alb"); - bntx.ImportBasicTextures("Basic_Nrm"); - bntx.ImportBasicTextures("Basic_Spm"); - bntx.ImportBasicTextures("Basic_Sphere"); - bntx.ImportBasicTextures("Basic_Mtl"); - bntx.ImportBasicTextures("Basic_Rgh"); - bntx.ImportBasicTextures("Basic_MRA"); - bntx.ImportBasicTextures("Basic_Bake_st0"); - bntx.ImportBasicTextures("Basic_Bake_st1"); - bntx.ImportBasicTextures("Basic_Emm"); - } - } - } + materials.Add(fmat.Text, fmat); + Nodes["FmatFolder"].Nodes.Add(fmat); - foreach (var tex in mat.TextureMaps) - { - foreach (var t in fmat.textures) - { - if (t.Type == tex.Type) - { - t.Name = tex.Name; - t.wrapModeS = tex.wrapModeS; - t.wrapModeT = tex.wrapModeT; - t.wrapModeW = tex.wrapModeW; - t.Type = tex.Type; - } - } - } + if (BFRES.IsWiiU) + { + fmat.MaterialU.Name = Text; + fmat.SetMaterial(fmat.MaterialU); + } + else + { fmat.Material.Name = Text; fmat.SetMaterial(fmat.Material); - - List keyList = new List(materials.Keys); - fmat.Text = Utils.RenameDuplicateString(keyList, fmat.Text); - - materials.Add(fmat.Text, fmat); - Nodes["FmatFolder"].Nodes.Add(fmat); } } + foreach (STGenericObject obj in assimp.objects) { FSHP shape = new FSHP(); @@ -579,9 +606,6 @@ namespace Bfres.Structs shape.boneIndx = obj.BoneIndex; shape.MaterialIndex = obj.MaterialIndex + MatStartIndex; - if (BFRES.IsWiiU) - shape.MaterialIndex = 0; - shape.Text = obj.ObjectName; shape.lodMeshes = obj.lodMeshes; shape.CreateNewBoundingBoxes(); diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FSCN.cs b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FSCN.cs index 6bfd2ccb..142d5695 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FSCN.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FSCN.cs @@ -61,8 +61,8 @@ namespace Bfres.Structs public SceneAnim SceneAnim; public FSCN() { - ImageKey = "skeletonAnimation"; - SelectedImageKey = "skeletonAnimation"; + ImageKey = "sceneAnimation"; + SelectedImageKey = "sceneAnimation"; ContextMenu = new ContextMenu(); MenuItem export = new MenuItem("Export"); @@ -81,7 +81,7 @@ namespace Bfres.Structs private void Export(object sender, EventArgs args) { SaveFileDialog sfd = new SaveFileDialog(); - sfd.Filter = "Supported Formats|*.bfska;"; + sfd.Filter = "Supported Formats|*.bfscn;"; sfd.FileName = Text; sfd.DefaultExt = ".bfska"; @@ -93,7 +93,7 @@ namespace Bfres.Structs private void Replace(object sender, EventArgs args) { OpenFileDialog ofd = new OpenFileDialog(); - ofd.Filter = "Supported Formats|*.bfska;"; + ofd.Filter = "Supported Formats|*.bfscn;"; if (ofd.ShowDialog() == DialogResult.OK) { diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/ResourceFile.cs b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/ResourceFile.cs index 23119210..a175094a 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/ResourceFile.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/ResourceFile.cs @@ -109,10 +109,6 @@ namespace Bfres.Structs //If has models if (Nodes.ContainsKey("FMDL")) { - if (Nodes["FMDL"].Nodes.ContainsKey("FshpFolder")) - { - - } LibraryGUI.Instance.LoadViewport(Viewport.Instance); Viewport.Instance.gL_ControlModern1.MainDrawable = BFRESRender; @@ -266,9 +262,9 @@ namespace Bfres.Structs if (resFile.MaterialAnims.Count > 0) AddMaterialAnims(resFile); if (resFile.ShapeAnims.Count > 0) - Nodes.Add(new FshpaFolder()); + AddShapeAnims(resFile); if (resFile.BoneVisibilityAnims.Count > 0) - Nodes.Add(new FbnvFolder()); + AddBoneVisAnims(resFile); if (resFile.SceneAnims.Count > 0) AddSceneAnims(resFile); if (resFile.ExternalFiles.Count > 0) @@ -276,6 +272,9 @@ namespace Bfres.Structs } private void AddFTEXTextures(ResU.ResFile resFile) { + MessageBox.Show("Note! Textures are disabled atm."); + return; + FTEXContainer ftexContainer = new FTEXContainer(); Nodes.Add(ftexContainer); foreach (ResU.Texture tex in resFile.Textures.Values) @@ -340,5 +339,29 @@ namespace Bfres.Structs fmaaFolder.Nodes.Add(materialAnim); } } + private void AddShapeAnims(ResFile resFile) + { + FshpaFolder fshaFolder = new FshpaFolder(); + Nodes.Add(fshaFolder); + foreach (var fsha in resFile.ShapeAnims) + { + FSHA shapeAnim = new FSHA(); + shapeAnim.Text = fsha.Name; + shapeAnim.Read(fsha); + fshaFolder.Nodes.Add(shapeAnim); + } + } + private void AddBoneVisAnims(ResFile resFile) + { + FbnvFolder fbnvFolder = new FbnvFolder(); + Nodes.Add(fbnvFolder); + foreach (var fbnv in resFile.BoneVisibilityAnims) + { + FBNV boneVis = new FBNV(); + boneVis.Text = fbnv.Name; + boneVis.Read(fbnv); + fbnvFolder.Nodes.Add(boneVis); + } + } } } diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/BfresSwitch.cs b/Switch_FileFormatsMain/FileFormats/BFRES/BfresSwitch.cs index 93da7558..c4ffc11f 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/BfresSwitch.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/BfresSwitch.cs @@ -20,6 +20,16 @@ namespace FirstPlugin public static Model SetModel(FMDL fmdl) { Model model = new Model(); + model.Name = fmdl.Text; + model.Shapes = new List(); + model.VertexBuffers = new List(); + model.Materials = new List(); + model.UserData = new List(); + model.Skeleton = new Skeleton(); + model.Skeleton = fmdl.Skeleton.node.Skeleton; + model.ShapeDict = new ResDict(); + model.MaterialDict = new ResDict(); + model.UserDataDict = new ResDict(); int i = 0; var duplicates = fmdl.shapes.GroupBy(c => c.Text).Where(g => g.Skip(1).Any()).SelectMany(c => c); @@ -33,13 +43,13 @@ namespace FirstPlugin model.Shapes.Add(shape.Shape); model.VertexBuffers.Add(shape.VertexBuffer); - shape.Shape.VertexBufferIndex = (ushort)(model.VertexBuffers.Count - 1); BFRES.SetShaderAssignAttributes(shape.GetMaterial().shaderassign, shape); } foreach (FMAT mat in fmdl.materials.Values) { + SetMaterial(mat, mat.Material); model.Materials.Add(mat.Material); } diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/BfresWiiU.cs b/Switch_FileFormatsMain/FileFormats/BFRES/BfresWiiU.cs index 9f688432..90b99ef7 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/BfresWiiU.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/BfresWiiU.cs @@ -19,6 +19,41 @@ namespace FirstPlugin { public static class BfresWiiU { + public static Model SetModel(FMDL fmdl) + { + Model model = new Model(); + model.Name = fmdl.Text; + model.Shapes = new ResDict(); + model.VertexBuffers = new List(); + model.Materials = new ResDict(); + model.UserData = new ResDict(); + model.Skeleton = new Skeleton(); + model.Skeleton = fmdl.Skeleton.node.SkeletonU; + + int i = 0; + var duplicates = fmdl.shapes.GroupBy(c => c.Text).Where(g => g.Skip(1).Any()).SelectMany(c => c); + 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); + SetShape(shape, shape.ShapeU); + shape.ShapeU.SubMeshBoundingNodes = new List(); + + model.Shapes.Add(shape.Text, shape.ShapeU); + model.VertexBuffers.Add(shape.VertexBufferU); + shape.ShapeU.VertexBufferIndex = (ushort)(model.VertexBuffers.Count - 1); + + BFRES.SetShaderAssignAttributes(shape.GetMaterial().shaderassign, shape); + } + return model; + } public static void Read(BFRESRender renderer, ResFile resFile, TreeNode ResFileNode) { int CurMdl = 0; diff --git a/Switch_FileFormatsMain/FileFormats/Texture/BNTX.cs b/Switch_FileFormatsMain/FileFormats/Texture/BNTX.cs index 237b8996..f52e80cb 100644 --- a/Switch_FileFormatsMain/FileFormats/Texture/BNTX.cs +++ b/Switch_FileFormatsMain/FileFormats/Texture/BNTX.cs @@ -17,6 +17,7 @@ using Switch_Toolbox.Library; using WeifenLuo.WinFormsUI.Docking; using Smash_Forge.Rendering; using Switch_Toolbox.Library.Forms; +using Switch_Toolbox.Library.IO; namespace FirstPlugin { @@ -142,10 +143,10 @@ namespace FirstPlugin return types.ToArray(); } } - class MenuExt : IFileMenuExtension + class MenuExt : IFileMenuExtension { public ToolStripItemDark[] NewFileMenuExtensions => null; - public ToolStripItemDark[] ToolsMenuExtensions => null; + public ToolStripItemDark[] ToolsMenuExtensions => newFileExt; public ToolStripItemDark[] TitleBarExtensions => null; public ToolStripItemDark[] CompressionMenuExtensions => null; public ToolStripItemDark[] ExperimentalMenuExtensions => null; @@ -153,9 +154,80 @@ namespace FirstPlugin ToolStripItemDark[] newFileExt = new ToolStripItemDark[1]; public MenuExt() { - newFileExt[0] = new ToolStripItemDark("BNTX "); + newFileExt[0] = new ToolStripItemDark("Extract BNTX"); + newFileExt[0].Click += Export; } - } + private void Export(object sender, EventArgs args) + { + OpenFileDialog ofd = new OpenFileDialog(); + ofd.Multiselect = true; + + if (ofd.ShowDialog() == DialogResult.OK) + { + foreach (string file in ofd.FileNames) + { + FileReader reader = new FileReader(ofd.FileName); + reader.Seek(16, SeekOrigin.Begin); + int offsetName = reader.ReadInt32(); + + reader.Seek(offsetName, SeekOrigin.Begin); + string Name = reader.ReadString(Syroot.BinaryData.BinaryStringFormat.ZeroTerminated); + + Console.WriteLine(file + " " + Name); + + reader.Close(); + reader.Dispose(); + + // System.IO.File.Move(file, Name); + } + } + } + } +/* + byte[] ByteBuffer = File.ReadAllBytes(ofd.FileName); + byte[] StringBytes = Encoding.UTF8.GetBytes("BNTX"); + try + { + while (true) + { + byte byt = reader.ReadByte(); + + if (byt == 0x42) + { + reader.Seek(-1, SeekOrigin.Current); + int TryRdMagic = reader.ReadInt32(); + if (TryRdMagic == 0x424E5458) + { + reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian; + + long BNTXpos = reader.Position - 4; + Console.WriteLine("String was found at offset {0}", reader.Position); + + reader.Seek(BNTXpos + 16, SeekOrigin.Begin); + int offsetName = reader.ReadInt32(); + + reader.Seek(BNTXpos + offsetName, SeekOrigin.Begin); + string Name = reader.ReadString(); + + reader.Seek(BNTXpos + 28, SeekOrigin.Begin); + int size = reader.ReadInt32(); + + reader.Seek(BNTXpos, SeekOrigin.Begin); + + File.WriteAllBytes(Name + ".bntx", reader.ReadBytes(size)); + reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; + } + } + } + + + } + catch + { + + } + } + }*/ BinaryTextureContainer bntx; @@ -1250,41 +1322,48 @@ namespace FirstPlugin { mipmaps.Clear(); - uint blk_dim = Formats.blk_dims((uint)((int)tex.Format >> 8)); - uint blkWidth = blk_dim >> 4; - uint blkHeight = blk_dim & 0xF; - - int linesPerBlockHeight = (1 << (int)tex.BlockHeightLog2) * 8; - - uint bpp = Formats.bpps((uint)((int)tex.Format >> 8)); - - for (int arrayLevel = 0; arrayLevel < tex.ArrayLength; arrayLevel++) + try { - int blockHeightShift = 0; + uint blk_dim = Formats.blk_dims((uint)((int)tex.Format >> 8)); + uint blkWidth = blk_dim >> 4; + uint blkHeight = blk_dim & 0xF; - List mips = new List(); - for (int mipLevel = 0; mipLevel < tex.TextureData[arrayLevel].Count; mipLevel++) + int linesPerBlockHeight = (1 << (int)tex.BlockHeightLog2) * 8; + + uint bpp = Formats.bpps((uint)((int)tex.Format >> 8)); + + for (int arrayLevel = 0; arrayLevel < tex.ArrayLength; arrayLevel++) { - uint width = (uint)Math.Max(1, tex.Width >> mipLevel); - uint height = (uint)Math.Max(1, tex.Height >> mipLevel); + int blockHeightShift = 0; - uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp; + List mips = new List(); + for (int mipLevel = 0; mipLevel < tex.TextureData[arrayLevel].Count; mipLevel++) + { + uint width = (uint)Math.Max(1, tex.Width >> mipLevel); + uint height = (uint)Math.Max(1, tex.Height >> mipLevel); - if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight) - blockHeightShift += 1; + uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp; - byte[] result = TegraX1Swizzle.deswizzle(width, height, blkWidth, blkHeight, target, bpp, (uint)tex.TileMode, (int)Math.Max(0, tex.BlockHeightLog2 - blockHeightShift), tex.TextureData[arrayLevel][mipLevel]); - //Create a copy and use that to remove uneeded data - byte[] result_ = new byte[size]; - Array.Copy(result, 0, result_, 0, size); + if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight) + blockHeightShift += 1; - mips.Add(result_); + byte[] result = TegraX1Swizzle.deswizzle(width, height, blkWidth, blkHeight, target, bpp, (uint)tex.TileMode, (int)Math.Max(0, tex.BlockHeightLog2 - blockHeightShift), tex.TextureData[arrayLevel][mipLevel]); + //Create a copy and use that to remove uneeded data + byte[] result_ = new byte[size]; + Array.Copy(result, 0, result_, 0, size); + mips.Add(result_); + } + mipmaps.Add(mips); } - mipmaps.Add(mips); - } - Texture = tex; + Texture = tex; + + } + catch (Exception e) + { + MessageBox.Show($"Failed to swizzle texture {Text}! Exception: {e}"); + } } public Bitmap DisplayTexture(int DisplayMipIndex = 0, int ArrayIndex = 0) diff --git a/Switch_FileFormatsMain/FileFormats/Texture/FTEX.cs b/Switch_FileFormatsMain/FileFormats/Texture/FTEX.cs index f0620fb5..a511cce7 100644 --- a/Switch_FileFormatsMain/FileFormats/Texture/FTEX.cs +++ b/Switch_FileFormatsMain/FileFormats/Texture/FTEX.cs @@ -170,8 +170,15 @@ namespace FirstPlugin format = (int)tex.Format; int swizzle = (int)tex.Swizzle; int pitch = (int)tex.Pitch; + uint bpp = GTX.surfaceGetBitsPerPixel((uint)format) >> 3; - renderedTex.data = GTX.swizzleBC(tex.Data, renderedTex.width, renderedTex.height, format, (int)tex.TileMode, pitch, swizzle); + GTX.GX2Surface surf = new GTX.GX2Surface(); + surf.bpp = bpp; + + for (int surfaceLevel = 0; surfaceLevel < tex.ArrayLength; surfaceLevel++) + { + } + GTX.Decode(surf, tex.MipData); } public void Export(string FileName, bool ExportSurfaceLevel = false, diff --git a/Switch_FileFormatsMain/FileFormats/Texture/GTX.cs b/Switch_FileFormatsMain/FileFormats/Texture/GTX.cs index 38c034dd..a387f5af 100644 --- a/Switch_FileFormatsMain/FileFormats/Texture/GTX.cs +++ b/Switch_FileFormatsMain/FileFormats/Texture/GTX.cs @@ -91,12 +91,80 @@ namespace FirstPlugin public int swizzle; public int alignment; public int pitch; + public uint bpp; public byte[] data; public int[] mipOffset; }; + public static int m_configFlags = 4; + public static int ADDR_OK = 0; + + public static int expPitch = 0; + public static int expHeight = 0; + public static int expNumSlices = 0; + + public class surfaceIn + { + public int size = 0; + public int tileMode = 0; + public int format = 0; + public int bpp = 0; + public int numSamples = 0; + public int width = 0; + public int height = 0; + public int numSlices = 0; + public int slice = 0; + public int mipLevel = 0; + public Flags flags = new Flags(); + public int numFrags = 0; + public TileInfo tileType = new TileInfo(); + public int tileIndex = 0; + } + public class surfaceOut + { + public int size = 0; + public int pitch = 0; + public int height = 0; + public int depth = 0; + public int surfSize = 0; + public int tileMode = 0; + public int baseAlign = 0; + public int pitchAlign = 0; + public int heightAlign = 0; + public int depthAlign = 0; + public int bpp = 0; + public int pixelPitch = 0; + public int pixelHeight = 0; + public int pixelBits = 0; + public int sliceSize = 0; + public int pitchTileMax = 0; + public int heightTileMax = 0; + public int sliceTileMax = 0; + public int pTileInfo = 0; + public TileInfo tileType = new TileInfo(); + public int tileIndex = 0; + } + + public class Flags + { + public uint value = 0; + } + + public class TileInfo + { + public int banks = 0; + public int bankWidth = 0; + public int bankHeight = 0; + public int macroAspectRatio = 0; + public int tileSplitBytes = 0; + public int pipeConfig = 0; + } + + static surfaceIn pIn = new surfaceIn(); + static surfaceOut pOut = new surfaceOut(); + public enum GX2SurfaceDimension { GX2_SURFACE_DIM_1D = 0x0, @@ -388,24 +456,47 @@ namespace FirstPlugin ADDR_FMT_RESERVED_63 = 0x3F, }; - private static byte[] formatHwInfo = { - 0x00, 0x00, 0x00, 0x01, 0x08, 0x03, 0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00, 0x10, 0x03, 0x00, 0x01, 0x10, 0x03, 0x00, 0x01, - 0x10, 0x0B, 0x00, 0x01, 0x10, 0x01, 0x00, 0x01, 0x10, 0x03, 0x00, 0x01, 0x10, 0x03, 0x00, 0x01, - 0x10, 0x03, 0x00, 0x01, 0x20, 0x03, 0x00, 0x00, 0x20, 0x07, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, - 0x20, 0x03, 0x00, 0x01, 0x20, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x20, 0x0B, 0x00, 0x01, 0x20, 0x0B, 0x00, 0x01, 0x20, 0x0B, 0x00, 0x01, - 0x40, 0x05, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, - 0x40, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x00, 0x00, - 0x10, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, - 0x60, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0x01, - 0x40, 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; + public static List Decode(GX2Surface tex, byte[] MipData) + { + var surfInfo = getSurfaceInfo((GX2SurfaceFormat)tex.format, tex.width, tex.height, tex.depth, (uint)tex.dim, (uint)tex.tileMode, (uint)tex.aa, 0); + if (surfInfo.depth != 1) + throw new Exception("Unsupported Depth!"); + + List result = new List(); + for (int mipLevel = 0; mipLevel < tex.numMips; mipLevel++) + { + int size; + if (IsFormatBCN((GX2SurfaceFormat)tex.format)) + size = ((Math.Max(1, tex.width >> mipLevel) + 3) >> 2) * ((Math.Max(1, tex.height >> mipLevel) + 3) >> 2) * (int)tex.bpp; + else + size = Math.Max(1, tex.width >> mipLevel) * Math.Max(1, tex.height >> mipLevel) * (int)tex.bpp; + + byte[] data; + if (mipLevel == 0) + { + data = new byte[surfInfo.surfSize]; + } + else + { + int mipOffset; + if (mipLevel == 1) + mipOffset = tex.mipOffset[mipLevel - 1] - surfInfo.surfSize; + else + mipOffset = tex.mipOffset[mipLevel - 1]; + + 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]; + Array.Copy(MipData, mipOffset, data, 0, surfInfo.surfSize); + } + byte[] deswizzled = deswizzle(Math.Max(1, (uint)tex.width >> mipLevel), Math.Max(1, (uint)tex.height >> mipLevel), (uint)surfInfo.height, (uint)tex.format, + (uint)surfInfo.tileMode, (uint)tex.swizzle, (uint)surfInfo.pitch, (uint)surfInfo.bpp, data); + //Create a copy and use that to remove uneeded data + byte[] result_ = new byte[size]; + Array.Copy(deswizzled, 0, result_, 0, size); + } + return result; + } @@ -430,24 +521,231 @@ namespace FirstPlugin { FORMAT_INVALID, GX2_SURFACE_FORMAT_INVALID, 0, 0xFFFFFFFF, 0x00, nullptr, 0x00, 0 } };*/ - - public static byte[] swizzleBC(byte[] data, int width, int height, int format, int tileMode, int pitch, int swizzle) + public static bool IsFormatBCN(GX2SurfaceFormat Format) { - GX2Surface sur = new GX2Surface(); - sur.width = width; - sur.height = height; - sur.tileMode = tileMode; - sur.format = format; - sur.swizzle = swizzle; - sur.pitch = pitch; - sur.data = data; - sur.imageSize = data.Length; - //return swizzleBC(sur); - return swizzleSurface(sur, (GX2SurfaceFormat)sur.format != GX2SurfaceFormat.GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM & - (GX2SurfaceFormat)sur.format != GX2SurfaceFormat.GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB); + switch (Format) + { + case GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_UNORM: + case GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_SRGB: + case GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC2_UNORM: + case GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC2_SRGB: + case GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_UNORM: + case GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_SRGB: + case GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_UNORM: + case GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_SNORM: + case GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_SNORM: + case GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_UNORM: + return true; + default: + return false; + } } - public static int getBPP(int i) + public static byte[] deswizzle(uint width, uint height, uint height_, uint format_, uint tileMode, uint swizzle_, + uint pitch, uint bpp, byte[] data) + { + return swizzleSurf(width, height, height_, format_, tileMode, swizzle_, pitch, bpp, data, 0); + } + public static byte[] swizzle(uint width, uint height, uint height_, uint format_, uint tileMode, uint swizzle_, + uint pitch, uint bpp, byte[] data) + { + return swizzleSurf(width, height, height_, format_, tileMode, swizzle_, pitch, bpp, data, 1); + } + + static uint m_banks = 4; + static uint m_banksBitcount = 2; + static uint m_pipes = 2; + static uint m_pipesBitcount = 1; + static uint m_pipeInterleaveBytes = 256; + static uint m_pipeInterleaveBytesBitcount = 8; + static uint m_rowSize = 2048; + static uint m_swapSize = 256; + static uint m_splitSize = 2048; + + static uint m_chipFamily = 2; + + static uint MicroTilePixels = 64; + + + private static byte[] swizzleSurf(uint width, uint height, uint height_, uint format, uint tileMode, uint swizzle_, + uint pitch, uint bitsPerPixel, byte[] data, int swizzle) + { + byte[] result = new byte[data.Length]; + + uint bytesPerPixel = bitsPerPixel / 8; + + uint pipeSwizzle, bankSwizzle, pos_; + uint pos; + + if (IsFormatBCN((GX2SurfaceFormat)format)) + { + width = (width + 3) / 4; + height = (height + 3) / 4; + } + + pipeSwizzle = (swizzle_ >> 8) & 1; + bankSwizzle = (swizzle_ >> 9) & 3; + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + var tileGrp1 = new List { 0, 1 }; + var tileGrp2 = new List { 2, 3 }; + + + if (tileGrp1.Contains(tileMode)) + pos = (uint)(y * pitch + x) * bytesPerPixel; + else if (tileGrp2.Contains(tileMode)) + { + pos = computeSurfaceAddrFromCoordMicroTiled(x, y, bitsPerPixel, pitch, tileMode); + } + else + { + pos = computeSurfaceAddrFromCoordMacroTiled(x, y, bitsPerPixel, (int)pitch, (int)height_, (int)tileMode, (int)pipeSwizzle, (int)bankSwizzle); + } + pos = 0; + + pos_ = (uint)(y * width + x) * bytesPerPixel; + + if (pos_ + bytesPerPixel <= data.Length && pos + bytesPerPixel <= data.Length) + { + if (swizzle == 0) + { + for (int n = 0; n < bytesPerPixel; n++) + result[pos_ + n] = data[(uint)pos + n]; + } + else + { + for (int n = 0; n < bytesPerPixel; n++) + result[(uint)pos + n] = data[pos_ + n]; + } + } + } + } + return result; + } + + private static byte[] formatHwInfo = { + 0x00, 0x00, 0x00, 0x01, 0x08, 0x03, 0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00, 0x10, 0x03, 0x00, 0x01, 0x10, 0x03, 0x00, 0x01, + 0x10, 0x0B, 0x00, 0x01, 0x10, 0x01, 0x00, 0x01, 0x10, 0x03, 0x00, 0x01, 0x10, 0x03, 0x00, 0x01, + 0x10, 0x03, 0x00, 0x01, 0x20, 0x03, 0x00, 0x00, 0x20, 0x07, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, + 0x20, 0x03, 0x00, 0x01, 0x20, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x20, 0x0B, 0x00, 0x01, 0x20, 0x0B, 0x00, 0x01, 0x20, 0x0B, 0x00, 0x01, + 0x40, 0x05, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, + 0x40, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x00, 0x00, + 0x10, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, + 0x60, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0x01, + 0x40, 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + private static byte[] formatExInfo = { + 0x00, 0x01, 0x01, 0x03, 0x08, 0x01, 0x01, 0x03, 0x08, 0x01, 0x01, 0x03, 0x08, 0x01, 0x01, 0x03, + 0x00, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03, + 0x10, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03, + 0x10, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, + 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, + 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, + 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, + 0x40, 0x01, 0x01, 0x03, 0x40, 0x01, 0x01, 0x03, 0x40, 0x01, 0x01, 0x03, 0x40, 0x01, 0x01, 0x03, + 0x40, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03, 0x80, 0x01, 0x01, 0x03, 0x80, 0x01, 0x01, 0x03, + 0x00, 0x01, 0x01, 0x03, 0x01, 0x08, 0x01, 0x05, 0x01, 0x08, 0x01, 0x06, 0x10, 0x01, 0x01, 0x07, + 0x10, 0x01, 0x01, 0x08, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, + 0x18, 0x03, 0x01, 0x04, 0x30, 0x03, 0x01, 0x04, 0x30, 0x03, 0x01, 0x04, 0x60, 0x03, 0x01, 0x04, + 0x60, 0x03, 0x01, 0x04, 0x40, 0x04, 0x04, 0x09, 0x80, 0x04, 0x04, 0x0A, 0x80, 0x04, 0x04, 0x0B, + 0x40, 0x04, 0x04, 0x0C, 0x40, 0x04, 0x04, 0x0D, 0x40, 0x04, 0x04, 0x0D, 0x40, 0x04, 0x04, 0x0D, + 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03, + 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03, 0x40, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03, + }; + + public static uint surfaceGetBitsPerPixel(uint surfaceFormat) + { + return formatHwInfo[(surfaceFormat & 0x35) + 4]; + } + + private static uint computePipeFromCoordWoRotation(uint x, uint y) + { + return ((y >> 3) ^ (x >> 3)) & 1; + } + + private static uint computeBankFromCoordWoRotation(uint x, uint y) + { + return ((y >> 5) ^ (x >> 3)) & 1 | 2 * (((y >> 4) ^ (x >> 4)) & 1); + } + + private static bool isThickMacroTiled(uint tileMode) + { + var Grp1 = new List { 7, 11, 13, 15 }; + if (Grp1.Contains(tileMode)) + return true; + + return false; + } + + private static bool isBankSwapped(uint tileMode) + { + var Grp1 = new List { 8, 9, 10, 11, 14, 15 }; + if (Grp1.Contains(tileMode)) + return true; + + return false; + } + + private static uint computeMacroTileAspectRatio(uint tileMode) + { + var Grp1 = new List { 5, 9 }; + var Grp2 = new List { 6, 10 }; + + if (Grp1.Contains(tileMode)) + return 2; + + if (Grp2.Contains(tileMode)) + return 4; + + return 1; + } + + private static uint computeSurfaceBankSwappedWidth(uint tileMode, uint bpp, uint pitch, uint numSamplers) + { + if (isBankSwapped(tileMode) == true) + return 0; + + return 0; + } + + private static uint computeSurfaceAddrFromCoordMicroTiled(int x, int y, uint bpp, uint pitch, uint tileMode) + { + return 0; //Todo + + /* uint microTileThickness = 1; + + if (tileMode == 3) + microTileThickness = 4; + + uint microTileBytes = (MicroTilePixels * microTileThickness * bpp + 7) / 8; + uint microTilesPerRow = pitch >> 3; + uint microTileIndexX = (uint)x >> 3; + uint microTileIndexY = (uint)y >> 3; + + uint microTileOffset = microTileBytes * (microTileIndexX + microTileIndexY * microTilesPerRow); + + uint pixelIndex = computePixelIndexWithinMicroTile(x, y, bpp, tileMode); + + uint pixelOffset = bpp * pixelIndex; + pixelOffset >>= 3; + + return pixelOffset + microTileOffset;*/ + } + + + + private static int getBPP(int i) { switch ((GX2SurfaceFormat)i) { @@ -471,90 +769,15 @@ namespace FirstPlugin return -1; } - public static byte[] swizzleSurface(GX2Surface surface, bool isCompressed) + + + private static uint computeSurfaceAddrFromCoordMacroTiled(int x, int y, uint bpp, int pitch, + int height, int tileMode, int pipeSwizzle, int bankSwizzle) { - byte[] original = new byte[surface.data.Length]; - - surface.data.CopyTo(original, 0); - - int swizzle = ((surface.swizzle >> 8) & 1) + (((surface.swizzle >> 9) & 3) << 1); - int blockSize; - int width = surface.width; - int height = surface.height; - - int format = getBPP(surface.format); - Console.WriteLine(((GX2SurfaceFormat)surface.format).ToString()); - - if (isCompressed) - { - width /= 4; - height /= 4; - - if ((GX2SurfaceFormat)surface.format == GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_UNORM || - (GX2SurfaceFormat)surface.format == GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_SRGB || - (GX2SurfaceFormat)surface.format == GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_UNORM || - (GX2SurfaceFormat)surface.format == GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_SNORM) - { - blockSize = 8; - } - else - { - blockSize = 16; - } - } - else - { - /*if ((GX2SurfaceFormat)surface.format == GX2SurfaceFormat.GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM) - { - blockSize = format / 4; - } - else*/ - blockSize = format / 8; - } - - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x++) - { - int pos = surfaceAddrFromCoordMacroTiled(x, y, format, surface.pitch, swizzle); - int pos_ = (y * width + x) * blockSize; - - for (int k = 0; k < blockSize; k++) - { - if (pos + k >= original.Length || pos_ + k >= surface.data.Length) - { - Console.WriteLine("Break Point " + pos_ + " " + pos); - break; - } - surface.data[pos_ + k] = original[pos + k]; - } - } - } - return surface.data; + return 0; //Todo } - public static int surfaceAddrFromCoordMacroTiled(int x, int y, int bpp, int pitch, int swizzle) - { - int pixelIndex = computePixelIndexWithinMicroTile(x, y, bpp); - int elemOffset = (bpp * pixelIndex) >> 3; - - int pipe = computePipeFromCoordWoRotation(x, y); - int bank = computeBankFromCoordWoRotation(x, y); - int bankPipe = ((pipe + 2 * bank) ^ swizzle) % 9; - - pipe = bankPipe % 2; - bank = bankPipe / 2; - - int macroTileBytes = (bpp * 512 + 7) >> 3; - int macroTileOffset = (x / 32 + pitch / 32 * (y / 16)) * macroTileBytes; - - int unk1 = elemOffset + (macroTileOffset >> 3); - int unk2 = unk1 & ~0xFF; - - return (unk2 << 3) | (0xFF & unk1) | (pipe << 8) | (bank << 9); - } - - public static int computePixelIndexWithinMicroTile(int x, int y, int bpp) + private static int computePixelIndexWithinMicroTile(int x, int y, uint bpp) { int bits = ((x & 4) << 1) | ((y & 2) << 3) | ((y & 4) << 3); @@ -574,13 +797,13 @@ namespace FirstPlugin return bits; } - public static int getFormatBpp(int format) + private static int getFormatBpp(int format) { int hwFormat = format & 0x3F; return formatHwInfo[hwFormat * 4]; } - public static int computeSurfaceThickness(AddrTileMode tileMode) + private static int computeSurfaceThickness(AddrTileMode tileMode) { switch (tileMode) { @@ -602,7 +825,7 @@ namespace FirstPlugin return 1; } - public static int isThickMacroTiled(AddrTileMode tileMode) + private static int isThickMacroTiled(AddrTileMode tileMode) { switch (tileMode) { @@ -618,7 +841,7 @@ namespace FirstPlugin return 0; } - public static int isBankSwappedTileMode(AddrTileMode tileMode) + private static int isBankSwappedTileMode(AddrTileMode tileMode) { switch (tileMode) { @@ -635,7 +858,7 @@ namespace FirstPlugin return 0; } - public static int computeSurfaceRotationFromTileMode(AddrTileMode tileMode) + private static int computeSurfaceRotationFromTileMode(AddrTileMode tileMode) { switch ((int)tileMode) { @@ -662,13 +885,13 @@ namespace FirstPlugin return 0; } - public static int computePipeFromCoordWoRotation(int x, int y) + private static int computePipeFromCoordWoRotation(int x, int y) { int pipe = ((y >> 3) ^ (x >> 3)) & 1; return pipe; } - public static int computeBankFromCoordWoRotation(int x, int y) + private static int computeBankFromCoordWoRotation(int x, int y) { int bankBit0 = ((y / (16 * 2)) ^ (x >> 3)) & 1; int bank = bankBit0 | 2 * (((y / (8 * 2)) ^ (x >> 4)) & 1); @@ -676,7 +899,7 @@ namespace FirstPlugin return bank; } - public static int computeMacroTileAspectRatio(AddrTileMode tileMode) + private static int computeMacroTileAspectRatio(AddrTileMode tileMode) { switch (tileMode) { @@ -701,7 +924,7 @@ namespace FirstPlugin return 1; } - public static int computeSurfaceBankSwappedWidth(AddrTileMode tileMode, int bpp, int numSamples, int pitch, int pSlicesPerTile) + private static int computeSurfaceBankSwappedWidth(AddrTileMode tileMode, int bpp, int numSamples, int pitch, int pSlicesPerTile) { int bankSwapWidth = 0; int numBanks = 4; @@ -787,7 +1010,7 @@ namespace FirstPlugin return bankSwapWidth; } - public static int computePixelIndexWithinMicroTile(int x, int y, int z, int bpp, AddrTileMode tileMode, int microTileType) + private static int computePixelIndexWithinMicroTile(int x, int y, int z, int bpp, AddrTileMode tileMode, int microTileType) { int pixelBit0 = 0; int pixelBit1 = 0; @@ -903,7 +1126,7 @@ namespace FirstPlugin (pixelBit1 << 1); } - public static int surfaceAddrFromCoordMacroTiled( + private static int surfaceAddrFromCoordMacroTiled( int x, int y, int slice, int sample, int bpp, int pitch, int height, int numSamples, AddrTileMode tileMode, int isDepth, int tileBase, int compBits, @@ -1045,93 +1268,266 @@ namespace FirstPlugin return subOffset1 | subOffset2 | p4 | p5; } - public static byte[] swizzleBC(GX2Surface surface) + private static int getFillSizeFieldsFlags() { - //std::vector result; - //List result = new List(); + return (m_configFlags >> 6) & 1; + } - //result.resize(surface->imageSize); + private static void computeSurfaceInfo(surfaceIn aSurfIn, surfaceOut aSurfOut) + { + //Todo! + surfaceIn pIn = aSurfIn; + surfaceOut pOut = aSurfOut; - //u8 *data = (u8*)surface->imagePtr; - byte[] data = surface.data; - byte[] result = new byte[surface.imageSize]; + int v4 = 0; + int v6 = 0; + int v7 = 0; + int v8 = 0; + int v10 = 0; + int v11 = 0; + int v12 = 0; + int v18 = 0; - int width = surface.width / 4; - int height = surface.height / 4; + TileInfo tileInfoNull = new TileInfo(); + int sliceFlags = 0; + int returnCode = 0; - for (int y = 0; y < height; ++y) + if (getFillSizeFieldsFlags() == 1 && (pIn.size != 60 || pOut.size != 96)) + returnCode = 6; + + if (pIn.bpp > 0x80) + returnCode = 3; + + if (returnCode == ADDR_OK) { - for (int x = 0; x < width; ++x) + v18 = 0; + + + computeMipLevel(); + + int width = pIn.width; + int height = pIn.height; + int bpp = pIn.bpp; + int expandX = 1; + int expandY = 1; + + } + } + private static void computeMipLevel() + { + uint slices = 0; + uint height = 0; + uint width = 0; + uint hwlHandled = 0; + + if ((49 <= pIn.format && 49 <= 55 && pIn.mipLevel != 49) || 49 <= ((pIn.flags.value >> 12) & 1)) + { + pIn.width = powTwoAlign(pIn.width, 4); + pIn.height = powTwoAlign(pIn.height, 4); + } + hwlHandled = hwlComputeMipLevel(); + + } + private static uint hwlComputeMipLevel() + { + //This part might be wrong? + uint handled = 0; + + if (49 <= pIn.format && 49 <= 55) + { + if (pIn.mipLevel != 0) { - int bpp = getFormatBpp(surface.format); - int pos = 0; + int width = pIn.width; + int height = pIn.height; + int slices = pIn.numSlices; - switch (surface.tileMode) + if (((pIn.flags.value >> 12) & 1) != 0) { - case 0: - case 1: - { - // pos = surfaceAddrFromCoordLinear( - // x, y, 0, 0, bpp, - // surface->pitch, height, surface->depth, 0 - // ); + int widtha = width >> pIn.mipLevel; + int heighta = height >> pIn.mipLevel; - //printf("Unsupported tilemode %d\n", surface->tileMode); - //exit(1); - } - break; + if (((pIn.flags.value >> 4) & 1) == 0) + slices >>= pIn.mipLevel; - case 2: - case 3: - { - // pos = surfaceAddrFromCoordMicroTiled( - // x, y, 0, bpp, surface->pitch, height, - // surface->tileMode, 0, 0, 0, 0 - // ); - - //printf("Unsupported tilemode %d\n", surface->tileMode); - //exit(1); - } - break; - - default: - { - pos = surfaceAddrFromCoordMacroTiled( - x, y, 0, 0, bpp, surface.pitch, height, - 1, (AddrTileMode)surface.tileMode, 0, 0, 0, - (surface.swizzle >> 8) & 1, - (surface.swizzle >> 9) & 3 - ); - } - break; + width = Math.Max(1, widtha); + height = Math.Max(1, heighta); + slices = Math.Max(1, slices); } - int q = y * width + x; - switch (surface.format) - { - case 0x31: - case 0x34: - case 0x234: - case 0x431: - { - System.Array.Copy(data, pos, result, q * 8, 8); - //memcpy(result.data() + q*8, data+pos, 8); - } - break; + pIn.width = nextPow2(width); + pIn.height = nextPow2(height); + pIn.numSlices = slices; - default: - { - System.Array.Copy(data, pos, result, q * 16, 16); - //memcpy(result.data() + q*16, data+pos, 16); - } - break; - } + handled = 1; + } + } + return handled; + } + private static int nextPow2(int dim) + { + uint newDim = 1; + if (newDim <= 0x7FFFFFFF) + { + while (newDim < dim) + newDim *= 2; + } + else + newDim = 2147483648; + + return (int)newDim; + } + private static int powTwoAlign(int x, int align) + { + return (int)(align - 1) & (x + align - 1); + } + + public static surfaceOut getSurfaceInfo(GX2SurfaceFormat surfaceFormat, int surfaceWidth, int surfaceHeight, int surfaceDepth, uint surfaceDim, uint surfaceTileMode, uint surfaceAA, int level) + { + GX2Surface surface = new GX2Surface(); + + uint dim = 0; + uint width = 0; + uint blockSize = 0; + int numSamples = 0; + int hwFormat = 0; + + var aSurfIn = new surfaceIn(); + var pSurfOut = new surfaceOut(); + + hwFormat = (int)surfaceFormat & 0x3F; + + if (surfaceTileMode == 16) + { + numSamples = 1 << (int)surfaceAA; + + if (hwFormat < 0x31 || hwFormat > 0x35) + blockSize = 1; + else + blockSize = 4; + + width = (uint)((blockSize - 1) & ((surfaceWidth >> level) + blockSize - 1)); + + if (hwFormat == 0x35) + return pSurfOut; + + pSurfOut.bpp = formatHwInfo[hwFormat * 4]; + pSurfOut.size = 96; + pSurfOut.pitch = (int)(width / blockSize); + pSurfOut.pixelBits = formatHwInfo[hwFormat * 4]; + pSurfOut.baseAlign = 1; + pSurfOut.pitchAlign = 1; + pSurfOut.heightAlign = 1; + pSurfOut.depthAlign = 1; + + if (dim == 0) + { + pSurfOut.height = 1; + pSurfOut.depth = 1; + } + else if (dim == 1) + { + pSurfOut.height = Math.Max(1, surfaceHeight >> level); + pSurfOut.depth = 1; + } + else if (dim == 2) + { + pSurfOut.height = Math.Max(1, surfaceHeight >> level); + pSurfOut.depth = Math.Max(1, surfaceDepth >> level); + } + else if (dim == 3) + { + pSurfOut.height = Math.Max(1, surfaceHeight >> level); + pSurfOut.depth = Math.Max(6, surfaceDepth); + } + else if (dim == 4) + { + pSurfOut.height = 1; + pSurfOut.depth = surfaceDepth; + } + else if (dim == 5) + { + pSurfOut.height = Math.Max(1, surfaceHeight >> level); + pSurfOut.depth = surfaceDepth; + } + + pSurfOut.height = (int)(((blockSize - 1) & (pSurfOut.height + blockSize - 1)) / blockSize); + pSurfOut.pixelPitch = (int)((blockSize - 1) & ((surfaceWidth >> level) + blockSize - 1)); + pSurfOut.pixelPitch = (int)Math.Max(blockSize, pSurfOut.pixelPitch); + pSurfOut.pixelHeight = (int)((blockSize - 1) & ((surfaceHeight >> level) + blockSize - 1)); + pSurfOut.pixelHeight = (int)Math.Max(blockSize, pSurfOut.pixelHeight); + pSurfOut.pitch = Math.Max(1, pSurfOut.pitch); + pSurfOut.height = Math.Max(1, pSurfOut.height); + pSurfOut.surfSize = pSurfOut.bpp * numSamples * pSurfOut.depth * pSurfOut.height * pSurfOut.pitch >> 3; + + if (surfaceDim == 2) + pSurfOut.sliceSize = pSurfOut.surfSize; + + else + pSurfOut.sliceSize = pSurfOut.surfSize / pSurfOut.depth; + + pSurfOut.pitchTileMax = (pSurfOut.pitch >> 3) - 1; + pSurfOut.heightTileMax = (pSurfOut.height >> 3) - 1; + pSurfOut.sliceTileMax = (pSurfOut.height * pSurfOut.pitch >> 6) - 1; + } + else + { + aSurfIn.size = 60; + aSurfIn.tileMode = (int)surfaceTileMode & 0x0F; + aSurfIn.format = hwFormat; + aSurfIn.bpp = formatHwInfo[hwFormat * 4]; + aSurfIn.numSamples = 1 << (int)surfaceAA; + aSurfIn.numFrags = aSurfIn.numSamples; + aSurfIn.width = Math.Max(1, surfaceWidth >> level); + + if (dim == 0) + { + aSurfIn.height = 1; + aSurfIn.numSlices = 1; + } + else if (dim == 1) + { + aSurfIn.height = Math.Max(1, surfaceHeight >> level); + aSurfIn.numSlices = 1; + } + else if (dim == 2) + { + aSurfIn.height = Math.Max(1, surfaceHeight >> level); + aSurfIn.numSlices = Math.Max(1, surfaceDepth >> level); + } + else if (dim == 3) + { + aSurfIn.height = Math.Max(1, surfaceHeight >> level); + aSurfIn.numSlices = Math.Max(6, surfaceDepth); + aSurfIn.flags.value |= 0x10; + } + else if (dim == 4) + { + aSurfIn.height = 1; + aSurfIn.numSlices = surfaceDepth; + } + else if (dim == 5) + { + aSurfIn.height = Math.Max(1, surfaceHeight >> level); + aSurfIn.numSlices = surfaceDepth; + } + else if (dim == 6) + { + aSurfIn.height = Math.Max(1, surfaceHeight >> level); + aSurfIn.numSlices = 1; + } + else if (dim == 7) + { + aSurfIn.height = Math.Max(1, surfaceHeight >> level); + aSurfIn.numSlices = surfaceDepth; } } - return result; + pSurfOut.size = 96; + computeSurfaceInfo(aSurfIn, pSurfOut); - //memcpy(data, result.data(), result.size()); + pSurfOut = pOut; + + return pSurfOut; } } } diff --git a/Switch_FileFormatsMain/FileFormats/Texture/NUTEXB.cs b/Switch_FileFormatsMain/FileFormats/Texture/NUTEXB.cs new file mode 100644 index 00000000..56b37058 --- /dev/null +++ b/Switch_FileFormatsMain/FileFormats/Texture/NUTEXB.cs @@ -0,0 +1,470 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Drawing; +using System.Threading.Tasks; +using Switch_Toolbox; +using System.Windows.Forms; +using Switch_Toolbox.Library; +using Switch_Toolbox.Library.IO; +using Switch_Toolbox.Library.Forms; + +namespace FirstPlugin +{ + public class NUTEXB : 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[] { "TEX" }; + public string[] Extension { get; set; } = new string[] { "*.nutexb" }; + public string Magic { get; set; } = "XET"; + public CompressionType CompressionType { get; set; } = CompressionType.None; + public byte[] Data { get; set; } + public string FileName { get; set; } + public TreeNodeFile EditorRoot { 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 enum NUTEXImageFormat : uint + { + R8G8B8A8_UNORM = 0x00, + R8G8B8A8_SRGB = 0x05, + BC1_UNORM = 0x80, + BC1_SRGB = 0x85, + BC2_UNORM = 0x90, + BC2_SRGB = 0x95, + BC3_UNORM = 0xa0, + BC3_SRGB = 0xa5, + BC4_UNORM = 0xb0, + BC4_SNORM = 0xb5, + BC5_UNORM = 0xc0, + BC5_SNORM = 0xc5, + BC6_UFLOAT = 0xd7, + BC7_UNORM = 0xe0, + BC7_SRGB = 0xe5, + }; + + public static uint blk_dims(byte format) + { + switch (format) + { + case (byte)NUTEXImageFormat.BC1_UNORM: + case (byte)NUTEXImageFormat.BC1_SRGB: + case (byte)NUTEXImageFormat.BC2_UNORM: + case (byte)NUTEXImageFormat.BC2_SRGB: + case (byte)NUTEXImageFormat.BC3_UNORM: + case (byte)NUTEXImageFormat.BC3_SRGB: + case (byte)NUTEXImageFormat.BC4_UNORM: + case (byte)NUTEXImageFormat.BC4_SNORM: + case (byte)NUTEXImageFormat.BC5_UNORM: + case (byte)NUTEXImageFormat.BC5_SNORM: + case (byte)NUTEXImageFormat.BC6_UFLOAT: + case (byte)NUTEXImageFormat.BC7_UNORM: + case (byte)NUTEXImageFormat.BC7_SRGB: + return 0x44; + + default: return 0x11; + } + } + + public static uint bpps(byte format) + { + switch (format) + { + case (byte)NUTEXImageFormat.R8G8B8A8_UNORM: + case (byte)NUTEXImageFormat.R8G8B8A8_SRGB: + return 4; + + case (byte)NUTEXImageFormat.BC1_UNORM: + case (byte)NUTEXImageFormat.BC1_SRGB: + case (byte)NUTEXImageFormat.BC4_UNORM: + case (byte)NUTEXImageFormat.BC4_SNORM: + return 8; + + case (byte)NUTEXImageFormat.BC2_UNORM: + case (byte)NUTEXImageFormat.BC2_SRGB: + case (byte)NUTEXImageFormat.BC3_UNORM: + case (byte)NUTEXImageFormat.BC3_SRGB: + case (byte)NUTEXImageFormat.BC5_UNORM: + case (byte)NUTEXImageFormat.BC5_SNORM: + case (byte)NUTEXImageFormat.BC6_UFLOAT: + case (byte)NUTEXImageFormat.BC7_UNORM: + case (byte)NUTEXImageFormat.BC7_SRGB: + return 16; + default: return 0x00; + } + } + + public Type[] Types + { + get + { + List types = new List(); + types.Add(typeof(MenuExt)); + return types.ToArray(); + } + } + class MenuExt : IFileMenuExtension + { + public ToolStripItemDark[] NewFileMenuExtensions => null; + public ToolStripItemDark[] ToolsMenuExtensions => newFileExt; + public ToolStripItemDark[] TitleBarExtensions => null; + public ToolStripItemDark[] CompressionMenuExtensions => null; + public ToolStripItemDark[] ExperimentalMenuExtensions => null; + + ToolStripItemDark[] newFileExt = new ToolStripItemDark[1]; + public MenuExt() + { + newFileExt[0] = new ToolStripItemDark("Batch Export NUTEXB"); + newFileExt[0].Click += Export; + } + private void Export(object sender, EventArgs args) + { + OpenFileDialog ofd = new OpenFileDialog(); + ofd.Multiselect = true; + + if (ofd.ShowDialog() == DialogResult.OK) + { + foreach (string file in ofd.FileNames) + { + NuTex texture = new NuTex(); + texture.Read(new FileReader(file)); + + Console.WriteLine(texture.Format.ToString("x") + " " + file + " " + texture.Text); + + /* + try + { + Bitmap bitmap = texture.DisplayImage(); + + if (bitmap != null) + bitmap.Save(System.IO.Path.GetDirectoryName(ofd.FileName) + texture.Text + ".png"); + else + Console.WriteLine(" Not supported Format! " + texture.Format); + + if (bitmap != null) + bitmap.Dispose(); + } + catch + { + Console.WriteLine(); + } + texture = null; + GC.Collect();*/ + } + } + } + } + public class NuTex : TreeNodeFile + { + public uint Width; + public uint Height; + public byte Format; + public uint[] mipSizes; + public uint Alignment; + public List> mipmaps = new List>(); + public List> blocksCompressed = new List>(); + bool IsSwizzled = true; + + MenuItem export = new MenuItem("Export"); + + public NuTex() + { + ImageKey = "Texture"; + SelectedImageKey = "Texture"; + + ContextMenu = new ContextMenu(); + ContextMenu.MenuItems.Add(export); + + export.Click += Export; + } + private void Export(object sender, EventArgs args) + { + SaveFileDialog sfd = new SaveFileDialog(); + sfd.FileName = Text; + sfd.DefaultExt = "png"; + sfd.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(*.*)|*.*"; + + 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(SurfaceLevel, MipLevel); + + bitMap.Save(FileName); + } + internal void SaveDDS(string FileName) + { + DDS dds = new DDS(); + dds.header = new DDS.Header(); + dds.header.width = Width; + dds.header.height = Height; + dds.header.mipmapCount = (uint)mipmaps.Count; + + bool IsDX10 = false; + + IsDX10 = true; + dds.DX10header = new DDS.DX10Header(); + dds.DX10header.DXGI_Format = DDS.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM; + + if (IsDX10) + dds.header.ddspf.fourCC = "DX10"; + + dds.Save(dds, FileName, IsDX10, mipmaps); + } + public void Read(FileReader reader) + { + ImageKey = "Texture"; + SelectedImageKey = "Texture"; + + long pos = reader.BaseStream.Length; + string magic = reader.ReadMagic((int)pos - 7, 3);//Check magic first! + + if (magic != "XET") + throw new Exception($"Invalid magic! Expected XET but got {magic}"); + + reader.Seek(pos - 112, System.IO.SeekOrigin.Begin); //Subtract size where the name occurs + byte padding = reader.ReadByte(); + Text = reader.ReadString(Syroot.BinaryData.BinaryStringFormat.ZeroTerminated); + + reader.Seek(pos - 48, System.IO.SeekOrigin.Begin); //Subtract size of header + uint padding2 = reader.ReadUInt32(); + Width = reader.ReadUInt32(); + Height = reader.ReadUInt32(); + uint ArrayCount = reader.ReadUInt32(); //6 for cubemaps + Format = reader.ReadByte(); + byte unk = reader.ReadByte(); //Might be unorm/snorm/srgb + ushort padding3 = reader.ReadUInt16(); + uint unk2 = reader.ReadUInt32(); + uint mipCount = reader.ReadUInt32(); + Alignment = reader.ReadUInt32(); + int unk3 = reader.ReadInt32(); + int imagesize = reader.ReadInt32(); + + reader.Seek(pos - 176, System.IO.SeekOrigin.Begin); //Get mipmap sizes + mipSizes = reader.ReadUInt32s((int)mipCount); + + List mips = new List(); + reader.Seek(0, System.IO.SeekOrigin.Begin); + + if (mipCount == 1 && IsSwizzled) + { + mips.Add(reader.ReadBytes((int)imagesize)); + blocksCompressed.Add(mips); + } + else + { + for (int arrayLevel = 0; arrayLevel < ArrayCount; arrayLevel++) + { + for (int mipLevel = 0; mipLevel < mipCount; mipLevel++) + { + mips.Add(reader.ReadBytes((int)mipSizes[mipLevel])); + break; //Don't load mip maps yet. They break for some reason???? + } + blocksCompressed.Add(mips); + } + } + } + + public override void OnClick(TreeView treeView) + { + UpdateEditor(); + } + + public Bitmap DisplayTexture(int DisplayMipIndex = 0, int ArrayIndex = 0) + { + if (IsSwizzled) + LoadTexture(); + else + mipmaps.Add(blocksCompressed[0]); + + if (mipmaps.Count <= 0) + { + throw new Exception("No texture data found"); + } + + uint width = (uint)Math.Max(1, Width >> DisplayMipIndex); + uint height = (uint)Math.Max(1, Height >> DisplayMipIndex); + + byte[] data = mipmaps[ArrayIndex][DisplayMipIndex]; + return DecodeBlock(data, width, height, (NUTEXImageFormat)Format); + } + public static Bitmap DecodeBlock(byte[] data, uint Width, uint Height, NUTEXImageFormat Format) + { + Bitmap decomp; + + if (Format == NUTEXImageFormat.BC5_SNORM) + 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 + d = DDSCompressor.DecodePixelBlock(data, (int)Width, (int)Height, GetUncompressedDXGI_FORMAT(Format)); + + if (d != null) + { + decomp = BitmapExtension.GetBitmap(d, (int)Width, (int)Height); + return TextureData.SwapBlueRedChannels(decomp); + } + return null; + } + private static DDS.DXGI_FORMAT GetUncompressedDXGI_FORMAT(NUTEXImageFormat Format) + { + switch (Format) + { + case NUTEXImageFormat.R8G8B8A8_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM; + case NUTEXImageFormat.R8G8B8A8_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + default: + throw new Exception($"Cannot convert format {Format}"); + } + } + private static DDS.DXGI_FORMAT GetCompressedDXGI_FORMAT(NUTEXImageFormat Format) + { + switch (Format) + { + case NUTEXImageFormat.BC1_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM; + case NUTEXImageFormat.BC1_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM_SRGB; + case NUTEXImageFormat.BC2_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM; + case NUTEXImageFormat.BC2_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM_SRGB; + case NUTEXImageFormat.BC3_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM; + case NUTEXImageFormat.BC3_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM_SRGB; + case NUTEXImageFormat.BC4_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM; + case NUTEXImageFormat.BC4_SNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_SNORM; + case NUTEXImageFormat.BC5_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM; + case NUTEXImageFormat.BC5_SNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC5_SNORM; + case NUTEXImageFormat.BC6_UFLOAT: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC6H_UF16; + case NUTEXImageFormat.BC7_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM; + case NUTEXImageFormat.BC7_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB; + default: + throw new Exception($"Cannot convert format {Format}"); + } + } + private static bool IsCompressedFormat(NUTEXImageFormat Format) + { + switch (Format) + { + case NUTEXImageFormat.BC1_UNORM: + case NUTEXImageFormat.BC1_SRGB: + case NUTEXImageFormat.BC2_UNORM: + case NUTEXImageFormat.BC2_SRGB: + case NUTEXImageFormat.BC3_UNORM: + case NUTEXImageFormat.BC3_SRGB: + case NUTEXImageFormat.BC4_UNORM: + case NUTEXImageFormat.BC4_SNORM: + case NUTEXImageFormat.BC5_UNORM: + case NUTEXImageFormat.BC5_SNORM: + case NUTEXImageFormat.BC6_UFLOAT: + case NUTEXImageFormat.BC7_UNORM: + case NUTEXImageFormat.BC7_SRGB: + return true; + default: + return false; + } + } + + public void LoadTexture(int target = 1) + { + mipmaps.Clear(); + + uint blk_dim = blk_dims(Format); + uint blkWidth = blk_dim >> 4; + uint blkHeight = blk_dim & 0xF; + + uint blockHeight = TegraX1Swizzle.GetBlockHeight(TegraX1Swizzle.DIV_ROUND_UP(Height, blkHeight)); + uint BlockHeightLog2 = (uint)Convert.ToString(blockHeight, 2).Length - 1; + uint tileMode = 0; + + int linesPerBlockHeight = (1 << (int)BlockHeightLog2) * 8; + + uint bpp = bpps(Format); + + for (int arrayLevel = 0; arrayLevel < blocksCompressed.Count; arrayLevel++) + { + int blockHeightShift = 0; + + List mips = new List(); + for (int mipLevel = 0; mipLevel < blocksCompressed[arrayLevel].Count; mipLevel++) + { + uint width = (uint)Math.Max(1, Width >> mipLevel); + uint height = (uint)Math.Max(1, Height >> mipLevel); + + uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp; + + 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}"); + + byte[] result = TegraX1Swizzle.deswizzle(width, height, blkWidth, blkHeight, target, bpp, tileMode, (int)Math.Max(0, BlockHeightLog2 - blockHeightShift), blocksCompressed[arrayLevel][mipLevel]); + //Create a copy and use that to remove uneeded data + byte[] result_ = new byte[size]; + Array.Copy(result, 0, result_, 0, size); + + mips.Add(result_); + } + mipmaps.Add(mips); + } + } + + public void UpdateEditor() + { + if (Viewport.Instance.gL_ControlModern1.Visible == false) + PluginRuntime.FSHPDockState = WeifenLuo.WinFormsUI.Docking.DockState.Document; + + NuTexEditor docked = (NuTexEditor)LibraryGUI.Instance.GetContentDocked(new NuTexEditor()); + if (docked == null) + { + docked = new NuTexEditor(); + LibraryGUI.Instance.LoadDockContent(docked, PluginRuntime.FSHPDockState); + } + docked.Text = Text; + docked.Dock = DockStyle.Fill; + docked.LoadProperty(this); + } + } + + public void Load() + { + IsActive = true; + EditorRoot = new NuTex(); + ((NuTex)EditorRoot).FileHandler = this; + ((NuTex)EditorRoot).Read(new FileReader(Data)); + } + public void Unload() + { + + } + public byte[] Save() + { + return null; + } + } +} diff --git a/Switch_FileFormatsMain/FileFormats/Texture/XTX.cs b/Switch_FileFormatsMain/FileFormats/Texture/XTX.cs index 3e662faf..5f0a9955 100644 --- a/Switch_FileFormatsMain/FileFormats/Texture/XTX.cs +++ b/Switch_FileFormatsMain/FileFormats/Texture/XTX.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; -using System.Linq; +using System.IO; using System.Text; +using System.Drawing; using System.Threading.Tasks; using Switch_Toolbox; using System.Windows.Forms; using Switch_Toolbox.Library; +using Switch_Toolbox.Library.IO; namespace FirstPlugin { @@ -38,6 +40,10 @@ namespace FirstPlugin public void Load() { IsActive = true; + EditorRoot = new XTXFile(); + ((XTXFile)EditorRoot).FileHandler = this; + ((XTXFile)EditorRoot).Text = FileName; + ((XTXFile)EditorRoot).LoadFile(Data); } public void Unload() { @@ -47,5 +53,330 @@ namespace FirstPlugin { return null; } + + public class XTXFormats + { + public enum XTXImageFormat : uint + { + NVN_FORMAT_RGBA8 = 0x00000025, + NVN_FORMAT_RGBA8_SRGB = 0x00000038, + NVN_FORMAT_RGB10A2 = 0x0000003d, + NVN_FORMAT_RGB565 = 0x0000003c, + NVN_FORMAT_RGB5A1 = 0x0000003b, + NVN_FORMAT_RGBA4 = 0x00000039, + NVN_FORMAT_R8 = 0x00000001, + NVN_FORMAT_RG8 = 0x0000000d, + DXT1 = 0x00000042, + DXT3 = 0x00000043, + DXT5 = 0x00000044, + BC4U = 0x00000049, + BC4S = 0x0000004a, + BC5U = 0x0000004b, + BC5S = 0x0000004c, + }; + + public enum BNTXImageTypes + { + UNORM = 0x01, + SNORM = 0x02, + SRGB = 0x06, + }; + + public static uint blk_dims(uint format) + { + switch (format) + { + case (uint)XTXImageFormat.DXT1: + case (uint)XTXImageFormat.DXT3: + case (uint)XTXImageFormat.DXT5: + case (uint)XTXImageFormat.BC4U: + case (uint)XTXImageFormat.BC4S: + case (uint)XTXImageFormat.BC5U: + case (uint)XTXImageFormat.BC5S: + case 0x2d: + return 0x44; + + default: return 0x11; + } + } + + public static uint bpps(uint format) + { + switch (format) + { + case (uint)XTXImageFormat.NVN_FORMAT_R8: + return 1; + + case (uint)XTXImageFormat.NVN_FORMAT_RGBA8: + case (uint)XTXImageFormat.NVN_FORMAT_RGBA8_SRGB: + case (uint)XTXImageFormat.NVN_FORMAT_RGB10A2: + return 4; + + case (uint)XTXImageFormat.NVN_FORMAT_RGB565: + case (uint)XTXImageFormat.NVN_FORMAT_RGB5A1: + case (uint)XTXImageFormat.NVN_FORMAT_RGBA4: + case (uint)XTXImageFormat.NVN_FORMAT_RG8: + return 2; + + case (uint)XTXImageFormat.DXT1: + case (uint)XTXImageFormat.BC4S: + case (uint)XTXImageFormat.BC4U: + return 8; + + case (uint)XTXImageFormat.DXT3: + case (uint)XTXImageFormat.DXT5: + case (uint)XTXImageFormat.BC5U: + case (uint)XTXImageFormat.BC5S: + return 16; + default: return 0x00; + } + } + } + + public class XTXFile : TreeNodeFile + { + public uint HeaderSize { get; set; } + public uint MajorVersion { get; set; } + public uint MinorVersion { get; set; } + public BlockHeader blockHeader { get; set; } + private const int texHeadBlkType = 2; + private const int dataBlkType = 3; + + public void LoadFile(byte[] data) + { + FileReader reader = new FileReader(new MemoryStream(data)); + string Signature = reader.ReadString(4, Encoding.ASCII); + if (Signature != "DFvN") + throw new Exception($"Invalid signature {Signature}! Expected DFvN."); + + HeaderSize = reader.ReadUInt32(); + MajorVersion = reader.ReadUInt32(); + MinorVersion = reader.ReadUInt32(); + + blockHeader = new BlockHeader(); + blockHeader.Read(reader); + } + + public override void OnClick(TreeView treeview) + { + UpdateEditor(); + } + + public void UpdateEditor() + { + NuTexEditor docked = (NuTexEditor)LibraryGUI.Instance.GetContentDocked(new NuTexEditor()); + if (docked == null) + { + docked = new NuTexEditor(); + LibraryGUI.Instance.LoadDockContent(docked, PluginRuntime.FSHPDockState); + } + docked.Text = Text; + docked.Dock = DockStyle.Fill; + } + + public class BlockHeader + { + public uint BlockSize { get; set; } + public UInt64 DataSize { get; set; } + public uint BlockType { get; set; } + public uint GlobalBlockIndex { get; set; } + public uint IncBlockTypeIndex { get; set; } + public TextureInfo textureInfo { get; set; } + public long DataOffset; + + public void Read(FileReader reader) + { + string Signature = reader.ReadString(4, Encoding.ASCII); + if (Signature != "HBvN") + throw new Exception($"Invalid signature {Signature}! Expected HBvN."); + + BlockSize = reader.ReadUInt32(); + DataSize = reader.ReadUInt64(); + DataOffset = reader.ReadInt64(); + BlockType = reader.ReadUInt32(); + GlobalBlockIndex = reader.ReadUInt32(); + IncBlockTypeIndex = reader.ReadUInt32(); + + if (BlockType == texHeadBlkType) + { + textureInfo = new TextureInfo(); + textureInfo.Read(reader); + } + if (BlockType == dataBlkType) + { + + } + } + } + public class TextureInfo : TreeNodeFile + { + public UInt64 DataSize { get; set; } + public uint Alignment { get; set; } + public uint Width { get; set; } + public uint Height { get; set; } + public uint Depth { get; set; } + public uint Target { get; set; } + public XTXFormats.XTXImageFormat Format { get; set; } + public uint MipCount { get; set; } + public uint SliceSize { get; set; } + public uint[] MipOffsets { get; set; } + public BlockHeader DataBlockHeader { get; set; } + public List mipmaps = new List(); + public byte[] data; + + public void Read(FileReader reader) + { + DataSize = reader.ReadUInt64(); + Alignment = reader.ReadUInt32(); + Width = reader.ReadUInt32(); + Height = reader.ReadUInt32(); + Depth = reader.ReadUInt32(); + Target = reader.ReadUInt32(); + Format = reader.ReadEnum(true); + MipCount = reader.ReadUInt32(); + SliceSize = reader.ReadUInt32(); + long offPos = reader.Position; + MipOffsets = reader.ReadUInt32s((int)MipCount); + + reader.Seek(offPos + 68, SeekOrigin.Begin); + byte[] Layout = reader.ReadBytes(8); + byte Sparse = reader.ReadByte(); + reader.Seek(3); + long DataBlockOff = reader.Position; + + DataBlockHeader = new BlockHeader(); + DataBlockHeader.Read(reader); + + reader.Seek(DataBlockOff + DataBlockHeader.DataOffset, SeekOrigin.Begin); + data = reader.ReadBytes((int)DataBlockHeader.DataSize); + + BlockHeader EndBlockHeader = new BlockHeader(); + EndBlockHeader.Read(reader); + } + + public Bitmap DisplayImage(int mipLevel = 0, int arrayLevel = 0) + { + LoadTexture(); + + Bitmap decomp; + + if (Format == XTXFormats.XTXImageFormat.BC5S) + return DDSCompressor.DecompressBC5(mipmaps[0], (int)Width, (int)Height, true); + + byte[] d = null; + if (IsCompressedFormat(Format)) + d = DDSCompressor.DecompressBlock(mipmaps[0], (int)Width, (int)Height, GetCompressedDXGI_FORMAT(Format)); + else + d = DDSCompressor.DecodePixelBlock(mipmaps[0], (int)Width, (int)Height, GetUncompressedDXGI_FORMAT(Format)); + + if (d != null) + { + decomp = BitmapExtension.GetBitmap(d, (int)Width, (int)Height); + return TextureData.SwapBlueRedChannels(decomp); + } + return null; + } + private static DDS.DXGI_FORMAT GetCompressedDXGI_FORMAT(XTXFormats.XTXImageFormat Format) + { + switch (Format) + { + case XTXFormats.XTXImageFormat.DXT1: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM; + case XTXFormats.XTXImageFormat.DXT3: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM; + case XTXFormats.XTXImageFormat.DXT5: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM; + case XTXFormats.XTXImageFormat.BC4U: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM; + case XTXFormats.XTXImageFormat.BC4S: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_SNORM; + case XTXFormats.XTXImageFormat.BC5U: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM; + case XTXFormats.XTXImageFormat.BC5S: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC5_SNORM; + default: + throw new Exception($"Cannot convert format {Format}"); + } + } + private static bool IsCompressedFormat(XTXFormats.XTXImageFormat Format) + { + switch (Format) + { + case XTXFormats.XTXImageFormat.DXT1: + case XTXFormats.XTXImageFormat.DXT3: + case XTXFormats.XTXImageFormat.DXT5: + case XTXFormats.XTXImageFormat.BC4U: + case XTXFormats.XTXImageFormat.BC4S: + case XTXFormats.XTXImageFormat.BC5U: + case XTXFormats.XTXImageFormat.BC5S: + return true; + default: + return false; + } + } + private static DDS.DXGI_FORMAT GetUncompressedDXGI_FORMAT(XTXFormats.XTXImageFormat Format) + { + switch (Format) + { + case XTXFormats.XTXImageFormat.NVN_FORMAT_R8: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8_UNORM; + case XTXFormats.XTXImageFormat.NVN_FORMAT_RG8: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8_UNORM; + case XTXFormats.XTXImageFormat.NVN_FORMAT_RGB10A2: return DDS.DXGI_FORMAT.DXGI_FORMAT_R10G10B10A2_UNORM; + case XTXFormats.XTXImageFormat.NVN_FORMAT_RGB565: return DDS.DXGI_FORMAT.DXGI_FORMAT_B5G6R5_UNORM; + case XTXFormats.XTXImageFormat.NVN_FORMAT_RGB5A1: return DDS.DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM; + case XTXFormats.XTXImageFormat.NVN_FORMAT_RGBA4: return DDS.DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM; + case XTXFormats.XTXImageFormat.NVN_FORMAT_RGBA8: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM; + case XTXFormats.XTXImageFormat.NVN_FORMAT_RGBA8_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + default: + throw new Exception($"Cannot convert format {Format}"); + } + } + + public void LoadTexture() + { + mipmaps.Clear(); + + Console.WriteLine(Format); + + uint blk_dim = XTXFormats.blk_dims((uint)((int)Format >> 8)); + uint blkWidth = blk_dim >> 4; + uint blkHeight = blk_dim & 0xF; + + uint blockHeight = TegraX1Swizzle.GetBlockHeight(TegraX1Swizzle.DIV_ROUND_UP(Height, blkHeight)); + uint BlockHeightLog2 = (uint)Convert.ToString(blockHeight, 2).Length - 1; + + int linesPerBlockHeight = (1 << (int)BlockHeightLog2) * 8; + + int TileMode = 0; + + uint bpp = XTXFormats.bpps((uint)Format); + + int blockHeightShift = 0; + for (int mipLevel = 0; mipLevel < MipCount; 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[] mipData = GetMipBlock(MipOffsets[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), mipData); + //Create a copy and use that to remove uneeded data + byte[] result_ = new byte[size]; + Array.Copy(result, 0, result_, 0, size); + + mipmaps.Add(result_); + Console.WriteLine("bpp " + bpp); + Console.WriteLine("result_ " + size); + Console.WriteLine("width " + width); + Console.WriteLine("height " + height); + } + } + private byte[] GetMipBlock(uint offset, uint Size) + { + FileReader reader = new FileReader(new MemoryStream(data)); + reader.Seek(offset, SeekOrigin.Begin); + return reader.ReadBytes((int)Size); + } + } + + } } } diff --git a/Switch_FileFormatsMain/GUI/BFRES/BfresMaterialEditor.cs b/Switch_FileFormatsMain/GUI/BFRES/BfresMaterialEditor.cs index 6953d464..8cd9fd73 100644 --- a/Switch_FileFormatsMain/GUI/BFRES/BfresMaterialEditor.cs +++ b/Switch_FileFormatsMain/GUI/BFRES/BfresMaterialEditor.cs @@ -481,6 +481,9 @@ namespace FirstPlugin private void btnSamplerEditor_Click(object sender, EventArgs e) { + if (textureRefListView.SelectedItems.Count <= 0) + return; + SamplerEditor samplerEditor = new SamplerEditor(); foreach (MatTexture tex in material.textures) { @@ -489,7 +492,6 @@ namespace FirstPlugin samplerEditor.LoadSampler(tex); } } - if (samplerEditor.ShowDialog() == DialogResult.OK) { @@ -499,9 +501,9 @@ namespace FirstPlugin private void textureRefListView_SelectedIndexChanged(object sender, EventArgs e) { if (textureRefListView.SelectedItems.Count > 0) - { btnSamplerEditor.Enabled = true; - } + else + btnSamplerEditor.Enabled = false; } private void shaderOptionsListView_ColumnClick(object sender, ColumnClickEventArgs e) diff --git a/Switch_FileFormatsMain/GUI/NuTexEditor.Designer.cs b/Switch_FileFormatsMain/GUI/NuTexEditor.Designer.cs new file mode 100644 index 00000000..1a46f28c --- /dev/null +++ b/Switch_FileFormatsMain/GUI/NuTexEditor.Designer.cs @@ -0,0 +1,353 @@ +namespace FirstPlugin +{ + partial class NuTexEditor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(NuTexEditor)); + 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.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.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.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); + this.replaceSurfaceLevelToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.exportSurfaceLevelToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.panel1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.panel4.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxCustom1)).BeginInit(); + this.panel3.SuspendLayout(); + this.contextMenuStrip1.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.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; + // + // 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); + // + // 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); + // + // contextMenuStrip1 + // + this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.replaceSurfaceLevelToolStripMenuItem, + this.exportSurfaceLevelToolStripMenuItem}); + this.contextMenuStrip1.Name = "contextMenuStrip1"; + this.contextMenuStrip1.Size = new System.Drawing.Size(188, 48); + // + // replaceSurfaceLevelToolStripMenuItem + // + this.replaceSurfaceLevelToolStripMenuItem.Name = "replaceSurfaceLevelToolStripMenuItem"; + this.replaceSurfaceLevelToolStripMenuItem.Size = new System.Drawing.Size(187, 22); + this.replaceSurfaceLevelToolStripMenuItem.Text = "Replace Surface Level"; + // + // exportSurfaceLevelToolStripMenuItem + // + this.exportSurfaceLevelToolStripMenuItem.Name = "exportSurfaceLevelToolStripMenuItem"; + this.exportSurfaceLevelToolStripMenuItem.Size = new System.Drawing.Size(187, 22); + this.exportSurfaceLevelToolStripMenuItem.Text = "Export Surface Level"; + // + // NuTexEditor + // + 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 = "NuTexEditor"; + 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.contextMenuStrip1.ResumeLayout(false); + 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.ContextMenuStrip contextMenuStrip1; + private System.Windows.Forms.ToolStripMenuItem replaceSurfaceLevelToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem exportSurfaceLevelToolStripMenuItem; + } +} diff --git a/Switch_FileFormatsMain/GUI/NuTexEditor.cs b/Switch_FileFormatsMain/GUI/NuTexEditor.cs new file mode 100644 index 00000000..59f6287c --- /dev/null +++ b/Switch_FileFormatsMain/GUI/NuTexEditor.cs @@ -0,0 +1,207 @@ +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 NuTexEditor : UserControl + { + private Thread Thread; + + public NuTexEditor() + { + InitializeComponent(); + + foreach (var type in Enum.GetValues(typeof(Runtime.PictureBoxBG)).Cast()) + imageBGComboBox.Items.Add(type); + + imageBGComboBox.SelectedItem = Runtime.pictureBoxStyle; + UpdateBackgroundImage(); + } + + NUTEXB.NuTex textureData; + int CurMipDisplayLevel = 0; + int CurArrayDisplayLevel = 0; + + class PropGridData + { + public string Name { get; set; } + public string Format { get; set; } + public uint Width { get; set; } + public uint Height { get; set; } + public uint MipCount { get; set; } + public uint ArrayCount { get; set; } + } + + public void LoadProperty(NUTEXB.NuTex tex) + { + pictureBoxCustom1.Image = Imaging.GetLoadingImage(); + LoadImage(); + + CurMipDisplayLevel = 0; + CurArrayDisplayLevel = 0; + + textureData = tex; + + UpdateMipDisplay(); + + PropGridData prop = new PropGridData(); + prop.Name = textureData.Text; + prop.Width = textureData.Width; + prop.Height = textureData.Height; + // prop.MipCount = (uint)textureData.blocksCompressed[0].Count; + // prop.ArrayCount = (uint)textureData.blocksCompressed.Count; + prop.Height = textureData.Height; + + prop.Format = ((NUTEXB.NUTEXImageFormat)textureData.Format).ToString(); + + propertyGrid1.PropertySort = PropertySort.Categorized; + propertyGrid1.SelectedObject = prop; + } + private void LoadImage() + { + if (Thread != null && Thread.IsAlive) + Thread.Abort(); + + Thread = new Thread((ThreadStart)(() => + { + pictureBoxCustom1.Image = textureData.DisplayTexture(CurMipDisplayLevel, CurArrayDisplayLevel); + })); + Thread.Start(); + + GC.Collect(); + } + private void UpdateMipDisplay() + { + LoadImage(); + + int MipCount = 1; + if (textureData.mipmaps.Count <= 0) + return; + else + MipCount = textureData.mipmaps[CurArrayDisplayLevel].Count; + + + mipLevelCounterLabel.Text = $"{CurMipDisplayLevel} / {textureData.mipmaps[CurArrayDisplayLevel].Count - 1}"; + arrayLevelCounterLabel.Text = $"{CurArrayDisplayLevel} / {textureData.mipmaps.Count - 1}"; + + if (CurMipDisplayLevel != MipCount - 1) + BtnMipsRight.Enabled = true; + else + BtnMipsRight.Enabled = false; + + if (CurMipDisplayLevel != 0) + BtmMipsLeft.Enabled = true; + else + BtmMipsLeft.Enabled = false; + + if (CurArrayDisplayLevel != textureData.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.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.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); + contextMenuStrip1.Show(ptLowerLeft); + } + } +} diff --git a/Switch_FileFormatsMain/GUI/NuTexEditor.resx b/Switch_FileFormatsMain/GUI/NuTexEditor.resx new file mode 100644 index 00000000..3572d1d7 --- /dev/null +++ b/Switch_FileFormatsMain/GUI/NuTexEditor.resx @@ -0,0 +1,331 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAACJuGjuAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6 + JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAADAFBMVEXMzMzNzc3Ozs7Pz8/Q0NDR0dHS + 0tLT09PU1NTV1dXW1tbX19fY2NjZ2dna2trb29vc3Nzd3d3e3t7f39/g4ODh4eHi4uLj4+Pk5OTl5eXm + 5ubn5+fo6Ojp6enq6urr6+vs7Ozt7e3u7u7v7+/w8PDx8fHy8vLz8/P09PT19fX29vb39/f4+Pj5+fn6 + +vr7+/v8/Pz9/f3+/v7///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDTbOhAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGXRF + 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 + + + + 17, 17 + + \ No newline at end of file diff --git a/Switch_FileFormatsMain/GUI/TexturePatternEditor.Designer.cs b/Switch_FileFormatsMain/GUI/TexturePatternEditor.Designer.cs new file mode 100644 index 00000000..9aa9512f --- /dev/null +++ b/Switch_FileFormatsMain/GUI/TexturePatternEditor.Designer.cs @@ -0,0 +1,129 @@ +namespace FirstPlugin.GUI +{ + partial class TexturePatternEditor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.listView1 = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.listView2 = new System.Windows.Forms.ListView(); + this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.panel1 = new System.Windows.Forms.Panel(); + this.panel2 = new System.Windows.Forms.Panel(); + this.panel1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.SuspendLayout(); + // + // listView1 + // + this.listView1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2}); + this.listView1.Location = new System.Drawing.Point(281, 0); + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(289, 480); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + // + // columnHeader1 + // + this.columnHeader1.Text = "Frame"; + this.columnHeader1.Width = 104; + // + // columnHeader2 + // + this.columnHeader2.Text = "Texture"; + this.columnHeader2.Width = 168; + // + // listView2 + // + this.listView2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.listView2.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader3}); + this.listView2.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView2.Location = new System.Drawing.Point(0, 0); + this.listView2.Name = "listView2"; + this.listView2.Size = new System.Drawing.Size(282, 479); + this.listView2.TabIndex = 1; + this.listView2.UseCompatibleStateImageBehavior = false; + this.listView2.View = System.Windows.Forms.View.Details; + this.listView2.SelectedIndexChanged += new System.EventHandler(this.listView2_SelectedIndexChanged); + // + // columnHeader3 + // + this.columnHeader3.Text = "Material"; + this.columnHeader3.Width = 190; + // + // panel1 + // + this.panel1.Controls.Add(this.listView2); + this.panel1.Dock = System.Windows.Forms.DockStyle.Left; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(282, 479); + this.panel1.TabIndex = 3; + // + // panel2 + // + this.panel2.Dock = System.Windows.Forms.DockStyle.Right; + this.panel2.Location = new System.Drawing.Point(576, 0); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(284, 479); + this.panel2.TabIndex = 4; + // + // TexturePatternEditor + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.ClientSize = new System.Drawing.Size(860, 479); + this.Controls.Add(this.panel2); + this.Controls.Add(this.panel1); + this.Controls.Add(this.listView1); + this.ForeColor = System.Drawing.Color.White; + this.Name = "TexturePatternEditor"; + this.Text = "TexturePatternEditor"; + this.panel1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.ColumnHeader columnHeader2; + private System.Windows.Forms.ListView listView2; + private System.Windows.Forms.ColumnHeader columnHeader3; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Panel panel2; + } +} \ No newline at end of file diff --git a/Switch_FileFormatsMain/GUI/TexturePatternEditor.cs b/Switch_FileFormatsMain/GUI/TexturePatternEditor.cs new file mode 100644 index 00000000..3947b745 --- /dev/null +++ b/Switch_FileFormatsMain/GUI/TexturePatternEditor.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace FirstPlugin.GUI +{ + public partial class TexturePatternEditor : Form + { + public TexturePatternEditor() + { + InitializeComponent(); + } + + private void listView2_SelectedIndexChanged(object sender, EventArgs e) + { + + } + } +} diff --git a/Switch_FileFormatsMain/GUI/TexturePatternEditor.resx b/Switch_FileFormatsMain/GUI/TexturePatternEditor.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/Switch_FileFormatsMain/GUI/TexturePatternEditor.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Switch_FileFormatsMain/Main.cs b/Switch_FileFormatsMain/Main.cs index 5a4a4090..6d2fa2e8 100644 --- a/Switch_FileFormatsMain/Main.cs +++ b/Switch_FileFormatsMain/Main.cs @@ -123,8 +123,8 @@ namespace FirstPlugin Formats.Add(typeof(BFLYT)); Formats.Add(typeof(CsvModel)); Formats.Add(typeof(GFPAK)); + Formats.Add(typeof(NUTEXB)); - return Formats.ToArray(); } #endregion diff --git a/Switch_FileFormatsMain/Switch_FileFormatsMain.csproj b/Switch_FileFormatsMain/Switch_FileFormatsMain.csproj index fab5e50c..8603e5fb 100644 --- a/Switch_FileFormatsMain/Switch_FileFormatsMain.csproj +++ b/Switch_FileFormatsMain/Switch_FileFormatsMain.csproj @@ -172,6 +172,7 @@ + @@ -266,6 +267,18 @@ BfresShapeEditor.cs + + UserControl + + + NuTexEditor.cs + + + Form + + + TexturePatternEditor.cs + UserControl @@ -405,6 +418,12 @@ BfresShapeEditor.cs + + NuTexEditor.cs + + + TexturePatternEditor.cs + FTEXEditor.cs diff --git a/Switch_Toolbox/Lib/Syroot.NintenTools.Bfres.dll b/Switch_Toolbox/Lib/Syroot.NintenTools.Bfres.dll index a4f90f61cc6b8a7db990654a8b5936c3a47c77b6..1e49e56d87646667990644d2044ae751cb1be8a3 100644 GIT binary patch literal 191488 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 }>Md0mQw4;It+u+Mvpr484da^IV` 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 z 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 + + + Syroot.NintenTools.Bfres + + + + + Represents an animation curve used by several sections to control different parameters over time. + + + + + Gets or sets the data type in which are loaded and saved. For simplicity, the class + always stores frames as converted instances. + + + + + Gets or sets the data type in which are loaded and saved. For simplicity, the class + always stores frames as converted instances. + + + + + Gets or sets the curve type, determining the number of elements stored with each key. + + + + + Gets or sets the memory offset relative to the start of the corresponding animation data structure to + animate the field stored at that address. Note that enums exist in the specific animation which map offsets + to names. + + + + + Gets or sets the first frame at which a key is placed. + + + + + Gets or sets the last frame at which a key is placed. + + + + + Gets or sets the scale to multiply values of the curve by. + + + + + Gets or sets the offset to add to the values of the curve (after multiplicating them). + + + + + Gets or sets the difference between the lowest and highest key value. + + + + + Gets the frame numbers at which keys of the same index in the array are placed. + + + + + Gets an array of elements forming the elements of keys placed at the frames of the same index in the + array. + + + + + Represents the possible data types in which are stored. For simple library use, + they are always converted them to and from instances. + + + + + The frames are stored as instances. + + + + + The frames are stored as instances. + + + + + The frames are stored as instances. + + + + + Represents the possible data types in which are stored. For simple library use, + they are always converted them to and from instances. + + + + + The keys are stored as instances. + + + + + The keys are stored as instances. + + + + + The keys are stored as instances. + + + + + Represents the type of key values stored by this curve. This also determines the number of required elements to + define a key in the array. Use the + method to retrieve the number of elements required for the of that curve. + + + + + The curve uses cubic interpolation. 4 elements of the array form a key. + + + + + The curve uses linear interpolation. 2 elements of the array form a key. + + + + + 1 element of the array forms a key. + + + + + 1 element of the array forms a key. + + + + + 1 element of the array forms a key. + + + + + 1 element of the array forms a key. + + + + + 1 element of the array forms a key. + + + + + Gets or sets the memory offset relative to the start of the corresponding animation data structure to + animate the field stored at that address. Note that enums exist in the specific animation which map offsets + to names. + + + + + Represents a buffer of data uploaded to the GX2 GPU which can hold arbitrary data. + + + + + The size of a full vertex in bytes. + + + + + The raw bytes stored for each buffering. + + + + + Represents a 16-bit fixed-point decimal consisting of 1 sign bit, 10 integer bits and 5 fractional bits (denoted + as Q10.5). Note that the implementation is not reporting over- and underflowing errors. + + + Examples: + SIIIIIII_IIIFFFFF + 0b00000000_00010000 = 0.5 + 0b00000000_00100000 = 1 + 0b00000001_00000000 = 8 + 0b01000000_00000000 = 512 + 0b10000000_00000000 = -1024 + + + + + Represents the largest possible value of . + + + + + Represents the smallest possible value of . + + + + + Initializes a new instance of the struct from the given + representation. + + The raw representation of the internally stored bits. + + + + Gets the internally stored value to represent the instance. + + Signed to get arithmetic rather than logical shifts. + + + + Returns the given . + + The . + The result. + + + + Adds the first to the second one. + + The first . + The second . + The addition result. + + + + Negates the given . + + The to negate. + The negated result. + + + + Subtracts the first from the second one. + + The first . + The second . + The subtraction result. + + + + Multiplicates the given by the scalar. + + The . + The scalar. + The multiplication result. + + + + Multiplicates the first by the second one. + + The first . + The second . + The multiplication result. + + + + Divides the given through the scalar. + + The . + The scalar. + The division result. + + + + Divides the first through the second one. + + The first . + The second . + The division result. + + + + Gets a value indicating whether the first specified is the same as the second + specified . + + The first to compare. + The second to compare. + true, if both are the same. + + + + Gets a value indicating whether the first specified is not the same as the second + specified . + + The first to compare. + The second to compare. + true, if both are not the same. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Gets a value indicating whether this is the same as the second specified + . + + The object to compare, if it is a . + true, if both are the same. + + + + Gets a hash code as an indication for object equality. + + The hash code. + + + + Gets a string describing this . + + A string describing this . + + + + Indicates whether the current is equal to another . + + A to compare with this . + true if the current is equal to the other parameter; otherwise, false. + + + + + Represents a 4-byte value which can hold differently typed data. + + + + + The data as an . + + + + + The data as a . + + + + + The data as an . + + + + + Converts the given value to a instance. + + The value to represent in the new instance. + + + + + Converts the given value to a instance. + + The value to represent in the new instance. + + + + + Converts the given value to a instance. + + The value to represent in the new instance. + + + + + Converts the given value to an instance. + + The value to represent in the new instance. + + + + + Converts the given value to a instance. + + The value to represent in the new instance. + + + + + Converts the given value to an instance. + + The value to represent in the new instance. + + + + + Returns the for this instance. + + The enumerated constant that is the of the class or value type that + implements this interface. + + + + This operation is not supported. + + + + + This operation is not supported. + + + + + This operation is not supported. + + + + + This operation is not supported. + + + + + This operation is not supported. + + + + + Converts the value of this instance to an equivalent double-precision floating-point number using the + specified culture-specific formatting information. + + An interface implementation that supplies + culture-specific formatting information. + A double-precision floating-point number equivalent to the value of this instance. + + + + This operation is not supported. + + + + + Converts the value of this instance to an equivalent 32-bit signed integer using the specified + culture-specific formatting information. + + An interface implementation that supplies + culture-specific formatting information. + An 32-bit signed integer equivalent to the value of this instance. + + + + Converts the value of this instance to an equivalent 64-bit signed integer using the specified + culture-specific formatting information. + + An interface implementation that supplies + culture-specific formatting information. + An 64-bit signed integer equivalent to the value of this instance. + + + + This operation is not supported. + + + + + Converts the value of this instance to an equivalent single-precision floating-point number using the + specified culture-specific formatting information. + + An interface implementation that supplies + culture-specific formatting information. + A single-precision floating-point number equivalent to the value of this instance. + + + + This operation is not supported. + + + + + Converts the value of this instance to an of the specified that has + an equivalent value, using the specified culture-specific formatting information. + + The to which the value of this instance is converted. + + An interface implementation that supplies + culture-specific formatting information. + An instance of type conversionType whose value is equivalent to the value of + this instance. + + + + This operation is not supported. + + + + + This operation is not supported. + + + + + This operation is not supported. + + + + + Represents a 16-bit half-precision floating point value according to the IEEE 754 standard. + + + Examples: + SEEEEEFF_FFFFFFFF + 0b00000000_00000000 = 0 + 1b00000000_00000000 = -0 + 0b00111100_00000000 = 1 + 0b11000000_00000000 = -2 + 0b11111011_11111111 = 65504 (MaxValue) + 0b01111100_00000000 = PositiveInfinity + 0b11111100_00000000 = NegativeInfinity + + + + + Represents the smallest positive value greater than zero. + + + + + Represents the largest possible value of . + + + + + Represents the smallest possible value of . + + + + + Represents not a number (NaN). + + + + + Represents negative infinity. + + + + + Represents positive infinity. + + + + + Initializes a new instance of the struct from the given + representation. + + The raw representation of the internally stored bits. + + + + Gets the internally stored value to represent the instance. + + Signed to get arithmetic rather than logical shifts. + + + + Returns the given . + + The . + The result. + + + + Adds the first to the second one. + + The first . + The second . + The addition result. + + + + Negates the given . + + The to negate. + The negated result. + + + + Subtracts the first from the second one. + + The first . + The second . + The subtraction result. + + + + Multiplicates the first by the second one. + + The first . + The second . + The multiplication result. + + + + Divides the first through the second one. + + The first . + The second . + The division result. + + + + Gets a value indicating whether the first specified is the same as the second + specified . + + The first to compare. + The second to compare. + true, if both are the same. + + + + Gets a value indicating whether the first specified is not the same as the second + specified . + + The first to compare. + The second to compare. + true, if both are not the same. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Converts the given value to a instance. + + The value to represent in the new + instance. + + + + Gets a value indicating whether this is the same as the second specified + . + + The object to compare, if it is a . + true, if both are the same. + + + + Gets a hash code as an indication for object equality. + + The hash code. + + + + Gets a string describing this . + + A string describing this . + + + + Indicates whether the current is equal to another . + + A to compare with this . + true if the current is equal to the other parameter; otherwise, false. + + + + + Returns a value indicating whether the specified number evaluates to not a number (). + + A half-precision floating-point number. + true if value evaluates to not a number (); otherwise false. + + + + Returns a value indicating whether the specified number evaluates to negative or positive infinity. + + A half-precision floating-point number. + true if half evaluates to or ; + otherwise false. + + + + Returns a value indicating whether the specified number evaluates to negative infinity. + + A half-precision floating-point number. + true if half evaluates to ; otherwise false. + + + + Returns a value indicating whether the specified number evaluates to positive infinity. + + A half-precision floating-point number. + true if half evaluates to ; otherwise false. + + + + Represents the non-generic base of a dictionary which can quickly look up instances via + key or index. + + + + + Initializes a new instance of the class. + + + + + Gets the number of instances stored. + + + + + Gets all keys under which instances are stored. + + + + + Gets all stored instances. + + + + + Returns only the publically visible nodes, excluding the root node. + + + + + Gets or sets the instance stored at the specified . + + The 0-based index of the instance to get or set. + The at the specified . + The index is smaller than 0 or bigger or equal to + . + + + + Gets or sets the instance stored under the specified . + + The textual key of the instance to get or set. + The with the specified . + An instance with the same + already exists. + An instance with the given + does not exist. + + + + Gets or sets the key under which the specified is stored. + + The instance of the key to get or set. + The key of the specified . + An instance with the same key already exists. + + A key for the given does not exist. + + + + + Removes all elements from the dictionary. + + + + + Determines whether an instance is saved under the given in the dictionary. + + The textual key to locate in the dictionary. The value can be null. + true if was found in the dictionary; otherwise false. + + + + Searches for the specified and returns the zero-based index of the first occurrence + within the entire dictionary. + + The textual key to locate in the dictionary. The value can be null. + The zero-based index of the first occurence of within the entire dictionary + if found; otherwise -1. + + + + Changes the key of the instance currently saved under the given to the + . + + The current textual key to rename. + The new textual key to use. + An instance with the same + already exists. + + The given does not exist. + + + + + Removes the first occurrence of the instance with the specific from the dictionary. + + The textual key of the instance which will be removed. + true if the instance under was successfully removed; otherwise + false. This method also returns false if was not found in the + dictionary. + + + + Removes the instance at the specified of the dictionary. + + The zero-based index of the instance to remove. + is less than 0 or equal to or greater + than . + + + + Returns true if an instance was stored under the given + and has been assigned to , or false if no instance is stored under the + given and null was assigned to . + + The textual key of the instance to get or set. + The variable receiving the found or null. + true if an instance was found and assigned; otherwise false. + + + + Adds the given under the specified . + + The textual key under which the instance will be stored. + The to add. + An instance with the same + already exists. + + + + Determines whether the given is in the dictionary. + + The instance to locate in the dictionary. The value can be + null. + true if was found in the dictionary; otherwise false. + + + + + Searches for the specified and returns the zero-based index of the first occurrence + within the entire dictionary. + + The instance to locate in the dictionary. The value can be + null. + The zero-based index of the first occurence of within the entire + dictionary if found; otherwise -1. + + + + Removes the first occurrence of a specific from the dictionary. + + The instance to remove from the dictionary. The value can be + null. + true if was successfully removed; otherwise false. This + method also returns false if was not found in the dictionary. + + + + Copies the elements of the dictionary as instances to a new + array and returns it. + + An array containing copies of the elements. + + + + Returns true if a key was found for the given and has been assigned to + , or false if no key was found for the value and null was assigned to + . + + The to look up a key for. + The variable receiving the found key or null. + true if a key was found and assigned; otherwise false. + + + + Returns a generic which can be used to iterate over the items in the dictionary. + + An enumerator to iterate over the items in the dictionary. + + + + Returns an which can be used to iterate over the items in the dictionary. + + An enumerator to iterate over the items in the dictionary. + + + + Returns the instance of the node with the given using the + Patricia trie logic. + + Nodes are looked up linearly by iterating over the node list internally, this method has been + implemented for test and validation purposes only. + The name of the node to look up. + The instance referenced by the found node. + + + + Loads an instance from the given . + + The to load the instance with. + The loaded instance. + + + + Represents a node forming the Patricia trie of the dictionary. + + + + + Represents a dictionary which can quickly look up instances of type + via key or index. + + The specialized type of the instances. + + + + Initializes a new instance of the class. + + + + + Gets all stored instances. + + + + + Gets or sets the value stored at the specified . + + The 0-based index of the instance to get or set. + The instance at the specified . + The index is smaller than 0 or bigger or equal to + . + + + + Gets or sets the value stored under the specified . + + The textual key of the instance to get or set. + The instance with the specified . + An instance with the same already exists. + + An instance with the given does not exist. + + + + + Adds the given under the specified . + + The textual key under which the instance will be stored. + The to add. + An instance with the same + already exists. + + + + Determines whether the given is in the dictionary. + + The instance to locate in the dictionary. The value can be + null. + true if was found in the dictionary; otherwise false. + + + + + Returns a generic which can be used to iterate over the items in the dictionary. + + An enumerator to iterate over the items in the dictionary. + + + + Searches for the specified and returns the zero-based index of the first occurrence + within the entire dictionary. + + The instance to locate in the dictionary. The value can be + null. + The zero-based index of the first occurence of within the entire + dictionary if found; otherwise -1. + + + + Removes the first occurrence of a specific from the dictionary. + + The instance to remove from the dictionary. The value can be + null. + true if was successfully removed; otherwise false. This + method also returns false if was not found in the dictionary. + + + + Copies the elements of the dictionary as instances to a new + array and returns it. + + An array containing copies of the elements. + + + + Returns true if a key was found for the given and has been assigned to + , or false if no key was found for the value and null was assigned to + . + + The to look up a key for. + The variable receiving the found key or null. + true if a key was found and assigned; otherwise false. + + + + Returns true if an instance was stored under the given and has been assigned + to , or false if no instance is stored under the given + and null was assigned to . + + The textual key of the instance to get or set. + The variable receiving the found instance or null. + true if an instance was found and assigned; otherwise false. + + + + Loads an instance from the given . + + The to load the instance with. + The loaded instance. + + + + Represents a which is stored in a . + + + + + The textual represented by this instance. + + + + + The with which this string was read or will be written. + + + + + Converts the given value to a instance. + + The value to represent in the new instance. + + + + + Converts the given value to an instance. + + The value to represent in the new instance. + + + + + Returns the value of the property. + + The value of the property. + + + + Represents a 2D transformation. + + + + + The size of this structure. + + + + + The scaling amount of the transformation. + + + + + The rotation angle of the transformation. + + + + + The translation amount of the transformation. + + + + + Represents a 3D transformation. + + + + + The size of this structure. + + + + + The scaling amount of the transformation. + + + + + The rotation amount of the transformation. + + + + + The translation amount of the transformation. + + + + + Represents a 2D texture transformation. + + + + + The size of this structure. + + + + + The with which the transformation is applied. + + + + + The scaling amount of the transformation. + + + + + The rotation angle of the transformation. + + + + + The translation amount of the transformation. + + + + + Represents a 2D texture transformation which is multiplied by a 3x4 matrix referenced at runtime by the + . + + + + + The size of this structure. + + + + + The with which the transformation is applied. + + + + + The scaling amount of the transformation. + + + + + The rotation angle of the transformation. + + + + + The translation amount of the transformation. + + + + + A pointer to a 3x4 matrix to multiply the transformation with. Set at runtime. + + + + + Represents the texture transformation mode used in and . + + + + + Represents a reference to a instance by name. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. Typically the same as the . + + + + + The referenced instance. + + + + + Represents custom user variables which can be attached to many sections and subfiles of a . + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + The data type of the stored values. + + + + + Returns the stored value as an array of instances when the is + . + + The typed value. + + + + Returns the stored value as an array of instances when the is + . + + The typed value. + + + + Returns the stored value as an array of instances when the is + or . + + The typed value. + + + + Returns the stored value as an array of instances when the is + . + + The typed value. + + + + Sets the stored as an array and the to + + + The value to store. + + + + Sets the stored as a array and the to + + + The value to store. + + + + Sets the stored as a array and the to + or depending on + . + + true to store data as UTF-16 encoded strings, or false to store it + as ASCII encoded strings. + The value to store. + + + + Sets the stored as a array and the to + + + The value to store. + + + + Represents the possible data types of values stored in instances. + + + + + The values is an array. + + + + + The values is a array. + + + + + The values is a array encoded in ASCII. + + + + + The values is a array encoded in UTF-16. + + + + + The values is a array. + + + + + Represents extension methods for the class. + + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads a instance from the current stream and returns it. + + The extended . + The number of instances to read. + The instance. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The in which values are stored. + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The in which values are stored. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The in which values are stored. + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The in which values are stored. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The in which values are stored. + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The in which values are stored. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Reads a instance from the current stream and returns it. + + The extended . + The instance. + + + + Reads instances from the current stream and returns them. + + The extended . + The number of instances to read. + The instances. + + + + Returns the conversion delegate for converting data available in the given + into a instance. Useful to prevent repetitive lookup for multiple values. + + The extended . + The of the data. + A conversion delegate for the data. + + + + Reads a instance converted from the given and + returns it. + + The extended . + The of the data. + The instance. + + + + Reads a instances converted from the given and + returns them. + + The extended . + The number of instances to read. + The of the data. + The instances. + + + + Represents extension methods for the class. + + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + The in which values are stored. + + + + Writes instances into the current stream. + + The extended . + The instances. + The in which values are stored. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + The in which values are stored. + + + + Writes instances into the current stream. + + The extended . + The instances. + The in which values are stored. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + The in which values are stored. + + + + Writes instances into the current stream. + + The extended . + The instances. + The in which values are stored. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Writes a instance into the current stream. + + The extended . + The instance. + + + + Writes instances into the current stream. + + The extended . + The instances. + + + + Returns the conversion delegate for converting data available in the given + from a instance. Useful to prevent repetitive lookup for multiple values. + + The extended . + The of the data. + A conversion delegate for the data. + + + + Writes a instance into the current stream with the given + . + + The extended . + The instance. + The of the data. + + + + Writes instances into the current stream with the given + . + + The extended . + The instances. + The of the data. + + + + Represents extension methods for instances. + + + + + Returns an instance represented by the given number of , starting + at the . + + The extended instance. + The first bit of the encoded value. + The number of least significant bits which are used to store the + value. + The decoded . + + + + Returns the current with the bit at the set (being 1). + + The extended instance. + The 0-based index of the bit to enable. + The current with the bit enabled. + + + + Returns the current with the given set into the given number + of starting at . + + The extended instance. + The value to encode. + The first bit used for the encoded value. + The number of bits which are used to store the value. + The current with the value encoded into it. + + + + Returns the current with the bit at the cleared (being 0). + + The extended instance. + The 0-based index of the bit to disable. + The current with the bit disabled. + + + + Returns a value indicating whether the bit at the in the current + is enabled or disabled. + + The extended instance. + The 0-based index of the bit to check. + true when the bit is set; otherwise false. + + + + Returns the current with all bits rotated in the given , + where positive directions rotate left and negative directions rotate right. + + The extended instance. + The direction in which to rotate, where positive directions rotate left. + The current with the bits rotated. + + + + Returns the current with the bit at the enabled or disabled, + according to . + + The extended instance. + The 0-based index of the bit to enable or disable. + true to enable the bit; otherwise false. + The current with the bit enabled or disabled. + + + + Returns the current with the bit at the enabled when it is + disabled or disabled when it is enabled. + + The extended instance. + The 0-based index of the bit to toggle. + The current with the bit toggled. + + + + Represents extension methods for instances. + + + + + Returns an instance represented by the given number of , starting + at the . + + The extended instance. + The first bit of the encoded value. + The number of least significant bits which are used to store the + value. + The decoded . + + + + Returns the current with the bit at the set (being 1). + + The extended instance. + The 0-based index of the bit to enable. + The current with the bit enabled. + + + + Returns the current with the given set into the given number + of starting at . + + The extended instance. + The value to encode. + The first bit used for the encoded value. + The number of bits which are used to store the value. + The current with the value encoded into it. + + + + Returns the current with the bit at the cleared (being 0). + + The extended instance. + The 0-based index of the bit to disable. + The current with the bit disabled. + + + + Returns a value indicating whether the bit at the in the current + is enabled or disabled. + + The extended instance. + The 0-based index of the bit to check. + true when the bit is set; otherwise false. + + + + Returns the current with all bits rotated in the given , + where positive directions rotate left and negative directions rotate right. + + The extended instance. + The direction in which to rotate, where positive directions rotate left. + The current with the bits rotated. + + + + Returns the current with the bit at the enabled or disabled, + according to . + + The extended instance. + The 0-based index of the bit to enable or disable. + true to enable the bit; otherwise false. + The current with the bit enabled or disabled. + + + + Returns the current with the bit at the enabled when it is + disabled or disabled when it is enabled. + + The extended instance. + The 0-based index of the bit to toggle. + The current with the bit toggled. + + + + Represents the common interface for data instances. + + + + + Loads raw data from the data stream into instances. + + The to load data with. + + + + Saves header data of the instance and queues referenced data in the given . + + The to save headers and queue data with. + + + + Loads the hierachy and data of a . + + + + + Initializes a new instance of the class loading data into the given + from the specified which is optionally left open. + + The instance to load data into. + The to read data from. + true to leave the stream open after reading, otherwise false. + + + + Initializes a new instance of the class from the file with the given + . + + The instance to load data into. + The name of the file to load the data from. + + + + Gets the loaded instance. + + + + + Gets the loaded instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the loaded instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the loaded instance. + + + + + Starts deserializing the data from the root. + + + + + Reads and returns an instance of type from the following + offset or returns null if the read offset is 0. + + The type of the to read. + The instance or null. + + + + Reads and returns an instance of arbitrary type from the following offset with the + given or returns null if the read offset is 0. + + The type of the data to read. + The callback to read the instance data with. + The optional offset to use instead of reading a following one. + The data instance or null. + Offset required for ExtFile header (offset specified before size). + + + + Reads and returns an instance with elements of type from + the following offset or returns an empty instance if the read offset is 0. + + The type of the elements. + The instance. + + + + Reads and returns an instance with elements of type + from the following offset or returns null if the read offset is 0. + + The type of the elements. + The number of elements to expect for the list. + The optional offset to use instead of reading a following one. + The instance or null. + Offset required for FMDL FVTX lists (offset specified before count). + + + + Reads and returns a instance from the following offset or null if the read + offset is 0. + + The optional encoding of the text. + The read text. + + + + Reads and returns instances from the following offsets. + + The number of instances to read. + The optional encoding of the texts. + The read texts. + + + + Reads a BFRES signature consisting of 4 ASCII characters encoded as an and checks for + validity. + + A valid signature. + + + + Reads a BFRES offset which is relative to itself, and returns the absolute address. + + The absolute address of the offset. + + + + Reads BFRES offsets which are relative to themselves, and returns the absolute addresses. + + The number of offsets to read. + The absolute addresses of the offsets. + + + + Saves the hierachy and data of a . + + + + + Gets or sets a data block alignment typically seen with . + + + + + Initializes a new instance of the class saving data from the given + into the specified which is optionally left open. + + The instance to save data from. + The to save data into. + true to leave the stream open after writing, otherwise false. + + + + Initializes a new instance of the class for the file with the given + . + + The instance to save. + The name of the file to save the data into. + + + + Initializes a new instance of the class for the file with the given + . + + The instance to save. + The name of the file to save the data into. + + + + Initializes a new instance of the class for the file with the given + . + + The instance to save. + The name of the file to save the data into. + + + + Initializes a new instance of the class for the file with the given + . + + The instance to save. + The name of the file to save the data into. + + + + Initializes a new instance of the class for the file with the given + . + + The instance to save. + The name of the file to save the data into. + + + + Initializes a new instance of the class for the file with the given + . + + The instance to save. + The name of the file to save the data into. + + + + Initializes a new instance of the class for the file with the given + . + + The instance to save. + The name of the file to save the data into. + + + + Initializes a new instance of the class for the file with the given + . + + The instance to save. + The name of the file to save the data into. + + + + Initializes a new instance of the class for the file with the given + . + + The instance to save. + The name of the file to save the data into. + + + + Initializes a new instance of the class for the file with the given + . + + The instance to save. + The name of the file to save the data into. + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the saved instance. + + + + + Gets the current index when writing lists or dicts. + + + + + Starts serializing the data from the root. + + + + + Starts serializing the data from the root. + + + + + Reserves space for an offset to the written later. + + The to save. + The index of the element, used for instances referenced by a . + + + + + Reserves space for the file size field which is automatically filled later. + + + + + Reserves space for the string pool size and offset fields which are automatically + filled later. + + + + + Reserves space for an offset to the written later. + + The type of the elements. + The to save. + + + + Reserves space for an offset to the written later. + + The type of the element values. + The to save. + + + + Reserves space for an offset to the written later with the + . + + The data to save. + The to invoke to write the data. + + + + Reserves space for an offset to the written later in the string pool with the + specified . + + The name to save. + The in which the name will be stored. + + + + Reserves space for offsets to the written later in the string pool with the + specified + + The names to save. + The in which the names will be stored. + + + + Reserves space for an offset to the written later in the data block pool. + + The data to save. + The alignment to seek to before invoking the callback. + The to invoke to write the data. + + + + Writes a BFRES signature consisting of 4 ASCII characters encoded as an . + + A valid signature. + + + + Represents a sorting empty strings to the end of lists. + + + + + Represents a file attachment to a which can be of arbitrary data. + + + + + Gets or sets the raw data stored by the external file. + + + + + Opens and returns a on the raw byte array, which optionally + can be written to. + + true to allow write access to the raw data. + The opened instance. + + + + Represents GX2 settings controlling additional alpha blending options. + + + + + Gets or sets a value indicating whether alpha testing is enabled at all. + + + + + Gets or sets the comparison functions to use for alpha testing. + + + + + Represents GX2 settings controlling color and alpha blending. + + + + + Gets or sets the color source blend operation. + + + + + Gets or sets the color combine operation. + + + + + Gets or sets the color destination blend operation. + + + + + Gets or sets the alpha source blend operation. + + + + + Gets or sets the alpha combine operation. + + + + + Gets or sets the alpha destination blend operation. + + + + + Gets or sets a value indicating whether alpha blending is separated from color blending. + + + + + Represents GX2 settings controlling additional color blending options. + + + + + Gets or sets a value indicating whether multi writes are enabled. + + + + + Gets or sets a value indicating whether the color buffer is enabled. + + + + + Gets or sets the bitmask used for blending. + + + + + Gets or sets the ROP3 logic operation. + + + + + Represents GX2 settings controlling how depth and stencil buffer checks are performed and handled. + + + + + Gets or sets a value indicating whether depth testing is enabled. + + + + + Gets or sets a value indicating whether writing to the depth buffer is enabled. + + + + + Gets or sets the depth buffer comparison function, controlling whether a new fragment is allowed to + overwrite the old value in the depth buffer. + + + + + Gets or sets a value indicating whether stencil testing is enabled. + + + + + Gets or sets a value indicating whether back-facing polygons are allowed to write to the stencil buffer or + not. + + + + + Gets or sets the front-facing polygon stencil comparison function. + + + + + Gets or sets the stencil function configuring what to do with the existing stencil value when the stencil + test fails for front-facing polygons. + + + + + Gets or sets the stencil function taking effect when the stencil test passes with the depth buffer for + front-facing polygons. + + + + + Gets or sets the function taking effect when the stencil test fails with the depth buffer for front-facing + polygons. + + + + + Gets or sets the back-facing polygon stencil comparison function. + + + + + Gets or sets the stencil function configuring what to do with the existing stencil value when the stencil + test fails for back-facing polygons. + + + + + Gets or sets the stencil function taking effect when the stencil test passes with the depth buffer for + back-facing polygons. + + + + + Gets or sets the function taking effect when the stencil test fails with the depth buffer for back-facing + polygons. + + + + + Represents the AA modes (number of samples) for a surface. + + + + + Represents the format of a vertex attribute entry. Possible type conversions: + UNorm: attrib unsigned integer is converted to/from [0.0, 1.0] in shader. + UInt: attrib unsigned integer is copied to/from shader as unsigned int. + SNorm: attrib signed integer is converted to/from [-1.0, 1.0] in shader. + SInt: attrib signed integer is copied to/from shader as signed int. + Single: attrib single is copied to/from shader as Single. + UIntToSingle: attrib unsigned integer is converted Single in shader. + SIntToSingle: attrib signed integer is converted Single in shader. + + + + + Represents how the terms of the blend function are combined. + + + + + Represents the factors used in the blend function. + + + + + Represents compare functions used for depth and stencil tests. + + + + + Represents the source channels to map to a color channel in textures. + + + + + Represents the vertex order of front-facing polygons. + + + + + Represents the type in which vertex indices are stored. + + + + + Represents the logic op function to perform. + + + + + Black + + + + + White + + + + + Source (Default) + + + + + ~Source + + + + + Destination + + + + + ~Destination + + + + + Source & Destination + + + + + ~(Source & Destination) + + + + + Source | Destination + + + + + ~(Source | Destination) + + + + + Source ^ Destination + + + + + ~(Source ^ Destination) + + + + + Source & ~Destination + + + + + ~Source & Destination + + + + + Source | ~Destination + + + + + ~Source | Destination + + + + + Represents the base primitive used to draw each side of the polygon when dual-sided polygon mode is enabled. + + + + + Represents the type of primitives to draw. + + + + + Requires at least 1 element and 1 more to draw another primitive. + + + + + Requires at least 2 elements and 2 more to draw another primitive. + + + + + Requires at least 2 elements and 1 more to draw another primitive. + + + + + Requires at least 3 elements and 3 more to draw another primitive. + + + + + Requires at least 3 elements and 1 more to draw another primitive. + + + + + Requires at least 3 elements and 1 more to draw another primitive. + + + + + Requires at least 4 elements and 4 more to draw another primitive. + + + + + Requires at least 4 elements and 1 more to draw another primitive. + + + + + Requires at least 6 elements and 6 more to draw another primitive. + + + + + Requires at least 6 elements and 2 more to draw another primitive. + + + + + Requires at least 3 elements and 3 more to draw another primitive. + + + + + Requires at least 2 elements and 1 more to draw another primitive. + + + + + Requires at least 4 elements and 4 more to draw another primitive. + + + + + Requires at least 4 elements and 2 more to draw another primitive. + + + + + Requires at least 2 elements and 2 more to draw another primitive. + + + + + Requires at least 2 elements and 1 more to draw another primitive. + + + + + Requires at least 3 elements and 3 more to draw another primitive. + + + + + Requires at least 3 elements and 1 more to draw another primitive. + + + + + Requires at least 4 elements and 4 more to draw another primitive. + + + + + Requires at least 4 elements and 2 more to draw another primitive. + + + + + Represents the stencil function to be performed if stencil tests pass. + + + + + Represents shapes of a given surface or texture. + + + + + Represents desired texture, color-buffer, depth-buffer, or scan-buffer formats. + + + + + Represents Indicates how a given surface may be used. A final TV render target is one that will be copied to a + TV scan buffer. It needs to be designated to handle certain display corner cases (when a HD surface must be + scaled down to display in NTSC/PAL). + + + + + Represents maximum desired anisotropic filter ratios. Higher ratios give better image quality, but slower + performance. + + + + + Represents type of border color to use. + + + + + Represents how to treat texture coordinates outside of the normalized coordinate texture range. + + + + + Represents desired texture filter options between mip levels. + + + + + Represents desired texture filter options within a plane. + + + + + Represents desired texture filter options between Z planes. + + + + + Represents the desired tiling modes for a surface. + + + + + Represents GX2 polygon drawing settings controlling if and how triangles are rendered. + + + + + Gets or sets a value indicating whether front-facing polygons are culled. + + + + + Gets or sets a value indicating whether back-facing polygons are culled. + + + + + Gets or sets the order in which vertices have to form the triangle to be handled as a front- rather than + back-face. + + + + + Gets or sets a value indicating whether polygons are drawn at all. + + + + + Gets or sets how front facing polygons are drawn. + + + + + Gets or sets how back facing polygons are drawn. + + + + + Gets or sets whether front-facing polygons are drawn offset (useful for decals to combat Z fighting). + + + + + Gets or sets whether back-facing polygons are drawn offset (useful for decals to combat Z fighting). + + + + + Gets or sets whether lines are drawn offset (useful for decals to combat Z fighting). + + + + + Represents a GX2 texture sampler controlling how a texture is samples and drawn onto a surface. + + + + + Initializes a new instance of the instance. + + + + + Gets or sets the texture repetition mode on the X axis. + + + + + Gets or sets the texture repetition mode on the Y axis. + + + + + Gets or sets the texture repetition mode on the Z axis. + + + + + Gets or sets the texture filtering on the X and Y axes when the texture is drawn larger than the actual + texture's resolution. + + + + + Gets or sets the texture filtering on the X and Y axes when the texture is drawn smaller than the actual + texture's resolution. + + + + + Gets or sets the texture filtering on the Z axis. + + + + + Gets or sets the texture filtering for mipmaps. + + + + + Gets or sets the maximum anisotropic filtering level to use. + + + + + Gets or sets what color to draw at places not reached by a texture if the clamp mode does not repeat it. + + + + + Gets or sets the depth comparison function. + + + + + Gets or sets the minimum LoD level. + + + + + Gets or sets the maximum LoD level. + + + + + Gets or sets the LoD bias. + + + + + Gets or sets a value indicating whether depth comparison is enabled (never set for a real console). + + + + + Represents a helper class for working with instances. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class with data read from the given + . The data is available in the , which defaults + to system byte order. + + The to initially read data from. + The in which vertex data is available. null to use + system byte order. + + + + Gets or sets the in which vertex data will be stored when calling + . This should be the same as the remainder of the in + which it will be stored. + + + + + Gets or sets the number of bones influencing the vertices stored in the buffer. 0 influences equal + rigidbodies (no skinning), 1 equal rigid skinning and 2 or more smooth skinning. + + + + + Gets or sets the list of instances which store the data. + + + + + Gets or sets the instance at the given . + + The index of the instance. + The instance at the given index. + + + + Gets or sets the first instance with the given + . + + The name of the instance. + The instance with the given name. + + + + Returns a instance out of the stored helper data. + + A new . + + + + Represents an attribute and the data it stores in a instance. + + + + + The name of the attribute, typically used to determine the use of the data. + + + + + The into which data will be converted upon creating a + . + + + + + The data stored for this attribute. Has to be of the same length as every other + . Depending on , not every component of the + elements is used. + + + + + Represents an FMAT subsection of a subfile, storing information on with which textures and + how technically a surface is drawn. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets flags specifying how a is rendered. + + + + + Gets or sets the list of instances referencing the instances + required to draw the material. + + + + + Gets or sets a dictionary of instances which configure how to draw + instances referenced by the list. + + + + + Gets or sets the raw data block which stores values. + + + + + Gets or sets customly attached instances. + + + + + Gets or sets a set of bits determining whether instances are volatile. + + + + + Initializes a new instance of the class from the given which + is optionally left open. + + The to load the data from. + true to leave the stream open after reading, otherwise false. + + + + Initializes a new instance of the class from the file with the given + . + + The name of the file to load the data from. + + + + Saves the contents in the given and optionally leaves it open + + The to save the contents into. + true to leave the stream open after writing, otherwise false. + + + + Saves the contents in the file with the given . + + The name of the file to save the contents into. + + + + Represents general flags specifying how a is rendered. + + + + + The material is not rendered at all. + + + + + The material is rendered. + + + + + Represents a render info in a FMAT section storing uniform parameters required to render the + . + + + + + Gets the determining the data type of the stored value. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets the stored value as an array. Only valid if is + . + + The stored value as an array. + + + + Gets the stored value as a array. Only valid if is + . + + The stored value as a array. + + + + Gets the stored value as a array. Only valid if is + . + + The stored value as a array. + + + + Sets the stored value as an array and sets to + . + + The array to set as the value. + + + + Sets the stored value as a array and sets to + . + + The array to set as the value. + + + + Sets the stored value as a array and sets to + . + + The array to set as the value. + + + + Represents the data type of elements of the value array. + + + + + The elements are instances. + + + + + The elements are instances. + + + + + The elements are instances. + + + + + Represents GX2 GPU configuration to determine how polygons are rendered. + + + + + Gets or sets GX2 polygon drawing settings controlling if and how triangles are rendered. + + + + + Gets or sets GX2 settings controlling how depth and stencil buffer checks are performed and handled. + + + + + Gets or sets GX2 settings controlling additional alpha blending options. + + + + + Gets or sets the reference value used for alpha testing. + + + + + Gets or sets GX2 settings controlling additional color blending options. + + + + + Gets or sets the blend target index. + + + + + Gets or sets GX2 settings controlling color and alpha blending. + + + + + Gets or sets the blend color to perform blending with. + + + + + Represents a sampler in a section, storing configuration on how to + draw and interpolate textures. + + + + + Gets or sets the internal representation of the sampler configuration. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Represents a parameter value in a section, passing data to shader variables. + + + + + Gets or sets the type of the value. + + + + + Gets the offset in the byte array in bytes. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets the size of the value in bytes. + + + + + Represents the data types in which instances can store their value. + + + + + The value is a single . + + + + + The value is a . + + + + + The value is a . + + + + + The value is a . + + + + + The value is a single . + + + + + The value is a . + + + + + The value is a . + + + + + The value is a . + + + + + The value is a single . + + + + + The value is a . + + + + + The value is a . + + + + + The value is a . + + + + + The value is a single . + + + + + The value is a . + + + + + The value is a . + + + + + The value is a . + + + + + An invalid type for values, only used for internal computations. + + + + + The value is a . + + + + + The value is a . + + + + + The value is a . + + + + + An invalid type for values, only used for internal computations. + + + + + The value is a . + + + + + The value is a . + + + + + The value is a . + + + + + An invalid type for values, only used for internal computations. + + + + + The value is a . + + + + + The value is a . + + + + + The value is a . + + + + + The value is a . + + + + + The value is a . + + + + + The value is a . + + + + + The value is a . + + + + + Represents an FMDL subfile in a , storing model vertex data, skeletons and used materials. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the path of the file which originally supplied the data of this instance. + + + + + Gets the instance to deform the model with animations. + + + + + Gets or sets the instances storing the vertex data used by the + . + + + + + Gets or sets the instances forming the surface of the model. + + + + + Gets or sets the instance applied on the to color their surface. + + + + + Gets or sets customly attached instances. + + + + + Gets the total number of vertices to process when drawing this model. + + This excludes vertices which are not processed by any shader. However, the exact value does not + seem to matter, so the total count of all vertices is taken to keep things trivial for now. + + + + Represents a spatial bounding box. + + + + + The center point of the bounding box. + + + + + The extent from the center point to the furthest point. + + + + + Represents a node in a bounding tree to determine when to show which sub mesh of a + . + + + + + Represents the surface net of a section, storing information on which + index to use for referencing vertices of the shape, mostly used for different levels of + detail (LoD) models. + + + + + Gets or sets the which determines how indices are used to form polygons. + + + + + Gets the determining the data type of the indices in the + . + + + + + Gets the number of indices stored in the . + + + + + Gets or sets the list of instances which split up a mesh into parts which can be + hidden if they are not visible to optimize rendering performance. + + + + + Gets or sets the storing the index data. + + + + + Gets or sets the offset to the first vertex element of a to reference by indices. + + + + + Returns the indices stored in the as instances. + + The indices stored in the . + + + + Stores the given in the in the provided + , or the current if none was specified. + + The indices to store in the . + The to use or null to use the current format. + + + + + Represents an FSHP section in a subfile. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets flags determining which data is available for this instance. + + + + + Gets or sets the index of the material to apply to the shapes surface in the owning + list. + + + + + Gets or sets the index of the to which this instance is directly attached to. The bone + must be part of the skeleton referenced by the owning instance. + + + + + Gets or sets the index of the in the owning + list. + + + + + Gets or sets the bounding radius/radii spanning the shape. BOTW uses multiple per LOD mesh. + + + + + Gets or sets the number of bones influencing the vertices stored in this buffer. 0 influences equal + rigidbodies (no skinning), 1 equal rigid skinning and 2 or more smooth skinning. + + + + + Gets or sets a value with unknown purpose. + + + + + Gets or sets the list of which are used to represent different level of details of the + shape. + + + + + Gets or sets the instances forming the bounding tree with which parts of a mesh + are culled when not visible. + + + + + Gets or sets the instance storing the data which forms the shape's surface. Saved + depending on . + + + + + Represents flags determining which data is available for instances. + + + + + The instance references a . + + + + + The boundings in all submeshes are consistent. + + + + + Represents a subarray of a section, storing a slice of indices to draw from the index buffer + referenced in the mesh, mostly used for hiding parts of a model when not visible. + + + + + Gets the offset into the index buffer in bytes. + + + + + Gets the number of indices to reference. + + + + + Represents a single bone in a section, storing its initial transform and transformation + effects. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the index of the parent this instance is a child of. + + + + + Gets or sets the index of a matrix used for smooth skinning. + + + + + Gets or sets the index of a matrix used for rigid skinning. + + + + + Gets or sets flags controlling bone behavior. + + + + + Gets or sets the rotation method used to store bone rotations in . + + + + + Gets or sets the billboard transformation applied to the bone. + + + + + Gets or sets the spatial scale of the bone. + + + + + Gets or sets the spatial rotation of the bone. If is used, the + fourth component is always 1.0f. + + + + + Gets or sets the spatial position of the bone. + + + + + Gets or sets customly attached instances. + + + + + Gets or sets the inverse matrix (Only used in bfres verson v3.3.X.X and below) + + + + + Represents flags controlling bone behavior. + + + + + Set when the bone is visible. + + + + + Represents the rotation method used to store bone rotations. + + + + + A quaternion represents the rotation. + + + + + A represents the Euler rotation in XYZ order. + + + + + Represents the possible transformations for bones to handle them as billboards. + + + + + No transformation is applied. + + + + + Transforms of the child are applied. + + + + + Transforms the Z axis parallel to the camera. + + + + + Transforms the Z axis parallel to the direction of the camera. + + + + + Transforms the Y axis parallel to the camera up vector, and the Z parallel to the camera up-vector. + + + + + Transforms the Y axis parallel to the camera up vector, and the Z axis parallel to the direction of the + camera. + + + + + Transforms the Z axis parallel to the camera by rotating only the Y axis. + + + + + Transforms the Z axis parallel to the direction of the camera by rotating only the Y axis. + + + + + Represents an FSKL section in a subfile, storing armature data. + + + + + Gets or sets the rotation method used to store bone rotations. + + + + + Gets or sets the list of instances forming the skeleton. + + + + + Represents the rotation method used to store bone rotations. + + + + + A quaternion represents the rotation. + + + + + A represents the Euler rotation in XYZ order. + + + + + Represents an attribute of a describing the data format, type and layout of a + specific data subset in the buffer. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the index of the buffer storing the data in the list. + + + + + Gets or sets the offset in bytes to the attribute in each vertex. + + + + + Gets or sets the determining the type in which attribute data is available. + + + + + Represents a data buffer holding vertices for a subfile. + + + + + Gets or sets the number of bones influencing the vertices stored in this buffer. 0 influences equal + rigidbodies (no skinning), 1 equal rigid skinning and 2 or more smooth skinning. + + + + + Gets the number of vertices stored by the . It is calculated from the size of the first + in bytes divided by the . + + + + + Gets or sets the dictionary of instances describing how to interprete data in the + . + + + + + Gets or sets the list of instances storing raw unformatted vertex data. + + + + + Represents an exception raised when handling data. + + + + + Initializes a new instance of the class with a specified error + . + + The error message that explains the reason for the exception. + + + + Initializes a new instance of the class with a specified error message created + from the given and . + + The format of the error message. + The parameters to format the error message with. + + + + Represents a NintendoWare for Cafe (NW4F) graphics data archive file. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class from the given which + is optionally left open. + + The to load the data from. + true to leave the stream open after reading, otherwise false. + + + + Initializes a new instance of the class from the file with the given + . + + The name of the file to load the data from. + + + + Gets or sets the revision of the BFRES structure formats. + + + + + Gets the byte order in which data is stored. Must be the endianness of the target platform. + + + + + Gets or sets the alignment to use for raw data blocks in the file. + + + + + Gets or sets a name describing the contents. + + + + + Gets or sets the stored (FMDL) instances. + + + + + Gets or sets the stored (FTEX) instances. + + + + + Gets or sets the stored (FSKA) instances. + + + + + Gets or sets the stored (FSHU) instances. + + + + + Gets or sets the stored (FSHU) instances for color animations. + + + + + Gets or sets the stored (FSHU) instances for texture SRT animations. + + + + + Gets or sets the stored (FTXP) instances. + + + + + Gets or sets the stored (FVIS) instances for bone visibility animations. + + + + + Gets or sets the stored (FVIS) instances for material visibility animations. + + + + + Gets or sets the stored (FSHA) instances. + + + + + Gets or sets the stored (FSCN) instances. + + + + + Gets or sets attached instances. The key of the dictionary typically represents + the name of the file they were originally created from. + + + + + Saves the contents in the given and optionally leaves it open + + The to save the contents into. + true to leave the stream open after writing, otherwise false. + + + + Saves the contents in the file with the given . + + The name of the file to save the contents into. + + + + Represents an FCAM section in a subfile, storing animations controlling camera settings. + + + + + Gets or sets flags controlling how animation data is stored or how the animation should be played. + + + + + Gets or sets the total number of frames this animation plays. + + + + + Gets or sets the number of bytes required to bake all . + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets instances animating properties of objects stored in this section. + + + + + Gets the instance storing initial camera parameters. + + + + + Gets or sets customly attached instances. + + + + + Represents flags specifying how animation data is stored or should be played. + + + + + The stored curve data has been baked. + + + + + The animation repeats from the start after the last frame has been played. + + + + + The rotation mode stores ZXY angles rather than look-at points in combination with a twist. + + + + + The projection mode is perspective rather than ortographic. + + + + + Represents the animatable data of scene cameras. + + + + + The near clipping plane distance. + + + + + The far clipping plane distance. + + + + + The aspect ratio of the projected image. + + + + + The field of view of the projected image. + + + + + The spatial position of the camera. + + + + + The spatial rotation of the camera. + + + + + The spatial twist of the camera. + + + + + Gets the for instances. + + + + + Animates . + + + + + Animates . + + + + + Animates . + + + + + Animates . + + + + + Animates the X component of . + + + + + Animates the Y component of . + + + + + Animates the Z component of . + + + + + Animates the X component of . + + + + + Animates the Y component of . + + + + + Animates the Z component of . + + + + + Animates . + + + + + Represents an FCAM section in a subfile, storing animations controlling fog settings. + + + + + Gets or sets flags controlling how animation data is stored or how the animation should be played. + + + + + Gets or sets the total number of frames this animation plays. + + + + + Gets or sets the index of the distance attenuation function to use. + + + + + Gets or sets the number of bytes required to bake all . + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the name of the distance attenuation function to use. + + + + + Gets or sets instances animating properties of objects stored in this section. + + + + + Gets or sets the instance storing initial fog parameters. + + + + + Gets or sets customly attached instances. + + + + + Represents flags specifying how animation data is stored or should be played. + + + + + The stored curve data has been baked. + + + + + The animation repeats from the start after the last frame has been played. + + + + + Represents the animatable data of scene fog. + + + + + The distance attenuation of the fog depth. + + + + + The color of the fog. + + + + + Gets the for instances. + + + + + Animates the X component of . + + + + + Animates the Y component of . + + + + + Animates the X (red) component of . + + + + + Animates the Y (green) component of . + + + + + Animates the Z (blue) component of . + + + + + Represents an FLIT section in a subfile, storing animations controlling light settings. + + + + + Gets or sets flags controlling how the animation should be played. + + + + + Gets or sets flags controlling how animation data is stored or how the animation should be played. + + + + + Gets or sets the total number of frames this animation plays. + + + + + Gets or sets the index of the light type. + + + + + Gets or sets the index of the distance attenuation function to use. + + + + + Gets or sets the index of the angle attenuation function to use. + + + + + Gets or sets the number of bytes required to bake all . + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the name of the light type. + + + + + Gets or sets the name of the distance attenuation function to use. + + + + + Gets or sets the name of the angle attenuation function to use. + + + + + Gets or sets instances animating properties of objects stored in this section. + + + + + Gets the instance storing initial light parameters. + + + + + Gets or sets customly attached instances. + + + + + Represents flags specifying how animation data is stored. + + + + + The stored curve data has been baked. + + + + + The animation repeats from the start after the last frame has been played. + + + + + Represents flags specifying which fields are animated. + + + + + Enabled state is animated. + + + + + Position is animated. + + + + + Rotation is animated. + + + + + Distance attenuation is animated. + + + + + Angle attenuation is animated in degrees. + + + + + Color 0 is animated. + + + + + Color 1 is animated. + + + + + Represents the animatable data of scene lighting. + + + + + Enables or disables the light in total. + + + + + The spatial origin of the light source for point or spot lights. + + + + + The spatial rotation of the light source. + + + + + The distance attenuation of the light. + + + + + The angle attenuation of the light in degrees. + + + + + The first light source color. + + + + + The second light source color. + + + + + Gets the for instances. + + + + + Animates . + + + + + Animates the X component of . + + + + + Animates the Y component of . + + + + + Animates the Z component of . + + + + + Animates the X component of . + + + + + Animates the Y component of . + + + + + Animates the Z component of . + + + + + Animates the X component of . + + + + + Animates the Y component of . + + + + + Animates the X component of . + + + + + Animates the Y component of . + + + + + Animates the X (red) component of . + + + + + Animates the Y (green) component of . + + + + + Animates the Z (blue) component of . + + + + + Animates the X (red) component of . + + + + + Animates the Y (green) component of . + + + + + Animates the Z (blue) component of . + + + + + Represents an FSCN subfile in a , storing scene animations controlling camera, light and + fog settings. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the path of the file which originally supplied the data of this instance. + + + + + Gets or sets the instances. + + + + + Gets or sets the instances. + + + + + Gets or sets the instances. + + + + + Gets or sets customly attached instances. + + + + + Represents a parameter animation info in a instance. + + + + + Gets or sets the index of the first instance in the parent + . + + + + + Gets or sets the index of the first instance in the parent + . + + + + + Gets or sets the number of instances used in the parent + . + + + + + Gets or sets the index of the in the . + + + + + Gets the name of the animated . + + + + + Represents an FSHU subfile in a , storing shader parameter animations of a + instance. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the path of the file which originally supplied the data of this instance. + + + + + Gets or sets flags controlling how animation data is stored or how the animation should be played. + + + + + Gets or sets the total number of frames this animation plays. + + + + + Gets or sets the number of bytes required to bake all instances of all + . + + + + + Gets or sets the instance affected by this animation. + + + + + Gets the indices of the instances in the dictionary to + bind for each animation. specifies no binding. + + + + + Gets or sets the instances creating the animation. + + + + + Gets or sets customly attached instances. + + + + + Represents flags specifying how animation data is stored or should be played. + + + + + The stored curve data has been baked. + + + + + The animation repeats from the start after the last frame has been played. + + + + + Represents a material parameter animation in a subfile. + + + + + Gets or sets the name of the animated . + + + + + Gets or sets the list of instances. + + + + + Gets or sets instances animating properties of objects stored in this section. + + + + + Gets or sets the index of the first relative to all curves of the parent + instances. + + + + + Gets or sets the index of the first relative to all param anim infos of the + parent instances. + + + + + Represents a key shape animation info in a instance. + + + + + Gets or sets the index of the curve in the . + + + + + Gets or sets the index of the in the . + + + + + Gets or sets the name of the in the . + + + + + Represents an FSHA subfile in a , storing shape animations of a + instance. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the path of the file which originally supplied the data of this instance. + + + + + Gets or sets flags controlling how animation data is stored or how the animation should be played. + + + + + Gets or sets the total number of frames this animation plays. + + + + + Gets or sets the number of bytes required to bake all instances of all + . + + + + + Gets or sets the instance affected by this animation. + + + + + Gets or sets the indices of the instances in the dictionary + to bind for each animation. specifies no binding. + + + + + Gets or sets the instances creating the animation. + + + + + Gets or sets customly attached instances. + + + + + Represents flags specifying how animation data is stored or should be played. + + + + + The stored curve data has been baked. + + + + + The animation repeats from the start after the last frame has been played. + + + + + Represents a vertex shape animation in a subfile. + + + + + Gets or sets the name of the animated . + + + + + Gets or sets the list of instances. + + + + + Gets or sets instances animating properties of objects stored in this section. + + + + + Gets or sets the list of base values, excluding the base shape (which is always being initialized with 0f). + + + + + Gets or sets the index of the first relative to all curves of the parent + instances. + + + + + Gets or sets the index of the first relative to all key shape anim infos of + the parent instances. + + + + + Represents the animation of a single in a subfile. + + + + + Gets or sets a set of flags indicating whether initial transformation values exist in + . + + + + + Gets or sets a set of flags indicating whether curves animating the corresponding transformation exist. + + + + + Gets or sets a set of flags controlling how to transform bones. + + + + + Gets or sets the name of the animated . + + + + + Gets or sets a field with unknown purpose. + + + + + Gets or sets a field with unknown purpose. + + + + + Gets or sets the element offset in the to an initial translation. + + + + + Gets or sets instances animating properties of objects stored in this section. + + + + + Gets or sets initial transformation values. Only stores specific transformations according to + . + + + + + Gets the index of the first relative to all curves of the parent + instances. + + + + + Represents if initial values exist for the corresponding transformation in the base animation data. + + + + + Initial scaling values exist. + + + + + Initial rotation values exist. + + + + + Initial translation values exist. + + + + + Represents if curves exist which animate the corresponding transformation component. + + + + + Curve animating the X component of a bone's scale. + + + + + Curve animating the Y component of a bone's scale. + + + + + Curve animating the Z component of a bone's scale. + + + + + Curve animating the X component of a bone's rotation. + + + + + Curve animating the Y component of a bone's rotation. + + + + + Curve animating the Z component of a bone's rotation. + + + + + Curve animating the W component of a bone's rotation. + + + + + Curve animating the X component of a bone's translation. + + + + + Curve animating the Y component of a bone's translation. + + + + + Curve animating the Z component of a bone's translation. + + + + + Represents how a bone transformation has to be applied. + + + + + Represents the animatable data of a instance. + + + + + The scaling of the bone. + + + + + The translation of the bone. + + + + + An unused field. + + + + + The rotation of the bone. + + + + + Gets the for instances. + + + + + Animates (never seen in files). + + + + + Animates the X component of . + + + + + Animates the Y component of . + + + + + Animates the Z component of . + + + + + Animates the X component of . + + + + + Animates the Y component of . + + + + + Animates the Z component of . + + + + + Animates the X component of . + + + + + Animates the Y component of . + + + + + Animates the Z component of . + + + + + Animates the W component of . + + + + + Represents an FSKA subfile in a , storing armature animations of + instances in a . + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the path of the file which originally supplied the data of this instance. + + + + + Gets or sets the mode used to control looping and baked settings. + + + + + Gets or sets the mode used to store scaling values. + + + + + Gets or sets the mode used to store rotation values. + + + + + Gets or sets the total number of frames this animation plays. + + + + + Gets or sets the number of bytes required to bake all instances of all + . + + + + + Gets or sets the instances creating the animation. + + + + + Gets or sets the instance affected by this animation. + + + + + Gets or sets the indices of the instances in the dictionary + to bind for each animation. specifies no binding. + + + + + Gets or sets customly attached instances. + + + + + Represents flags specifying how animation data is stored or should be played. + + + + + The stored curve data has been baked. + + + + + The animation repeats from the start after the last frame has been played. + + + + + Represents the data format in which scaling values are stored. + + + + + No scaling. + + + + + Default scaling. + + + + + Autodesk Maya scaling. + + + + + Autodesk Softimage scaling. + + + + + Represents the data format in which rotation values are stored. + + + + + Quaternion, 4 components. + + + + + Euler XYZ, 3 components. + + + + + Represents a pattern animation info in a instance. + + + + + Gets or sets the index of the curve in the . + + + + + Gets or sets the index of the texture in the . + + + + + Gets or sets the name of the in the . + + + + + Represents an FTXP subfile in a , storing texture material pattern animations. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the path of the file which originally supplied the data of this instance. + + + + + Gets or sets flags controlling how animation data is stored or how the animation should be played. + + + + + Gets or sets the total number of frames this animation plays. + + + + + Gets or sets the number of bytes required to bake all instances of all + . + + + + + Gets or sets the instance affected by this animation. + + + + + Gets or sets the indices of the instances in the + dictionary to bind for each animation. specifies no binding. + + + + + Gets or sets the instances creating the animation. + + + + + Gets or sets the instances pointing to instances + participating in the animation. + + + + + Note used for older bfres files + Gets or sets the instances pointing to instances + participating in the animation. + + + + + Gets or sets customly attached instances. + + + + + Represents flags specifying how animation data is stored or should be played. + + + + + The stored curve data has been baked. + + + + + The animation repeats from the start after the last frame has been played. + + + + + Represents a texture pattern material animation in a subfile. + + + + + Gets the name of the animated . + + + + + Gets or sets the list of instances. + + + + + Gets or sets instances animating properties of objects stored in this section. + + + + + Gets or sets the initial indices. + + + + + Gets or sets the index of the first relative to all curves of the parent + instances. + + + + + Gets or sets the index of the first relative to all param anim infos of the + parent instances. + + + + + Represents an FMDL subfile in a , storing multi-dimensional texture data. + + + + + Gets or sets the shape of the texture. + + + + + Gets or sets the width of the texture. + + + + + Gets or sets the height of the texture. + + + + + Gets or sets the depth of the texture. + + + + + Gets or sets the number of mipmaps stored in the . + + + + + Gets or sets the desired texture data buffer format. + + + + + Gets or sets the number of samples for the texture. + + + + + Gets or sets the texture data usage hint. + + + + + Gets or sets the tiling mode. + + + + + Gets or sets the swizzling value. + + + + + Gets or sets the swizzling alignment. + + + + + Gets or sets the pixel swizzling stride. + + + + + Gets or sets the offsets in the array to the data of the mipmap level corresponding + to the array index. + + + + + Gets or sets the source channel to map to the R (red) channel. + + + + + Gets or sets the source channel to map to the G (green) channel. + + + + + Gets or sets the source channel to map to the B (blue) channel. + + + + + Gets or sets the source channel to map to the A (alpha) channel. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the path of the file which originally supplied the data of this instance. + + + + + Gets or sets the raw texture data bytes. + + + + + Gets or sets the raw mipmap level data bytes for all levels. + + + + + Gets or sets customly attached instances. + + + + + Represents an FVIS subfile in a , storing visibility animations of or + instances. + + + + + Gets or sets the name with which the instance can be referenced uniquely in + instances. + + + + + Gets or sets the path of the file which originally supplied the data of this instance. + + + + + Gets or sets flags controlling how animation data is stored or how the animation should be played. + + + + + Gets or sets the kind of data the animation controls. + + + + + Gets or sets the total number of frames this animation plays. + + + + + Gets or sets the number of bytes required to bake all . + + + + + Gets or sets the instance affected by this animation. + + + + + Gets or sets the indices of entries in the or + dictionaries to bind to for each animation. specifies no binding. + + + + + Gets or sets the names of entries in the or + dictionaries to bind to for each animation. + + + + + Gets or sets instances animating properties of objects stored in this section. + + + + + Gets or sets boolean values storing the initial visibility for each or + . + + + + + Gets or sets customly attached instances. + + + + + Represents flags specifying how animation data is stored or should be played. + + + + + The stored curve data has been baked. + + + + + The animation repeats from the start after the last frame has been played. + + + + + Represents the kind of data the visibility animation controls. + + + + + Bone visiblity is controlled. + + + + + Material visibility is controlled. + + + + diff --git a/Switch_Toolbox/MainForm.cs b/Switch_Toolbox/MainForm.cs index 2a564346..4c147c12 100644 --- a/Switch_Toolbox/MainForm.cs +++ b/Switch_Toolbox/MainForm.cs @@ -238,6 +238,7 @@ namespace Switch_Toolbox FileReader f = new FileReader(data); 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") @@ -268,7 +269,7 @@ namespace Switch_Toolbox //Check magic first regardless of extension foreach (IFileFormat format in SupportedFormats) { - if (format.Magic == Magic || format.Magic == Magic2 || format.Magic.Reverse() == Magic2) + if (format.Magic == Magic || format.Magic == Magic3 || format.Magic == Magic2 || format.Magic.Reverse() == Magic2) { format.CompressionType = CompType; format.FileIsCompressed = Compressed; diff --git a/Switch_Toolbox/Program.cs b/Switch_Toolbox/Program.cs index 41d7296a..cd71da41 100644 --- a/Switch_Toolbox/Program.cs +++ b/Switch_Toolbox/Program.cs @@ -21,6 +21,5 @@ namespace Switch_Toolbox Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } - } } diff --git a/Switch_Toolbox/Switch_Toolbox.csproj b/Switch_Toolbox/Switch_Toolbox.csproj index 786a8635..d65fd17a 100644 --- a/Switch_Toolbox/Switch_Toolbox.csproj +++ b/Switch_Toolbox/Switch_Toolbox.csproj @@ -367,9 +367,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest diff --git a/Switch_Toolbox_Library/FileFormats/Assimp/Assimp.cs b/Switch_Toolbox_Library/FileFormats/Assimp/Assimp.cs index 556e9a78..3731251b 100644 --- a/Switch_Toolbox_Library/FileFormats/Assimp/Assimp.cs +++ b/Switch_Toolbox_Library/FileFormats/Assimp/Assimp.cs @@ -8,6 +8,7 @@ using Assimp; using Assimp.Configs; using OpenTK; using Switch_Toolbox.Library.Rendering; +using System.Windows.Forms; namespace Switch_Toolbox.Library { @@ -31,12 +32,23 @@ namespace Switch_Toolbox.Library } public void LoadFile(string FileName) { - AssimpContext Importer = new AssimpContext(); + try + { + AssimpContext Importer = new AssimpContext(); - scene = Importer.ImportFile(FileName, PostProcessSteps.Triangulate | PostProcessSteps.JoinIdenticalVertices - | PostProcessSteps.FlipUVs | PostProcessSteps.LimitBoneWeights | - PostProcessSteps.CalculateTangentSpace | PostProcessSteps.GenerateNormals); - LoadMeshes(); + scene = Importer.ImportFile(FileName, PostProcessSteps.Triangulate | PostProcessSteps.JoinIdenticalVertices +| PostProcessSteps.FlipUVs | PostProcessSteps.LimitBoneWeights | +PostProcessSteps.CalculateTangentSpace | PostProcessSteps.GenerateNormals); + LoadMeshes(); + } + catch (Exception e) + { + if (e.ToString().Contains("Error loading unmanaged library from path")) + { + MessageBox.Show($"Failed to load assimp! Make sure you have Assimp32.dll next to the program!"); + } + Console.WriteLine(e); + } } public void processNode() { diff --git a/Switch_Toolbox_Library/FileFormats/DDS.cs b/Switch_Toolbox_Library/FileFormats/DDS.cs index eda64e55..52a3d894 100644 --- a/Switch_Toolbox_Library/FileFormats/DDS.cs +++ b/Switch_Toolbox_Library/FileFormats/DDS.cs @@ -325,9 +325,6 @@ namespace Switch_Toolbox.Library reader.TemporarySeek((int)(4 + header.size + DX10HeaderSize), SeekOrigin.Begin); bdata = reader.ReadBytes((int)(reader.BaseStream.Length - reader.Position)); - - - reader.Dispose(); reader.Close(); }