diff --git a/Penumbra/Import/Models/MeshConverter.cs b/Penumbra/Import/Models/MeshConverter.cs index 30d24c17..9f55383e 100644 --- a/Penumbra/Import/Models/MeshConverter.cs +++ b/Penumbra/Import/Models/MeshConverter.cs @@ -10,7 +10,7 @@ namespace Penumbra.Import.Modules; public sealed class MeshConverter { - public static IMeshBuilder ToGltf(MdlFile mdl, byte lod, ushort meshIndex, Dictionary? boneNameMap) + public static IMeshBuilder[] ToGltf(MdlFile mdl, byte lod, ushort meshIndex, Dictionary? boneNameMap) { var self = new MeshConverter(mdl, lod, meshIndex, boneNameMap); return self.BuildMesh(); @@ -65,12 +65,23 @@ public sealed class MeshConverter return indexMap; } - // TODO: consider a struct return type - private IMeshBuilder BuildMesh() + private IMeshBuilder[] BuildMesh() { - var indices = BuildIndices(); var vertices = BuildVertices(); + // TODO: handle submeshCount = 0 + + return _mdl.SubMeshes + .Skip(Mesh.SubMeshIndex) + .Take(Mesh.SubMeshCount) + .Select(submesh => BuildSubMesh(submesh, vertices)) + .ToArray(); + } + + private IMeshBuilder BuildSubMesh(MdlStructs.SubmeshStruct submesh, IReadOnlyList vertices) + { + var indices = BuildIndices(submesh); + var meshBuilderType = typeof(MeshBuilder<,,,>).MakeGenericType( typeof(MaterialBuilder), _geometryType, @@ -89,7 +100,7 @@ public sealed class MeshConverter // All XIV meshes use triangle lists. // TODO: split by submeshes - for (var indexOffset = 0; indexOffset < Mesh.IndexCount; indexOffset += 3) + for (var indexOffset = 0; indexOffset < submesh.IndexCount; indexOffset += 3) primitiveBuilder.AddTriangle( vertices[indices[indexOffset + 0]], vertices[indices[indexOffset + 1]], @@ -99,11 +110,11 @@ public sealed class MeshConverter return meshBuilder; } - private IReadOnlyList BuildIndices() + private IReadOnlyList BuildIndices(MdlStructs.SubmeshStruct submesh) { var reader = new BinaryReader(new MemoryStream(_mdl.RemainingData)); - reader.Seek(_mdl.IndexOffset[_lod] + Mesh.StartIndex * sizeof(ushort)); - return reader.ReadStructuresAsArray((int)Mesh.IndexCount); + reader.Seek(_mdl.IndexOffset[_lod] + submesh.IndexOffset * sizeof(ushort)); + return reader.ReadStructuresAsArray((int)submesh.IndexCount); } private IReadOnlyList BuildVertices() diff --git a/Penumbra/Import/Models/ModelManager.cs b/Penumbra/Import/Models/ModelManager.cs index 027ac841..2dd64235 100644 --- a/Penumbra/Import/Models/ModelManager.cs +++ b/Penumbra/Import/Models/ModelManager.cs @@ -87,12 +87,13 @@ public sealed class ModelManager : SingleTaskQueue, IDisposable // TODO: consider other types of mesh? for (ushort meshOffset = 0; meshOffset < lod.MeshCount; meshOffset++) { - var meshBuilder = MeshConverter.ToGltf(_mdl, lodIndex, (ushort)(lod.MeshIndex + meshOffset), skeleton?.Names); + var meshBuilders = MeshConverter.ToGltf(_mdl, lodIndex, (ushort)(lod.MeshIndex + meshOffset), skeleton?.Names); // TODO: use a value from the mesh converter for this check, rather than assuming that it has joints - if (skeleton == null) - scene.AddRigidMesh(meshBuilder, Matrix4x4.Identity); - else - scene.AddSkinnedMesh(meshBuilder, Matrix4x4.Identity, skeleton?.Joints); + foreach (var meshBuilder in meshBuilders) + if (skeleton == null) + scene.AddRigidMesh(meshBuilder, Matrix4x4.Identity); + else + scene.AddSkinnedMesh(meshBuilder, Matrix4x4.Identity, skeleton?.Joints); } }