diff --git a/FNA.Core.csproj b/FNA.Core.csproj index 4f7e1e0f..4c3f707c 100644 --- a/FNA.Core.csproj +++ b/FNA.Core.csproj @@ -188,6 +188,7 @@ + diff --git a/FNA.NetFramework.csproj b/FNA.NetFramework.csproj index 9c6e7e2a..4aae2182 100644 --- a/FNA.NetFramework.csproj +++ b/FNA.NetFramework.csproj @@ -189,6 +189,7 @@ + diff --git a/FNA.NetStandard.csproj b/FNA.NetStandard.csproj index 64157a3d..0c22453f 100644 --- a/FNA.NetStandard.csproj +++ b/FNA.NetStandard.csproj @@ -188,6 +188,7 @@ + diff --git a/FNA.csproj b/FNA.csproj index 0a86e6da..d39a2096 100644 --- a/FNA.csproj +++ b/FNA.csproj @@ -259,6 +259,7 @@ + diff --git a/src/Graphics/ModelBuilderEXT.cs b/src/Graphics/ModelBuilderEXT.cs new file mode 100644 index 00000000..a7f77965 --- /dev/null +++ b/src/Graphics/ModelBuilderEXT.cs @@ -0,0 +1,227 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; + +namespace Microsoft.Xna.Framework.Graphics +{ + /// + /// Model mesh descriptor + /// + public class ModelMeshDescEXT + { + /// + /// Name of the model mesh + /// + public string Name { get; set; } + + /// + /// Bounding Sphere of the model mesh + /// + public BoundingSphere BoundingSphere { get; set; } + + /// + /// Parts of the model mesh + /// + public readonly List Parts = new List(); + + internal int Index { get; set; } + + /// + /// Adds a mesh part to the model mesh + /// + /// The index buffer for this mesh part + /// The location in the index array at which to start reading vertices + /// The vertex buffer for this mesh part + /// The offset (in vertices) from the top of vertex buffer + /// The number of vertices used during a draw call + /// The number of primitives to render + /// + /// + public void AddModelMeshPart(IndexBuffer indexBuffer, int startIndex, + VertexBuffer vertexBuffer, int vertexOffset, int numVertices, + int primitiveCount) + { + if (indexBuffer == null) + { + throw new ArgumentNullException(nameof(indexBuffer)); + } + + if (startIndex < 0 || startIndex >= indexBuffer.IndexCount) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + if (vertexBuffer == null) + { + throw new ArgumentNullException(nameof(vertexBuffer)); + } + + if (vertexOffset < 0 || vertexOffset >= vertexBuffer.VertexCount) + { + throw new ArgumentOutOfRangeException(nameof(vertexOffset)); + } + + if (numVertices <= 0 || numVertices > vertexBuffer.VertexCount) + { + throw new ArgumentOutOfRangeException(nameof(numVertices)); + } + + if (primitiveCount <= 0) + { + throw new ArgumentOutOfRangeException(nameof(primitiveCount)); + } + + var part = new ModelMeshPart() + { + IndexBuffer = indexBuffer, + StartIndex = startIndex, + VertexBuffer = vertexBuffer, + VertexOffset = vertexOffset, + NumVertices = numVertices, + PrimitiveCount = primitiveCount + }; + + Parts.Add(part); + } + + /// + /// Creates the model mesh + /// + /// Graphics Device + /// + public ModelMesh Create(GraphicsDevice device) + { + var modelMesh = new ModelMesh(device, Parts) + { + Name = Name, + BoundingSphere = BoundingSphere, + }; + + return modelMesh; + } + } + + /// + /// Model bone descriptor + /// + public class ModelBoneDescEXT + { + /// + /// Name of the model bone + /// + public string Name { get; set; } + + /// + /// Transform of the model bone + /// + public Matrix Transform { get; set; } + + /// + /// Meshes of the model bone + /// + public readonly List Meshes = new List(); + + /// + /// Children of the model bone + /// + public readonly List Children = new List(); + + internal int Index { get; set; } + } + + /// + /// Grants ability to create a Model at the run-time + /// + public static class ModelBuilderEXT + { + /// + /// Creates the model + /// + /// Graphics Device + /// Meshes of the model + /// Bones of the model + /// Root bone of the model + /// + /// + public static Model Create(GraphicsDevice device, List meshes, List bones, ModelBoneDescEXT root) + { + if (meshes == null) + { + throw new ArgumentNullException(nameof(meshes)); + } + + if (bones == null) + { + throw new ArgumentNullException(nameof(bones)); + } + + if (root == null) + { + throw new ArgumentNullException(nameof(root)); + } + + // Assign indexes + for (var i = 0; i < meshes.Count; ++i) + { + meshes[i].Index = i; + } + + for (var i = 0; i < bones.Count; ++i) + { + bones[i].Index = i; + } + + // Create meshes + var modelMeshes = new List(); + foreach (var desc in meshes) + { + var modelMesh = desc.Create(device); + modelMeshes.Add(modelMesh); + } + + // Create bones + var modelBones = new List(); + for (var i = 0; i < bones.Count; ++i) + { + var desc = bones[i]; + var bone = new ModelBone + { + Index = i, + Name = desc.Name, + Transform = desc.Transform + }; + + foreach (var mesh in desc.Meshes) + { + var modelMesh = modelMeshes[mesh.Index]; + modelMesh.ParentBone = bone; + bone.AddMesh(modelMesh); + } + + modelBones.Add(bone); + } + + // Assign children + for (var i = 0; i < bones.Count; ++i) + { + var desc = bones[i]; + var bone = modelBones[i]; + + foreach (var child in desc.Children) + { + var childBone = modelBones[child.Index]; + childBone.Parent = bone; + bone.AddChild(childBone); + } + } + + // Create the model + var model = new Model(device, modelBones, modelMeshes) + { + Root = modelBones[root.Index] + }; + + return model; + } + } +}