Merge branch 'mdl-io-triage-2'

This commit is contained in:
Ottermandias 2024-01-20 13:17:23 +01:00
commit 1e33a8bb22
5 changed files with 63 additions and 17 deletions

@ -1 +1 @@
Subproject commit 9259090121b26f097948e7bbd83b32708ea0410d
Subproject commit c6f101bbef976b74eb651523445563dd81fafbaf

View file

@ -134,7 +134,6 @@ public partial class ModelImporter(ModelRoot model)
var subMeshOffset = _subMeshes.Count;
var vertexOffset = _vertexBuffer.Count;
var indexOffset = _indices.Count;
var shapeValueOffset = _shapeValues.Count;
var mesh = MeshImporter.Import(subMeshNodes);
var meshStartIndex = (uint)(mesh.MeshStruct.StartIndex + indexOffset);
@ -184,7 +183,7 @@ public partial class ModelImporter(ModelRoot model)
shapeMeshes.Add(meshShapeKey.ShapeMesh with
{
MeshIndexOffset = meshStartIndex,
ShapeValueOffset = (uint)shapeValueOffset,
ShapeValueOffset = (uint)_shapeValues.Count,
});
_shapeValues.AddRange(meshShapeKey.ShapeValues);

View file

@ -234,7 +234,7 @@ public class SubMeshImporter
foreach (var (modifiedVertices, morphIndex) in morphModifiedVertices.WithIndex())
{
// Each for a given mesh, each shape key contains a list of shape value mappings.
// For a given mesh, each shape key contains a list of shape value mappings.
var shapeValues = new List<MdlStructs.ShapeValueStruct>();
foreach (var vertexIndex in modifiedVertices)

View file

@ -14,7 +14,7 @@ public partial class ModEditWindow
private readonly ModEditWindow _edit;
public MdlFile Mdl { get; private set; }
private List<string>[] _attributes;
private List<string>?[] _attributes;
public bool ImportKeepMaterials;
public bool ImportKeepAttributes;
@ -290,15 +290,21 @@ public partial class ModEditWindow
}
/// <summary> Create a list of attributes per sub mesh. </summary>
private static List<string>[] CreateAttributes(MdlFile mdl)
=> mdl.SubMeshes.Select(s => Enumerable.Range(0, 32)
.Where(idx => ((s.AttributeIndexMask >> idx) & 1) == 1)
.Select(idx => mdl.Attributes[idx])
.ToList()
).ToArray();
private static List<string>?[] CreateAttributes(MdlFile mdl)
=> mdl.SubMeshes.Select(s =>
{
var maxAttribute = 31 - BitOperations.LeadingZeroCount(s.AttributeIndexMask);
// TODO: Research what results in this - it seems to primarily be reproducible on bgparts, is it garbage data, or an alternative usage of the value?
return maxAttribute < mdl.Attributes.Length
? Enumerable.Range(0, 32)
.Where(idx => ((s.AttributeIndexMask >> idx) & 1) == 1)
.Select(idx => mdl.Attributes[idx])
.ToList()
: null;
}).ToArray();
/// <summary> Obtain the attributes associated with a sub mesh by its index. </summary>
public IReadOnlyList<string> GetSubMeshAttributes(int subMeshIndex)
public IReadOnlyList<string>? GetSubMeshAttributes(int subMeshIndex)
=> _attributes[subMeshIndex];
/// <summary> Remove or add attributes from a sub mesh by its index. </summary>
@ -308,6 +314,8 @@ public partial class ModEditWindow
public void UpdateSubMeshAttribute(int subMeshIndex, string? old, string? @new)
{
var attributes = _attributes[subMeshIndex];
if (attributes == null)
return;
if (old != null)
attributes.Remove(old);
@ -325,6 +333,9 @@ public partial class ModEditWindow
foreach (var (attributes, subMeshIndex) in _attributes.WithIndex())
{
if (attributes == null)
continue;
var mask = 0u;
foreach (var attribute in attributes)

View file

@ -1,6 +1,7 @@
using Dalamud.Interface;
using ImGuiNET;
using OtterGui;
using OtterGui.Custom;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.GameData;
@ -13,7 +14,9 @@ namespace Penumbra.UI.AdvancedWindow;
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#import";
private const string MdlExportDocumentation = @"https://github.com/xivdev/Penumbra/wiki/Model-IO#export";
private readonly FileEditor<MdlTab> _modelTab;
private readonly ModelManager _models;
@ -67,6 +70,8 @@ public partial class ModEditWindow
private void DrawImport(MdlTab tab, Vector2 size, bool _1)
{
using var id = ImRaii.PushId("import");
_dragDropManager.CreateImGuiSource("ModelDragDrop",
m => m.Extensions.Any(e => ValidModelExtensions.Contains(e.ToLowerInvariant())), m =>
{
@ -89,6 +94,9 @@ public partial class ModEditWindow
if (success && paths.Count > 0)
tab.Import(paths[0]);
}, 1, _mod!.ModPath.FullName, false);
ImGui.SameLine();
DrawDocumentationLink(MdlImportDocumentation);
}
if (_dragDropManager.CreateImGuiTarget("ModelDragDrop", out var files, out _) && GetFirstModel(files, out var importFile))
@ -97,6 +105,7 @@ public partial class ModEditWindow
private void DrawExport(MdlTab tab, Vector2 size, bool _)
{
using var id = ImRaii.PushId("export");
using var frame = ImRaii.FramedGroup("Export", size, headerPreIcon: FontAwesomeIcon.FileExport);
if (tab.GamePaths == null)
@ -110,10 +119,10 @@ public partial class ModEditWindow
}
DrawGamePathCombo(tab);
var gamePath = tab.GamePathIndex >= 0 && tab.GamePathIndex < tab.GamePaths.Count
? tab.GamePaths[tab.GamePathIndex]
: _customGamePath;
if (ImGuiUtil.DrawDisabledButton("Export to glTF", Vector2.Zero, "Exports this mdl file to glTF, for use in 3D authoring applications.",
tab.PendingIo || gamePath.IsEmpty))
_fileDialog.OpenSavePicker("Save model as glTF.", ".gltf", Path.GetFileNameWithoutExtension(gamePath.Filename().ToString()),
@ -127,6 +136,9 @@ public partial class ModEditWindow
_mod!.ModPath.FullName,
false
);
ImGui.SameLine();
DrawDocumentationLink(MdlExportDocumentation);
}
private static void DrawIoExceptions(MdlTab tab)
@ -205,6 +217,24 @@ public partial class ModEditWindow
ImGuiUtil.HoverTooltip("Right-Click to copy to clipboard.", ImGuiHoveredFlags.AllowWhenDisabled);
}
private void DrawDocumentationLink(string address)
{
const string text = "Documentation →";
var framePadding = ImGui.GetStyle().FramePadding;
var width = ImGui.CalcTextSize(text).X + framePadding.X * 2;
// Draw the link button. We set the background colour to transparent to mimic the look of a link.
using var color = ImRaii.PushColor(ImGuiCol.Button, 0x00000000);
CustomGui.DrawLinkButton(Penumbra.Messager, text, address, width);
// Draw an underline for the text.
var lineStart = ImGui.GetItemRectMax();
lineStart -= framePadding;
var lineEnd = lineStart with { X = ImGui.GetItemRectMin().X + framePadding.X };
ImGui.GetWindowDrawList().AddLine(lineStart, lineEnd, 0xFFFFFFFF);
}
private bool DrawModelMaterialDetails(MdlTab tab, bool disabled)
{
if (!ImGui.CollapsingHeader("Materials"))
@ -326,7 +356,7 @@ public partial class ModEditWindow
// Sub meshes
for (var subMeshOffset = 0; subMeshOffset < mesh.SubMeshCount; subMeshOffset++)
ret |= DrawSubMeshAttributes(tab, meshIndex, disabled, subMeshOffset);
ret |= DrawSubMeshAttributes(tab, meshIndex, subMeshOffset, disabled);
return ret;
}
@ -354,7 +384,7 @@ public partial class ModEditWindow
return ret;
}
private bool DrawSubMeshAttributes(MdlTab tab, int meshIndex, bool disabled, int subMeshOffset)
private bool DrawSubMeshAttributes(MdlTab tab, int meshIndex, int subMeshOffset, bool disabled)
{
using var _ = ImRaii.PushId(subMeshOffset);
@ -369,6 +399,12 @@ public partial class ModEditWindow
var widget = _subMeshAttributeTagWidgets[subMeshIndex];
var attributes = tab.GetSubMeshAttributes(subMeshIndex);
if (attributes == null)
{
attributes = ["invalid attribute data"];
disabled = true;
}
var tagIndex = widget.Draw(string.Empty, string.Empty, attributes,
out var editedAttribute, !disabled);
if (tagIndex < 0)
@ -383,7 +419,7 @@ public partial class ModEditWindow
private static bool DrawOtherModelDetails(MdlFile file, bool _)
{
if (!ImGui.CollapsingHeader("Further Content"))
if (!ImRaii.CollapsingHeader("Further Content"))
return false;
using (var table = ImRaii.Table("##data", 2, ImGuiTableFlags.SizingFixedFit))