From edcffb9d9f7f6ee7ac5e454a15842b3c4d3ed01d Mon Sep 17 00:00:00 2001 From: ackwell Date: Thu, 11 Jan 2024 21:26:34 +1100 Subject: [PATCH] Allow keeping existing mdl attributes --- .../ModEditWindow.Models.MdlTab.cs | 34 +++++++++++++++++++ .../UI/AdvancedWindow/ModEditWindow.Models.cs | 1 + 2 files changed, 35 insertions(+) diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs index d38d8d92..cdaf399f 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs @@ -16,6 +16,7 @@ public partial class ModEditWindow private List[] _attributes; public bool ImportKeepMaterials; + public bool ImportKeepAttributes; public List? GamePaths { get; private set; } public int GamePathIndex; @@ -158,6 +159,9 @@ public partial class ModEditWindow if (ImportKeepMaterials) MergeMaterials(newMdl, Mdl); + if (ImportKeepAttributes) + MergeAttributes(newMdl, Mdl); + Initialize(newMdl); _dirty = true; } @@ -177,6 +181,36 @@ public partial class ModEditWindow } } + /// Merge attribute configuration from the source onto the target. + /// + /// Model to copy attribute configuration from. + public void MergeAttributes(MdlFile target, MdlFile source) + { + target.Attributes = source.Attributes; + + var indexEnumerator = Enumerable.Range(0, target.Meshes.Length) + .SelectMany(mi => Enumerable.Range(0, target.Meshes[mi].SubMeshCount).Select(so => (mi, so))); + foreach (var (meshIndex, subMeshOffset) in indexEnumerator) + { + var subMeshIndex = target.Meshes[meshIndex].SubMeshIndex + subMeshOffset; + + // Preemptively reset the mask in case we need to shortcut out. + target.SubMeshes[subMeshIndex].AttributeIndexMask = 0u; + + // Rather than comparing sub-meshes directly, we're grouping by parent mesh in an attempt + // to maintain semantic connection betwen mesh index and submesh attributes. + if (meshIndex >= source.Meshes.Length) + continue; + var sourceMesh = source.Meshes[meshIndex]; + + if (subMeshOffset >= sourceMesh.SubMeshCount) + continue; + var sourceSubMesh = source.SubMeshes[sourceMesh.SubMeshIndex + subMeshOffset]; + + target.SubMeshes[subMeshIndex].AttributeIndexMask = sourceSubMesh.AttributeIndexMask; + } + } + private void RecordIoExceptions(Exception? exception) { IoExceptions = exception switch { diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs index fbdfcc74..8c298d4f 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs @@ -80,6 +80,7 @@ public partial class ModEditWindow using (var frame = ImRaii.FramedGroup("Import", size, headerPreIcon: FontAwesomeIcon.FileImport)) { ImGui.Checkbox("Keep current materials", ref tab.ImportKeepMaterials); + ImGui.Checkbox("Keep current attributes", ref tab.ImportKeepAttributes); if (ImGuiUtil.DrawDisabledButton("Import from glTF", Vector2.Zero, "Imports a glTF file, overriding the content of this mdl.", tab.PendingIo))