mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
Clean up model import UI/wiring
This commit is contained in:
parent
1a88cefd52
commit
b62bc44564
3 changed files with 72 additions and 31 deletions
|
|
@ -10,7 +10,7 @@ using SharpGLTF.Schema2;
|
||||||
|
|
||||||
namespace Penumbra.Import.Models;
|
namespace Penumbra.Import.Models;
|
||||||
|
|
||||||
public sealed class ModelManager(IFramework framework, GamePathParser _parser) : SingleTaskQueue, IDisposable
|
public sealed class ModelManager(IFramework framework, GamePathParser parser) : SingleTaskQueue, IDisposable
|
||||||
{
|
{
|
||||||
private readonly IFramework _framework = framework;
|
private readonly IFramework _framework = framework;
|
||||||
|
|
||||||
|
|
@ -29,17 +29,17 @@ public sealed class ModelManager(IFramework framework, GamePathParser _parser) :
|
||||||
public Task ExportToGltf(MdlFile mdl, SklbFile? sklb, string outputPath)
|
public Task ExportToGltf(MdlFile mdl, SklbFile? sklb, string outputPath)
|
||||||
=> Enqueue(new ExportToGltfAction(this, mdl, sklb, outputPath));
|
=> Enqueue(new ExportToGltfAction(this, mdl, sklb, outputPath));
|
||||||
|
|
||||||
public Task<MdlFile> ImportGltf()
|
public Task<MdlFile?> ImportGltf(string inputPath)
|
||||||
{
|
{
|
||||||
var action = new ImportGltfAction();
|
var action = new ImportGltfAction(inputPath);
|
||||||
return Enqueue(action).ContinueWith(_ => action.Out!);
|
return Enqueue(action).ContinueWith(_ => action.Out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Try to find the .sklb path for a .mdl file. </summary>
|
/// <summary> Try to find the .sklb path for a .mdl file. </summary>
|
||||||
/// <param name="mdlPath"> .mdl file to look up the skeleton for. </param>
|
/// <param name="mdlPath"> .mdl file to look up the skeleton for. </param>
|
||||||
public string? ResolveSklbForMdl(string mdlPath)
|
public string? ResolveSklbForMdl(string mdlPath)
|
||||||
{
|
{
|
||||||
var info = _parser.GetFileInfo(mdlPath);
|
var info = parser.GetFileInfo(mdlPath);
|
||||||
if (info.FileType is not FileType.Model)
|
if (info.FileType is not FileType.Model)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
|
@ -126,18 +126,13 @@ public sealed class ModelManager(IFramework framework, GamePathParser _parser) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private partial class ImportGltfAction : IAction
|
private partial class ImportGltfAction(string inputPath) : IAction
|
||||||
{
|
{
|
||||||
public MdlFile? Out;
|
public MdlFile? Out;
|
||||||
|
|
||||||
public ImportGltfAction()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Execute(CancellationToken cancel)
|
public void Execute(CancellationToken cancel)
|
||||||
{
|
{
|
||||||
var model = ModelRoot.Load("C:\\Users\\ackwell\\blender\\gltf-tests\\c0201e6180_top.gltf");
|
var model = ModelRoot.Load(inputPath);
|
||||||
|
|
||||||
Out = ModelImporter.Import(model);
|
Out = ModelImporter.Import(model);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@ public partial class ModEditWindow
|
||||||
public List<Utf8GamePath>? GamePaths { get; private set; }
|
public List<Utf8GamePath>? GamePaths { get; private set; }
|
||||||
public int GamePathIndex;
|
public int GamePathIndex;
|
||||||
|
|
||||||
public bool PendingIo { get; private set; }
|
private bool _dirty;
|
||||||
public string? IoException { get; private set; }
|
public bool PendingIo { get; private set; }
|
||||||
|
public string? IoException { get; private set; }
|
||||||
|
|
||||||
public MdlTab(ModEditWindow edit, byte[] bytes, string path, IMod? mod)
|
public MdlTab(ModEditWindow edit, byte[] bytes, string path, IMod? mod)
|
||||||
{
|
{
|
||||||
|
|
@ -46,6 +47,16 @@ public partial class ModEditWindow
|
||||||
public byte[] Write()
|
public byte[] Write()
|
||||||
=> Mdl.Write();
|
=> Mdl.Write();
|
||||||
|
|
||||||
|
public bool Dirty
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var dirty = _dirty;
|
||||||
|
_dirty = false;
|
||||||
|
return dirty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Find the list of game paths that may correspond to this model. </summary>
|
/// <summary> Find the list of game paths that may correspond to this model. </summary>
|
||||||
/// <param name="path"> Resolved path to a .mdl. </param>
|
/// <param name="path"> Resolved path to a .mdl. </param>
|
||||||
/// <param name="mod"> Mod within which the .mdl is resolved. </param>
|
/// <param name="mod"> Mod within which the .mdl is resolved. </param>
|
||||||
|
|
@ -77,14 +88,28 @@ public partial class ModEditWindow
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Import()
|
/// <summary> Import a model from an interchange format. </summary>
|
||||||
|
/// <param name="inputPath"> Disk path to load model data from. </param>
|
||||||
|
public void Import(string inputPath)
|
||||||
{
|
{
|
||||||
// TODO: this needs to be fleshed out a bunch.
|
PendingIo = true;
|
||||||
_edit._models.ImportGltf().ContinueWith(v => Initialize(v.Result ?? Mdl));
|
_edit._models.ImportGltf(inputPath)
|
||||||
|
.ContinueWith(task =>
|
||||||
|
{
|
||||||
|
IoException = task.Exception?.ToString();
|
||||||
|
PendingIo = false;
|
||||||
|
|
||||||
|
if (task.IsCompletedSuccessfully && task.Result != null)
|
||||||
|
{
|
||||||
|
Initialize(task.Result);
|
||||||
|
_dirty = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Export model to an interchange format. </summary>
|
/// <summary> Export model to an interchange format. </summary>
|
||||||
/// <param name="outputPath"> Disk path to save the resulting file to. </param>
|
/// <param name="outputPath"> Disk path to save the resulting file to. </param>
|
||||||
|
/// <param name="mdlPath"> Game path to consider as the canonical .mdl path during export, used for resolution of other files. </param>
|
||||||
public void Export(string outputPath, Utf8GamePath mdlPath)
|
public void Export(string outputPath, Utf8GamePath mdlPath)
|
||||||
{
|
{
|
||||||
SklbFile? sklb = null;
|
SklbFile? sklb = null;
|
||||||
|
|
|
||||||
|
|
@ -35,15 +35,9 @@ public partial class ModEditWindow
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawExport(tab, disabled);
|
DrawImportExport(tab, disabled);
|
||||||
|
|
||||||
var ret = false;
|
var ret = tab.Dirty;
|
||||||
|
|
||||||
if (ImGui.Button("import test"))
|
|
||||||
{
|
|
||||||
tab.Import();
|
|
||||||
ret |= true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret |= DrawModelMaterialDetails(tab, disabled);
|
ret |= DrawModelMaterialDetails(tab, disabled);
|
||||||
|
|
||||||
|
|
@ -56,11 +50,41 @@ public partial class ModEditWindow
|
||||||
return !disabled && ret;
|
return !disabled && ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawExport(MdlTab tab, bool disabled)
|
private void DrawImportExport(MdlTab tab, bool disabled)
|
||||||
{
|
{
|
||||||
if (!ImGui.CollapsingHeader("Export"))
|
if (!ImGui.CollapsingHeader("Import / Export"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var windowWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X;
|
||||||
|
var childWidth = (windowWidth - ImGui.GetStyle().ItemSpacing.X * 3) / 2;
|
||||||
|
var childSize = new Vector2(childWidth, 0);
|
||||||
|
|
||||||
|
DrawImport(tab, childSize, disabled);
|
||||||
|
ImGui.SameLine();
|
||||||
|
DrawExport(tab, childSize, disabled);
|
||||||
|
|
||||||
|
if (tab.IoException != null)
|
||||||
|
ImGuiUtil.TextWrapped(tab.IoException);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawImport(MdlTab tab, Vector2 size, bool disabled)
|
||||||
|
{
|
||||||
|
using var frame = ImRaii.FramedGroup("Import", size);
|
||||||
|
|
||||||
|
if (ImGuiUtil.DrawDisabledButton("Import from glTF", Vector2.Zero, "Imports a glTF file, overriding the content of this mdl.", tab.PendingIo))
|
||||||
|
{
|
||||||
|
_fileDialog.OpenFilePicker("Load model from glTF.", "glTF{.gltf,.glb}", (success, paths) =>
|
||||||
|
{
|
||||||
|
if (success && paths.Count > 0)
|
||||||
|
tab.Import(paths[0]);
|
||||||
|
}, 1, _mod!.ModPath.FullName, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawExport(MdlTab tab, Vector2 size, bool disabled)
|
||||||
|
{
|
||||||
|
using var frame = ImRaii.FramedGroup("Export", size);
|
||||||
|
|
||||||
if (tab.GamePaths == null)
|
if (tab.GamePaths == null)
|
||||||
{
|
{
|
||||||
if (tab.IoException == null)
|
if (tab.IoException == null)
|
||||||
|
|
@ -89,9 +113,6 @@ public partial class ModEditWindow
|
||||||
_mod!.ModPath.FullName,
|
_mod!.ModPath.FullName,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
if (tab.IoException != null)
|
|
||||||
ImGuiUtil.TextWrapped(tab.IoException);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawGamePathCombo(MdlTab tab)
|
private void DrawGamePathCombo(MdlTab tab)
|
||||||
|
|
@ -116,7 +137,7 @@ public partial class ModEditWindow
|
||||||
const string label = "Game Path";
|
const string label = "Game Path";
|
||||||
var preview = tab.GamePaths![tab.GamePathIndex].ToString();
|
var preview = tab.GamePaths![tab.GamePathIndex].ToString();
|
||||||
var labelWidth = ImGui.CalcTextSize(label).X + ImGui.GetStyle().ItemInnerSpacing.X;
|
var labelWidth = ImGui.CalcTextSize(label).X + ImGui.GetStyle().ItemInnerSpacing.X;
|
||||||
var buttonWidth = ImGui.GetContentRegionAvail().X - labelWidth;
|
var buttonWidth = ImGui.GetContentRegionAvail().X - labelWidth - ImGui.GetStyle().ItemSpacing.X;
|
||||||
if (tab.GamePaths!.Count == 1)
|
if (tab.GamePaths!.Count == 1)
|
||||||
{
|
{
|
||||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f));
|
using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue