using System; using System.Collections.Generic; using System.Linq; using System.IO; using System.Data; using System.Threading; using System.Windows.Forms; using Switch_Toolbox.Library; using Switch_Toolbox.Library.Forms; using Switch_Toolbox.Library.IO; using Bfres.Structs; using ResU = Syroot.NintenTools.Bfres; using Syroot.NintenTools.NSW.Bfres; using Switch_Toolbox.Library.Animations; using Switch_Toolbox.Library.NodeWrappers; using GL_EditorFramework.Interfaces; using FirstPlugin.Forms; using FirstPlugin.NodeWrappers; namespace FirstPlugin { public class BFRES : BFRESWrapper, IFileFormat { public bool CanSave { get; set; } public string[] Description { get; set; } = new string[] { "BFRES" }; public string[] Extension { get; set; } = new string[] { "*.bfres", "*.sbfres", "*.sbmapopen", "*.sbstftex", "*.sbitemico", "*.sbmaptex", "*.sbreviewtex" }; public string FileName { get; set; } public string FilePath { get; set; } public IFileInfo IFileInfo { get; set; } public bool Identify(Stream stream) { using (var reader = new FileReader(stream, true)) { return reader.CheckSignature(4, "FRES"); } } public Type[] Types { get { List types = new List(); types.Add(typeof(MenuExt)); return types.ToArray(); } } private Thread Thread; public override string ExportFilter => Utils.GetAllFilters(new BFRES()); class MenuExt : IFileMenuExtension { public STToolStripItem[] NewFileMenuExtensions => newFileExt; public STToolStripItem[] NewFromFileMenuExtensions => null; public STToolStripItem[] EditMenuExtensions => editExt; public STToolStripItem[] ToolsMenuExtensions => toolExt; public STToolStripItem[] TitleBarExtensions => null; public STToolStripItem[] CompressionMenuExtensions => null; public STToolStripItem[] ExperimentalMenuExtensions => null; STToolStripItem[] toolExt = new STToolStripItem[1]; STToolStripItem[] newFileExt = new STToolStripItem[2]; STToolStripItem[] editExt = new STToolStripItem[1]; public MenuExt() { editExt[0] = new STToolStripItem("Use Advanced Editor As Default"); editExt[0].Click += AdvancedEditor; toolExt[0] = new STToolStripItem("Open Bfres Debugger"); toolExt[0].Click += DebugInfo; newFileExt[0] = new STToolStripItem("BFRES (Switch)"); newFileExt[0].Click += NewSwitchBfres; newFileExt[1] = new STToolStripItem("BFRES (Wii U)"); newFileExt[1].Click += NewWiiUBfres; editExt[0].Checked = !PluginRuntime.UseSimpleBfresEditor; } private void AdvancedEditor(object sender, EventArgs args) { if (editExt[0].Checked) { editExt[0].Checked = false; PluginRuntime.UseSimpleBfresEditor = true; } else { editExt[0].Checked = true; PluginRuntime.UseSimpleBfresEditor = false; } } private void NewWiiUBfres(object sender, EventArgs args) { BFRES bfres = new BFRES(); bfres.IFileInfo = new IFileInfo(); bfres.FileName = "Untitled.bfres"; bfres.Load(new MemoryStream(BfresWiiU.CreateNewBFRES("Untitled.bfres"))); ObjectEditor editor = new ObjectEditor(); editor.Text = "Untitled-" + 0; editor.treeViewCustom1.Nodes.Add(bfres); LibraryGUI.Instance.CreateMdiWindow(editor); } private void NewSwitchBfres(object sender, EventArgs args) { BFRES bfres = new BFRES(); bfres.IFileInfo = new IFileInfo(); bfres.FileName = "Untitled.bfres"; bfres.Load(new MemoryStream(CreateNewBFRESSwitch("Untitled.bfres"))); ObjectEditor editor = new ObjectEditor(); editor.Text = "Untitled-" + 0; editor.treeViewCustom1.Nodes.Add(bfres); LibraryGUI.Instance.CreateMdiWindow(editor); } private void DebugInfo(object sender, EventArgs args) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = Utils.GetAllFilters(new BFRES()); if (ofd.ShowDialog() != DialogResult.OK) return; var debugInfo = new DebugInfoBox(); debugInfo.Show(); debugInfo.PrintDebugInfo(ofd.FileName); } } private static byte[] CreateNewBFRESSwitch(string Name) { MemoryStream mem = new MemoryStream(); ResFile resFile = new ResFile(); resFile.Name = Name; resFile.Save(mem); var data = mem.ToArray(); mem.Close(); mem.Dispose(); return data; } public void OnPropertyChanged() { if (resFile != null) { Text = resFile.Name; } else { Text = resFileU.Name; } STPropertyGrid editor = (STPropertyGrid)LibraryGUI.Instance.GetActiveContent(typeof(STPropertyGrid)); if (editor != null) editor.Refresh(); } //Used for adding new skeleton drawables public void AddSkeletonDrawable(STSkeleton skeleton) { BfresEditor bfresEditor = (BfresEditor)LibraryGUI.Instance.GetActiveContent(typeof(BfresEditor)); if (bfresEditor != null) { bfresEditor.AddDrawable(skeleton); } drawables.Add(skeleton); } public void RemoveSkeletonDrawable(STSkeleton skeleton) { BfresEditor bfresEditor = (BfresEditor)LibraryGUI.Instance.GetActiveContent(typeof(BfresEditor)); if (bfresEditor != null) { bfresEditor.RemoveDrawable(skeleton); } drawables.Remove(skeleton); } List drawables = new List(); public void LoadEditors(object SelectedSection) { bool IsSimpleEditor = PluginRuntime.UseSimpleBfresEditor; if (IsSimpleEditor) { STPropertyGrid editor = (STPropertyGrid)LibraryGUI.Instance.GetActiveContent(typeof(STPropertyGrid)); if (editor == null) { editor = new STPropertyGrid(); editor.Dock = DockStyle.Fill; LibraryGUI.Instance.LoadEditor(editor); } editor.Text = Text; if (SelectedSection is BFRES) { if (resFile != null) editor.LoadProperty(resFile, OnPropertyChanged); else editor.LoadProperty(resFileU, OnPropertyChanged); } else if (SelectedSection is FMDL) { if (((FMDL)SelectedSection).ModelU != null) editor.LoadProperty(((FMDL)SelectedSection).ModelU, OnPropertyChanged); else editor.LoadProperty(((FMDL)SelectedSection).Model, OnPropertyChanged); } else if (SelectedSection is FSHP) { if (((FSHP)SelectedSection).ShapeU != null) editor.LoadProperty(((FSHP)SelectedSection).ShapeU, OnPropertyChanged); else editor.LoadProperty(((FSHP)SelectedSection).Shape, OnPropertyChanged); } else if (SelectedSection is FMAT) { if (((FMAT)SelectedSection).MaterialU != null) editor.LoadProperty(((FMAT)SelectedSection).MaterialU, OnPropertyChanged); else editor.LoadProperty(((FMAT)SelectedSection).MaterialU, OnPropertyChanged); } else editor.LoadProperty(null, OnPropertyChanged); } else { BfresEditor bfresEditor = (BfresEditor)LibraryGUI.Instance.GetActiveContent(typeof(BfresEditor)); bool HasModels = BFRESRender.models.Count > 0; if (bfresEditor == null) { bfresEditor = new BfresEditor(HasModels); bfresEditor.Dock = DockStyle.Fill; LibraryGUI.Instance.LoadEditor(bfresEditor); } var toolstrips = new List(); var menu = new ToolStripMenuItem("Animation Loader", null, AnimLoader); toolstrips.Add(menu); bool IsLoaded = drawables.Count != 0; bfresEditor.IsLoaded = IsLoaded; if (drawables.Count <= 0) { //Add drawables drawables.Add(BFRESRender); foreach (var mdl in BFRESRender.models) drawables.Add(mdl.Skeleton); } bfresEditor.LoadViewport(drawables, toolstrips); if (!IsLoaded) { bfresEditor.OnLoadedTab(); } if (SelectedSection is BFRES) { STPropertyGrid editor = (STPropertyGrid)bfresEditor.GetActiveEditor(typeof(STPropertyGrid)); if (editor == null) { editor = new STPropertyGrid(); editor.Dock = DockStyle.Fill; bfresEditor.LoadEditor(editor); } editor.Text = Text; if (resFile != null) editor.LoadProperty(resFile, OnPropertyChanged); else editor.LoadProperty(resFileU, OnPropertyChanged); } else if (SelectedSection is BFRESGroupNode) { STPropertyGrid editor = (STPropertyGrid)bfresEditor.GetActiveEditor(typeof(STPropertyGrid)); if (editor == null) { editor = new STPropertyGrid(); editor.Dock = DockStyle.Fill; bfresEditor.LoadEditor(editor); } editor.Text = Text; editor.LoadProperty(null, null); } else if (SelectedSection is FSKL.fsklNode) { FSKLEditor editor = (FSKLEditor)bfresEditor.GetActiveEditor(typeof(FSKLEditor)); if (editor == null) { editor = new FSKLEditor(); editor.Text = Text; editor.Dock = DockStyle.Fill; bfresEditor.LoadEditor(editor); } editor.LoadSkeleton(((FSKL.fsklNode)SelectedSection).fskl); } else if (SelectedSection is BfresBone) { BfresBoneEditor editor = (BfresBoneEditor)bfresEditor.GetActiveEditor(typeof(BfresBoneEditor)); if (editor == null) { editor = new BfresBoneEditor(); editor.Text = Text; editor.Dock = DockStyle.Fill; bfresEditor.LoadEditor(editor); } editor.LoadBone((BfresBone)SelectedSection); } else if (SelectedSection is FSHP) { BfresShapeEditor editor = (BfresShapeEditor)bfresEditor.GetActiveEditor(typeof(BfresShapeEditor)); if (editor == null) { editor = new BfresShapeEditor(); editor.Text = Text; editor.Dock = DockStyle.Fill; bfresEditor.LoadEditor(editor); } editor.LoadShape((FSHP)SelectedSection); } else if (SelectedSection is FMAT) { FMATEditor editor = (FMATEditor)bfresEditor.GetActiveEditor(typeof(FMATEditor)); if (editor == null) { editor = new FMATEditor(); editor.Text = Text; editor.Dock = DockStyle.Fill; bfresEditor.LoadEditor(editor); } editor.LoadMaterial((FMAT)SelectedSection); } else if (SelectedSection is FSKA.BoneAnimNode) { BoneAnimEditor editor = (BoneAnimEditor)bfresEditor.GetActiveEditor(typeof(BoneAnimEditor)); if (editor == null) { editor = new BoneAnimEditor(); editor.Text = Text; editor.Dock = DockStyle.Fill; bfresEditor.LoadEditor(editor); } editor.LoadBoneAnim((FSKA.BoneAnimNode)SelectedSection); } else if (SelectedSection is FSCN.BfresCameraAnim) { SceneAnimEditor editor = (SceneAnimEditor)bfresEditor.GetActiveEditor(typeof(SceneAnimEditor)); if (editor == null) { editor = new SceneAnimEditor(); editor.Text = Text; editor.Dock = DockStyle.Fill; bfresEditor.LoadEditor(editor); } editor.LoadCameraAnim((FSCN.BfresCameraAnim)SelectedSection); } else if (SelectedSection is FSCN.BfresLightAnim) { SceneAnimEditor editor = (SceneAnimEditor)bfresEditor.GetActiveEditor(typeof(SceneAnimEditor)); if (editor == null) { editor = new SceneAnimEditor(); editor.Text = Text; editor.Dock = DockStyle.Fill; bfresEditor.LoadEditor(editor); } editor.LoadLightAnim((FSCN.BfresLightAnim)SelectedSection); } else if (SelectedSection is FSCN.BfresFogAnim) { SceneAnimEditor editor = (SceneAnimEditor)bfresEditor.GetActiveEditor(typeof(SceneAnimEditor)); if (editor == null) { editor = new SceneAnimEditor(); editor.Text = Text; editor.Dock = DockStyle.Fill; bfresEditor.LoadEditor(editor); } editor.LoadFogAnim((FSCN.BfresFogAnim)SelectedSection); } else if (SelectedSection is FMDL) OpenSubFileEditor(SelectedSection, bfresEditor); else if (SelectedSection is FSKA) OpenSubFileEditor(SelectedSection, bfresEditor); else if (SelectedSection is FSHU) OpenSubFileEditor(SelectedSection, bfresEditor); else if (SelectedSection is FSCN) OpenSubFileEditor(SelectedSection, bfresEditor); else if (SelectedSection is FSHA) OpenSubFileEditor(SelectedSection, bfresEditor); else if (SelectedSection is FTXP) OpenSubFileEditor(SelectedSection, bfresEditor); else if (SelectedSection is FMAA) OpenSubFileEditor(SelectedSection, bfresEditor); else if (SelectedSection is FVIS) OpenSubFileEditor(SelectedSection, bfresEditor); /* else if (SelectedSection is FMAA && ((FMAA)SelectedSection).AnimType == MaterialAnimation.AnimationType.TexturePattern) { BfresTexturePatternEditor editor = (BfresTexturePatternEditor)bfresEditor.GetActiveEditor(typeof(BfresTexturePatternEditor)); if (editor == null) { editor = new BfresTexturePatternEditor(); bfresEditor.LoadEditor(editor); } editor.Text = Text; editor.Dock = DockStyle.Fill; editor.LoadAnim((FMAA)SelectedSection); }*/ } } private SubFileEditor OpenSubFileEditor(object node, BfresEditor bfresEditor) where T : STGenericWrapper { SubFileEditor editor = (SubFileEditor)bfresEditor.GetActiveEditor(typeof(SubFileEditor)); if (editor == null) { editor = new SubFileEditor(); editor.Dock = DockStyle.Fill; bfresEditor.LoadEditor(editor); } editor.LoadSubFile(node); return editor; } public void AnimLoader(object sender, EventArgs args) { AnimationLoader loader = new AnimationLoader(); loader.TopLevel = true; loader.Show(); } public BFRESRender BFRESRender; public void Load(System.IO.Stream stream) { CanSave = true; ImageKey = "bfres"; SelectedImageKey = "bfres"; using (FileReader reader = new FileReader(stream, true)) { reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; reader.Position = 4; if (reader.ReadInt32() != 0x20202020) IsWiiU = true; reader.Position = 0; } LoadMenus(IsWiiU); BFRESRender = new BFRESRender(); BFRESRender.ModelTransform = MarioCostumeEditor.SetTransform(FileName); BFRESRender.ResFileNode = this; if (IsWiiU) { BFRESRender.LoadFile(new Syroot.NintenTools.Bfres.ResFile(stream)); } else { BFRESRender.LoadFile(new Syroot.NintenTools.NSW.Bfres.ResFile(stream)); } } public void Unload() { BFRESRender.Destroy(); foreach (var node in TreeViewExtensions.Collect(BFRESRender.ResFileNode.Nodes)) { if (node is BFRESGroupNode) { if (((BFRESGroupNode)node).Type == BRESGroupType.Textures) { if (PluginRuntime.ftexContainers.Contains(((BFRESGroupNode)node))) PluginRuntime.ftexContainers.Remove(((BFRESGroupNode)node)); } } if (node is BNTX) ((BNTX)node).Unload(); } Nodes.Clear(); } public byte[] Save() { MemoryStream mem = new MemoryStream(); if (IsWiiU) SaveWiiU(mem); else SaveSwitch(mem); return mem.ToArray(); } public ResFile resFile = null; public ResU.ResFile resFileU = null; public override void OnClick(TreeView treeView) { LoadEditors(this); } public void Load(ResU.ResFile res) { CanDelete = true; resFileU = res; Text = resFileU.Name; var modelFolder = new BFRESGroupNode(BRESGroupType.Models); var texturesFolder = new BFRESGroupNode(BRESGroupType.Textures); var animFolder = new BFRESAnimFolder(); var externalFilesFolder = new BFRESGroupNode(BRESGroupType.Embedded); Nodes.Add(modelFolder); Nodes.Add(texturesFolder); Nodes.Add(animFolder); Nodes.Add(externalFilesFolder); animFolder.LoadMenus(IsWiiU); PluginRuntime.ftexContainers.Add(texturesFolder); if (resFileU.Models.Count > 0) { foreach (ResU.Model mdl in resFileU.Models.Values) { var fmdl = new FMDL(); BfresWiiU.ReadModel(fmdl, mdl); modelFolder.AddNode(fmdl); } } if (resFileU.Textures.Count > 0) { foreach (ResU.Texture tex in resFileU.Textures.Values) { var ftex = new FTEX(tex); texturesFolder.AddNode(ftex); ftex.UpdateMipMaps(); } } if (resFileU.SkeletalAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.SkeletalAnim); animFolder.Nodes.Add(group); foreach (ResU.SkeletalAnim anim in resFileU.SkeletalAnims.Values) group.AddNode(new FSKA(anim)); } if (resFileU.ShaderParamAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.ShaderParamAnim); animFolder.Nodes.Add(group); foreach (ResU.ShaderParamAnim anim in resFileU.ShaderParamAnims.Values) group.AddNode(new FSHU(anim, MaterialAnimation.AnimationType.ShaderParam)); } if (resFileU.ColorAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.ColorAnim); animFolder.Nodes.Add(group); foreach (ResU.ShaderParamAnim anim in resFileU.ColorAnims.Values) group.AddNode(new FSHU(anim, MaterialAnimation.AnimationType.Color)); } if (resFileU.TexSrtAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.TexSrtAnim); animFolder.Nodes.Add(group); foreach (ResU.ShaderParamAnim anim in resFileU.TexSrtAnims.Values) group.AddNode(new FSHU(anim, MaterialAnimation.AnimationType.TexturePattern)); } if (resFileU.TexPatternAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.TexPatAnim); animFolder.Nodes.Add(group); foreach (ResU.TexPatternAnim anim in resFileU.TexPatternAnims.Values) group.AddNode(new FTXP(anim)); } if (resFileU.ShapeAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.ShapeAnim); animFolder.Nodes.Add(group); foreach (ResU.ShapeAnim anim in resFileU.ShapeAnims.Values) group.AddNode(new FSHA(anim)); } if (resFileU.BoneVisibilityAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.BoneVisAnim); animFolder.Nodes.Add(group); foreach (ResU.VisibilityAnim anim in resFileU.BoneVisibilityAnims.Values) group.AddNode(new FVIS(anim)); } if (resFileU.MatVisibilityAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.MatVisAnim); animFolder.Nodes.Add(group); foreach (ResU.VisibilityAnim anim in resFileU.BoneVisibilityAnims.Values) group.AddNode(new FVIS(anim)); } if (resFileU.SceneAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.SceneAnim); animFolder.Nodes.Add(group); foreach (ResU.SceneAnim anim in resFileU.SceneAnims.Values) group.AddNode(new FSCN(anim)); } if (resFileU.ExternalFiles.Count > 0) { foreach (var anim in resFileU.ExternalFiles) { externalFilesFolder.AddNode(new ExternalFileData(anim.Key, anim.Value.Data)); } } } public void Load(ResFile res) { resFile = res; Text = resFile.Name; var modelFolder = new BFRESGroupNode(BRESGroupType.Models); var texturesFolder = new BNTX() { ImageKey = "folder", SelectedImageKey = "folder", Text = "Textures" }; var animFolder = new BFRESAnimFolder(); var externalFilesFolder = new BFRESGroupNode(BRESGroupType.Embedded); //Texture folder acts like a bntx for saving back //This will only save if the user adds textures to it or the file has a bntx already texturesFolder.IFileInfo = new IFileInfo(); texturesFolder.FileName = "Textures"; texturesFolder.Load(new MemoryStream(BNTX.CreateNewBNTX("Textures"))); animFolder.LoadMenus(IsWiiU); Nodes.Add(modelFolder); Nodes.Add(texturesFolder); Nodes.Add(animFolder); Nodes.Add(externalFilesFolder); if (resFile.Models.Count > 0) { foreach (Model mdl in resFile.Models) { var fmdl = new FMDL(); BfresSwitch.ReadModel(fmdl, mdl); modelFolder.AddNode(fmdl); } } if (resFile.SkeletalAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.SkeletalAnim); animFolder.Nodes.Add(group); foreach (SkeletalAnim anim in resFile.SkeletalAnims) group.AddNode(new FSKA(anim)); } if (resFile.MaterialAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.ShaderParamAnim); var group2 = new BFRESGroupNode(BRESGroupType.TexSrtAnim); var group3 = new BFRESGroupNode(BRESGroupType.TexPatAnim); var group4 = new BFRESGroupNode(BRESGroupType.ColorAnim); var group5 = new BFRESGroupNode(BRESGroupType.MatVisAnim); var group6 = new BFRESGroupNode(BRESGroupType.MaterialAnim); bool HasShaderParamsAnim = false; bool HasTextureSrtAnim = false; bool HasTexturePatternAnim = false; bool HasColorAnim = false; bool HasMatVisAnim = false; bool HasMaterialAnim = false; foreach (MaterialAnim anim in resFile.MaterialAnims) { if (FMAA.IsShaderParamAnimation(anim.Name)) { group.AddNode(new FMAA(anim, MaterialAnimation.AnimationType.ShaderParam)); HasShaderParamsAnim = true; } else if (FMAA.IsSRTAnimation(anim.Name)) { group2.AddNode(new FMAA(anim, MaterialAnimation.AnimationType.TextureSrt)); HasTextureSrtAnim = true; } else if(FMAA.IsTexturePattern(anim.Name)) { group3.AddNode(new FMAA(anim, MaterialAnimation.AnimationType.TexturePattern)); HasTexturePatternAnim = true; } else if (FMAA.IsColorAnimation(anim.Name)) { group4.AddNode(new FMAA(anim, MaterialAnimation.AnimationType.Color)); HasColorAnim = true; } else if (FMAA.IsVisibiltyAnimation(anim.Name)) { group5.AddNode(new FMAA(anim, MaterialAnimation.AnimationType.Visibilty)); HasMatVisAnim = true; } else { group6.AddNode(new FMAA(anim, MaterialAnimation.AnimationType.ShaderParam)); HasMaterialAnim = true; } } if (HasShaderParamsAnim) animFolder.Nodes.Add(group); if (HasTextureSrtAnim) animFolder.Nodes.Add(group2); if (HasTexturePatternAnim) animFolder.Nodes.Add(group3); if (HasColorAnim) animFolder.Nodes.Add(group4); if (HasMatVisAnim) animFolder.Nodes.Add(group5); if (HasMaterialAnim) animFolder.Nodes.Add(group6); } if (resFile.BoneVisibilityAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.BoneVisAnim); animFolder.Nodes.Add(group); foreach (VisibilityAnim anim in resFile.BoneVisibilityAnims) group.AddNode(new FVIS(anim)); } if (resFile.SceneAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.SceneAnim); animFolder.Nodes.Add(group); foreach (SceneAnim anim in resFile.SceneAnims) group.AddNode(new FSCN(anim)); } if (resFile.ShapeAnims.Count > 0) { var group = new BFRESGroupNode(BRESGroupType.ShapeAnim); animFolder.Nodes.Add(group); foreach (ShapeAnim anim in resFile.ShapeAnims) group.AddNode(new FSHA(anim)); } if (resFile.ExternalFiles.Count > 0) { int index = 0; //This also can be set to true if we don't want to rebuild the bntx for debug purposes bool IsTexturesReplaced = false; foreach (var anim in resFile.ExternalFiles) { // group.AddNode(new ExternalFileData(Name, anim.Data) { FileFormat = file }); string Name = resFile.ExternalFileDict.GetKey(index++); var file = STFileLoader.OpenFileFormat(Name, anim.Data, false, true); //Only do once. There's usually one bntx embedded but incase there are multiple if (file is BNTX && !IsTexturesReplaced) { ((TreeNode)file).Text = texturesFolder.Text; ((TreeNode)file).ImageKey = texturesFolder.ImageKey; ((TreeNode)file).SelectedImageKey = texturesFolder.SelectedImageKey; //Remove temporary bntx file with file one PluginRuntime.bntxContainers.Remove(texturesFolder); ReplaceNode(texturesFolder.Parent, texturesFolder, (TreeNode)file); IsTexturesReplaced = true; } else { externalFilesFolder.AddNode(new ExternalFileData(Name, anim.Data)); } } } } public static void ReplaceNode(TreeNode node, TreeNode replaceNode, TreeNode NewNode) { if (NewNode == null) return; int index = node.Nodes.IndexOf(replaceNode); node.Nodes.RemoveAt(index); node.Nodes.Insert(index, NewNode); } public override void Export(string FileName) { bool IsTex1 = FileName.Contains("Tex1"); bool HasTextures = false; foreach (TreeNode group in Nodes) { if (group is BFRESGroupNode) { if (((BFRESGroupNode)group).Type == BRESGroupType.Textures && group.Nodes.Count > 0) HasTextures = true; } } if (IsTex1 && HasTextures) { STFileSaver.SaveFileFormat(this, FileName); byte[] Tex2 = GenerateTex2(); SaveFileDialog sfd = new SaveFileDialog(); sfd.FileName = FileName.Replace("Tex1", "Tex2"); sfd.DefaultExt = ".sbfres"; List formats = new List(); formats.Add(this); sfd.Filter = Utils.GetAllFilters(formats); if (sfd.ShowDialog() == DialogResult.OK) STFileSaver.SaveFileFormat(Tex2, true, 0, CompressionType.Yaz0, sfd.FileName); } else STFileSaver.SaveFileFormat(this, FileName); } private byte[] GenerateTex2() { var mem = new MemoryStream(); var resFileU = BFRESRender.ResFileNode.resFileU; //Create a tex2 file ResU.ResFile resFileTex2 = new ResU.ResFile(); resFileTex2.Alignment = resFileU.Alignment; resFileTex2.Name = resFileU.Name.Replace("Tex1", "Tex2"); resFileTex2.VersionMajor = resFileU.VersionMajor; resFileTex2.VersionMajor2 = resFileU.VersionMajor2; resFileTex2.VersionMinor = resFileU.VersionMinor; resFileTex2.VersionMinor2 = resFileU.VersionMinor2; resFileTex2.Textures = resFileU.Textures; foreach (var group in Nodes) { if (group is BFRESGroupNode) { if (((BFRESGroupNode)group).Type != BRESGroupType.Textures) continue; foreach (FTEX tex in ((BFRESGroupNode)group).Nodes) { if (resFileTex2.Textures.ContainsKey(tex.Text)) { resFileTex2.Textures[tex.Text].MipData = tex.texture.MipData; resFileTex2.Textures[tex.Text].MipOffsets = tex.texture.MipOffsets; resFileTex2.Textures[tex.Text].MipCount = tex.texture.MipCount; resFileTex2.Textures[tex.Text].Swizzle = tex.Tex2Swizzle; } } } } resFileTex2.Save(mem); return mem.ToArray(); } private void SaveTex2(string fileName) { bool Compressed = fileName.EndsWith("sbfres"); byte[] data; if (Compressed) data = EveryFileExplorer.YAZ0.Decompress(fileName); else data = File.ReadAllBytes(fileName); ResU.ResFile resFileTex2 = new ResU.ResFile(new MemoryStream(data)); foreach (BFRESGroupNode group in Nodes) { if (group.Type != BRESGroupType.Textures) return; foreach (FTEX tex in group.Nodes) { if (resFileTex2.Textures.ContainsKey(tex.Text)) { resFileTex2.Textures[tex.Text].MipData = tex.texture.MipData; resFileTex2.Textures[tex.Text].MipOffsets = tex.texture.MipOffsets; resFileTex2.Textures[tex.Text].MipCount = tex.texture.MipCount; } } } MemoryStream mem2 = new MemoryStream(); resFileTex2.Save(mem2); SaveFileDialog sfd = new SaveFileDialog(); sfd.FileName = FileName + "NewTex2.sbfres"; List formats = new List(); formats.Add(this); sfd.Filter = Utils.GetAllFilters(formats); if (sfd.ShowDialog() == DialogResult.OK) STFileSaver.SaveFileFormat(mem2.ToArray(), Compressed, 0, CompressionType.Yaz0, sfd.FileName); } private void Rename(object sender, EventArgs args) { RenameDialog dialog = new RenameDialog(); dialog.SetString(Text); if (dialog.ShowDialog() == DialogResult.OK) { Text = dialog.textBox1.Text; } } private void Remove(object sender, EventArgs args) { Unload(); } private void SaveSwitch(MemoryStream mem) { var resFile = BFRESRender.ResFileNode.resFile; resFile.Models.Clear(); resFile.SkeletalAnims.Clear(); resFile.MaterialAnims.Clear(); 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(); resFile.ExternalFiles.Clear(); resFile.ExternalFileDict.Clear(); foreach (TreeNode node in Nodes) { if (node is BFRESGroupNode) SaveBfresSwitchGroup((BFRESGroupNode)node, resFile); if (node is BFRESAnimFolder) { foreach (var animGroup in node.Nodes) SaveBfresSwitchGroup((BFRESGroupNode)animGroup, resFile); } if (node is BNTX) { if (((BNTX)node).Textures.Count > 0) { resFile.ExternalFiles.Add(new ExternalFile() { Data = ((BNTX)node).Save() }); resFile.ExternalFileDict.Add("textures.bntx"); } } } ErrorCheck(); resFile.Save(mem); } private static void SaveBfresSwitchGroup(BFRESGroupNode group, ResFile resFile) { switch (group.Type) { case BRESGroupType.Models: foreach (FMDL model in group.Nodes) { model.Model.Name = model.Text; resFile.Models.Add(BfresSwitch.SetModel(model)); } break; case BRESGroupType.SkeletalAnim: foreach (FSKA ska in group.Nodes) { // ska.SkeletalAnim.BoneAnims.Clear(); // foreach (FSKA.BoneAnimNode bone in ska.Bones) // ska.SkeletalAnim.BoneAnims.Add(bone.SaveData()); ska.SkeletalAnim.Name = ska.Text; resFile.SkeletalAnims.Add(ska.SkeletalAnim); } break; case BRESGroupType.TexPatAnim: case BRESGroupType.ShaderParamAnim: case BRESGroupType.ColorAnim: case BRESGroupType.TexSrtAnim: case BRESGroupType.MatVisAnim: foreach (FMAA fmaa in group.Nodes) { fmaa.MaterialAnim.MaterialAnimDataList.Clear(); foreach (FMAA.MaterialAnimEntry mat in fmaa.Materials) fmaa.MaterialAnim.MaterialAnimDataList.Add(mat.SaveData()); fmaa.SetName(); fmaa.SaveAnimData(); resFile.MaterialAnims.Add(fmaa.MaterialAnim); } break; case BRESGroupType.BoneVisAnim: foreach (FVIS fbnv in group.Nodes) { fbnv.SaveData(); fbnv.VisibilityAnim.Name = fbnv.Text; resFile.BoneVisibilityAnims.Add(fbnv.VisibilityAnim); } break; case BRESGroupType.ShapeAnim: foreach (FSHA fsha in group.Nodes) { fsha.ShapeAnim.VertexShapeAnims.Clear(); foreach (FSHA.ShapeAnimEntry shp in fsha.Nodes) fsha.ShapeAnim.VertexShapeAnims.Add(shp.SaveData()); fsha.ShapeAnim.Name = fsha.Text; resFile.ShapeAnims.Add(fsha.ShapeAnim); } break; case BRESGroupType.SceneAnim: foreach (FSCN fscn in group.Nodes) { fscn.SceneAnim.Name = fscn.Text; resFile.SceneAnims.Add(fscn.SceneAnim); } break; case BRESGroupType.Embedded: foreach (var ext in group.Nodes) { if (ext is ExternalFileData) { resFile.ExternalFiles.Add(new ExternalFile() { Data = ((ExternalFileData)ext).Data }); resFile.ExternalFileDict.Add(((ExternalFileData)ext).Text); } else if (ext is TreeNodeFile) { resFile.ExternalFiles.Add(new ExternalFile() { Data = ((IFileFormat)ext).Save() }); resFile.ExternalFileDict.Add(((TreeNodeFile)ext).Text); } } break; } } private void SaveMaterialAnims(TreeNodeCollection nodes) { } private void SaveWiiU(MemoryStream mem) { var resFileU = BFRESRender.ResFileNode.resFileU; resFileU.Models.Clear(); resFileU.Textures.Clear(); resFileU.SkeletalAnims.Clear(); resFileU.ShaderParamAnims.Clear(); resFileU.ColorAnims.Clear(); resFileU.TexSrtAnims.Clear(); resFileU.TexPatternAnims.Clear(); resFileU.BoneVisibilityAnims.Clear(); resFileU.MatVisibilityAnims.Clear(); resFileU.ShapeAnims.Clear(); resFileU.SceneAnims.Clear(); resFileU.ExternalFiles.Clear(); bool IsTex1 = FilePath.Contains("Tex1"); foreach (TreeNode node in Nodes) { if (node is BFRESGroupNode) SaveBfresWiiUGroup((BFRESGroupNode)node, resFileU); if (node is BFRESAnimFolder) { foreach (var animGroup in node.Nodes) SaveBfresWiiUGroup((BFRESGroupNode)animGroup, resFileU); } } // ErrorCheck(); resFileU.Save(mem); } private static void SaveBfresWiiUGroup(BFRESGroupNode group, ResU.ResFile resFileU) { switch (group.Type) { case BRESGroupType.Models: foreach (FMDL model in group.Nodes) { model.ModelU.Name = model.Text; resFileU.Models.Add(model.Text, BfresWiiU.SetModel(model)); } break; case BRESGroupType.Textures: foreach (FTEX tex in group.Nodes) { tex.texture.Name = tex.Text; resFileU.Textures.Add(tex.Text, tex.texture); } break; case BRESGroupType.SkeletalAnim: foreach (FSKA ska in group.Nodes) { ska.SkeletalAnimU.BoneAnims.Clear(); foreach (FSKA.BoneAnimNode bone in ska.Bones) ska.SkeletalAnimU.BoneAnims.Add(bone.SaveDataU()); ska.SkeletalAnimU.Name = ska.Text; resFileU.SkeletalAnims.Add(ska.Text, ska.SkeletalAnimU); } break; case BRESGroupType.ShaderParamAnim: foreach (FSHU anim in group.Nodes) { anim.ShaderParamAnim.ShaderParamMatAnims.Clear(); foreach (FSHU.MaterialAnimEntry bone in anim.Materials) anim.ShaderParamAnim.ShaderParamMatAnims.Add(bone.SaveData()); anim.ShaderParamAnim.Name = anim.Text; resFileU.ShaderParamAnims.Add(anim.Text, anim.ShaderParamAnim); } break; case BRESGroupType.ColorAnim: foreach (FSHU anim in group.Nodes) { anim.ShaderParamAnim.ShaderParamMatAnims.Clear(); foreach (FSHU.MaterialAnimEntry bone in anim.Materials) anim.ShaderParamAnim.ShaderParamMatAnims.Add(bone.SaveData()); anim.ShaderParamAnim.Name = anim.Text; resFileU.ColorAnims.Add(anim.Text, anim.ShaderParamAnim); } break; case BRESGroupType.TexSrtAnim: foreach (FSHU anim in group.Nodes) { anim.ShaderParamAnim.ShaderParamMatAnims.Clear(); foreach (FSHU.MaterialAnimEntry bone in anim.Materials) anim.ShaderParamAnim.ShaderParamMatAnims.Add(bone.SaveData()); anim.ShaderParamAnim.Name = anim.Text; resFileU.TexSrtAnims.Add(anim.Text, anim.ShaderParamAnim); } break; case BRESGroupType.TexPatAnim: foreach (FTXP anim in group.Nodes) { anim.TexPatternAnim.Name = anim.Text; resFileU.TexPatternAnims.Add(anim.Text, anim.TexPatternAnim); } break; case BRESGroupType.MatVisAnim: foreach (FVIS anim in group.Nodes) { anim.SaveData(); anim.VisibilityAnimU.Name = anim.Text; resFileU.MatVisibilityAnims.Add(anim.Text, anim.VisibilityAnimU); } break; case BRESGroupType.BoneVisAnim: foreach (FVIS anim in group.Nodes) { anim.SaveData(); anim.VisibilityAnimU.Name = anim.Text; resFileU.BoneVisibilityAnims.Add(anim.Text, anim.VisibilityAnimU); } break; case BRESGroupType.ShapeAnim: foreach (FSHA anim in group.Nodes) { anim.ShapeAnimU.VertexShapeAnims.Clear(); foreach (FSHA.ShapeAnimEntry shp in anim.Nodes) anim.ShapeAnimU.VertexShapeAnims.Add(shp.SaveDataU()); anim.ShapeAnimU.Name = anim.Text; resFileU.ShapeAnims.Add(anim.Text, anim.ShapeAnimU); } break; case BRESGroupType.SceneAnim: foreach (FSCN anim in group.Nodes) { anim.SceneAnimU.Name = anim.Text; resFileU.SceneAnims.Add(anim.Text, anim.SceneAnimU); } break; case BRESGroupType.Embedded: foreach (TreeNode ext in group.Nodes) { if (ext is ExternalFileData) { resFileU.ExternalFiles.Add(ext.Text, new ResU.ExternalFile() { Data = ((ExternalFileData)ext).Data }); } } break; } } public static void SetShaderAssignAttributes(FMAT.ShaderAssign shd, FSHP shape) { foreach (var att in shape.vertexAttributes) { if (!shd.attributes.ContainsValue(att.Name)) { try { shd.attributes.Add(att.Name, att.Name); } catch (Exception ex) { Console.WriteLine("Attribute link failed! \n " + ex); } } } foreach (var tex in shape.GetMaterial().TextureMaps) { if (!shd.samplers.ContainsValue(tex.SamplerName)) { try { shd.samplers.Add(tex.SamplerName, tex.SamplerName); } catch (Exception ex) { Console.WriteLine("Sampler link failed! \n " + ex); } } } } private void SetDuplicateShapeName(FSHP shape) { DialogResult dialogResult = MessageBox.Show($"A shape {shape.Text} already exists with that name", "", MessageBoxButtons.OK); if (dialogResult == DialogResult.OK) { RenameDialog renameDialog = new RenameDialog(); renameDialog.Text = "Rename Texture"; if (renameDialog.ShowDialog() == DialogResult.OK) { shape.Text = renameDialog.textBox1.Text; } } } static bool ImportMissingTextures = false; public static void CheckMissingTextures(FSHP shape) { // FSHP > Objects > FMDL > Models > BFRES BFRES root = (BFRES)shape.Parent.Parent.Parent.Parent; foreach (var node in root.Nodes) { if (node is BNTX) { BNTX bntx = (BNTX)node; if (bntx.Textures.Count == 0) return; foreach (MatTexture tex in shape.GetMaterial().TextureMaps) { if (!bntx.Textures.ContainsKey(tex.Name)) { if (!ImportMissingTextures) { DialogResult result = MessageBox.Show("Missing textures found! Would you like to use placeholders?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { ImportMissingTextures = true; } else return; } if (ImportMissingTextures) bntx.ImportPlaceholderTexture(tex.Name); } } } } foreach (var node in root.Nodes) { if (node is BFRESGroupNode && ((BFRESGroupNode)node).Type == BRESGroupType.Textures) { if (((BFRESGroupNode)node).ResourceNodes.Count <= 0) return; foreach (MatTexture tex in shape.GetMaterial().TextureMaps) { if (!((BFRESGroupNode)node).ResourceNodes.ContainsKey(tex.Name)) { if (!ImportMissingTextures) { DialogResult result = MessageBox.Show("Missing textures found! Would you like to use placeholders?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { ImportMissingTextures = true; } else { return; } } if (ImportMissingTextures) ((BFRESGroupNode)node).ImportPlaceholderTexture(tex.Name); } } } } } public void ErrorCheck() { if (BFRESRender != null) { List Errors = new List(); foreach (FMDL model in BFRESRender.models) { foreach (FSHP shp in model.shapes) { 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)) STConsole.WriteLine($"Error! Attribute {vtx.Attributes[att].Name} is unlinked!"); } for (int att = 0; att < mat.Samplers.Count; att++) { if (!shdr.SamplerAssigns.Contains(mat.SamplerDict.GetKey(att))) //mat.SamplerDict[att] STConsole.WriteLine($"Error! Sampler {mat.Samplers[att].Name} is unlinked!"); } } else { 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++) { ResU.ResString str = new ResU.ResString(); str.String = vtx.Attributes[att].Name; if (!shdr.AttribAssigns.ContainsValue(str)) STConsole.WriteLine($"Error! Attribute {vtx.Attributes[att].Name} is unlinked!"); } for (int att = 0; att < mat.Samplers.Count; att++) { ResU.ResString str2 = new ResU.ResString(); str2.String = mat.Samplers[att].Name; if (!shdr.SamplerAssigns.ContainsValue(str2)) //mat.SamplerDict[att] STConsole.WriteLine($"Error! Sampler {mat.Samplers[att].Name} is unlinked!"); } } } } // ErrorList errorList = new ErrorList(); // errorList.LoadList(Errors); // errorList.Show(); } } public class Errors { public string Section = "None"; public string Section2 = "None"; public string Message = ""; public string Type = "Unkown"; } } }