1
0
mirror of synced 2024-12-11 07:16:05 +01:00
Switch-Toolbox/File_Format_Library/FileFormats/BFRES/BFRES.cs

2092 lines
81 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Data;
using System.Threading;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.Forms;
using Toolbox.Library.IO;
using Bfres.Structs;
using ResU = Syroot.NintenTools.Bfres;
using Syroot.NintenTools.NSW.Bfres;
using Toolbox.Library.Animations;
using Toolbox.Library.NodeWrappers;
using GL_EditorFramework.Interfaces;
using FirstPlugin.Forms;
using FirstPlugin.NodeWrappers;
using OpenTK;
namespace FirstPlugin
{
public class BFRES : BFRESWrapper, IFileFormat, ITextureContainer, IExportableModelContainer, IDisposable
{
public FileType FileType { get; set; } = FileType.Resource;
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<Type> types = new List<Type>();
types.Add(typeof(MenuExt));
return types.ToArray();
}
}
//Determines if the binary is in a PTCL binary file.
public bool IsParticlePrimitive = false;
public bool DisplayIcons => false;
public List<STGenericTexture> TextureList
{
get { return GetTextures(); }
set { }
}
public IEnumerable<STGenericModel> ExportableModels
{
get { return BFRESRender.models; }
}
public IEnumerable<STGenericTexture> ExportableTextures => TextureList;
public override string ExportFilter => Utils.GetAllFilters(this);
//Stores the skeleton and models in this
public DrawableContainer DrawableContainer = new DrawableContainer();
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;
public ToolStripButton[] IconButtonMenuExtensions => null;
STToolStripItem[] toolExt = new STToolStripItem[1];
STToolStripItem[] newFileExt = new STToolStripItem[2];
STToolStripItem[] editExt = new STToolStripItem[1];
public MenuExt()
{
// toolExt[0] = new STToolStripItem("Models");
// toolExt[0].DropDownItems.Add(new STToolStripItem("Batch Export (BFRES)", Export));
editExt[0] = new STToolStripItem("Use Advanced Editor As Default", AdvancedEditor);
newFileExt[0] = new STToolStripItem("BFRES (Switch)", NewSwitchBfres);
newFileExt[1] = new STToolStripItem("BFRES (Wii U)", NewWiiUBfres);
editExt[0].Checked = !PluginRuntime.UseSimpleBfresEditor;
}
private void AdvancedEditor(object sender, EventArgs args)
{
BFRES file = null;
ObjectEditor editor = (ObjectEditor)LibraryGUI.GetActiveForm();
if (editor != null)
{
file = (BFRES)editor.GetActiveFile();
}
if (editExt[0].Checked)
{
editExt[0].Checked = false;
PluginRuntime.UseSimpleBfresEditor = true;
if (file != null)
file.LoadSimpleMode();
}
else
{
editExt[0].Checked = true;
PluginRuntime.UseSimpleBfresEditor = false;
if (file != null)
file.LoadAdvancedMode();
}
}
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(bfres);
editor.Text = "Untitled-" + 0;
LibraryGUI.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(bfres);
editor.Text = "Untitled-" + 0;
LibraryGUI.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 void Export(object sender, EventArgs args)
{
string formats = FileFilters.FMDL_EXPORT;
string[] forms = formats.Split('|');
List<string> Formats = new List<string>();
for (int i = 0; i < forms.Length; i++)
{
if (i > 1 || i == (forms.Length - 1)) //Skip lines with all extensions
{
if (!forms[i].StartsWith("*"))
Formats.Add(forms[i]);
}
}
BatchFormatExport form = new BatchFormatExport(Formats);
if (form.ShowDialog() == DialogResult.OK)
{
string Extension = form.GetSelectedExtension();
OpenFileDialog ofd = new OpenFileDialog();
ofd.Multiselect = true;
ofd.Filter = Utils.GetAllFilters(new Type[] { typeof(BFRES), typeof(SARC) });
if (ofd.ShowDialog() == DialogResult.OK)
{
FolderSelectDialog folderDialog = new FolderSelectDialog();
if (folderDialog.ShowDialog() == DialogResult.OK)
{
foreach (string file in ofd.FileNames)
{
var FileFormat = STFileLoader.OpenFileFormat(file, new Type[] { typeof(BFRES), typeof(SARC) });
if (FileFormat == null)
continue;
SearchBinary(FileFormat, folderDialog.SelectedPath, Extension);
}
}
}
}
}
private void SearchBinary(IFileFormat FileFormat, string Folder, string Extension)
{
if (FileFormat is SARC)
{
foreach (var file in ((SARC)FileFormat).Files)
{
var archiveFile = STFileLoader.OpenFileFormat(file.FileName, new Type[] { typeof(BFRES), typeof(SARC) }, file.FileData);
if (archiveFile == null)
continue;
SearchBinary(archiveFile, Folder, Extension);
}
}
if (FileFormat is BFRES)
{
// ((BFRES)FileFormat).Export(Path.Combine(Folder, $"{FileFormat.FileName}{Extension}"));
}
FileFormat.Unload();
}
}
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 BoundingBox GetBoundingBox()
{
Vector3 Min = new Vector3(0);
Vector3 Max = new Vector3(0);
var Models = GetModels();
if (Models == null)
return new BoundingBox();
foreach (FMDL model in Models)
{
foreach (var shape in model.shapes)
{
foreach (var vertex in shape.vertices)
{
Min.X = Math.Min(Min.X, vertex.pos.X);
Min.Y = Math.Min(Min.Y, vertex.pos.Y);
Min.Z = Math.Min(Min.Z, vertex.pos.Z);
Max.X = Math.Max(Max.X, vertex.pos.X);
Max.Y = Math.Max(Max.Y, vertex.pos.Y);
Max.Z = Math.Max(Max.Z, vertex.pos.Z);
}
}
}
return new BoundingBox()
{
Max = Max,
Min = Min,
};
}
public void OnPropertyChanged()
{
if (resFile != null)
{
Text = resFile.Name;
}
else
{
Text = resFileU.Name;
}
STPropertyGrid editor = (STPropertyGrid)LibraryGUI.GetActiveContent(typeof(STPropertyGrid));
if (editor != null)
editor.Refresh();
}
public void LoadAdvancedMode()
{
foreach (var model in BFRESRender.models)
{
foreach (var mat in model.materials.Values)
{
foreach (var tex in mat.TextureMaps)
{
mat.Nodes.RemoveByKey(tex.Name);
}
}
}
}
public void LoadSimpleMode()
{
ObjectEditor editor = (ObjectEditor)LibraryGUI.GetActiveForm();
if (editor == null)
return;
editor.BeginUpdate();
foreach (var model in BFRESRender.models)
{
foreach (var mat in model.materials.Values)
{
mat.Nodes.Clear();
foreach (MatTexture tex in mat.TextureMaps)
{
mat.Nodes.Add(new MatTextureWrapper(tex.Name, tex.Name, tex));
}
}
}
foreach (TreeNode node in Nodes)
{
if (node is BFRESAnimFolder)
{
foreach (BFRESGroupNode animFolder in node.Nodes)
{
if (animFolder.Type == BRESGroupType.SkeletalAnim)
{
foreach (FSKA anim in animFolder.Nodes)
{
foreach (FSKA.BoneAnimNode bone in ((FSKA)anim).Bones)
{
int index = 0;
if (bone.BoneAnimU != null)
{
foreach (var curve in bone.BoneAnimU.Curves)
GetSkeletonAnimCurveOffset(curve.AnimDataOffset);
}
else
{
foreach (var curve in bone.BoneAnim.Curves)
GetSkeletonAnimCurveOffset(curve.AnimDataOffset);
}
}
}
}
if (animFolder.Type == BRESGroupType.ColorAnim)
{
foreach (var anim in animFolder.Nodes)
{
if (anim is FMAA)
{
foreach (FMAA.MaterialAnimEntry mat in ((FMAA)anim).Nodes)
{
}
}
}
}
}
}
}
editor.EndUpdate();
}
private string GetSkeletonAnimCurveOffset(uint offset)
{
switch ((FSKA.TrackType)offset)
{
case FSKA.TrackType.XPOS: return "Translate_X";
case FSKA.TrackType.YPOS: return "Translate_Y";
case FSKA.TrackType.ZPOS: return "Translate_Z";
case FSKA.TrackType.XROT: return "Rotate_X";
case FSKA.TrackType.YROT: return "Rotate_Y";
case FSKA.TrackType.ZROT: return "Rotate_Z";
case FSKA.TrackType.WROT: return "Rotate_W";
case FSKA.TrackType.XSCA: return "Scale_X";
case FSKA.TrackType.YSCA: return "Scale_Y";
case FSKA.TrackType.ZSCA: return "Scale_Z";
default: offset.ToString(); break;
}
return "";
}
public bool HasShapes()
{
BFRESRender.UpdateModelList();
for (int i = 0; i < BFRESRender.models.Count; i++)
{
if (BFRESRender.models[i].shapes.Count > 0)
return true;
}
return false;
}
public STForm ActiveFormEditor; //For active form windows as editors
private bool DrawablesLoaded = false;
public void LoadEditors(object SelectedSection)
{
Console.WriteLine($"SelectedSection {SelectedSection}");
BfresEditor bfresEditor = (BfresEditor)LibraryGUI.GetActiveContent(typeof(BfresEditor));
bool HasModels = false;
bool hasShapes = HasShapes();
if (bfresEditor == null)
{
HasModels = BFRESRender.models.Count > 0;
bfresEditor = new BfresEditor(HasModels);
bfresEditor.Dock = DockStyle.Fill;
LibraryGUI.LoadEditor(bfresEditor);
}
bool ViewportToggled = bfresEditor.DisplayViewport;
if (SelectedSection is FTEX)
{
ImageEditorBase editorFtex = (ImageEditorBase)bfresEditor.GetActiveEditor(typeof(ImageEditorBase));
if (editorFtex == null)
{
editorFtex = new ImageEditorBase();
editorFtex.Dock = DockStyle.Fill;
bfresEditor.LoadEditor(editorFtex);
}
editorFtex.Text = Text;
editorFtex.LoadProperties(((FTEX)SelectedSection).texture);
editorFtex.LoadImage((FTEX)SelectedSection);
if (Runtime.DisplayViewport && ViewportToggled)
editorFtex.SetEditorOrientation(true);
if (((FTEX)SelectedSection).texture.UserData != null)
{
UserDataEditor userEditor = (UserDataEditor)editorFtex.GetActiveTabEditor(typeof(UserDataEditor));
if (userEditor == null)
{
userEditor = new UserDataEditor();
userEditor.Name = "User Data";
editorFtex.AddCustomControl(userEditor, typeof(UserDataEditor));
}
userEditor.LoadUserData(((FTEX)SelectedSection).texture.UserData);
}
return;
}
if (SelectedSection is TextureData)
{
ImageEditorBase editor = (ImageEditorBase)bfresEditor.GetActiveEditor(typeof(ImageEditorBase));
if (editor == null)
{
editor = new ImageEditorBase();
editor.Dock = DockStyle.Fill;
bfresEditor.LoadEditor(editor);
}
if (((TextureData)SelectedSection).Texture.UserData != null)
{
UserDataEditor userEditor = (UserDataEditor)editor.GetActiveTabEditor(typeof(UserDataEditor));
if (userEditor == null)
{
userEditor = new UserDataEditor();
userEditor.Name = "User Data";
editor.AddCustomControl(userEditor, typeof(UserDataEditor));
}
userEditor.LoadUserData(((TextureData)SelectedSection).Texture.UserData.ToList());
}
editor.Text = Text;
if (Runtime.DisplayViewport && ViewportToggled)
editor.SetEditorOrientation(true);
editor.LoadProperties(((TextureData)SelectedSection).Texture);
editor.LoadImage((TextureData)SelectedSection);
return;
}
if (SelectedSection is BNTX)
{
STPropertyGrid editor = (STPropertyGrid)bfresEditor.GetActiveEditor(typeof(STPropertyGrid));
if (editor == null)
{
editor = new STPropertyGrid();
editor.Dock = DockStyle.Fill;
bfresEditor.LoadEditor(editor);
}
editor.LoadProperty(((BNTX)SelectedSection).BinaryTexFile, OnPropertyChanged);
return;
}
if (SelectedSection is ExternalFileData)
{
ArchiveFilePanel editor = (ArchiveFilePanel)LibraryGUI.GetActiveContent(typeof(ArchiveFilePanel));
if (editor == null)
{
editor = new ArchiveFilePanel();
editor.Dock = DockStyle.Fill;
LibraryGUI.LoadEditor(editor);
}
editor.LoadFile(((ExternalFileData)SelectedSection).ArchiveFileInfo);
editor.UpdateEditor();
return;
}
if (!DrawablesLoaded)
{
ObjectEditor.AddContainer(DrawableContainer);
DrawablesLoaded = true;
}
if (Runtime.UseOpenGL)
bfresEditor.LoadViewport(this, hasShapes, DrawableContainer);
if (SelectedSection is BFRES && hasShapes)
bfresEditor.FrameCamera(BFRESRender);
bool IsSimpleEditor = PluginRuntime.UseSimpleBfresEditor;
if (IsSimpleEditor)
{
if (SelectedSection is MatTextureWrapper)
{
SamplerEditorSimple editorT = (SamplerEditorSimple)bfresEditor.GetActiveEditor(typeof(SamplerEditorSimple));
if (editorT == null)
{
editorT = new SamplerEditorSimple();
editorT.Dock = DockStyle.Fill;
bfresEditor.LoadEditor(editorT);
}
editorT.Text = Text;
editorT.LoadTexture(((MatTextureWrapper)SelectedSection).textureMap);
return;
}
STPropertyGrid editor = (STPropertyGrid)bfresEditor.GetActiveEditor(typeof(STPropertyGrid));
if (editor == null)
{
editor = new STPropertyGrid();
editor.Dock = DockStyle.Fill;
bfresEditor.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).Material, OnPropertyChanged);
}
else if (SelectedSection is BfresBone)
{
if (((BfresBone)SelectedSection).BoneU != null)
editor.LoadProperty(((BfresBone)SelectedSection).BoneU, OnPropertyChanged);
else
editor.LoadProperty(((BfresBone)SelectedSection).Bone, OnPropertyChanged);
}
else if (SelectedSection is FSKL.fsklNode)
{
if (((FSKL.fsklNode)SelectedSection).SkeletonU != null)
editor.LoadProperty(((FSKL.fsklNode)SelectedSection).SkeletonU, OnPropertyChanged);
else
editor.LoadProperty(((FSKL.fsklNode)SelectedSection).Skeleton, OnPropertyChanged);
}
else if (SelectedSection is FSKA)
{
if (((FSKA)SelectedSection).SkeletalAnimU != null)
editor.LoadProperty(((FSKA)SelectedSection).SkeletalAnimU, OnPropertyChanged);
else
editor.LoadProperty(((FSKA)SelectedSection).SkeletalAnim, OnPropertyChanged);
}
else if (SelectedSection is FMAA)
{
editor.LoadProperty(((FMAA)SelectedSection).MaterialAnim, OnPropertyChanged);
}
else
editor.LoadProperty(null, OnPropertyChanged);
}
else
{
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<FMDL>(SelectedSection, bfresEditor);
else if (SelectedSection is FSKA)
OpenSubFileEditor<FSKA>(SelectedSection, bfresEditor);
else if (SelectedSection is FSHU)
OpenSubFileEditor<FSHU>(SelectedSection, bfresEditor);
else if (SelectedSection is FSCN)
OpenSubFileEditor<FSCN>(SelectedSection, bfresEditor);
else if (SelectedSection is FSHA)
OpenSubFileEditor<FSHA>(SelectedSection, bfresEditor);
else if (SelectedSection is FTXP)
OpenSubFileEditor<FTXP>(SelectedSection, bfresEditor);
else if (SelectedSection is FMAA)
OpenSubFileEditor<FMAA>(SelectedSection, bfresEditor);
else if (SelectedSection is FVIS)
OpenSubFileEditor<FVIS>(SelectedSection, bfresEditor);
}
}
private SubFileEditor OpenSubFileEditor<T>(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<T>(node);
return editor;
}
public static bool CheckWiiU(Stream stream)
{
bool IsWiiU = false;
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;
}
return IsWiiU;
}
public BFRESRenderBase BFRESRender;
private MeshCodec MeshCodec;
public void Dispose() { MeshCodec.Dispose(); }
public void Load(System.IO.Stream stream)
{
CanSave = true;
ImageKey = "bfres";
SelectedImageKey = "bfres";
IsWiiU = CheckWiiU(stream);
LoadMenus(IsWiiU);
BFRESRender = new BFRESRender();
DrawableContainer.Name = FileName;
BFRESRender.ModelTransform = MarioCostumeEditor.SetTransform(FileName);
BFRESRender.ResFileNode = this;
MeshCodec = new MeshCodec();
var externalFlags = MeshCodec.GetExternalFlags(stream);
//External flags used
if (externalFlags.HasFlag(MeshCodec.ExternalFlags.HasExternalGPU) || this.FileName.EndsWith(".mc"))
{
//Ensure it uses mc compressor for save
this.IFileInfo.FileIsCompressed = true;
if (this.IFileInfo.FileCompression == null)
{
this.IFileInfo.FileCompression = new MeshCodecFormat();
if (!this.FileName.EndsWith(".mc"))
this.FileName += ".mc";
if (!this.FilePath.EndsWith(".mc"))
this.FilePath += ".mc";
}
}
if (externalFlags.HasFlag(MeshCodec.ExternalFlags.HasExternalString))
MeshCodec.Prepare();
if (IsWiiU)
{
LoadFile(new Syroot.NintenTools.Bfres.ResFile(stream));
}
else
{
LoadFile(new Syroot.NintenTools.NSW.Bfres.ResFile(stream));
}
if (resFileU != null) {
if (resFileU.VersioFull == "3,0,0,1")
{
//Todo check for valid sharc files to parse as programs via materials to map
// Console.WriteLine("RedPro_Renderer!");
/* BFRESRender = new RedPro_Renderer();
BFRESRender.ModelTransform = Matrix4.Identity;
BFRESRender.ResFileNode = this;*/
}
}
//Mesh codec type of bfres, load textures externallly
if (externalFlags != (MeshCodec.ExternalFlags)0)
{
MeshCodec.PrepareTexToGo(resFile);
MeshCodec.TextureFolder = new TexToGoFolder(MeshCodec);
this.Nodes.Add(MeshCodec.TextureFolder);
}
DrawableContainer.Drawables.Add(BFRESRender);
var Models = GetModels();
if (Models != null)
{
foreach (FMDL mdl in Models)
{
BFRESRender.models.Add(mdl);
DrawableContainer.Drawables.Add(mdl.Skeleton);
}
}
}
public void Unload()
{
BFRESRender.Destroy();
DrawableContainer.Drawables.Clear();
ObjectEditor.RemoveContainer(DrawableContainer);
if (resFile != null)
{
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();
}
else if (resFileU != null)
{
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();
}
foreach (var node in TreeViewExtensions.Collect(BFRESRender.ResFileNode.Nodes))
{
if (node is BFRESGroupNode)
{
if (((BFRESGroupNode)node).Type == BRESGroupType.Models)
{
for (int i = 0; i < ((BFRESGroupNode)node).Nodes.Count; i++)
{
FMDL model = ((FMDL)((BFRESGroupNode)node).Nodes[i]);
for (int shp = 0; shp < model.shapes.Count; shp++)
{
model.shapes[shp].vertices.Clear();
model.shapes[shp].faces.Clear();
foreach (var lod in model.shapes[shp].lodMeshes)
lod.faces.Clear();
}
}
}
if (((BFRESGroupNode)node).Type == BRESGroupType.Textures)
{
for (int i = 0; i < ((BFRESGroupNode)node).Nodes.Count; i++)
((FTEX)((BFRESGroupNode)node).Nodes[i]).Unload();
if (PluginRuntime.ftexContainers.Contains(((BFRESGroupNode)node)))
PluginRuntime.ftexContainers.Remove(((BFRESGroupNode)node));
}
((BFRESGroupNode)node).ResourceNodes.Clear();
((BFRESGroupNode)node).Nodes.Clear();
}
if (node is BNTX)
((BNTX)node).Unload();
}
Nodes.Clear();
GC.SuppressFinalize(this);
}
public void Save(Stream stream)
{
//Force mesh codec compression on save
if (this.FilePath.EndsWith(".mc"))
{
this.IFileInfo.FileCompression = new MeshCodecFormat();
this.IFileInfo.FileIsCompressed = true;
}
var Models = GetModels();
if (Models != null && !IsParticlePrimitive)
{
foreach (FMDL mdl in Models)
{
for (int s = 0; s < mdl.shapes.Count; s++)
{
SetShaderAssignAttributes(mdl.shapes[s]);
}
}
}
if (IsWiiU)
SaveWiiU(stream);
else
SaveSwitch(stream);
if (MeshCodec.TextureList.Count > 0)
MeshCodec.SaveTexToGo();
}
public TreeNodeCollection GetModels()
{
foreach (var folder in Nodes)
{
if (folder is BFRESGroupNode && ((BFRESGroupNode)folder).Type == BRESGroupType.Models)
return ((BFRESGroupNode)folder).Nodes;
}
return null;
}
public List<STGenericTexture> GetTextures()
{
List<STGenericTexture> textures = new List<STGenericTexture>();
var bntx = GetBNTX;
if (bntx != null)
return bntx.TextureList;
foreach (TreeNode folder in Nodes)
{
if (folder is BFRESGroupNode && ((BFRESGroupNode)folder).Type == BRESGroupType.Textures)
{
foreach (STGenericTexture node in folder.Nodes)
textures.Add(node);
}
}
return textures;
}
public ResFile resFile = null;
public ResU.ResFile resFileU = null;
public override void OnClick(TreeView treeView)
{
LoadEditors(this);
}
public BFRESGroupNode GetFTEXContainer
{
get
{
foreach (TreeNode folder in Nodes)
{
if (folder is BFRESGroupNode)
{
if (((BFRESGroupNode)folder).Type == BRESGroupType.Textures)
return (BFRESGroupNode)folder;
}
}
return null;
}
}
public BNTX GetBNTX
{
get
{
foreach (TreeNode folder in Nodes)
{
if (folder is BNTX)
return (BNTX)folder;
}
return null;
}
}
public bool HasTextures
{
get
{
foreach (TreeNode folder in Nodes)
{
if (folder is BFRESGroupNode)
{
bool hasTextures = (((BFRESGroupNode)folder).Type == BRESGroupType.Textures &&
folder.Nodes.Count > 0);
if (hasTextures) return true;
}
if (folder is BNTX)
{
return ((BNTX)folder).Textures.Count > 0;
}
}
return false;
}
}
public void LoadFile(ResU.ResFile res)
{
resFileU = res;
Text = resFileU.Name;
var modelFolder = new BFRESGroupNode(BRESGroupType.Models, true);
var texturesFolder = new BFRESGroupNode(BRESGroupType.Textures, true);
var animFolder = new BFRESAnimFolder();
var externalFilesFolder = new BFRESGroupNode(BRESGroupType.Embedded, true);
texturesFolder.ShowNewContextMenu = false;
Nodes.Add(modelFolder);
Nodes.Add(texturesFolder);
Nodes.Add(animFolder);
Nodes.Add(externalFilesFolder);
animFolder.LoadMenus(IsWiiU);
PluginRuntime.ftexContainers.Add(texturesFolder);
if (resFileU.Models.Count > 0)
{
for (int i = 0; i < resFileU.Models.Count; i++)
{
var fmdl = new FMDL();
BfresWiiU.ReadModel(fmdl, resFileU.Models[i]);
modelFolder.AddNode(fmdl);
}
}
if (resFileU.Textures.Count > 0)
{
for (int i = 0; i < resFileU.Textures.Count; i++)
{
var ftex = new FTEX(resFileU.Textures[i]);
texturesFolder.AddNode(ftex);
ftex.UpdateMipMaps();
}
}
if (resFileU.SkeletalAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.SkeletalAnim, true);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFileU.SkeletalAnims.Count; i++)
group.AddNode(new FSKA(resFileU.SkeletalAnims[i]));
}
if (resFileU.ShaderParamAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.ShaderParamAnim, true);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFileU.ShaderParamAnims.Count; i++)
group.AddNode(new FSHU(resFileU.ShaderParamAnims[i], MaterialAnimation.AnimationType.ShaderParam));
}
if (resFileU.ColorAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.ColorAnim, true);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFileU.ColorAnims.Count; i++)
group.AddNode(new FSHU(resFileU.ColorAnims[i], MaterialAnimation.AnimationType.Color));
}
if (resFileU.TexSrtAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.TexSrtAnim, true);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFileU.TexSrtAnims.Count; i++)
group.AddNode(new FSHU(resFileU.TexSrtAnims[i], MaterialAnimation.AnimationType.TextureSrt));
}
if (resFileU.TexPatternAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.TexPatAnim, true);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFileU.TexPatternAnims.Count; i++)
group.AddNode(new FTXP(resFileU.TexPatternAnims[i]));
}
if (resFileU.ShapeAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.ShapeAnim, true);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFileU.ShapeAnims.Count; i++)
group.AddNode(new FSHA(resFileU.ShapeAnims[i]));
}
if (resFileU.BoneVisibilityAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.BoneVisAnim, true);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFileU.BoneVisibilityAnims.Count; i++)
group.AddNode(new FVIS(resFileU.BoneVisibilityAnims[i]));
}
if (resFileU.MatVisibilityAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.MatVisAnim, true);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFileU.MatVisibilityAnims.Count; i++)
group.AddNode(new FVIS(resFileU.MatVisibilityAnims[i]));
}
if (resFileU.SceneAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.SceneAnim, true);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFileU.SceneAnims.Count; i++)
group.AddNode(new FSCN(resFileU.SceneAnims[i]));
}
if (resFileU.ExternalFiles.Count > 0)
{
foreach (var anim in resFileU.ExternalFiles)
{
externalFilesFolder.AddNode(new ExternalFileData(anim.Key, anim.Value.Data));
}
}
if (PluginRuntime.UseSimpleBfresEditor)
LoadSimpleMode();
}
public void LoadFile(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)
{
for (int i = 0; i < resFile.Models.Count; i++)
{
var fmdl = new FMDL();
BfresSwitch.ReadModel(fmdl, resFile.Models[i]);
modelFolder.AddNode(fmdl);
}
}
if (resFile.SkeletalAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.SkeletalAnim);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFile.SkeletalAnims.Count; i++)
group.AddNode(new FSKA(resFile.SkeletalAnims[i]));
}
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;
for (int i = 0; i < resFile.MaterialAnims.Count; i++)
{
var anim = resFile.MaterialAnims[i];
var fmaa = new FMAA(anim);
if (fmaa.AnimType == MaterialAnimation.AnimationType.ShaderParam)
{
group.AddNode(fmaa);
HasShaderParamsAnim = true;
}
else if (fmaa.AnimType == MaterialAnimation.AnimationType.TextureSrt)
{
group2.AddNode(fmaa);
HasTextureSrtAnim = true;
}
else if (fmaa.AnimType == MaterialAnimation.AnimationType.TexturePattern)
{
group3.AddNode(fmaa);
HasTexturePatternAnim = true;
}
else if (fmaa.AnimType == MaterialAnimation.AnimationType.Color)
{
group4.AddNode(fmaa);
HasColorAnim = true;
}
else if (fmaa.AnimType == MaterialAnimation.AnimationType.Visibilty)
{
group5.AddNode(fmaa);
HasMatVisAnim = true;
}
else
{
group.AddNode(fmaa);
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);
for (int i = 0; i < resFile.BoneVisibilityAnims.Count; i++)
group.AddNode(new FVIS(resFile.BoneVisibilityAnims[i]));
}
if (resFile.SceneAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.SceneAnim);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFile.SceneAnims.Count; i++)
group.AddNode(new FSCN(resFile.SceneAnims[i]));
}
if (resFile.ShapeAnims.Count > 0)
{
var group = new BFRESGroupNode(BRESGroupType.ShapeAnim);
animFolder.Nodes.Add(group);
for (int i = 0; i < resFile.ShapeAnims.Count; i++)
group.AddNode(new FSHA(resFile.ShapeAnims[i]));
}
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)
{
if (anim.Data == null) anim.Data = new byte[0];
// group.AddNode(new ExternalFileData(Name, anim.Data) { FileFormat = file });
string Name = resFile.ExternalFileDict.GetKey(index++);
//Bfsha changes versions alot so ignore these for now
if (Utils.GetExtension(Name) == ".bfsha")
{
externalFilesFolder.AddNode(new ExternalFileData(Name, anim.Data));
continue;
}
var file = STFileLoader.OpenFileFormat(new MemoryStream(anim.Data), Name, 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));
}
}
}
if (PluginRuntime.UseSimpleBfresEditor)
LoadSimpleMode();
}
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 = Path.GetFileName(FileName.Replace("Tex1", "Tex2"));
sfd.DefaultExt = ".sbfres";
List<IFileFormat> formats = new List<IFileFormat>();
formats.Add(this);
sfd.Filter = Utils.GetAllFilters(formats);
if (sfd.ShowDialog() == DialogResult.OK)
STFileSaver.SaveFileFormat(Tex2, true,new Yaz0(), 0, sfd.FileName);
}
else
STFileSaver.SaveFileFormat(this, FileName);
}
private byte[] GenerateTex2()
{
STProgressBar progressBar = new STProgressBar();
progressBar.Task = "Generating Tex2...";
progressBar.Value = 0;
progressBar.StartPosition = FormStartPosition.CenterScreen;
progressBar.Show();
progressBar.Refresh();
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;
int curTex = 0;
foreach (var group in Nodes)
{
if (group is BFRESGroupNode)
{
if (((BFRESGroupNode)group).Type != BRESGroupType.Textures)
continue;
foreach (FTEX tex in ((BFRESGroupNode)group).Nodes)
{
Console.WriteLine("tex " + tex.Text + (resFileTex2.Textures.ContainsKey(tex.Text))) ;
if (resFileTex2.Textures.ContainsKey(tex.Text))
{
Console.WriteLine("NoMips " + tex.texture.MipData == null || tex.texture.MipData.Length <= 0);
if (tex.texture.MipData == null || tex.texture.MipData.Length <= 0)
{
progressBar.Task = $"Generating Mipmaps for {tex.Text}";
progressBar.Value = ((curTex * 100) / resFileTex2.Textures.Count);
progressBar.Refresh();
FTEX.GenerateMipmaps(tex.texture.MipCount, tex.Format, tex.GetBitmap(), resFileTex2.Textures[tex.Text]);
}
else
{
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;
}
curTex++;
}
}
}
}
progressBar.Task = $"Saving File";
progressBar.Value = 90;
resFileTex2.Save(mem);
progressBar.Value = 100;
progressBar.Close();
progressBar.Dispose();
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<IFileFormat> formats = new List<IFileFormat>();
formats.Add(this);
sfd.Filter = Utils.GetAllFilters(formats);
if (sfd.ShowDialog() == DialogResult.OK)
STFileSaver.SaveFileFormat(mem2.ToArray(), Compressed,new Yaz0(), 0, 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(Stream stream)
{
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 (SettingRemoveUnusedTextures)
RemoveUnusedTextures((BNTX)node);
if (((BNTX)node).Textures.Count > 0)
{
var mem = new System.IO.MemoryStream();
((BNTX)node).Save(mem);
resFile.ExternalFiles.Add(new ExternalFile() { Data = mem.ToArray() });
resFile.ExternalFileDict.Add(((BNTX)node).FileName);
}
}
}
ErrorCheck();
resFile.Save(stream);
}
private void RemoveUnusedTextures(BFRESGroupNode ftexGroup)
{
var models = GetModels();
if (models == null)
return;
List<string> Keys = ftexGroup.ResourceNodes.Select(x => x.Key).ToList();
var AllTextures = GetAllTextures();
for (int i = 0; i < Keys.Count; i++)
{
//If nowhere in the bfres contains the key, we can remove it
if (!AllTextures.Contains(Keys[i]))
{
ftexGroup.RemoveChild(ftexGroup.ResourceNodes[Keys[i]]);
}
}
}
private void RemoveUnusedTextures(BNTX bntx)
{
var models = GetModels();
if (models == null)
return;
List<string> Keys = bntx.Textures.Select(x => x.Key).ToList();
var AllTextures = GetAllTextures();
for (int i = 0; i < Keys.Count; i++)
{
//If nowhere in the bfres contains the key, we can remove it
if (!AllTextures.Contains(Keys[i]))
{
bntx.RemoveTexture(bntx.Textures[Keys[i]]);
}
}
}
private List<string> GetAllTextures()
{
List<string> AllTextures = new List<string>();
foreach (TreeNode group in Nodes)
{
if (group is BFRESGroupNode && ((BFRESGroupNode)group).Type == BRESGroupType.Models)
{
for (int i = 0; i < group.Nodes.Count; i++)
{
foreach (var material in ((FMDL)group.Nodes[i]).materials.Values)
{
foreach (var tex in material.TextureMaps)
{
if (!AllTextures.Contains(tex.Name))
AllTextures.Add(tex.Name);
}
}
}
}
if (group is BFRESAnimFolder)
{
foreach (BFRESGroupNode animGroup in group.Nodes)
{
if (animGroup.Type == BRESGroupType.TexPatAnim)
{
for (int i = 0; i < group.Nodes.Count; i++)
{
foreach (var tex in ((MaterialAnimation)group.Nodes[i]).Textures)
{
if (!AllTextures.Contains(tex))
AllTextures.Add(tex);
}
}
}
}
}
}
return AllTextures;
}
private static void SaveBfresSwitchGroup(BFRESGroupNode group, ResFile resFile)
{
switch (group.Type)
{
case BRESGroupType.Models:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FMDL)group.Nodes[i]).Model.Name = ((FMDL)group.Nodes[i]).Text;
resFile.Models.Add(BfresSwitch.SetModel((FMDL)group.Nodes[i]));
}
break;
case BRESGroupType.SkeletalAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FSKA)group.Nodes[i]).SkeletalAnim.BoneAnims.Clear();
((FSKA)group.Nodes[i]).SkeletalAnim.Name = ((FSKA)group.Nodes[i]).Text;
for (int b = 0; b < ((FSKA)group.Nodes[i]).Bones.Count; b++)
((FSKA)group.Nodes[i]).SkeletalAnim.BoneAnims.Add(
((FSKA.BoneAnimNode)((FSKA)group.Nodes[i]).Bones[b]).SaveData(((FSKA)group.Nodes[i]).IsEdited));
resFile.SkeletalAnims.Add(((FSKA)group.Nodes[i]).SkeletalAnim);
}
break;
case BRESGroupType.TexPatAnim:
case BRESGroupType.ShaderParamAnim:
case BRESGroupType.ColorAnim:
case BRESGroupType.TexSrtAnim:
case BRESGroupType.MatVisAnim:
case BRESGroupType.MaterialAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FMAA)group.Nodes[i]).SaveAnimData();
resFile.MaterialAnims.Add(((FMAA)group.Nodes[i]).MaterialAnim);
}
break;
case BRESGroupType.BoneVisAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FVIS)group.Nodes[i]).SaveAnimData();
resFile.BoneVisibilityAnims.Add(((FVIS)group.Nodes[i]).VisibilityAnim);
}
break;
case BRESGroupType.ShapeAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FSHA)group.Nodes[i]).SaveAnimData();
resFile.ShapeAnims.Add(((FSHA)group.Nodes[i]).ShapeAnim);
}
break;
case BRESGroupType.SceneAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FSCN)group.Nodes[i]).SaveAnimData();
resFile.SceneAnims.Add(((FSCN)group.Nodes[i]).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)
{
var mem = new System.IO.MemoryStream();
((IFileFormat)ext).Save(mem);
resFile.ExternalFiles.Add(new ExternalFile()
{
Data = mem.ToArray(),
});
resFile.ExternalFileDict.Add(((TreeNodeFile)ext).Text);
}
}
break;
}
}
private void SaveMaterialAnims(TreeNodeCollection nodes)
{
}
private void SaveWiiU(Stream 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(this, (BFRESGroupNode)node, resFileU);
if (node is BFRESAnimFolder)
{
foreach (var animGroup in node.Nodes)
SaveBfresWiiUGroup(this, (BFRESGroupNode)animGroup, resFileU);
}
}
// ErrorCheck();
resFileU.Save(mem);
}
private static void SaveBfresWiiUGroup(BFRES bfres, BFRESGroupNode group, ResU.ResFile resFileU)
{
switch (group.Type)
{
case BRESGroupType.Models:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FMDL)group.Nodes[i]).ModelU.Name = group.Nodes[i].Text;
resFileU.Models.Add(group.Nodes[i].Text, BfresWiiU.SetModel((FMDL)group.Nodes[i]));
}
break;
case BRESGroupType.Textures:
if (bfres.SettingRemoveUnusedTextures)
bfres.RemoveUnusedTextures(group);
for (int i = 0; i < group.Nodes.Count; i++)
{
((FTEX)group.Nodes[i]).texture.Name = group.Nodes[i].Text;
resFileU.Textures.Add(group.Nodes[i].Text, ((FTEX)group.Nodes[i]).texture);
}
break;
case BRESGroupType.SkeletalAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FSKA)group.Nodes[i]).SkeletalAnimU.BoneAnims.Clear();
((FSKA)group.Nodes[i]).SkeletalAnimU.Name = ((FSKA)group.Nodes[i]).Text;
for (int b = 0; b < ((FSKA)group.Nodes[i]).Bones.Count; b++)
((FSKA)group.Nodes[i]).SkeletalAnimU.BoneAnims.Add(
((FSKA.BoneAnimNode)((FSKA)group.Nodes[i]).Bones[b]).SaveDataU(((FSKA)group.Nodes[i]).IsEdited));
resFileU.SkeletalAnims.Add(group.Nodes[i].Text, ((FSKA)group.Nodes[i]).SkeletalAnimU);
}
break;
case BRESGroupType.ShaderParamAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FSHU)group.Nodes[i]).SaveAnimData();
resFileU.ShaderParamAnims.Add(group.Nodes[i].Text, ((FSHU)group.Nodes[i]).ShaderParamAnim);
}
break;
case BRESGroupType.ColorAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FSHU)group.Nodes[i]).SaveAnimData();
resFileU.ColorAnims.Add(group.Nodes[i].Text, ((FSHU)group.Nodes[i]).ShaderParamAnim);
}
break;
case BRESGroupType.TexSrtAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FSHU)group.Nodes[i]).SaveAnimData();
resFileU.TexSrtAnims.Add(group.Nodes[i].Text, ((FSHU)group.Nodes[i]).ShaderParamAnim);
}
break;
case BRESGroupType.TexPatAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FTXP)group.Nodes[i]).SaveAnimData();
resFileU.TexPatternAnims.Add(group.Nodes[i].Text, ((FTXP)group.Nodes[i]).TexPatternAnim);
}
break;
case BRESGroupType.MatVisAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FVIS)group.Nodes[i]).SaveAnimData();
resFileU.MatVisibilityAnims.Add(group.Nodes[i].Text, ((FVIS)group.Nodes[i]).VisibilityAnimU);
}
break;
case BRESGroupType.BoneVisAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FVIS)group.Nodes[i]).SaveAnimData();
resFileU.BoneVisibilityAnims.Add(group.Nodes[i].Text, ((FVIS)group.Nodes[i]).VisibilityAnimU);
}
break;
case BRESGroupType.ShapeAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FSHA)group.Nodes[i]).SaveAnimData();
resFileU.ShapeAnims.Add(group.Nodes[i].Text, ((FSHA)group.Nodes[i]).ShapeAnimU);
}
break;
case BRESGroupType.SceneAnim:
for (int i = 0; i < group.Nodes.Count; i++)
{
((FSCN)group.Nodes[i]).SaveAnimData();
resFileU.SceneAnims.Add(group.Nodes[i].Text, ((FSCN)group.Nodes[i]).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(FSHP shape)
{
var shd = shape.GetFMAT().shaderassign;
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;
List<string> textureList = new List<string>();
foreach (MatTexture tex in shape.GetMaterial().TextureMaps)
{
if (!bntx.Textures.ContainsKey(tex.Name) && !textureList.Contains(tex.Name))
textureList.Add(tex.Name);
}
foreach (var tex in textureList)
{
if (!bntx.Textures.ContainsKey(tex))
{
if (!ImportMissingTextures)
{
string textureDetails = string.Join("\n",textureList);
DialogResult result = MessageBox.Show($"Missing textures found! Would you like to use placeholders?\nTextures:\n{textureDetails}", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
ImportMissingTextures = true;
}
else
return;
}
if (ImportMissingTextures)
{
foreach (var texture in textureList)
bntx.ImportPlaceholderTexture(texture);
}
}
}
}
}
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> Errors = new List<Errors>();
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.GetFMAT().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.GetFMAT().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";
}
}
}