mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
Merge branch 'master' into mdl-io-warnings
# Conflicts: # Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs
This commit is contained in:
commit
fff9fb00f8
8 changed files with 73 additions and 21 deletions
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
|||
Subproject commit 9259090121b26f097948e7bbd83b32708ea0410d
|
||||
Subproject commit c6f101bbef976b74eb651523445563dd81fafbaf
|
||||
|
|
@ -156,9 +156,14 @@ public class CollectionEditor
|
|||
// Either copy the unused source settings directly if they are not inheriting,
|
||||
// or remove any unused settings for the target if they are inheriting.
|
||||
if (savedSettings != null)
|
||||
{
|
||||
((Dictionary<string, ModSettings.SavedSettings>)collection.UnusedSettings)[targetName] = savedSettings.Value;
|
||||
else
|
||||
((Dictionary<string, ModSettings.SavedSettings>)collection.UnusedSettings).Remove(targetName);
|
||||
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
|
||||
}
|
||||
else if (((Dictionary<string, ModSettings.SavedSettings>)collection.UnusedSettings).Remove(targetName))
|
||||
{
|
||||
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -135,7 +135,6 @@ public partial class ModelImporter(ModelRoot model, IoNotifier notifier)
|
|||
var subMeshOffset = _subMeshes.Count;
|
||||
var vertexOffset = _vertexBuffer.Count;
|
||||
var indexOffset = _indices.Count;
|
||||
var shapeValueOffset = _shapeValues.Count;
|
||||
|
||||
var mesh = MeshImporter.Import(subMeshNodes, notifier.WithContext($"Mesh {index}"));
|
||||
var meshStartIndex = (uint)(mesh.MeshStruct.StartIndex + indexOffset);
|
||||
|
|
@ -185,7 +184,7 @@ public partial class ModelImporter(ModelRoot model, IoNotifier notifier)
|
|||
shapeMeshes.Add(meshShapeKey.ShapeMesh with
|
||||
{
|
||||
MeshIndexOffset = meshStartIndex,
|
||||
ShapeValueOffset = (uint)shapeValueOffset,
|
||||
ShapeValueOffset = (uint)_shapeValues.Count,
|
||||
});
|
||||
|
||||
_shapeValues.AddRange(meshShapeKey.ShapeValues);
|
||||
|
|
|
|||
|
|
@ -235,7 +235,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)
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ public sealed unsafe class CharacterBaseDestructor : EventWrapperPtr<CharacterBa
|
|||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="PathResolving.DrawObjectState"/>
|
||||
/// <seealso cref="PathResolving.DrawObjectState.OnCharacterBaseDestructor"/>
|
||||
DrawObjectState = 0,
|
||||
|
||||
/// <seealso cref="ModEditWindow.MtrlTab"/>
|
||||
/// <seealso cref="ModEditWindow.MtrlTab.UnbindFromDrawObjectMaterialInstances"/>
|
||||
MtrlTab = -1000,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.Interop.Hooks;
|
||||
using Object = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.Object;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.Hooks.Objects;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,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;
|
||||
|
|
@ -296,15 +296,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)
|
||||
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()
|
||||
).ToArray();
|
||||
: 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>
|
||||
|
|
@ -314,6 +320,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);
|
||||
|
|
@ -331,6 +339,9 @@ public partial class ModEditWindow
|
|||
|
||||
foreach (var (attributes, subMeshIndex) in _attributes.WithIndex())
|
||||
{
|
||||
if (attributes == null)
|
||||
continue;
|
||||
|
||||
var mask = 0u;
|
||||
|
||||
foreach (var attribute in attributes)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Dalamud.Interface;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Custom;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData;
|
||||
|
|
@ -14,6 +15,8 @@ namespace Penumbra.UI.AdvancedWindow;
|
|||
public partial class ModEditWindow
|
||||
{
|
||||
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 readonly FileEditor<MdlTab> _modelTab;
|
||||
private readonly ModelManager _models;
|
||||
|
|
@ -68,6 +71,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 =>
|
||||
{
|
||||
|
|
@ -90,6 +95,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))
|
||||
|
|
@ -98,6 +106,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)
|
||||
|
|
@ -122,6 +131,7 @@ public partial class ModEditWindow
|
|||
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()),
|
||||
|
|
@ -135,6 +145,9 @@ public partial class ModEditWindow
|
|||
_mod!.ModPath.FullName,
|
||||
false
|
||||
);
|
||||
|
||||
ImGui.SameLine();
|
||||
DrawDocumentationLink(MdlExportDocumentation);
|
||||
}
|
||||
|
||||
private static void DrawIoExceptions(MdlTab tab)
|
||||
|
|
@ -249,6 +262,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"))
|
||||
|
|
@ -370,7 +401,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;
|
||||
}
|
||||
|
|
@ -398,7 +429,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);
|
||||
|
||||
|
|
@ -413,6 +444,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)
|
||||
|
|
@ -427,7 +464,8 @@ public partial class ModEditWindow
|
|||
|
||||
private static bool DrawOtherModelDetails(MdlFile file, bool _)
|
||||
{
|
||||
if (!ImGui.CollapsingHeader("Further Content"))
|
||||
using var header = ImRaii.CollapsingHeader("Further Content");
|
||||
if (!header)
|
||||
return false;
|
||||
|
||||
using (var table = ImRaii.Table("##data", 2, ImGuiTableFlags.SizingFixedFit))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue