using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Toolbox.Library; using Toolbox.Library.IO; using Toolbox.Library.Forms; using System.Windows.Forms; using FirstPlugin.Forms; using SPICA.Formats.CtrH3D; using SPICA.Formats.CtrH3D.Model; using SPICA.Formats.CtrH3D.Texture; using SPICA.Formats.CtrH3D.Shader; using SPICA.Formats.CtrH3D.Animation; using SPICA.Formats.CtrH3D.Camera; using SPICA.Formats.CtrH3D.Fog; using SPICA.Formats.CtrH3D.Light; using SPICA.Formats.CtrH3D.LUT; using SPICA.WinForms.Formats; namespace FirstPlugin.CtrLibrary { public class BCH : TreeNodeFile, IContextMenuNode, IFileFormat { public FileType FileType { get; set; } = FileType.Model; public bool CanSave { get; set; } public string[] Description { get; set; } = new string[] { "BCH", "BCRES" }; public string[] Extension { get; set; } = new string[] { "*.bch", "*.bcres" }; public string FileName { get; set; } public string FilePath { get; set; } public IFileInfo IFileInfo { get; set; } public bool Identify(System.IO.Stream stream) { using (var reader = new Toolbox.Library.IO.FileReader(stream, true)) { return (reader.CheckSignature(3, "BCH") || reader.CheckSignature(4, "CGFX")) || (GFPackage.IsValidPackage(stream)); } } public Type[] Types { get { List types = new List(); return types.ToArray(); } } bool DrawablesLoaded = false; public override void OnClick(TreeView treeView) { var propertyGrid = LoadEditor(); propertyGrid.LoadProperty(new FileSettings(H3DFile)); } public class FileSettings { private H3D H3DFile; public enum VersionList : ushort { LatestVersion = 44943, } public VersionList VersionPreset { get { return (VersionList)H3DFile.ConverterVersion; } set { H3DFile.ConverterVersion = (ushort)value; } } public ushort Version { get { return H3DFile.ConverterVersion; } set { H3DFile.ConverterVersion = value; } } public byte BackwardCompatibility { get { return H3DFile.BackwardCompatibility; } set { H3DFile.BackwardCompatibility = value; } } public byte ForwardCompatibility { get { return H3DFile.ForwardCompatibility; } set { H3DFile.ForwardCompatibility = value; } } public FileSettings(H3D h3d) { H3DFile = h3d; } } public T LoadEditor() where T : UserControl, new() { ViewportEditor editor = (ViewportEditor)LibraryGUI.GetActiveContent(typeof(ViewportEditor)); if (editor == null) { editor = new ViewportEditor(true); editor.Dock = DockStyle.Fill; LibraryGUI.LoadEditor(editor); } if (!DrawablesLoaded) { ObjectEditor.AddContainer(DrawableContainer); DrawablesLoaded = true; } if (Runtime.UseOpenGL) editor.LoadViewport(DrawableContainer); foreach (var subControl in editor.GetEditorPanel().Controls) if (subControl.GetType() == typeof(T)) return subControl as T; T control = new T(); control.Dock = DockStyle.Fill; editor.LoadEditor(control); return control; } public BCH_Renderer Renderer; public DrawableContainer DrawableContainer = new DrawableContainer(); public List Textures = new List(); public H3D H3DFile; public FileFormatType FormatType = FileFormatType.BCH; public enum FileFormatType { BCH, BCRES, MBN, GFModel, GFTexture, GFModelPack, GFMotion, GFPackedTexture, GFL2OverWorld, GFBtlSklAnim, GFCharaModel, GFOWMapModel, GFOWCharaModel, GFPkmnModel, GFPkmnSklAnim, MTModel, } private void ConvertH3D(System.IO.Stream stream) { CanSave = true; System.IO.BinaryReader Reader = new System.IO.BinaryReader(stream); using (FileReader reader = new FileReader(stream, true)) { uint magicNumber = reader.ReadUInt32(); switch (magicNumber) { case 0x15122117: FormatType = FileFormatType.GFModel; H3DFile = new H3D(); H3DFile.Models.Add(new SPICA.Formats.GFL2.Model.GFModel(Reader, "Model").ToH3DModel()); break; } string mbnPath = FilePath.Replace("bch", "mbn"); if (reader.CheckSignature(3, "BCH")) { H3DFile = H3D.Open(stream.ToBytes()); FormatType = FileFormatType.BCH; return; } else if (reader.CheckSignature(4, "CGFX")) { H3DFile = SPICA.Formats.CtrGfx.Gfx.Open(stream); FormatType = FileFormatType.BCRES; } else if (GFPackage.IsValidPackage(stream)) { GFPackage.Header PackHeader = GFPackage.GetPackageHeader(stream); switch (PackHeader.Magic) { case "PC": H3DFile = GFPkmnModel.OpenAsH3D(stream, PackHeader, null); break; } } else if (System.IO.File.Exists(mbnPath)) { var ModelBinary = new SPICA.Formats.ModelBinary.MBn(new System.IO.BinaryReader( System.IO.File.OpenRead(mbnPath)), H3DFile); H3DFile = ModelBinary.ToH3D(); FormatType = FileFormatType.MBN; } else H3DFile = H3D.Open(stream.ToBytes()); } } public void UpdateViewport() { LibraryGUI.UpdateViewport(); } public void Load(System.IO.Stream stream) { Text = FileName; ConvertH3D(stream); Renderer = new BCH_Renderer(); DrawableContainer.Name = FileName; DrawableContainer.Drawables.Add(Renderer); AddNodeGroup(H3DFile.Models, new BCHGroupNode(BCHGroupType.Models)); AddNodeGroup(H3DFile.Textures, new TextureFolder(BCHGroupType.Textures)); AddNodeGroup(H3DFile.LUTs, new BCHGroupNode(BCHGroupType.Lookups)); AddNodeGroup(H3DFile.Shaders, new BCHGroupNode(BCHGroupType.Shaders)); AddNodeGroup(H3DFile.Cameras, new BCHGroupNode(BCHGroupType.Cameras)); AddNodeGroup(H3DFile.Lights, new BCHGroupNode(BCHGroupType.Lights)); AddNodeGroup(H3DFile.Fogs, new BCHGroupNode(BCHGroupType.Fogs)); AddNodeGroup(H3DFile.Scenes, new BCHGroupNode(BCHGroupType.Scenes)); AddNodeGroup(H3DFile.SkeletalAnimations, new BCHGroupNode(BCHGroupType.SkeletalAnim)); AddNodeGroup(H3DFile.MaterialAnimations, new BCHGroupNode(BCHGroupType.MaterialAnim)); AddNodeGroup(H3DFile.VisibilityAnimations, new BCHGroupNode(BCHGroupType.VisibiltyAnim)); AddNodeGroup(H3DFile.CameraAnimations, new BCHGroupNode(BCHGroupType.CameraAnim)); AddNodeGroup(H3DFile.LightAnimations, new BCHGroupNode(BCHGroupType.LightAnim)); AddNodeGroup(H3DFile.FogAnimations, new BCHGroupNode(BCHGroupType.EmitterAnim)); } private void AddNodeGroup(H3DDict SubSections, BCHGroupNode Folder) where T : SPICA.Formats.Common.INamed { if (SubSections == null || SubSections.Count == 0) return; Nodes.Add(Folder); if (Folder.Type == BCHGroupType.Textures) PluginRuntime.bchTexContainers.Add(Folder); for (int i = 0; i < SubSections?.Count; i++) { var section = SubSections[i] as SPICA.Formats.Common.INamed; switch (Folder.Type) { case BCHGroupType.Models: var CMDLWrapper = new H3DModelWrapper((H3DModel)section, this); Folder.AddNode(CMDLWrapper); break; case BCHGroupType.SkeletalAnim: var CSKAWrapper = new H3DSkeletalAnimWrapper((H3DAnimation)section, this); Folder.AddNode(CSKAWrapper); break; case BCHGroupType.Textures: { var wrapper = new H3DTextureWrapper((H3DTexture)section, this); wrapper.ImageKey = "texture"; wrapper.SelectedImageKey = "texture"; Folder.AddNode(wrapper); Textures.Add(wrapper); } break; default: Folder.AddNode(new Toolbox.Library.NodeWrappers.STGenericWrapper(SubSections[i].Name)); break; } } } public void Save(System.IO.Stream stream) { switch (FormatType) { case FileFormatType.BCH: H3D.Save(stream, H3DFile); break; default: throw new Exception($"File format cannot be saved yet! {FormatType}"); } } public ToolStripItem[] GetContextMenuItems() { List Items = new List(); Items.Add(new ToolStripMenuItem("Export Model", null, ExportAction, Keys.Control | Keys.E)); return Items.ToArray(); } private void ExportAction(object sender, EventArgs e) { } public void Unload() { ObjectEditor.RemoveContainer(DrawableContainer); foreach (var node in Nodes) { if (PluginRuntime.bchTexContainers.Contains(node)) PluginRuntime.bchTexContainers.Remove((BCHGroupNode)node); } foreach (var tex in Textures) tex?.DisposeRenderable(); Textures.Clear(); } public class TextureFolder : BCHGroupNode, ITextureContainer { public bool DisplayIcons => true; public TextureFolder(BCHGroupType type) : base(type) { } public List TextureList { get { List textures = new List(); foreach (STGenericTexture node in Nodes) textures.Add(node); return textures; } set { } } } } }