MeshPrimitiveWriter.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using Microsoft.Xna.Framework.Graphics;
  7. using SharpGLTF.Runtime.Template;
  8. namespace SharpGLTF.Runtime.Pipeline
  9. {
  10. /// <summary>
  11. /// Writes the vertex and index buffer data to MonoGame vertex and index buffers.
  12. /// </summary>
  13. sealed class MeshPrimitiveWriter
  14. {
  15. #region data
  16. // shared buffers
  17. private readonly Dictionary<Type, IPrimitivesBuffers> _Buffers = new Dictionary<Type, IPrimitivesBuffers>();
  18. // primitives
  19. private readonly List<_MeshPrimitive> _MeshPrimitives = new List<_MeshPrimitive>();
  20. #endregion
  21. #region API
  22. public void WriteMeshPrimitive<TVertex>(int logicalMeshIndex, Effect effect, MeshPrimitiveReader primitive)
  23. where TVertex : unmanaged, IVertexType
  24. {
  25. if (!_Buffers.TryGetValue(typeof(TVertex), out IPrimitivesBuffers pb))
  26. {
  27. _Buffers[typeof(TVertex)] = pb = new _PrimitivesBuffers<TVertex>();
  28. }
  29. var part = (pb as _PrimitivesBuffers<TVertex>).Append(logicalMeshIndex, effect, primitive);
  30. _MeshPrimitives.Add(part);
  31. }
  32. internal IReadOnlyDictionary<int, RuntimeModelMesh> GetRuntimeMeshes(GraphicsDevice device, GraphicsResourceTracker disposables)
  33. {
  34. // create shared vertex/index buffers
  35. var vbuffers = _Buffers.Values.ToDictionary(key => key, val => val.CreateVertexBuffer(device));
  36. var ibuffers = _Buffers.Values.ToDictionary(key => key, val => val.CreateIndexBuffer(device));
  37. foreach (var vb in vbuffers.Values) disposables.AddDisposable(vb);
  38. foreach (var ib in ibuffers.Values) disposables.AddDisposable(ib);
  39. // create RuntimeModelMesh
  40. RuntimeModelMesh _convert(IEnumerable<_MeshPrimitive> srcParts)
  41. {
  42. var dstMesh = new RuntimeModelMesh(device);
  43. foreach (var srcPart in srcParts)
  44. {
  45. var vb = vbuffers[srcPart.PrimitiveBuffers];
  46. var ib = ibuffers[srcPart.PrimitiveBuffers];
  47. var dstPart = dstMesh.CreateMeshPart();
  48. dstPart.Effect = srcPart.PrimitiveEffect;
  49. dstPart.SetVertexBuffer(vb, srcPart.VertexOffset, srcPart.VertexCount);
  50. dstPart.SetIndexBuffer(ib, srcPart.TriangleOffset * 3, srcPart.TriangleCount);
  51. }
  52. return dstMesh;
  53. }
  54. return _MeshPrimitives
  55. .GroupBy(item => item.LogicalMeshIndex)
  56. .ToDictionary(k => k.Key, v => _convert(v));
  57. }
  58. #endregion
  59. #region nested types
  60. interface IPrimitivesBuffers
  61. {
  62. VertexBuffer CreateVertexBuffer(GraphicsDevice device);
  63. IndexBuffer CreateIndexBuffer(GraphicsDevice device);
  64. }
  65. /// <summary>
  66. /// Contains the shared vertex/index buffers of all the mesh primitive that share the same vertex type.
  67. /// </summary>
  68. /// <typeparam name="TVertex"></typeparam>
  69. sealed class _PrimitivesBuffers<TVertex> : IPrimitivesBuffers
  70. where TVertex : unmanaged, IVertexType
  71. {
  72. #region data
  73. private readonly List<TVertex> _Vertices = new List<TVertex>();
  74. private readonly List<(int, int, int)> _Triangles = new List<(int, int, int)>();
  75. #endregion
  76. #region API
  77. public _MeshPrimitive Append(int meshKey, Effect effect, MeshPrimitiveReader primitive)
  78. {
  79. var partVertices = primitive.ToXnaVertices<TVertex>();
  80. var partTriangles = primitive.TriangleIndices;
  81. var part = new _MeshPrimitive
  82. {
  83. LogicalMeshIndex = meshKey,
  84. PrimitiveEffect = effect,
  85. PrimitiveBuffers = this,
  86. VertexOffset = _Vertices.Count,
  87. VertexCount = partVertices.Length,
  88. TriangleOffset = _Triangles.Count,
  89. TriangleCount = partTriangles.Length
  90. };
  91. _Vertices.AddRange(partVertices);
  92. _Triangles.AddRange(partTriangles);
  93. return part;
  94. }
  95. public VertexBuffer CreateVertexBuffer(GraphicsDevice device)
  96. {
  97. var data = new VertexBuffer(device, typeof(TVertex), _Vertices.Count, BufferUsage.None);
  98. data.SetData(_Vertices.ToArray());
  99. return data;
  100. }
  101. public IndexBuffer CreateIndexBuffer(GraphicsDevice device)
  102. {
  103. return CreateIndexBuffer(device, _Triangles);
  104. }
  105. private static IndexBuffer CreateIndexBuffer(GraphicsDevice device, IEnumerable<(int A, int B, int C)> triangles)
  106. {
  107. var sequence32 = triangles
  108. .SelectMany(item => new[] { (UInt32)item.C, (UInt32)item.B, (UInt32)item.A })
  109. .ToArray();
  110. var max = sequence32.Max();
  111. if (max > 65535)
  112. {
  113. var indices = new IndexBuffer(device, typeof(UInt32), sequence32.Length, BufferUsage.None);
  114. indices.SetData(sequence32);
  115. return indices;
  116. }
  117. else
  118. {
  119. var sequence16 = sequence32.Select(item => (UInt16)item).ToArray();
  120. var indices = new IndexBuffer(device, typeof(UInt16), sequence16.Length, BufferUsage.None);
  121. indices.SetData(sequence16);
  122. return indices;
  123. }
  124. }
  125. #endregion
  126. }
  127. /// <summary>
  128. /// Represents a mesh primitive
  129. /// </summary>
  130. struct _MeshPrimitive
  131. {
  132. public int LogicalMeshIndex;
  133. public Effect PrimitiveEffect;
  134. public IPrimitivesBuffers PrimitiveBuffers;
  135. public int VertexOffset;
  136. public int VertexCount;
  137. public int TriangleOffset;
  138. public int TriangleCount;
  139. }
  140. #endregion
  141. }
  142. }