From 28246244cd04c37689278a2c13259fc17508bf68 Mon Sep 17 00:00:00 2001 From: ackwell Date: Thu, 21 Dec 2023 20:25:01 +1100 Subject: [PATCH] Move persitence logic to tab file --- .../ModEditWindow.Models.MdlTab.cs | 87 +++++++++++++++++++ .../UI/AdvancedWindow/ModEditWindow.Models.cs | 69 ++------------- 2 files changed, 96 insertions(+), 60 deletions(-) diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs index aeae20cc..3ba39543 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs @@ -1,3 +1,5 @@ +using System.Collections.ObjectModel; +using OtterGui; using Penumbra.GameData.Files; namespace Penumbra.UI.AdvancedWindow; @@ -8,9 +10,94 @@ public partial class ModEditWindow { public readonly MdlFile Mdl; + private List _materials; + private List[] _attributes; + public MdlTab(byte[] bytes) { Mdl = new MdlFile(bytes); + + _materials = Mdl.Meshes.Select(mesh => Mdl.Materials[mesh.MaterialIndex]).ToList(); + _attributes = HydrateAttributes(Mdl); + } + + private List[] HydrateAttributes(MdlFile mdl) + { + return mdl.SubMeshes.Select(submesh => + Enumerable.Range(0,32) + .Where(index => ((submesh.AttributeIndexMask >> index) & 1) == 1) + .Select(index => mdl.Attributes[index]) + .ToList() + ).ToArray(); + } + + public string GetMeshMaterial(int meshIndex) => _materials[meshIndex]; + + public void SetMeshMaterial(int meshIndex, string materialPath) + { + _materials[meshIndex] = materialPath; + + PersistMaterials(); + } + + private void PersistMaterials() + { + var allMaterials = new List(); + + foreach (var (material, meshIndex) in _materials.WithIndex()) + { + var materialIndex = allMaterials.IndexOf(material); + if (materialIndex == -1) + { + allMaterials.Add(material); + materialIndex = allMaterials.Count() - 1; + } + + Mdl.Meshes[meshIndex].MaterialIndex = (ushort)materialIndex; + } + + Mdl.Materials = allMaterials.ToArray(); + } + + public IReadOnlyCollection GetSubmeshAttributes(int submeshIndex) => _attributes[submeshIndex]; + + public void UpdateSubmeshAttribute(int submeshIndex, string? old, string? new_) + { + var attributes = _attributes[submeshIndex]; + + if (old != null) + attributes.Remove(old); + + if (new_ != null) + attributes.Add(new_); + + PersistAttributes(); + } + + private void PersistAttributes() + { + var allAttributes = new List(); + + foreach (var (attributes, submeshIndex) in _attributes.WithIndex()) + { + var mask = 0u; + + foreach (var attribute in attributes) + { + var attributeIndex = allAttributes.IndexOf(attribute); + if (attributeIndex == -1) + { + allAttributes.Add(attribute); + attributeIndex = allAttributes.Count() - 1; + } + + mask |= 1u << attributeIndex; + } + + Mdl.SubMeshes[submeshIndex].AttributeIndexMask = mask; + } + + Mdl.Attributes = allAttributes.ToArray(); } public bool Valid => Mdl.Valid; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs index bcfc77ad..0a4c9c1b 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs @@ -29,32 +29,33 @@ public partial class ModEditWindow var ret = false; for (var i = 0; i < file.Meshes.Length; ++i) - ret |= DrawMeshDetails(file, i, disabled); + ret |= DrawMeshDetails(tab, i, disabled); ret |= DrawOtherModelDetails(file, disabled); return !disabled && ret; } - private static bool DrawMeshDetails(MdlFile file, int meshIndex, bool disabled) + private static bool DrawMeshDetails(MdlTab tab, int meshIndex, bool disabled) { if (!ImGui.CollapsingHeader($"Mesh {meshIndex}")) return false; using var id = ImRaii.PushId(meshIndex); + var file = tab.Mdl; var mesh = file.Meshes[meshIndex]; var ret = false; // Mesh material. - var temp = file.Materials[mesh.MaterialIndex]; + var temp = tab.GetMeshMaterial(meshIndex); if ( ImGui.InputText("Material", ref temp, Utf8GamePath.MaxGamePathLength, disabled ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None) && temp.Length > 0 - && temp != file.Materials[mesh.MaterialIndex] + && temp != tab.GetMeshMaterial(meshIndex) ) { - file.Materials[mesh.MaterialIndex] = temp; + tab.SetMeshMaterial(meshIndex, temp); ret = true; } @@ -64,20 +65,16 @@ public partial class ModEditWindow using var submeshId = ImRaii.PushId(submeshOffset); var submeshIndex = mesh.SubMeshIndex + submeshOffset; - - var submesh = file.SubMeshes[submeshIndex]; var widget = _submeshAttributeTagWidgets[submeshIndex]; - - var attributes = HydrateAttributes(file, submesh.AttributeIndexMask).ToArray(); + var attributes = tab.GetSubmeshAttributes(submeshIndex); UiHelpers.DefaultLineSpace(); var tagIndex = widget.Draw($"Submesh {submeshOffset} Attributes", "", attributes, out var editedAttribute, !disabled); if (tagIndex >= 0) { - EditSubmeshAttribute( - file, + tab.UpdateSubmeshAttribute( submeshIndex, - tagIndex < attributes.Length ? attributes[tagIndex] : null, + tagIndex < attributes.Count() ? attributes.ElementAt(tagIndex) : null, editedAttribute != "" ? editedAttribute : null ); @@ -88,54 +85,6 @@ public partial class ModEditWindow return ret; } - private static void EditSubmeshAttribute(MdlFile file, int changedSubmeshIndex, string? old, string? new_) - { - // Build a hydrated view of all attributes in the model - var submeshAttributes = file.SubMeshes - .Select(submesh => HydrateAttributes(file, submesh.AttributeIndexMask).ToList()) - .ToArray(); - - // Make changes to the submesh we're actually editing here. - var changedSubmesh = submeshAttributes[changedSubmeshIndex]; - - if (old != null) - changedSubmesh.Remove(old); - - if (new_ != null) - changedSubmesh.Add(new_); - - // Re-serialize all the attributes. - var allAttributes = new List(); - foreach (var (attributes, submeshIndex) in submeshAttributes.WithIndex()) - { - var mask = 0u; - - foreach (var attribute in attributes) - { - var attributeIndex = allAttributes.IndexOf(attribute); - if (attributeIndex == -1) - { - allAttributes.Add(attribute); - attributeIndex = allAttributes.Count() - 1; - } - - mask |= 1u << attributeIndex; - } - - file.SubMeshes[submeshIndex].AttributeIndexMask = mask; - } - - file.Attributes = allAttributes.ToArray(); - } - - private static IEnumerable HydrateAttributes(MdlFile file, uint mask) - { - return Enumerable - .Range(0, 32) - .Where(index => ((mask >> index) & 1) == 1) - .Select(index => file.Attributes[index]); - } - private static bool DrawOtherModelDetails(MdlFile file, bool _) { if (!ImGui.CollapsingHeader("Further Content"))