mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-15 21:24:18 +01:00
Remarked changes.
This commit is contained in:
parent
0ad769e08e
commit
72979a9743
2 changed files with 82 additions and 59 deletions
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
||||||
Subproject commit b4b14367d8235eabedd561ad3626beb1d2a83889
|
Subproject commit 2bbb9b2a8a4479461b252594b9d1b788b551c13c
|
||||||
|
|
@ -7,6 +7,7 @@ using OtterGui.Widgets;
|
||||||
using Penumbra.GameData;
|
using Penumbra.GameData;
|
||||||
using Penumbra.GameData.Files;
|
using Penumbra.GameData.Files;
|
||||||
using Penumbra.Import.Models;
|
using Penumbra.Import.Models;
|
||||||
|
using Penumbra.Mods;
|
||||||
using Penumbra.String.Classes;
|
using Penumbra.String.Classes;
|
||||||
using Penumbra.UI.Classes;
|
using Penumbra.UI.Classes;
|
||||||
|
|
||||||
|
|
@ -14,9 +15,13 @@ namespace Penumbra.UI.AdvancedWindow;
|
||||||
|
|
||||||
public partial class ModEditWindow
|
public partial class ModEditWindow
|
||||||
{
|
{
|
||||||
private const int MdlMaterialMaximum = 4;
|
private const int MdlMaterialMaximum = 4;
|
||||||
private const string MdlImportDocumentation = @"https://github.com/xivdev/Penumbra/wiki/Model-IO#user-content-9b49d296-23ab-410a-845b-a3be769b71ea";
|
|
||||||
private const string MdlExportDocumentation = @"https://github.com/xivdev/Penumbra/wiki/Model-IO#user-content-25968400-ebe5-4861-b610-cb1556db7ec4";
|
private const string MdlImportDocumentation =
|
||||||
|
@"https://github.com/xivdev/Penumbra/wiki/Model-IO#user-content-9b49d296-23ab-410a-845b-a3be769b71ea";
|
||||||
|
|
||||||
|
private const string MdlExportDocumentation =
|
||||||
|
@"https://github.com/xivdev/Penumbra/wiki/Model-IO#user-content-25968400-ebe5-4861-b610-cb1556db7ec4";
|
||||||
|
|
||||||
private readonly FileEditor<MdlTab> _modelTab;
|
private readonly FileEditor<MdlTab> _modelTab;
|
||||||
private readonly ModelManager _models;
|
private readonly ModelManager _models;
|
||||||
|
|
@ -25,31 +30,51 @@ public partial class ModEditWindow
|
||||||
private readonly List<TagButtons> _subMeshAttributeTagWidgets = [];
|
private readonly List<TagButtons> _subMeshAttributeTagWidgets = [];
|
||||||
private string _customPath = string.Empty;
|
private string _customPath = string.Empty;
|
||||||
private Utf8GamePath _customGamePath = Utf8GamePath.Empty;
|
private Utf8GamePath _customGamePath = Utf8GamePath.Empty;
|
||||||
|
private MdlFile _lastFile = null!;
|
||||||
|
private long[] _lodTriCount = [];
|
||||||
|
|
||||||
|
private void UpdateFile(MdlFile file, bool force)
|
||||||
|
{
|
||||||
|
if (file == _lastFile)
|
||||||
|
{
|
||||||
|
if (force)
|
||||||
|
UpdateMeshes();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateMeshes();
|
||||||
|
_lastFile = file;
|
||||||
|
_lodTriCount = Enumerable.Range(0, file.Lods.Length).Select(l => GetTriangleCountForLod(file, l)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
void UpdateMeshes()
|
||||||
|
{
|
||||||
|
var subMeshTotal = file.Meshes.Aggregate(0, (count, mesh) => count + mesh.SubMeshCount);
|
||||||
|
if (_subMeshAttributeTagWidgets.Count != subMeshTotal)
|
||||||
|
{
|
||||||
|
_subMeshAttributeTagWidgets.Clear();
|
||||||
|
_subMeshAttributeTagWidgets.AddRange(
|
||||||
|
Enumerable.Range(0, subMeshTotal).Select(_ => new TagButtons())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool DrawModelPanel(MdlTab tab, bool disabled)
|
private bool DrawModelPanel(MdlTab tab, bool disabled)
|
||||||
{
|
{
|
||||||
var file = tab.Mdl;
|
UpdateFile(tab.Mdl, tab.Dirty);
|
||||||
|
|
||||||
var subMeshTotal = file.Meshes.Aggregate(0, (count, mesh) => count + mesh.SubMeshCount);
|
|
||||||
if (_subMeshAttributeTagWidgets.Count != subMeshTotal)
|
|
||||||
{
|
|
||||||
_subMeshAttributeTagWidgets.Clear();
|
|
||||||
_subMeshAttributeTagWidgets.AddRange(
|
|
||||||
Enumerable.Range(0, subMeshTotal).Select(_ => new TagButtons())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawImportExport(tab, disabled);
|
DrawImportExport(tab, disabled);
|
||||||
|
|
||||||
var ret = tab.Dirty;
|
var ret = tab.Dirty;
|
||||||
|
|
||||||
ret |= DrawModelMaterialDetails(tab, disabled);
|
ret |= DrawModelMaterialDetails(tab, disabled);
|
||||||
|
|
||||||
if (ImGui.CollapsingHeader($"Meshes ({file.Meshes.Length})###meshes"))
|
if (ImGui.CollapsingHeader($"Meshes ({_lastFile.Meshes.Length})###meshes"))
|
||||||
for (var i = 0; i < file.LodCount; ++i)
|
for (var i = 0; i < _lastFile.LodCount; ++i)
|
||||||
ret |= DrawModelLodDetails(tab, i, disabled);
|
ret |= DrawModelLodDetails(tab, i, disabled);
|
||||||
|
|
||||||
ret |= DrawOtherModelDetails(file, disabled);
|
ret |= DrawOtherModelDetails(disabled);
|
||||||
|
|
||||||
return !disabled && ret;
|
return !disabled && ret;
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +110,7 @@ public partial class ModEditWindow
|
||||||
|
|
||||||
using (var frame = ImRaii.FramedGroup("Import", size, headerPreIcon: FontAwesomeIcon.FileImport))
|
using (var frame = ImRaii.FramedGroup("Import", size, headerPreIcon: FontAwesomeIcon.FileImport))
|
||||||
{
|
{
|
||||||
ImGui.Checkbox("Keep current materials", ref tab.ImportKeepMaterials);
|
ImGui.Checkbox("Keep current materials", ref tab.ImportKeepMaterials);
|
||||||
ImGui.Checkbox("Keep current attributes", ref tab.ImportKeepAttributes);
|
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.",
|
if (ImGuiUtil.DrawDisabledButton("Import from glTF", Vector2.Zero, "Imports a glTF file, overriding the content of this mdl.",
|
||||||
|
|
@ -111,10 +136,7 @@ public partial class ModEditWindow
|
||||||
|
|
||||||
if (tab.GamePaths == null)
|
if (tab.GamePaths == null)
|
||||||
{
|
{
|
||||||
if (tab.IoExceptions.Count == 0)
|
ImGui.TextUnformatted(tab.IoExceptions.Count == 0 ? "Resolving model game paths." : "Failed to resolve model game paths.");
|
||||||
ImGui.TextUnformatted("Resolving model game paths.");
|
|
||||||
else
|
|
||||||
ImGui.TextUnformatted("Failed to resolve model game paths.");
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -149,14 +171,15 @@ public partial class ModEditWindow
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
DrawDocumentationLink(MdlExportDocumentation);
|
DrawDocumentationLink(MdlExportDocumentation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawIoExceptions(MdlTab tab)
|
private static void DrawIoExceptions(MdlTab tab)
|
||||||
{
|
{
|
||||||
if (tab.IoExceptions.Count == 0)
|
if (tab.IoExceptions.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var size = new Vector2(ImGui.GetContentRegionAvail().X, 0);
|
var size = new Vector2(ImGui.GetContentRegionAvail().X, 0);
|
||||||
using var frame = ImRaii.FramedGroup("Exceptions", size, headerPreIcon: FontAwesomeIcon.TimesCircle, borderColor: Colors.RegexWarningBorder);
|
using var frame = ImRaii.FramedGroup("Exceptions", size, headerPreIcon: FontAwesomeIcon.TimesCircle,
|
||||||
|
borderColor: Colors.RegexWarningBorder);
|
||||||
|
|
||||||
var spaceAvail = ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X - 100;
|
var spaceAvail = ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X - 100;
|
||||||
foreach (var (exception, index) in tab.IoExceptions.WithIndex())
|
foreach (var (exception, index) in tab.IoExceptions.WithIndex())
|
||||||
|
|
@ -181,7 +204,7 @@ public partial class ModEditWindow
|
||||||
if (tab.IoWarnings.Count == 0)
|
if (tab.IoWarnings.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var size = new Vector2(ImGui.GetContentRegionAvail().X, 0);
|
var size = new Vector2(ImGui.GetContentRegionAvail().X, 0);
|
||||||
using var frame = ImRaii.FramedGroup("Warnings", size, headerPreIcon: FontAwesomeIcon.ExclamationCircle, borderColor: 0xFF40FFFF);
|
using var frame = ImRaii.FramedGroup("Warnings", size, headerPreIcon: FontAwesomeIcon.ExclamationCircle, borderColor: 0xFF40FFFF);
|
||||||
|
|
||||||
var spaceAvail = ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X - 100;
|
var spaceAvail = ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X - 100;
|
||||||
|
|
@ -445,7 +468,7 @@ public partial class ModEditWindow
|
||||||
if (attributes == null)
|
if (attributes == null)
|
||||||
{
|
{
|
||||||
attributes = ["invalid attribute data"];
|
attributes = ["invalid attribute data"];
|
||||||
disabled = true;
|
disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagIndex = widget.Draw(string.Empty, string.Empty, attributes,
|
var tagIndex = widget.Draw(string.Empty, string.Empty, attributes,
|
||||||
|
|
@ -460,7 +483,7 @@ public partial class ModEditWindow
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool DrawOtherModelDetails(MdlFile file, bool _)
|
private bool DrawOtherModelDetails(bool _)
|
||||||
{
|
{
|
||||||
using var header = ImRaii.CollapsingHeader("Further Content");
|
using var header = ImRaii.CollapsingHeader("Further Content");
|
||||||
if (!header)
|
if (!header)
|
||||||
|
|
@ -471,47 +494,47 @@ public partial class ModEditWindow
|
||||||
if (table)
|
if (table)
|
||||||
{
|
{
|
||||||
ImGuiUtil.DrawTableColumn("Version");
|
ImGuiUtil.DrawTableColumn("Version");
|
||||||
ImGuiUtil.DrawTableColumn(file.Version.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.Version.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Radius");
|
ImGuiUtil.DrawTableColumn("Radius");
|
||||||
ImGuiUtil.DrawTableColumn(file.Radius.ToString(CultureInfo.InvariantCulture));
|
ImGuiUtil.DrawTableColumn(_lastFile.Radius.ToString(CultureInfo.InvariantCulture));
|
||||||
ImGuiUtil.DrawTableColumn("Model Clip Out Distance");
|
ImGuiUtil.DrawTableColumn("Model Clip Out Distance");
|
||||||
ImGuiUtil.DrawTableColumn(file.ModelClipOutDistance.ToString(CultureInfo.InvariantCulture));
|
ImGuiUtil.DrawTableColumn(_lastFile.ModelClipOutDistance.ToString(CultureInfo.InvariantCulture));
|
||||||
ImGuiUtil.DrawTableColumn("Shadow Clip Out Distance");
|
ImGuiUtil.DrawTableColumn("Shadow Clip Out Distance");
|
||||||
ImGuiUtil.DrawTableColumn(file.ShadowClipOutDistance.ToString(CultureInfo.InvariantCulture));
|
ImGuiUtil.DrawTableColumn(_lastFile.ShadowClipOutDistance.ToString(CultureInfo.InvariantCulture));
|
||||||
ImGuiUtil.DrawTableColumn("LOD Count");
|
ImGuiUtil.DrawTableColumn("LOD Count");
|
||||||
ImGuiUtil.DrawTableColumn(file.LodCount.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.LodCount.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Enable Index Buffer Streaming");
|
ImGuiUtil.DrawTableColumn("Enable Index Buffer Streaming");
|
||||||
ImGuiUtil.DrawTableColumn(file.EnableIndexBufferStreaming.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.EnableIndexBufferStreaming.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Enable Edge Geometry");
|
ImGuiUtil.DrawTableColumn("Enable Edge Geometry");
|
||||||
ImGuiUtil.DrawTableColumn(file.EnableEdgeGeometry.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.EnableEdgeGeometry.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Flags 1");
|
ImGuiUtil.DrawTableColumn("Flags 1");
|
||||||
ImGuiUtil.DrawTableColumn(file.Flags1.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.Flags1.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Flags 2");
|
ImGuiUtil.DrawTableColumn("Flags 2");
|
||||||
ImGuiUtil.DrawTableColumn(file.Flags2.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.Flags2.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Vertex Declarations");
|
ImGuiUtil.DrawTableColumn("Vertex Declarations");
|
||||||
ImGuiUtil.DrawTableColumn(file.VertexDeclarations.Length.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.VertexDeclarations.Length.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Bone Bounding Boxes");
|
ImGuiUtil.DrawTableColumn("Bone Bounding Boxes");
|
||||||
ImGuiUtil.DrawTableColumn(file.BoneBoundingBoxes.Length.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.BoneBoundingBoxes.Length.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Bone Tables");
|
ImGuiUtil.DrawTableColumn("Bone Tables");
|
||||||
ImGuiUtil.DrawTableColumn(file.BoneTables.Length.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.BoneTables.Length.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Element IDs");
|
ImGuiUtil.DrawTableColumn("Element IDs");
|
||||||
ImGuiUtil.DrawTableColumn(file.ElementIds.Length.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.ElementIds.Length.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Extra LoDs");
|
ImGuiUtil.DrawTableColumn("Extra LoDs");
|
||||||
ImGuiUtil.DrawTableColumn(file.ExtraLods.Length.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.ExtraLods.Length.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Meshes");
|
ImGuiUtil.DrawTableColumn("Meshes");
|
||||||
ImGuiUtil.DrawTableColumn(file.Meshes.Length.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.Meshes.Length.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Shape Meshes");
|
ImGuiUtil.DrawTableColumn("Shape Meshes");
|
||||||
ImGuiUtil.DrawTableColumn(file.ShapeMeshes.Length.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.ShapeMeshes.Length.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("LoDs");
|
ImGuiUtil.DrawTableColumn("LoDs");
|
||||||
ImGuiUtil.DrawTableColumn(file.Lods.Length.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.Lods.Length.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Vertex Declarations");
|
ImGuiUtil.DrawTableColumn("Vertex Declarations");
|
||||||
ImGuiUtil.DrawTableColumn(file.VertexDeclarations.Length.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.VertexDeclarations.Length.ToString());
|
||||||
ImGuiUtil.DrawTableColumn("Stack Size");
|
ImGuiUtil.DrawTableColumn("Stack Size");
|
||||||
ImGuiUtil.DrawTableColumn(file.StackSize.ToString());
|
ImGuiUtil.DrawTableColumn(_lastFile.StackSize.ToString());
|
||||||
for (var lod = 0; lod < file.Lods.Length; lod++)
|
foreach (var (triCount, lod) in _lodTriCount.WithIndex())
|
||||||
{
|
{
|
||||||
ImGuiUtil.DrawTableColumn("LoD " + lod + " Triangle Count");
|
ImGuiUtil.DrawTableColumn($"LOD #{lod + 1} Triangle Count");
|
||||||
ImGuiUtil.DrawTableColumn(GetTriangleCountForLod(file, lod).ToString());
|
ImGuiUtil.DrawTableColumn(triCount.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -519,36 +542,36 @@ public partial class ModEditWindow
|
||||||
using (var materials = ImRaii.TreeNode("Materials", ImGuiTreeNodeFlags.DefaultOpen))
|
using (var materials = ImRaii.TreeNode("Materials", ImGuiTreeNodeFlags.DefaultOpen))
|
||||||
{
|
{
|
||||||
if (materials)
|
if (materials)
|
||||||
foreach (var material in file.Materials)
|
foreach (var material in _lastFile.Materials)
|
||||||
ImRaii.TreeNode(material, ImGuiTreeNodeFlags.Leaf).Dispose();
|
ImRaii.TreeNode(material, ImGuiTreeNodeFlags.Leaf).Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var attributes = ImRaii.TreeNode("Attributes", ImGuiTreeNodeFlags.DefaultOpen))
|
using (var attributes = ImRaii.TreeNode("Attributes", ImGuiTreeNodeFlags.DefaultOpen))
|
||||||
{
|
{
|
||||||
if (attributes)
|
if (attributes)
|
||||||
foreach (var attribute in file.Attributes)
|
foreach (var attribute in _lastFile.Attributes)
|
||||||
ImRaii.TreeNode(attribute, ImGuiTreeNodeFlags.Leaf).Dispose();
|
ImRaii.TreeNode(attribute, ImGuiTreeNodeFlags.Leaf).Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var bones = ImRaii.TreeNode("Bones", ImGuiTreeNodeFlags.DefaultOpen))
|
using (var bones = ImRaii.TreeNode("Bones", ImGuiTreeNodeFlags.DefaultOpen))
|
||||||
{
|
{
|
||||||
if (bones)
|
if (bones)
|
||||||
foreach (var bone in file.Bones)
|
foreach (var bone in _lastFile.Bones)
|
||||||
ImRaii.TreeNode(bone, ImGuiTreeNodeFlags.Leaf).Dispose();
|
ImRaii.TreeNode(bone, ImGuiTreeNodeFlags.Leaf).Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var shapes = ImRaii.TreeNode("Shapes", ImGuiTreeNodeFlags.DefaultOpen))
|
using (var shapes = ImRaii.TreeNode("Shapes", ImGuiTreeNodeFlags.DefaultOpen))
|
||||||
{
|
{
|
||||||
if (shapes)
|
if (shapes)
|
||||||
foreach (var shape in file.Shapes)
|
foreach (var shape in _lastFile.Shapes)
|
||||||
ImRaii.TreeNode(shape.ShapeName, ImGuiTreeNodeFlags.Leaf).Dispose();
|
ImRaii.TreeNode(shape.ShapeName, ImGuiTreeNodeFlags.Leaf).Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.RemainingData.Length > 0)
|
if (_lastFile.RemainingData.Length > 0)
|
||||||
{
|
{
|
||||||
using var t = ImRaii.TreeNode($"Additional Data (Size: {file.RemainingData.Length})###AdditionalData");
|
using var t = ImRaii.TreeNode($"Additional Data (Size: {_lastFile.RemainingData.Length})###AdditionalData");
|
||||||
if (t)
|
if (t)
|
||||||
ImGuiUtil.TextWrapped(string.Join(' ', file.RemainingData.Select(c => $"{c:X2}")));
|
ImGuiUtil.TextWrapped(string.Join(' ', _lastFile.RemainingData.Select(c => $"{c:X2}")));
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -562,7 +585,7 @@ public partial class ModEditWindow
|
||||||
|
|
||||||
private static long GetTriangleCountForLod(MdlFile model, int lod)
|
private static long GetTriangleCountForLod(MdlFile model, int lod)
|
||||||
{
|
{
|
||||||
var vertSum = 0u;
|
var vertSum = 0u;
|
||||||
var meshIndex = model.Lods[lod].MeshIndex;
|
var meshIndex = model.Lods[lod].MeshIndex;
|
||||||
var meshCount = model.Lods[lod].MeshCount;
|
var meshCount = model.Lods[lod].MeshCount;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue