mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-14 12:44:19 +01:00
Minimal cleanup.
This commit is contained in:
parent
3f8ac1e8d0
commit
2f6905cf35
4 changed files with 30 additions and 32 deletions
|
|
@ -1,6 +1,5 @@
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.GameData.Enums;
|
|
||||||
|
|
||||||
namespace Penumbra.Communication;
|
namespace Penumbra.Communication;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,12 @@ public class ModelExporter
|
||||||
var names = new Dictionary<string, int>();
|
var names = new Dictionary<string, int>();
|
||||||
var joints = new List<NodeBuilder>();
|
var joints = new List<NodeBuilder>();
|
||||||
|
|
||||||
// Flatten out the bones across all the recieved skeletons, but retain a reference to the parent skeleton for lookups.
|
// Flatten out the bones across all the received skeletons, but retain a reference to the parent skeleton for lookups.
|
||||||
var iterator = skeletons.SelectMany(skeleton => skeleton.Bones.Select(bone => (skeleton, bone)));
|
var iterator = skeletons.SelectMany(skeleton => skeleton.Bones.Select(bone => (skeleton, bone)));
|
||||||
foreach (var (skeleton, bone) in iterator)
|
foreach (var (skeleton, bone) in iterator)
|
||||||
{
|
{
|
||||||
if (names.ContainsKey(bone.Name)) continue;
|
if (names.ContainsKey(bone.Name))
|
||||||
|
continue;
|
||||||
|
|
||||||
var node = new NodeBuilder(bone.Name);
|
var node = new NodeBuilder(bone.Name);
|
||||||
names[bone.Name] = joints.Count;
|
names[bone.Name] = joints.Count;
|
||||||
|
|
|
||||||
|
|
@ -29,16 +29,17 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
|
||||||
_tasks.Clear();
|
_tasks.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task ExportToGltf(MdlFile mdl, IEnumerable<SklbFile>? sklbs, string outputPath)
|
public Task ExportToGltf(MdlFile mdl, IEnumerable<SklbFile> sklbs, string outputPath)
|
||||||
=> Enqueue(new ExportToGltfAction(this, mdl, sklbs, outputPath));
|
=> Enqueue(new ExportToGltfAction(this, mdl, sklbs, outputPath));
|
||||||
|
|
||||||
/// <summary> Try to find the .sklb paths for a .mdl file. </summary>
|
/// <summary> Try to find the .sklb paths for a .mdl file. </summary>
|
||||||
/// <param name="mdlPath"> .mdl file to look up the skeletons for. </param>
|
/// <param name="mdlPath"> .mdl file to look up the skeletons for. </param>
|
||||||
public string[]? ResolveSklbsForMdl(string mdlPath, EstManipulation[] estManipulations)
|
/// <param name="estManipulations"> Modified extra skeleton template parameters. </param>
|
||||||
|
public string[] ResolveSklbsForMdl(string mdlPath, EstManipulation[] estManipulations)
|
||||||
{
|
{
|
||||||
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 [];
|
||||||
|
|
||||||
var baseSkeleton = GamePaths.Skeleton.Sklb.Path(info.GenderRace, "base", 1);
|
var baseSkeleton = GamePaths.Skeleton.Sklb.Path(info.GenderRace, "base", 1);
|
||||||
|
|
||||||
|
|
@ -59,7 +60,7 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
|
||||||
ObjectType.DemiHuman => [GamePaths.DemiHuman.Sklb.Path(info.PrimaryId)],
|
ObjectType.DemiHuman => [GamePaths.DemiHuman.Sklb.Path(info.PrimaryId)],
|
||||||
ObjectType.Monster => [GamePaths.Monster.Sklb.Path(info.PrimaryId)],
|
ObjectType.Monster => [GamePaths.Monster.Sklb.Path(info.PrimaryId)],
|
||||||
ObjectType.Weapon => [GamePaths.Weapon.Sklb.Path(info.PrimaryId)],
|
ObjectType.Weapon => [GamePaths.Weapon.Sklb.Path(info.PrimaryId)],
|
||||||
_ => null,
|
_ => [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,31 +114,38 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ExportToGltfAction(ModelManager manager, MdlFile mdl, IEnumerable<SklbFile>? sklbs, string outputPath)
|
private class ExportToGltfAction(ModelManager manager, MdlFile mdl, IEnumerable<SklbFile> sklbs, string outputPath)
|
||||||
: IAction
|
: IAction
|
||||||
{
|
{
|
||||||
public void Execute(CancellationToken cancel)
|
public void Execute(CancellationToken cancel)
|
||||||
{
|
{
|
||||||
Penumbra.Log.Debug("Reading skeletons.");
|
Penumbra.Log.Debug($"[GLTF Export] Exporting model to {outputPath}...");
|
||||||
|
Penumbra.Log.Debug("[GLTF Export] Reading skeletons...");
|
||||||
var xivSkeletons = BuildSkeletons(cancel);
|
var xivSkeletons = BuildSkeletons(cancel);
|
||||||
|
|
||||||
Penumbra.Log.Debug("Converting model.");
|
Penumbra.Log.Debug("[GLTF Export] Converting model...");
|
||||||
var model = ModelExporter.Export(mdl, xivSkeletons);
|
var model = ModelExporter.Export(mdl, xivSkeletons);
|
||||||
|
|
||||||
Penumbra.Log.Debug("Building scene.");
|
Penumbra.Log.Debug("[GLTF Export] Building scene...");
|
||||||
var scene = new SceneBuilder();
|
var scene = new SceneBuilder();
|
||||||
model.AddToScene(scene);
|
model.AddToScene(scene);
|
||||||
|
|
||||||
Penumbra.Log.Debug("Saving.");
|
Penumbra.Log.Debug("[GLTF Export] Saving...");
|
||||||
var gltfModel = scene.ToGltf2();
|
var gltfModel = scene.ToGltf2();
|
||||||
gltfModel.SaveGLTF(outputPath);
|
gltfModel.SaveGLTF(outputPath);
|
||||||
|
Penumbra.Log.Debug("[GLTF Export] Done.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Attempt to read out the pertinent information from a .sklb. </summary>
|
/// <summary> Attempt to read out the pertinent information from a .sklb. </summary>
|
||||||
private IEnumerable<XivSkeleton>? BuildSkeletons(CancellationToken cancel)
|
private IEnumerable<XivSkeleton> BuildSkeletons(CancellationToken cancel)
|
||||||
{
|
{
|
||||||
if (sklbs == null)
|
var havokTasks = sklbs
|
||||||
return null;
|
.WithIndex()
|
||||||
|
.Select(CreateHavokTask)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
// Result waits automatically.
|
||||||
|
return havokTasks.Select(task => SkeletonConverter.FromXml(task.Result));
|
||||||
|
|
||||||
// The havok methods we're relying on for this conversion are a bit
|
// The havok methods we're relying on for this conversion are a bit
|
||||||
// finicky at the best of times, and can outright cause a CTD if they
|
// finicky at the best of times, and can outright cause a CTD if they
|
||||||
|
|
@ -146,16 +154,7 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
|
||||||
Task<string> CreateHavokTask((SklbFile Sklb, int Index) pair) =>
|
Task<string> CreateHavokTask((SklbFile Sklb, int Index) pair) =>
|
||||||
manager._framework.RunOnTick(
|
manager._framework.RunOnTick(
|
||||||
() => HavokConverter.HkxToXml(pair.Sklb.Skeleton),
|
() => HavokConverter.HkxToXml(pair.Sklb.Skeleton),
|
||||||
delayTicks: pair.Index
|
delayTicks: pair.Index, cancellationToken: cancel);
|
||||||
);
|
|
||||||
|
|
||||||
var havokTasks = sklbs
|
|
||||||
.WithIndex()
|
|
||||||
.Select(CreateHavokTask)
|
|
||||||
.ToArray();
|
|
||||||
Task.WaitAll(havokTasks, cancel);
|
|
||||||
|
|
||||||
return havokTasks.Select(task => SkeletonConverter.FromXml(task.Result));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Equals(IAction? other)
|
public bool Equals(IAction? other)
|
||||||
|
|
|
||||||
|
|
@ -86,31 +86,30 @@ public partial class ModEditWindow
|
||||||
.Where(subMod => subMod != option)
|
.Where(subMod => subMod != option)
|
||||||
.Prepend(option)
|
.Prepend(option)
|
||||||
.SelectMany(subMod => subMod.Manipulations)
|
.SelectMany(subMod => subMod.Manipulations)
|
||||||
.Where(manipulation => manipulation.ManipulationType == MetaManipulation.Type.Est)
|
.Where(manipulation => manipulation.ManipulationType is MetaManipulation.Type.Est)
|
||||||
.Select(manipulation => manipulation.Est)
|
.Select(manipulation => manipulation.Est)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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"> The game path of the model. </param>
|
||||||
public void Export(string outputPath, Utf8GamePath mdlPath)
|
public void Export(string outputPath, Utf8GamePath mdlPath)
|
||||||
{
|
{
|
||||||
IEnumerable<SklbFile>? sklbs = null;
|
IEnumerable<SklbFile> skeletons;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sklbPaths = _edit._models.ResolveSklbsForMdl(mdlPath.ToString(), GetCurrentEstManipulations());
|
var sklbPaths = _edit._models.ResolveSklbsForMdl(mdlPath.ToString(), GetCurrentEstManipulations());
|
||||||
sklbs = sklbPaths != null
|
skeletons = sklbPaths.Select(ReadSklb).ToArray();
|
||||||
? sklbPaths.Select(ReadSklb).ToArray()
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
IoException = exception?.ToString();
|
IoException = exception.ToString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingIo = true;
|
PendingIo = true;
|
||||||
_edit._models.ExportToGltf(Mdl, sklbs, outputPath)
|
_edit._models.ExportToGltf(Mdl, skeletons, outputPath)
|
||||||
.ContinueWith(task =>
|
.ContinueWith(task =>
|
||||||
{
|
{
|
||||||
IoException = task.Exception?.ToString();
|
IoException = task.Exception?.ToString();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue