Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Material Editor: Extend live preview. #345

Merged
merged 1 commit into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 37 additions & 50 deletions Penumbra/Interop/MaterialPreview/MaterialInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -52,18 +31,17 @@ public static unsafe nint GetDrawObject(DrawObjectType type, nint address)

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)
Expand All @@ -82,33 +60,42 @@ public static unsafe nint GetDrawObject(DrawObjectType type, nint address)
return model->Materials[MaterialSlot];
}

public static unsafe List<MaterialInfo> FindMaterials(IObjectTable objects, string materialPath)
public static unsafe List<MaterialInfo> FindMaterials(IEnumerable<nint> gameObjects, string materialPath)
{
var needle = ByteString.FromString(materialPath.Replace('\\', '/'), out var m, true) ? m : ByteString.Empty;

var result = new List<MaterialInfo>(Enum.GetValues<DrawObjectType>().Length);
foreach (var type in Enum.GetValues<DrawObjectType>())
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<DrawObjectType>())
{
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));
}
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs
Original file line number Diff line number Diff line change
Expand Up @@ -454,13 +454,12 @@ public unsafe void BindToMaterialInstances()
{
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<nint>();
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;

Expand Down
1 change: 1 addition & 0 deletions Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace Penumbra.UI.AdvancedWindow;

public partial class ModEditWindow
{
private readonly ResourceTreeFactory _resourceTreeFactory;
private readonly ResourceTreeViewer _quickImportViewer;
private readonly Dictionary<FullPath, IWritable?> _quickImportWritables = new();
private readonly Dictionary<(Utf8GamePath, IWritable?), QuickImportAction> _quickImportActions = new();
Expand Down
7 changes: 4 additions & 3 deletions Penumbra/UI/AdvancedWindow/ModEditWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -576,9 +576,10 @@ public ModEditWindow(PerformanceTracker performance, FileDialogService fileDialo
_shaderPackageTab = new FileEditor<ShpkTab>(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);
}
Expand Down
Loading