diff --git a/Penumbra/Import/Models/ModelManager.cs b/Penumbra/Import/Models/ModelManager.cs index fbccf4b7..bded3b0c 100644 --- a/Penumbra/Import/Models/ModelManager.cs +++ b/Penumbra/Import/Models/ModelManager.cs @@ -1,3 +1,4 @@ +using Lumina.Extensions; using OtterGui.Tasks; using Penumbra.GameData.Files; using SharpGLTF.Geometry; @@ -45,39 +46,75 @@ public sealed class ModelManager : SingleTaskQueue, IDisposable return task; } - public Task ExportToGltf(/* MdlFile mdl, */string path) - => Enqueue(new ExportToGltfAction(path)); + public Task ExportToGltf(MdlFile mdl, string path) + => Enqueue(new ExportToGltfAction(mdl, path)); private class ExportToGltfAction : IAction { + private readonly MdlFile _mdl; private readonly string _path; - public ExportToGltfAction(string path) + public ExportToGltfAction(MdlFile mdl, string path) { + _mdl = mdl; _path = path; } public void Execute(CancellationToken token) { - var mesh = new MeshBuilder("mesh"); + var meshBuilder = new MeshBuilder("mesh"); - var material1 = new MaterialBuilder() + var material = 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)); + .WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 1, 1, 1)); + + // lol, lmao even + var meshIndex = 2; + var lod = 0; + + var mesh = _mdl.Meshes[meshIndex]; + var submesh = _mdl.SubMeshes[mesh.SubMeshIndex]; // just first for now + + var positionVertexElement = _mdl.VertexDeclarations[meshIndex].VertexElements + .Where(decl => decl.Usage == 0 /* POSITION */) + .First(); + + // reading in the entire indices list + var dataReader = new BinaryReader(new MemoryStream(_mdl.RemainingData)); + dataReader.Seek(_mdl.IndexOffset[lod]); + var indices = dataReader.ReadStructuresAsArray((int)_mdl.IndexBufferSize[lod] / sizeof(ushort)); + + // read in verts for this mesh + var baseOffset = _mdl.VertexOffset[lod] + mesh.VertexBufferOffset[positionVertexElement.Stream] + positionVertexElement.Offset; + var vertices = new List(); + for (var vertexIndex = 0; vertexIndex < mesh.VertexCount; vertexIndex++) + { + dataReader.Seek(baseOffset + vertexIndex * mesh.VertexBufferStride[positionVertexElement.Stream]); + // todo handle type + vertices.Add(new VertexPosition( + dataReader.ReadSingle(), + dataReader.ReadSingle(), + dataReader.ReadSingle() + )); + } + + // build a primitive for the submesh + var primitiveBuilder = meshBuilder.UsePrimitive(material); + // they're all tri list + for (var indexOffset = 0; indexOffset < submesh.IndexCount; indexOffset += 3) + { + var index = indexOffset + submesh.IndexOffset; + + primitiveBuilder.AddTriangle( + vertices[indices[index + 0]], + vertices[indices[index + 1]], + vertices[indices[index + 2]] + ); + } var scene = new SceneBuilder(); - scene.AddRigidMesh(mesh, Matrix4x4.Identity); + scene.AddRigidMesh(meshBuilder, Matrix4x4.Identity); var model = scene.ToGltf2(); model.SaveGLTF(_path); diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs index 89497cfd..b64b4f40 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs @@ -38,7 +38,7 @@ public partial class ModEditWindow if (ImGuiUtil.DrawDisabledButton("bingo bango", Vector2.Zero, "description", _pendingIo)) { _pendingIo = true; - var task = _models.ExportToGltf("C:\\Users\\ackwell\\blender\\gltf-tests\\bingo.gltf"); + var task = _models.ExportToGltf(file, "C:\\Users\\ackwell\\blender\\gltf-tests\\bingo.gltf"); task.ContinueWith(_ => _pendingIo = false); }