TiledMapLayerModelBuilder.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. using System.Collections.Generic;
  2. using System.Diagnostics;
  3. using System.Linq;
  4. using Microsoft.Xna.Framework;
  5. using Microsoft.Xna.Framework.Graphics;
  6. namespace MonoGame.Extended.Tiled.Renderers
  7. {
  8. public abstract class TiledMapLayerModelBuilder<T>
  9. {
  10. protected TiledMapLayerModelBuilder()
  11. {
  12. Indices = new List<ushort>();
  13. Vertices = new List<VertexPositionTexture>();
  14. }
  15. public List<ushort> Indices { get; }
  16. public List<VertexPositionTexture> Vertices { get; }
  17. public bool IsFull => Vertices.Count + TiledMapHelper.VerticesPerTile >= TiledMapHelper.MaximumVerticesPerModel;
  18. public bool IsBuildable => Vertices.Any();
  19. protected abstract void ClearBuffers();
  20. protected abstract T CreateModel(GraphicsDevice graphicsDevice, Texture2D texture);
  21. public T Build(GraphicsDevice graphicsDevice, Texture2D texture)
  22. {
  23. var model = CreateModel(graphicsDevice, texture);
  24. Vertices.Clear();
  25. Indices.Clear();
  26. ClearBuffers();
  27. return model;
  28. }
  29. public void AddSprite(Texture2D texture, Vector2 position, Rectangle sourceRectangle, TiledMapTileFlipFlags flipFlags)
  30. {
  31. Indices.AddRange(CreateTileIndices(Vertices.Count));
  32. Debug.Assert(Indices.Count <= TiledMapHelper.MaximumIndicesPerModel);
  33. Vertices.AddRange(CreateVertices(texture, position, sourceRectangle, flipFlags));
  34. Debug.Assert(Vertices.Count <= TiledMapHelper.MaximumVerticesPerModel);
  35. }
  36. private static IEnumerable<VertexPositionTexture> CreateVertices(Texture2D texture, Vector2 position, Rectangle sourceRectangle, TiledMapTileFlipFlags flags = TiledMapTileFlipFlags.None)
  37. {
  38. var reciprocalWidth = 1f / texture.Width;
  39. var reciprocalHeight = 1f / texture.Height;
  40. var texelLeft = sourceRectangle.X * reciprocalWidth;
  41. var texelTop = sourceRectangle.Y * reciprocalHeight;
  42. var texelRight = (sourceRectangle.X + sourceRectangle.Width) * reciprocalWidth;
  43. var texelBottom = (sourceRectangle.Y + sourceRectangle.Height) * reciprocalHeight;
  44. VertexPositionTexture vertexTopLeft, vertexTopRight, vertexBottomLeft, vertexBottomRight;
  45. vertexTopLeft.Position = new Vector3(position, 0);
  46. vertexTopRight.Position = new Vector3(position + new Vector2(sourceRectangle.Width, 0), 0);
  47. vertexBottomLeft.Position = new Vector3(position + new Vector2(0, sourceRectangle.Height), 0);
  48. vertexBottomRight.Position = new Vector3(position + new Vector2(sourceRectangle.Width, sourceRectangle.Height), 0);
  49. vertexTopLeft.TextureCoordinate.Y = texelTop;
  50. vertexTopLeft.TextureCoordinate.X = texelLeft;
  51. vertexTopRight.TextureCoordinate.Y = texelTop;
  52. vertexTopRight.TextureCoordinate.X = texelRight;
  53. vertexBottomLeft.TextureCoordinate.Y = texelBottom;
  54. vertexBottomLeft.TextureCoordinate.X = texelLeft;
  55. vertexBottomRight.TextureCoordinate.Y = texelBottom;
  56. vertexBottomRight.TextureCoordinate.X = texelRight;
  57. var flipDiagonally = (flags & TiledMapTileFlipFlags.FlipDiagonally) != 0;
  58. var flipHorizontally = (flags & TiledMapTileFlipFlags.FlipHorizontally) != 0;
  59. var flipVertically = (flags & TiledMapTileFlipFlags.FlipVertically) != 0;
  60. if (flipDiagonally)
  61. {
  62. FloatHelper.Swap(ref vertexTopRight.TextureCoordinate.X, ref vertexBottomLeft.TextureCoordinate.X);
  63. FloatHelper.Swap(ref vertexTopRight.TextureCoordinate.Y, ref vertexBottomLeft.TextureCoordinate.Y);
  64. }
  65. if (flipHorizontally)
  66. {
  67. if (flipDiagonally)
  68. {
  69. FloatHelper.Swap(ref vertexTopLeft.TextureCoordinate.Y, ref vertexTopRight.TextureCoordinate.Y);
  70. FloatHelper.Swap(ref vertexBottomLeft.TextureCoordinate.Y, ref vertexBottomRight.TextureCoordinate.Y);
  71. }
  72. else
  73. {
  74. FloatHelper.Swap(ref vertexTopLeft.TextureCoordinate.X, ref vertexTopRight.TextureCoordinate.X);
  75. FloatHelper.Swap(ref vertexBottomLeft.TextureCoordinate.X, ref vertexBottomRight.TextureCoordinate.X);
  76. }
  77. }
  78. if (flipVertically)
  79. {
  80. if (flipDiagonally)
  81. {
  82. FloatHelper.Swap(ref vertexTopLeft.TextureCoordinate.X, ref vertexBottomLeft.TextureCoordinate.X);
  83. FloatHelper.Swap(ref vertexTopRight.TextureCoordinate.X, ref vertexBottomRight.TextureCoordinate.X);
  84. }
  85. else
  86. {
  87. FloatHelper.Swap(ref vertexTopLeft.TextureCoordinate.Y, ref vertexBottomLeft.TextureCoordinate.Y);
  88. FloatHelper.Swap(ref vertexTopRight.TextureCoordinate.Y, ref vertexBottomRight.TextureCoordinate.Y);
  89. }
  90. }
  91. yield return vertexTopLeft;
  92. yield return vertexTopRight;
  93. yield return vertexBottomLeft;
  94. yield return vertexBottomRight;
  95. }
  96. private static IEnumerable<ushort> CreateTileIndices(int indexOffset)
  97. {
  98. yield return (ushort)(0 + indexOffset);
  99. yield return (ushort)(1 + indexOffset);
  100. yield return (ushort)(2 + indexOffset);
  101. yield return (ushort)(1 + indexOffset);
  102. yield return (ushort)(3 + indexOffset);
  103. yield return (ushort)(2 + indexOffset);
  104. }
  105. }
  106. }