async is a great idea lets do more of that

This commit is contained in:
ackwell 2023-12-27 01:44:24 +11:00
parent df43083101
commit ed283afe2c
2 changed files with 81 additions and 28 deletions

View file

@ -1,3 +1,4 @@
using OtterGui.Tasks;
using Penumbra.GameData.Files; using Penumbra.GameData.Files;
using SharpGLTF.Geometry; using SharpGLTF.Geometry;
using SharpGLTF.Geometry.VertexTypes; using SharpGLTF.Geometry.VertexTypes;
@ -6,40 +7,89 @@ using SharpGLTF.Scenes;
namespace Penumbra.Import.Models; namespace Penumbra.Import.Models;
public sealed class ModelManager public sealed class ModelManager : SingleTaskQueue, IDisposable
{ {
private readonly ConcurrentDictionary<IAction, (Task, CancellationTokenSource)> _tasks = new();
private bool _disposed = false;
public ModelManager() public ModelManager()
{ {
// //
} }
// TODO: Consider moving import/export onto an async queue, check ../textures/texturemanager public void Dispose()
public void ExportToGltf(/* MdlFile mdl, */string path)
{ {
var mesh = new MeshBuilder<VertexPosition>("mesh"); _disposed = true;
foreach (var (_, cancel) in _tasks.Values.ToArray())
cancel.Cancel();
_tasks.Clear();
}
var material1 = new MaterialBuilder() private Task Enqueue(IAction action)
.WithDoubleSide(true) {
.WithMetallicRoughnessShader() if (_disposed)
.WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 0, 0, 1)); return Task.FromException(new ObjectDisposedException(nameof(ModelManager)));
var primitive1 = mesh.UsePrimitive(material1);
primitive1.AddTriangle(new VertexPosition(-10, 0, 0), new VertexPosition(10, 0, 0), new VertexPosition(0, 10, 0));
primitive1.AddTriangle(new VertexPosition(10, 0, 0), new VertexPosition(-10, 0, 0), new VertexPosition(0, -10, 0));
var material2 = new MaterialBuilder()
.WithDoubleSide(true)
.WithMetallicRoughnessShader()
.WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 0, 1, 1));
var primitive2 = mesh.UsePrimitive(material2);
primitive2.AddQuadrangle(new VertexPosition(-5, 0, 3), new VertexPosition(0, -5, 3), new VertexPosition(5, 0, 3), new VertexPosition(0, 5, 3));
var scene = new SceneBuilder(); Task task;
scene.AddRigidMesh(mesh, Matrix4x4.Identity); lock (_tasks)
{
task = _tasks.GetOrAdd(action, action =>
{
var token = new CancellationTokenSource();
var task = Enqueue(action, token.Token);
task.ContinueWith(_ => _tasks.TryRemove(action, out var unused), CancellationToken.None);
return (task, token);
}).Item1;
}
var model = scene.ToGltf2(); return task;
model.SaveGLTF(path); }
// TODO: Draw the rest of the owl. public Task ExportToGltf(/* MdlFile mdl, */string path)
=> Enqueue(new ExportToGltfAction(path));
private class ExportToGltfAction : IAction
{
private readonly string _path;
public ExportToGltfAction(string path)
{
_path = path;
}
public void Execute(CancellationToken token)
{
var mesh = new MeshBuilder<VertexPosition>("mesh");
var material1 = new MaterialBuilder()
.WithDoubleSide(true)
.WithMetallicRoughnessShader()
.WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 0, 0, 1));
var primitive1 = mesh.UsePrimitive(material1);
primitive1.AddTriangle(new VertexPosition(-10, 0, 0), new VertexPosition(10, 0, 0), new VertexPosition(0, 10, 0));
primitive1.AddTriangle(new VertexPosition(10, 0, 0), new VertexPosition(-10, 0, 0), new VertexPosition(0, -10, 0));
var material2 = new MaterialBuilder()
.WithDoubleSide(true)
.WithMetallicRoughnessShader()
.WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 0, 1, 1));
var primitive2 = mesh.UsePrimitive(material2);
primitive2.AddQuadrangle(new VertexPosition(-5, 0, 3), new VertexPosition(0, -5, 3), new VertexPosition(5, 0, 3), new VertexPosition(0, 5, 3));
var scene = new SceneBuilder();
scene.AddRigidMesh(mesh, Matrix4x4.Identity);
var model = scene.ToGltf2();
model.SaveGLTF(_path);
}
public bool Equals(IAction? other)
{
if (other is not ExportToGltfAction rhs)
return false;
// TODO: compare configuration
return true;
}
} }
} }

View file

@ -14,10 +14,11 @@ public partial class ModEditWindow
{ {
private const int MdlMaterialMaximum = 4; private const int MdlMaterialMaximum = 4;
private readonly ModelManager _models;
private readonly FileEditor<MdlTab> _modelTab; private readonly FileEditor<MdlTab> _modelTab;
private readonly ModelManager _models;
private bool _pendingIo = false;
private string _modelNewMaterial = string.Empty; private string _modelNewMaterial = string.Empty;
private readonly List<TagButtons> _subMeshAttributeTagWidgets = []; private readonly List<TagButtons> _subMeshAttributeTagWidgets = [];
@ -34,9 +35,11 @@ public partial class ModEditWindow
); );
} }
if (ImGui.Button("bingo bango")) if (ImGuiUtil.DrawDisabledButton("bingo bango", Vector2.Zero, "description", _pendingIo))
{ {
_models.ExportToGltf("C:\\Users\\ackwell\\blender\\gltf-tests\\bingo.gltf"); _pendingIo = true;
var task = _models.ExportToGltf("C:\\Users\\ackwell\\blender\\gltf-tests\\bingo.gltf");
task.ContinueWith(_ => _pendingIo = false);
} }
var ret = false; var ret = false;