Flesh out material wiring

This commit is contained in:
ackwell 2023-12-22 23:49:50 +11:00
parent 829016a1c4
commit a581495c7e
2 changed files with 62 additions and 64 deletions

View file

@ -1,5 +1,6 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using OtterGui; using OtterGui;
using Penumbra.GameData;
using Penumbra.GameData.Files; using Penumbra.GameData.Files;
namespace Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.AdvancedWindow;
@ -10,53 +11,37 @@ public partial class ModEditWindow
{ {
public readonly MdlFile Mdl; public readonly MdlFile Mdl;
private List<string> _materials;
private List<string>[] _attributes; private List<string>[] _attributes;
public MdlTab(byte[] bytes) public MdlTab(byte[] bytes)
{ {
Mdl = new MdlFile(bytes); Mdl = new MdlFile(bytes);
_attributes = PopulateAttributes();
_materials = Mdl.Meshes.Select(mesh => Mdl.Materials[mesh.MaterialIndex]).ToList();
_attributes = HydrateAttributes(Mdl);
} }
private List<string>[] HydrateAttributes(MdlFile mdl) public void RemoveMaterial(int materialIndex)
{ {
return mdl.SubMeshes.Select(submesh => // Meshes using the removed material are redirected to material 0, and those after the index are corrected.
Enumerable.Range(0,32) for (var meshIndex = 0; meshIndex < Mdl.Meshes.Length; meshIndex++)
.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<string>();
foreach (var (material, meshIndex) in _materials.WithIndex())
{ {
var materialIndex = allMaterials.IndexOf(material); var mesh = Mdl.Meshes[meshIndex];
if (materialIndex == -1) if (mesh.MaterialIndex == materialIndex)
{ mesh.MaterialIndex = 0;
allMaterials.Add(material); else if (mesh.MaterialIndex > materialIndex)
materialIndex = allMaterials.Count() - 1; mesh.MaterialIndex -= 1;
}
Mdl.Meshes[meshIndex].MaterialIndex = (ushort)materialIndex;
} }
Mdl.Materials = allMaterials.ToArray(); Mdl.Materials = Mdl.Materials.RemoveItems(materialIndex);
}
private List<string>[] PopulateAttributes()
{
return Mdl.SubMeshes.Select(submesh =>
Enumerable.Range(0,32)
.Where(index => ((submesh.AttributeIndexMask >> index) & 1) == 1)
.Select(index => Mdl.Attributes[index])
.ToList()
).ToArray();
} }
public IReadOnlyCollection<string> GetSubmeshAttributes(int submeshIndex) => _attributes[submeshIndex]; public IReadOnlyCollection<string> GetSubmeshAttributes(int submeshIndex) => _attributes[submeshIndex];

View file

@ -3,6 +3,7 @@ using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using OtterGui.Widgets; using OtterGui.Widgets;
using Penumbra.GameData;
using Penumbra.GameData.Files; using Penumbra.GameData.Files;
using Penumbra.String.Classes; using Penumbra.String.Classes;
@ -14,6 +15,7 @@ public partial class ModEditWindow
private readonly FileEditor<MdlTab> _modelTab; private readonly FileEditor<MdlTab> _modelTab;
private static string _modelNewMaterial = string.Empty;
private static List<TagButtons> _submeshAttributeTagWidgets = new(); private static List<TagButtons> _submeshAttributeTagWidgets = new();
private static bool DrawModelPanel(MdlTab tab, bool disabled) private static bool DrawModelPanel(MdlTab tab, bool disabled)
@ -47,12 +49,13 @@ public partial class ModEditWindow
if (!ImGui.CollapsingHeader("Materials")) if (!ImGui.CollapsingHeader("Materials"))
return false; return false;
var materials = tab.Mdl.Materials;
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit); using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
if (!table) if (!table)
return false; return false;
var ret = false;
var materials = tab.Mdl.Materials;
ImGui.TableSetupColumn("index", ImGuiTableColumnFlags.WidthFixed, 80 * UiHelpers.Scale); ImGui.TableSetupColumn("index", ImGuiTableColumnFlags.WidthFixed, 80 * UiHelpers.Scale);
ImGui.TableSetupColumn("path", ImGuiTableColumnFlags.WidthStretch, 1); ImGui.TableSetupColumn("path", ImGuiTableColumnFlags.WidthStretch, 1);
ImGui.TableSetupColumn("actions", ImGuiTableColumnFlags.WidthFixed, UiHelpers.IconButtonSize.X); ImGui.TableSetupColumn("actions", ImGuiTableColumnFlags.WidthFixed, UiHelpers.IconButtonSize.X);
@ -63,6 +66,8 @@ public partial class ModEditWindow
for (var materialIndex = 0; materialIndex < materials.Length; materialIndex++) for (var materialIndex = 0; materialIndex < materials.Length; materialIndex++)
{ {
using var id = ImRaii.PushId(materialIndex);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.Text($"Material #{materialIndex + 1}"); ImGui.Text($"Material #{materialIndex + 1}");
@ -70,44 +75,52 @@ public partial class ModEditWindow
var temp = materials[materialIndex]; var temp = materials[materialIndex];
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.SetNextItemWidth(-1); ImGui.SetNextItemWidth(-1);
ImGui.InputText($"##material{materialIndex}", ref temp, Utf8GamePath.MaxGamePathLength, inputFlags); if (
ImGui.InputText($"##material{materialIndex}", ref temp, Utf8GamePath.MaxGamePathLength, inputFlags)
&& temp.Length > 0
&& temp != materials[materialIndex]
) {
materials[materialIndex] = temp;
ret = true;
}
ImGui.TableNextColumn(); ImGui.TableNextColumn();
var todoDelete = ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), UiHelpers.IconButtonSize, "description", disabled || !ImGui.GetIO().KeyCtrl, true);
// Need to have at least one material.
if (materials.Length <= 1)
continue;
if (ImGuiUtil.DrawDisabledButton(
FontAwesomeIcon.Trash.ToIconString(),
UiHelpers.IconButtonSize,
"Delete this material.\nAny meshes targeting this material will be updated to use material #1.\nHold Control while clicking to delete.",
disabled || !ImGui.GetIO().KeyCtrl,
true
)) {
tab.RemoveMaterial(materialIndex);
ret = true;
}
} }
if (materials.Length < MdlMaterialMaximum) if (materials.Length < MdlMaterialMaximum)
{ {
ImGui.TableNextColumn(); ImGui.TableNextColumn();
// todo: persist
var temp = "";
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.SetNextItemWidth(-1); ImGui.SetNextItemWidth(-1);
ImGui.InputTextWithHint($"##newMaterial", "Add new material...", ref temp, Utf8GamePath.MaxGamePathLength, inputFlags); ImGui.InputTextWithHint($"##newMaterial", "Add new material...", ref _modelNewMaterial, Utf8GamePath.MaxGamePathLength, inputFlags);
// todo: flesh out this validation var validName = _modelNewMaterial != "";
var validName = temp != "";
ImGui.TableNextColumn(); ImGui.TableNextColumn();
var todoAdd = ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), UiHelpers.IconButtonSize, "description", disabled || !validName, true); if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), UiHelpers.IconButtonSize, "description", disabled || !validName, true))
{
tab.Mdl.Materials = materials.AddItem(_modelNewMaterial);
_modelNewMaterial = string.Empty;
ret = true;
}
} }
// for (var index = 0; index < MdlMaterialMaximum; index++) return ret;
// {
// var temp = "";
// ImGui.InputText($"Material {index}", ref temp, Utf8GamePath.MaxGamePathLength, inputFlags);
// }
// var temp = tab.GetMeshMaterial(meshIndex);
// if (
// ImGui.InputText("Material", ref temp, Utf8GamePath.MaxGamePathLength, disabled ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None)
// && temp.Length > 0
// && temp != tab.GetMeshMaterial(meshIndex)
// ) {
// tab.SetMeshMaterial(meshIndex, temp);
// ret = true;
// }
return false;
} }
private static bool DrawModelLodDetails(MdlTab tab, int lodIndex, bool disabled) private static bool DrawModelLodDetails(MdlTab tab, int lodIndex, bool disabled)
@ -160,7 +173,7 @@ public partial class ModEditWindow
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.SetNextItemWidth(-1); ImGui.SetNextItemWidth(-1);
using (var materialCombo = ImRaii.Combo("##material", tab.GetMeshMaterial(meshIndex))) using (var materialCombo = ImRaii.Combo("##material", "TODO material"))
{ {
// todo // todo
} }