AssetCreator.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. using System;
  2. using System.Collections.Generic;
  3. using FarseerPhysics.Collision;
  4. using FarseerPhysics.Collision.Shapes;
  5. using FarseerPhysics.Common;
  6. using FarseerPhysics.Common.Decomposition;
  7. using FarseerPhysics.Dynamics;
  8. using Microsoft.Xna.Framework;
  9. using Microsoft.Xna.Framework.Content;
  10. using Microsoft.Xna.Framework.Graphics;
  11. namespace FarseerPhysics.SamplesFramework
  12. {
  13. public enum MaterialType
  14. {
  15. Blank,
  16. Dots,
  17. Squares,
  18. Waves,
  19. Pavement
  20. }
  21. public class AssetCreator
  22. {
  23. private const int CircleSegments = 32;
  24. private GraphicsDevice _device;
  25. private BasicEffect _effect;
  26. private Dictionary<MaterialType, Texture2D> _materials = new Dictionary<MaterialType, Texture2D>();
  27. public AssetCreator(GraphicsDevice device)
  28. {
  29. _device = device;
  30. _effect = new BasicEffect(_device);
  31. }
  32. public static Vector2 CalculateOrigin(Body b)
  33. {
  34. Vector2 lBound = new Vector2(float.MaxValue);
  35. AABB bounds;
  36. Transform trans;
  37. b.GetTransform(out trans);
  38. for (int i = 0; i < b.FixtureList.Count; ++i)
  39. {
  40. for (int j = 0; j < b.FixtureList[i].Shape.ChildCount; ++j)
  41. {
  42. b.FixtureList[i].Shape.ComputeAABB(out bounds, ref trans, j);
  43. Vector2.Min(ref lBound, ref bounds.LowerBound, out lBound);
  44. }
  45. }
  46. // calculate body offset from its center and add a 1 pixel border
  47. // because we generate the textures a little bigger than the actual body's fixtures
  48. return ConvertUnits.ToDisplayUnits(b.Position - lBound) + new Vector2(1f);
  49. }
  50. public void LoadContent(ContentManager contentManager)
  51. {
  52. _materials[MaterialType.Blank] = contentManager.Load<Texture2D>("Materials/blank");
  53. _materials[MaterialType.Dots] = contentManager.Load<Texture2D>("Materials/dots");
  54. _materials[MaterialType.Squares] = contentManager.Load<Texture2D>("Materials/squares");
  55. _materials[MaterialType.Waves] = contentManager.Load<Texture2D>("Materials/waves");
  56. _materials[MaterialType.Pavement] = contentManager.Load<Texture2D>("Materials/pavement");
  57. }
  58. public Texture2D TextureFromShape(Shape shape, MaterialType type, Color color, float materialScale)
  59. {
  60. switch (shape.ShapeType)
  61. {
  62. case ShapeType.Circle:
  63. return CircleTexture(shape.Radius, type, color, materialScale);
  64. case ShapeType.Polygon:
  65. return TextureFromVertices(((PolygonShape) shape).Vertices, type, color, materialScale);
  66. default:
  67. throw new NotSupportedException("The specified shape type is not supported.");
  68. }
  69. }
  70. public Texture2D TextureFromVertices(Vertices vertices, MaterialType type, Color color, float materialScale)
  71. {
  72. // copy vertices
  73. Vertices verts = new Vertices(vertices);
  74. // scale to display units (i.e. pixels) for rendering to texture
  75. Vector2 scale = ConvertUnits.ToDisplayUnits(Vector2.One);
  76. verts.Scale(ref scale);
  77. // translate the boundingbox center to the texture center
  78. // because we use an orthographic projection for rendering later
  79. AABB vertsBounds = verts.GetCollisionBox();
  80. verts.Translate(-vertsBounds.Center);
  81. List<Vertices> decomposedVerts;
  82. if (!verts.IsConvex())
  83. {
  84. decomposedVerts = EarclipDecomposer.ConvexPartition(verts);
  85. }
  86. else
  87. {
  88. decomposedVerts = new List<Vertices>();
  89. decomposedVerts.Add(verts);
  90. }
  91. List<VertexPositionColorTexture[]> verticesFill =
  92. new List<VertexPositionColorTexture[]>(decomposedVerts.Count);
  93. materialScale /= _materials[type].Width;
  94. for (int i = 0; i < decomposedVerts.Count; ++i)
  95. {
  96. verticesFill.Add(new VertexPositionColorTexture[3 * (decomposedVerts[i].Count - 2)]);
  97. for (int j = 0; j < decomposedVerts[i].Count - 2; ++j)
  98. {
  99. // fill vertices
  100. verticesFill[i][3 * j].Position = new Vector3(decomposedVerts[i][0], 0f);
  101. verticesFill[i][3 * j + 1].Position = new Vector3(decomposedVerts[i].NextVertex(j), 0f);
  102. verticesFill[i][3 * j + 2].Position = new Vector3(decomposedVerts[i].NextVertex(j + 1), 0f);
  103. verticesFill[i][3 * j].TextureCoordinate = decomposedVerts[i][0] * materialScale;
  104. verticesFill[i][3 * j + 1].TextureCoordinate = decomposedVerts[i].NextVertex(j) * materialScale;
  105. verticesFill[i][3 * j + 2].TextureCoordinate = decomposedVerts[i].NextVertex(j + 1) * materialScale;
  106. verticesFill[i][3 * j].Color =
  107. verticesFill[i][3 * j + 1].Color = verticesFill[i][3 * j + 2].Color = color;
  108. }
  109. }
  110. // calculate outline
  111. VertexPositionColor[] verticesOutline = new VertexPositionColor[2 * verts.Count];
  112. for (int i = 0; i < verts.Count; ++i)
  113. {
  114. verticesOutline[2 * i].Position = new Vector3(verts[i], 0f);
  115. verticesOutline[2 * i + 1].Position = new Vector3(verts.NextVertex(i), 0f);
  116. verticesOutline[2 * i].Color = verticesOutline[2 * i + 1].Color = Color.Black;
  117. }
  118. Vector2 vertsSize = new Vector2(vertsBounds.UpperBound.X - vertsBounds.LowerBound.X,
  119. vertsBounds.UpperBound.Y - vertsBounds.LowerBound.Y);
  120. return RenderTexture((int)vertsSize.X, (int)vertsSize.Y,
  121. _materials[type], verticesFill, verticesOutline);
  122. }
  123. public Texture2D CircleTexture(float radius, MaterialType type, Color color, float materialScale)
  124. {
  125. return EllipseTexture(radius, radius, type, color, materialScale);
  126. }
  127. public Texture2D EllipseTexture(float radiusX, float radiusY, MaterialType type, Color color,
  128. float materialScale)
  129. {
  130. VertexPositionColorTexture[] verticesFill = new VertexPositionColorTexture[3 * (CircleSegments - 2)];
  131. VertexPositionColor[] verticesOutline = new VertexPositionColor[2 * CircleSegments];
  132. const float segmentSize = MathHelper.TwoPi / CircleSegments;
  133. float theta = segmentSize;
  134. radiusX = ConvertUnits.ToDisplayUnits(radiusX);
  135. radiusY = ConvertUnits.ToDisplayUnits(radiusY);
  136. materialScale /= _materials[type].Width;
  137. Vector2 start = new Vector2(radiusX, 0f);
  138. for (int i = 0; i < CircleSegments - 2; ++i)
  139. {
  140. Vector2 p1 = new Vector2(radiusX * (float)Math.Cos(theta), radiusY * (float)Math.Sin(theta));
  141. Vector2 p2 = new Vector2(radiusX * (float)Math.Cos(theta + segmentSize),
  142. radiusY * (float)Math.Sin(theta + segmentSize));
  143. // fill vertices
  144. verticesFill[3 * i].Position = new Vector3(start, 0f);
  145. verticesFill[3 * i + 1].Position = new Vector3(p1, 0f);
  146. verticesFill[3 * i + 2].Position = new Vector3(p2, 0f);
  147. verticesFill[3 * i].TextureCoordinate = start * materialScale;
  148. verticesFill[3 * i + 1].TextureCoordinate = p1 * materialScale;
  149. verticesFill[3 * i + 2].TextureCoordinate = p2 * materialScale;
  150. verticesFill[3 * i].Color = verticesFill[3 * i + 1].Color = verticesFill[3 * i + 2].Color = color;
  151. // outline vertices
  152. if (i == 0)
  153. {
  154. verticesOutline[0].Position = new Vector3(start, 0f);
  155. verticesOutline[1].Position = new Vector3(p1, 0f);
  156. verticesOutline[0].Color = verticesOutline[1].Color = Color.Black;
  157. }
  158. if (i == CircleSegments - 3)
  159. {
  160. verticesOutline[2 * CircleSegments - 2].Position = new Vector3(p2, 0f);
  161. verticesOutline[2 * CircleSegments - 1].Position = new Vector3(start, 0f);
  162. verticesOutline[2 * CircleSegments - 2].Color =
  163. verticesOutline[2 * CircleSegments - 1].Color = Color.Black;
  164. }
  165. verticesOutline[2 * i + 2].Position = new Vector3(p1, 0f);
  166. verticesOutline[2 * i + 3].Position = new Vector3(p2, 0f);
  167. verticesOutline[2 * i + 2].Color = verticesOutline[2 * i + 3].Color = Color.Black;
  168. theta += segmentSize;
  169. }
  170. return RenderTexture((int)(radiusX * 2f), (int)(radiusY * 2f),
  171. _materials[type], verticesFill, verticesOutline);
  172. }
  173. private Texture2D RenderTexture(int width, int height, Texture2D material,
  174. VertexPositionColorTexture[] verticesFill,
  175. VertexPositionColor[] verticesOutline)
  176. {
  177. List<VertexPositionColorTexture[]> fill = new List<VertexPositionColorTexture[]>(1);
  178. fill.Add(verticesFill);
  179. return RenderTexture(width, height, material, fill, verticesOutline);
  180. }
  181. private Texture2D RenderTexture(int width, int height, Texture2D material,
  182. List<VertexPositionColorTexture[]> verticesFill,
  183. VertexPositionColor[] verticesOutline)
  184. {
  185. Matrix halfPixelOffset = Matrix.CreateTranslation(-0.5f, -0.5f, 0f);
  186. PresentationParameters pp = _device.PresentationParameters;
  187. RenderTarget2D texture = new RenderTarget2D(_device, width + 2, height + 2, false, SurfaceFormat.Color,
  188. DepthFormat.None, pp.MultiSampleCount,
  189. RenderTargetUsage.DiscardContents);
  190. _device.RasterizerState = RasterizerState.CullNone;
  191. _device.SamplerStates[0] = SamplerState.LinearWrap;
  192. _device.SetRenderTarget(texture);
  193. _device.Clear(Color.Transparent);
  194. _effect.Projection = Matrix.CreateOrthographic(width + 2f, -height - 2f, 0f, 1f);
  195. _effect.View = halfPixelOffset;
  196. // render shape;
  197. _effect.TextureEnabled = true;
  198. _effect.Texture = material;
  199. _effect.VertexColorEnabled = true;
  200. _effect.Techniques[0].Passes[0].Apply();
  201. for (int i = 0; i < verticesFill.Count; ++i)
  202. {
  203. _device.DrawUserPrimitives(PrimitiveType.TriangleList, verticesFill[i], 0, verticesFill[i].Length / 3);
  204. }
  205. // render outline;
  206. _effect.TextureEnabled = false;
  207. _effect.Techniques[0].Passes[0].Apply();
  208. _device.DrawUserPrimitives(PrimitiveType.LineList, verticesOutline, 0, verticesOutline.Length / 2);
  209. _device.SetRenderTarget(null);
  210. return texture;
  211. }
  212. }
  213. }