diff --git a/File_Format_Library/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL.cs b/File_Format_Library/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL.cs index bc0c369c..2b523bcc 100644 --- a/File_Format_Library/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL.cs +++ b/File_Format_Library/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL.cs @@ -211,7 +211,7 @@ namespace Bfres.Structs { foreach (var shape in shapes) { - if (!shape.HasUV0()) + if (!shape.HasAttributeUV0()) { MessageBox.Show($"Error! {Text} does not have UVs!", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -227,7 +227,7 @@ namespace Bfres.Structs { foreach (var shape in shapes) { - if (!shape.HasUV0()) + if (!shape.HasAttributeUV0()) { MessageBox.Show($"Error! {Text} does not have UVs!", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -344,7 +344,7 @@ namespace Bfres.Structs bool HasTans = shp.vertexAttributes.Any(x => x.Name == "_t0"); bool HasBiTans = shp.vertexAttributes.Any(x => x.Name == "_b0"); - if (!shp.HasUV0()) + if (!shp.HasAttributeUV0()) { MessageBox.Show($"Error! {Text} does not have UVs!", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -683,7 +683,7 @@ namespace Bfres.Structs } BfresModelImportSettings csvsettings = new BfresModelImportSettings(); csvsettings.DisableMaterialEdits(); - csvsettings.SetModelAttributes(csvModel.objects[0]); + csvsettings.SetModelAttributes(csvModel.objects); if (csvsettings.ShowDialog() == DialogResult.OK) { if (csvsettings.LimitSkinCount || @@ -861,7 +861,7 @@ namespace Bfres.Structs settings.UpdateTexturePlaceholderSetting(HasTextures); } - settings.SetModelAttributes(ImportedObjects[0]); + settings.SetModelAttributes(ImportedObjects); if (settings.ShowDialog() == DialogResult.OK) { STProgressBar progressBar = new STProgressBar(); diff --git a/File_Format_Library/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL/FSHP.cs b/File_Format_Library/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL/FSHP.cs index bf832715..c30388bd 100644 --- a/File_Format_Library/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL/FSHP.cs +++ b/File_Format_Library/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL/FSHP.cs @@ -685,7 +685,7 @@ namespace Bfres.Structs bool HasTans = vertexAttributes.Any(x => x.Name == "_t0"); bool HasBiTans = vertexAttributes.Any(x => x.Name == "_b0"); - if (!HasUV0()) + if (!HasAttributeUV0()) { MessageBox.Show($"Error! {Text} does not have UVs!", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -738,21 +738,21 @@ namespace Bfres.Structs UpdateVertexData(); Cursor.Current = Cursors.Default; } - public bool HasUV0() + public bool HasAttributeUV0() { return vertexAttributes.Any(x => x.Name == "_u0"); } - public bool HasUV1() + public bool HasAttributeUV1() { return vertexAttributes.Any(x => x.Name == "_u1"); } - public bool HasUV2() + public bool HasAttributeUV2() { return vertexAttributes.Any(x => x.Name == "_u2"); } public void FlipUvsVertical(object sender, EventArgs args) { - if (!HasUV0()) + if (!HasAttributeUV0()) { MessageBox.Show($"Error! {Text} does not have UVs!", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -764,7 +764,7 @@ namespace Bfres.Structs } public void FlipUvsHorizontal(object sender, EventArgs args) { - if (!HasUV0()) + if (!HasAttributeUV0()) { MessageBox.Show($"Error! {Text} does not have UVs!", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -888,7 +888,7 @@ namespace Bfres.Structs var originalAttributes = vertexAttributes; BfresModelImportSettings settings = new BfresModelImportSettings(); - settings.SetModelAttributes(assimp.objects[0]); + settings.SetModelAttributes(assimp.objects); if (settings.ShowDialog() == DialogResult.OK) { STGenericObject obj = selector.GetSelectedMesh(); diff --git a/File_Format_Library/FileFormats/BFRES/BfresStructs.cs b/File_Format_Library/FileFormats/BFRES/BfresStructs.cs index 8b835e49..62276f5a 100644 --- a/File_Format_Library/FileFormats/BFRES/BfresStructs.cs +++ b/File_Format_Library/FileFormats/BFRES/BfresStructs.cs @@ -2254,15 +2254,15 @@ namespace Bfres.Structs BFRESRender.UpdateVertexData(); Cursor.Current = Cursors.Default; } - public bool HasUV0() + public bool HasAttributeUV0() { return vertexAttributes.Any(x => x.Name == "_u0"); } - public bool HasUV1() + public bool HasAttributeUV1() { return vertexAttributes.Any(x => x.Name == "_u1"); } - public bool HasUV2() + public bool HasAttributeUV2() { return vertexAttributes.Any(x => x.Name == "_u2"); } diff --git a/File_Format_Library/FileFormats/Pokemon/GFBANIM/GFBANM.cs b/File_Format_Library/FileFormats/Pokemon/GFBANIM/GFBANM.cs index bd7d1c84..9234e5cd 100644 --- a/File_Format_Library/FileFormats/Pokemon/GFBANIM/GFBANM.cs +++ b/File_Format_Library/FileFormats/Pokemon/GFBANIM/GFBANM.cs @@ -8,6 +8,7 @@ using System.Windows.Forms; using Toolbox.Library; using Toolbox.Library.IO; using OpenTK; +using System.Reflection; namespace FirstPlugin { @@ -16,8 +17,8 @@ namespace FirstPlugin public FileType FileType { get; set; } = FileType.Model; public bool CanSave { get; set; } - public string[] Description { get; set; } = new string[] { "MDL" }; - public string[] Extension { get; set; } = new string[] { "*.mdl" }; + public string[] Description { get; set; } = new string[] { "GFBANM" }; + public string[] Extension { get; set; } = new string[] { "*.gfbanm" }; public string FileName { get; set; } public string FilePath { get; set; } public IFileInfo IFileInfo { get; set; } @@ -36,11 +37,12 @@ namespace FirstPlugin } } + Header header; public void Load(System.IO.Stream stream) { using (var reader = new FileReader(stream)) { - + header = new Header(reader); } } @@ -56,30 +58,46 @@ namespace FirstPlugin public class Header { public Config config; + public BoneList boneList; - public void Read(FileReader reader) + public Header(FileReader reader) { - reader.ReadUInt32(); config = ParseSection(reader, this); + boneList = ParseSection(reader, this); + + Console.WriteLine($"config NumKeyFrames {config.NumKeyFrames}"); + Console.WriteLine($"config FramesPerSecond {config.FramesPerSecond}"); } } private static T ParseSection(FileReader reader, Header header) where T : GFSection, new() { - var layoutOffset = reader.ReadOffset(true, typeof(uint)); + var offset = reader.ReadOffset(true, typeof(uint)); + reader.SeekBegin(offset); + + long origin = reader.Position; + + int layoutOffset = reader.ReadInt32(); var dataOffset = reader.ReadOffset(true, typeof(uint)); T section = new T(); - using (reader.TemporarySeek(layoutOffset, System.IO.SeekOrigin.Begin)) + using (reader.TemporarySeek(origin - layoutOffset, System.IO.SeekOrigin.Begin)) { ushort layoutSize = reader.ReadUInt16(); ushort layoutStride = reader.ReadUInt16(); - section.LayoutPointers = reader.ReadUInt16s((int)(layoutSize / 2)); + + List pointers = new List(); + uint looper = 4; + while (looper < layoutSize) { + pointers.Add(reader.ReadUInt16()); + looper += 2; + } + + section.LayoutPointers = reader.ReadUInt16s((int)(layoutSize / 4)); } - using (reader.TemporarySeek(dataOffset, System.IO.SeekOrigin.Begin)) - { + using (reader.TemporarySeek(dataOffset, System.IO.SeekOrigin.Begin)) { section.Read(reader, header); } @@ -88,30 +106,117 @@ namespace FirstPlugin public class GFSection { + public ushort LayoutSize { get; set; } + public ushort LayoutStride { get; set; } + public ushort[] LayoutPointers { get; set; } - public virtual void Read(FileReader reader, Header header) + public void Read(FileReader reader, Header header) { + long origin = reader.Position; + PropertyInfo[] types = new PropertyInfo[(int)LayoutPointers?.Length]; + + var sectionType = this.GetType(); + + int index = 0; + foreach (var prop in sectionType.GetProperties()) { + if (!Attribute.IsDefined(prop, typeof(FlatTableParse))) + continue; + + types[index++] = prop; + } + + for (int i = 0; i < LayoutPointers?.Length; i++) + { + reader.SeekBegin(origin + LayoutPointers[i]); + if (types[i] != null) + { + var prop = types[i]; + var propertyType = prop.PropertyType; + + if (propertyType == typeof(uint)) + prop.SetValue(this, reader.ReadUInt32()); + else if (propertyType == typeof(int)) + prop.SetValue(this, reader.ReadInt32()); + else if(propertyType == typeof(byte)) + prop.SetValue(this, reader.ReadByte()); + else if(propertyType == typeof(sbyte)) + prop.SetValue(this, reader.ReadSByte()); + else if (propertyType == typeof(ushort)) + prop.SetValue(this, reader.ReadUInt16()); + else if (propertyType == typeof(short)) + prop.SetValue(this, reader.ReadInt16()); + else if (propertyType == typeof(Vector2)) + prop.SetValue(this, new Vector2( + reader.ReadSingle(), + reader.ReadSingle()) + ); + else if (propertyType == typeof(Vector3)) + prop.SetValue(this, new Vector3( + reader.ReadSingle(), + reader.ReadSingle(), + reader.ReadSingle()) + ); + else if (propertyType == typeof(Vector4)) + prop.SetValue(this, new Vector4( + reader.ReadSingle(), + reader.ReadSingle(), + reader.ReadSingle(), + reader.ReadSingle()) + ); + else if (propertyType == typeof(GFSection)) + { + var offset = reader.ReadOffset(true, typeof(uint)); + reader.SeekBegin(offset); + } + else if (propertyType is IEnumerable) { + + } + } + } } } + public class FlatTableParse : Attribute { } + public class OffsetProperty : Attribute { } + + [OffsetProperty] public class Config : GFSection { + [FlatTableParse] public int Unknown { get; set; } + [FlatTableParse] public uint NumKeyFrames { get; set; } + [FlatTableParse] public uint FramesPerSecond { get; set; } } + [OffsetProperty] public class BoneList : GFSection { + [FlatTableParse] public List Bones = new List(); + + [FlatTableParse] public List BoneDefaults = new List(); } public class Bone { + [FlatTableParse, OffsetProperty] public string Name { get; set; } + + [FlatTableParse] + public byte ScaleType { get; set; } + } + + public class NammeOffset + { + [FlatTableParse, OffsetProperty] + public string Name { get; set; } + + [FlatTableParse] public byte ScaleType { get; set; } } diff --git a/File_Format_Library/GUI/BFRES/BfresModelImportSettings.cs b/File_Format_Library/GUI/BFRES/BfresModelImportSettings.cs index c60c7c80..4ce5f951 100644 --- a/File_Format_Library/GUI/BFRES/BfresModelImportSettings.cs +++ b/File_Format_Library/GUI/BFRES/BfresModelImportSettings.cs @@ -6,6 +6,7 @@ using Toolbox.Library; using Toolbox.Library.Forms; using Toolbox.Library.Rendering; using Bfres.Structs; +using System.Linq; namespace FirstPlugin { @@ -98,40 +99,40 @@ namespace FirstPlugin originalMeshListView.EndUpdate(); } - public void SetModelAttributes(STGenericObject obj) + public void SetModelAttributes(List objects) { chkBoxEnablePositions.Enabled = true; - chkBoxEnablePositions.Checked = obj.HasPos; - chkBoxEnableNormals.Checked = obj.HasNrm; - chkBoxEnableUVs.Checked = obj.HasUv0; - chkBoxEnableTans.Checked = obj.HasUv0; - chkBoxEnableBitans.Checked = obj.HasUv0; - chkBoxEnableWeightIndices.Checked = obj.HasWeights; - chkBoxEnableVertColors.Checked = obj.HasVertColors; + chkBoxEnablePositions.Checked = objects.Any(o => o.HasPos); + chkBoxEnableNormals.Checked = objects.Any(o => o.HasNrm); + chkBoxEnableUVs.Checked = objects.Any(o => o.HasUv0); + chkBoxEnableTans.Checked = objects.Any(o => o.HasUv0); + chkBoxEnableBitans.Checked = objects.Any(o => o.HasUv0); + chkBoxEnableWeightIndices.Checked = objects.Any(o => o.HasWeights); + chkBoxEnableVertColors.Checked = objects.Any(o => o.HasVertColors); chkResetUVParams.Checked = true; chkBoxTransformMatrix.Checked = true; - if (!obj.HasPos) + if (!objects.Any(o => o.HasPos)) DisableAttribute(chkBoxEnablePositions, comboBoxFormatPositions); - if (!obj.HasNrm) + if (!objects.Any(o => o.HasNrm)) DisableAttribute(chkBoxEnableNormals, comboBoxFormatPositions); - if (!obj.HasUv0) + if (!objects.Any(o => o.HasUv0)) DisableAttribute(chkBoxEnableUVs, comboBoxFormatUvs); //Note. Bitans/tans uses uvs to generate - if (!obj.HasUv0) + if (!objects.Any(o => o.HasUv0)) DisableAttribute(chkBoxEnableTans, comboBoxFormatTangents); - if (!obj.HasUv0) + if (!objects.Any(o => o.HasUv0)) DisableAttribute(chkBoxEnableBitans, comboBoxFormatBitans); - if (!obj.HasWeights && !obj.HasIndices) + if (!objects.Any(o => o.HasWeights) && !objects.Any(o => o.HasIndices)) { DisableAttribute(chkBoxEnableWeightIndices, comboBoxFormatWeights); DisableAttribute(chkBoxEnableWeightIndices, comboBoxFormatIndices); } - if (!obj.HasVertColors) + if (!objects.Any(o => o.HasVertColors)) DisableAttribute(chkBoxEnableVertColors, comboBoxFormatVertexColors); - EnableUV1 = obj.HasUv1; - EnableUV2 = obj.HasUv2; + EnableUV1 = objects.Any(o => o.HasUv1); + EnableUV2 = objects.Any(o => o.HasUv2); } public List CreateNewAttributes(List Attributes) diff --git a/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs b/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs index a5911594..3979521c 100644 --- a/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs +++ b/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs @@ -320,6 +320,7 @@ namespace Toolbox.Library.Forms if (e.Node is IContextMenuNode) { bool IsRoot = e.Node.Parent == null; + bool HasChildren = e.Node.Nodes.Count > 0; treeNodeContextMenu.Items.Clear(); if (e.Node.Tag != null && e.Node.Tag is ArchiveFileInfo) @@ -354,10 +355,10 @@ namespace Toolbox.Library.Forms HasExpand = true; } - if (!HasCollpase) + if (!HasCollpase && HasChildren) treeNodeContextMenu.Items.Add(new ToolStripMenuItem("Collapse All", null, CollapseAllAction, Keys.Control | Keys.Q)); - if (!HasExpand) + if (!HasExpand && HasChildren) treeNodeContextMenu.Items.Add(new ToolStripMenuItem("Expand All", null, ExpandAllAction, Keys.Control | Keys.P)); treeNodeContextMenu.Show(Cursor.Position); @@ -405,7 +406,9 @@ namespace Toolbox.Library.Forms } treeViewCustom1.Nodes.Remove(node); - ResetEditor(); + + if (treeViewCustom1.Nodes.Count == 0) + ResetEditor(); //Force garbage collection. GC.Collect(); @@ -424,8 +427,6 @@ namespace Toolbox.Library.Forms { if (control is STUserControl) ((STUserControl)control).OnControlClosing(); - - control.Dispose(); } stPanel2.Controls.Clear();