From 69388689ac20d92de722a328fc061d64a448e330 Mon Sep 17 00:00:00 2001 From: Exter-N Date: Wed, 20 Sep 2023 01:53:10 +0200 Subject: [PATCH] Material Editor: Extend live preview. --- .../Interop/MaterialPreview/MaterialInfo.cs | 87 ++++++++----------- .../ModEditWindow.Materials.MtrlTab.cs | 5 +- .../ModEditWindow.QuickImport.cs | 1 + Penumbra/UI/AdvancedWindow/ModEditWindow.cs | 7 +- 4 files changed, 44 insertions(+), 56 deletions(-) diff --git a/Penumbra/Interop/MaterialPreview/MaterialInfo.cs b/Penumbra/Interop/MaterialPreview/MaterialInfo.cs index 3f02e7e8..26e809f9 100644 --- a/Penumbra/Interop/MaterialPreview/MaterialInfo.cs +++ b/Penumbra/Interop/MaterialPreview/MaterialInfo.cs @@ -9,41 +9,20 @@ namespace Penumbra.Interop.MaterialPreview; public enum DrawObjectType { - PlayerCharacter, - PlayerMainhand, - PlayerOffhand, - PlayerVfx, - MinionCharacter, - MinionUnk1, - MinionUnk2, - MinionUnk3, + Character, + Mainhand, + Offhand, + Vfx, }; -public readonly record struct MaterialInfo(DrawObjectType Type, int ModelSlot, int MaterialSlot) +public readonly record struct MaterialInfo(ushort ObjectIndex, DrawObjectType Type, int ModelSlot, int MaterialSlot) { public nint GetCharacter(IObjectTable objects) - => GetCharacter(Type, objects); - - public static nint GetCharacter(DrawObjectType type, IObjectTable objects) - => type switch - { - DrawObjectType.PlayerCharacter => objects.GetObjectAddress(0), - DrawObjectType.PlayerMainhand => objects.GetObjectAddress(0), - DrawObjectType.PlayerOffhand => objects.GetObjectAddress(0), - DrawObjectType.PlayerVfx => objects.GetObjectAddress(0), - DrawObjectType.MinionCharacter => objects.GetObjectAddress(1), - DrawObjectType.MinionUnk1 => objects.GetObjectAddress(1), - DrawObjectType.MinionUnk2 => objects.GetObjectAddress(1), - DrawObjectType.MinionUnk3 => objects.GetObjectAddress(1), - _ => nint.Zero, - }; + => objects.GetObjectAddress(ObjectIndex); public nint GetDrawObject(nint address) => GetDrawObject(Type, address); - public static nint GetDrawObject(DrawObjectType type, IObjectTable objects) - => GetDrawObject(type, GetCharacter(type, objects)); - public static unsafe nint GetDrawObject(DrawObjectType type, nint address) { var gameObject = (Character*)address; @@ -52,18 +31,17 @@ public readonly record struct MaterialInfo(DrawObjectType Type, int ModelSlot, i return type switch { - DrawObjectType.PlayerCharacter => (nint)gameObject->GameObject.GetDrawObject(), - DrawObjectType.PlayerMainhand => *((nint*)&gameObject->DrawData.MainHand + 1), - DrawObjectType.PlayerOffhand => *((nint*)&gameObject->DrawData.OffHand + 1), - DrawObjectType.PlayerVfx => *((nint*)&gameObject->DrawData.UnkF0 + 1), - DrawObjectType.MinionCharacter => (nint)gameObject->GameObject.GetDrawObject(), - DrawObjectType.MinionUnk1 => *((nint*)&gameObject->DrawData.MainHand + 1), - DrawObjectType.MinionUnk2 => *((nint*)&gameObject->DrawData.OffHand + 1), - DrawObjectType.MinionUnk3 => *((nint*)&gameObject->DrawData.UnkF0 + 1), - _ => nint.Zero, + DrawObjectType.Character => (nint)gameObject->GameObject.GetDrawObject(), + DrawObjectType.Mainhand => *((nint*)&gameObject->DrawData.MainHand + 1), + DrawObjectType.Offhand => *((nint*)&gameObject->DrawData.OffHand + 1), + DrawObjectType.Vfx => *((nint*)&gameObject->DrawData.UnkF0 + 1), + _ => nint.Zero, }; } + public unsafe Material* GetDrawObjectMaterial(IObjectTable objects) + => GetDrawObjectMaterial((CharacterBase*)GetDrawObject(GetCharacter(objects))); + public unsafe Material* GetDrawObjectMaterial(CharacterBase* drawObject) { if (drawObject == null) @@ -82,33 +60,42 @@ public readonly record struct MaterialInfo(DrawObjectType Type, int ModelSlot, i return model->Materials[MaterialSlot]; } - public static unsafe List FindMaterials(IObjectTable objects, string materialPath) + public static unsafe List FindMaterials(IEnumerable gameObjects, string materialPath) { var needle = ByteString.FromString(materialPath.Replace('\\', '/'), out var m, true) ? m : ByteString.Empty; var result = new List(Enum.GetValues().Length); - foreach (var type in Enum.GetValues()) + foreach (var objectPtr in gameObjects) { - var drawObject = (CharacterBase*)GetDrawObject(type, objects); - if (drawObject == null) + var gameObject = (Character*)objectPtr; + if (gameObject == null) continue; - for (var i = 0; i < drawObject->SlotCount; ++i) + var index = gameObject->GameObject.ObjectIndex; + + foreach (var type in Enum.GetValues()) { - var model = drawObject->Models[i]; - if (model == null) + var drawObject = (CharacterBase*)GetDrawObject(type, objectPtr); + if (drawObject == null) continue; - for (var j = 0; j < model->MaterialCount; ++j) + for (var i = 0; i < drawObject->SlotCount; ++i) { - var material = model->Materials[j]; - if (material == null) + var model = drawObject->Models[i]; + if (model == null) continue; - var mtrlHandle = material->MaterialResourceHandle; - var path = ResolveContext.GetResourceHandlePath((Structs.ResourceHandle*)mtrlHandle); - if (path == needle) - result.Add(new MaterialInfo(type, i, j)); + for (var j = 0; j < model->MaterialCount; ++j) + { + var material = model->Materials[j]; + if (material == null) + continue; + + var mtrlHandle = material->MaterialResourceHandle; + var path = ResolveContext.GetResourceHandlePath((Structs.ResourceHandle*)mtrlHandle); + if (path == needle) + result.Add(new MaterialInfo(index, type, i, j)); + } } } } diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs index ad83843d..ebe980d7 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs @@ -454,13 +454,12 @@ public partial class ModEditWindow { UnbindFromMaterialInstances(); - var instances = MaterialInfo.FindMaterials(_edit._dalamud.Objects, FilePath); + var instances = MaterialInfo.FindMaterials(_edit._resourceTreeFactory.GetLocalPlayerRelatedCharacters().Select(ch => ch.Address), FilePath); var foundMaterials = new HashSet(); foreach (var materialInfo in instances) { - var drawObject = (CharacterBase*)MaterialInfo.GetDrawObject(materialInfo.Type, _edit._dalamud.Objects); - var material = materialInfo.GetDrawObjectMaterial(drawObject); + var material = materialInfo.GetDrawObjectMaterial(_edit._dalamud.Objects); if (foundMaterials.Contains((nint)material)) continue; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs index 2f64f82a..48d617db 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs @@ -14,6 +14,7 @@ namespace Penumbra.UI.AdvancedWindow; public partial class ModEditWindow { + private readonly ResourceTreeFactory _resourceTreeFactory; private readonly ResourceTreeViewer _quickImportViewer; private readonly Dictionary _quickImportWritables = new(); private readonly Dictionary<(Utf8GamePath, IWritable?), QuickImportAction> _quickImportActions = new(); diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs index 745b412b..febb01cb 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs @@ -576,9 +576,10 @@ public partial class ModEditWindow : Window, IDisposable _shaderPackageTab = new FileEditor(this, gameData, config, _editor.Compactor, _fileDialog, "Shaders", ".shpk", () => _editor.Files.Shpk, DrawShaderPackagePanel, () => _mod?.ModPath.FullName ?? string.Empty, (bytes, _, _) => new ShpkTab(_fileDialog, bytes)); - _center = new CombinedTexture(_left, _right); - _textureSelectCombo = new TextureDrawer.PathSelectCombo(textures, editor); - _quickImportViewer = + _center = new CombinedTexture(_left, _right); + _textureSelectCombo = new TextureDrawer.PathSelectCombo(textures, editor); + _resourceTreeFactory = resourceTreeFactory; + _quickImportViewer = new ResourceTreeViewer(_config, resourceTreeFactory, changedItemDrawer, 2, OnQuickImportRefresh, DrawQuickImportActions); _communicator.ModPathChanged.Subscribe(OnModPathChanged, ModPathChanged.Priority.ModEditWindow); }