2
0

DebugViewXNA.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using FarseerPhysics.Collision;
  6. using FarseerPhysics.Collision.Shapes;
  7. using FarseerPhysics.Common;
  8. using FarseerPhysics.Controllers;
  9. using FarseerPhysics.Dynamics;
  10. using FarseerPhysics.Dynamics.Contacts;
  11. using FarseerPhysics.Dynamics.Joints;
  12. using Microsoft.Xna.Framework;
  13. using Microsoft.Xna.Framework.Content;
  14. using Microsoft.Xna.Framework.Graphics;
  15. namespace FarseerPhysics.DebugViews
  16. {
  17. /// <summary>
  18. /// A debug view that works in XNA.
  19. /// A debug view shows you what happens inside the physics engine. You can view
  20. /// bodies, joints, fixtures and more.
  21. /// </summary>
  22. public class DebugViewXNA : DebugView, IDisposable
  23. {
  24. //Drawing
  25. private PrimitiveBatch _primitiveBatch;
  26. private SpriteBatch _batch;
  27. private SpriteFont _font;
  28. private GraphicsDevice _device;
  29. private Vector2[] _tempVertices = new Vector2[Settings.MaxPolygonVertices];
  30. private List<StringData> _stringData;
  31. private Matrix _localProjection;
  32. private Matrix _localView;
  33. //Shapes
  34. public Color DefaultShapeColor = new Color(0.9f, 0.7f, 0.7f);
  35. public Color InactiveShapeColor = new Color(0.5f, 0.5f, 0.3f);
  36. public Color KinematicShapeColor = new Color(0.5f, 0.5f, 0.9f);
  37. public Color SleepingShapeColor = new Color(0.6f, 0.6f, 0.6f);
  38. public Color StaticShapeColor = new Color(0.5f, 0.9f, 0.5f);
  39. public Color TextColor = Color.White;
  40. //Contacts
  41. private int _pointCount;
  42. private const int MaxContactPoints = 2048;
  43. private ContactPoint[] _points = new ContactPoint[MaxContactPoints];
  44. //Debug panel
  45. #if XBOX
  46. public Vector2 DebugPanelPosition = new Vector2(55, 100);
  47. #else
  48. public Vector2 DebugPanelPosition = new Vector2(40, 100);
  49. #endif
  50. private int _max;
  51. private int _avg;
  52. private int _min;
  53. //Performance graph
  54. public bool AdaptiveLimits = true;
  55. public int ValuesToGraph = 500;
  56. public int MinimumValue;
  57. public int MaximumValue = 1000;
  58. private List<float> _graphValues = new List<float>();
  59. #if XBOX
  60. public Rectangle PerformancePanelBounds = new Rectangle(265, 100, 200, 100);
  61. #else
  62. public Rectangle PerformancePanelBounds = new Rectangle(250, 100, 200, 100);
  63. #endif
  64. private Vector2[] _background = new Vector2[4];
  65. public bool Enabled = true;
  66. #if XBOX || WINDOWS_PHONE
  67. public const int CircleSegments = 16;
  68. #else
  69. public const int CircleSegments = 32;
  70. #endif
  71. public DebugViewXNA(World world)
  72. : base(world)
  73. {
  74. world.ContactManager.PreSolve += PreSolve;
  75. //Default flags
  76. AppendFlags(DebugViewFlags.Shape);
  77. AppendFlags(DebugViewFlags.Controllers);
  78. AppendFlags(DebugViewFlags.Joint);
  79. }
  80. public void BeginCustomDraw(ref Matrix projection, ref Matrix view)
  81. {
  82. _primitiveBatch.Begin(ref projection, ref view);
  83. }
  84. public void EndCustomDraw()
  85. {
  86. _primitiveBatch.End();
  87. }
  88. #region IDisposable Members
  89. public void Dispose()
  90. {
  91. World.ContactManager.PreSolve -= PreSolve;
  92. }
  93. #endregion
  94. private void PreSolve(Contact contact, ref Manifold oldManifold)
  95. {
  96. if ((Flags & DebugViewFlags.ContactPoints) == DebugViewFlags.ContactPoints)
  97. {
  98. Manifold manifold = contact.Manifold;
  99. if (manifold.PointCount == 0)
  100. {
  101. return;
  102. }
  103. Fixture fixtureA = contact.FixtureA;
  104. FixedArray2<PointState> state1, state2;
  105. Collision.Collision.GetPointStates(out state1, out state2, ref oldManifold, ref manifold);
  106. FixedArray2<Vector2> points;
  107. Vector2 normal;
  108. contact.GetWorldManifold(out normal, out points);
  109. for (int i = 0; i < manifold.PointCount && _pointCount < MaxContactPoints; ++i)
  110. {
  111. if (fixtureA == null)
  112. {
  113. _points[i] = new ContactPoint();
  114. }
  115. ContactPoint cp = _points[_pointCount];
  116. cp.Position = points[i];
  117. cp.Normal = normal;
  118. cp.State = state2[i];
  119. _points[_pointCount] = cp;
  120. ++_pointCount;
  121. }
  122. }
  123. }
  124. /// <summary>
  125. /// Call this to draw shapes and other debug draw data.
  126. /// </summary>
  127. private void DrawDebugData()
  128. {
  129. if ((Flags & DebugViewFlags.Shape) == DebugViewFlags.Shape)
  130. {
  131. foreach (Body b in World.BodyList)
  132. {
  133. Transform xf;
  134. b.GetTransform(out xf);
  135. foreach (Fixture f in b.FixtureList)
  136. {
  137. if (b.Enabled == false)
  138. {
  139. DrawShape(f, xf, InactiveShapeColor);
  140. }
  141. else if (b.BodyType == BodyType.Static)
  142. {
  143. DrawShape(f, xf, StaticShapeColor);
  144. }
  145. else if (b.BodyType == BodyType.Kinematic)
  146. {
  147. DrawShape(f, xf, KinematicShapeColor);
  148. }
  149. else if (b.Awake == false)
  150. {
  151. DrawShape(f, xf, SleepingShapeColor);
  152. }
  153. else
  154. {
  155. DrawShape(f, xf, DefaultShapeColor);
  156. }
  157. }
  158. }
  159. }
  160. if ((Flags & DebugViewFlags.ContactPoints) == DebugViewFlags.ContactPoints)
  161. {
  162. const float axisScale = 0.3f;
  163. for (int i = 0; i < _pointCount; ++i)
  164. {
  165. ContactPoint point = _points[i];
  166. if (point.State == PointState.Add)
  167. {
  168. // Add
  169. DrawPoint(point.Position, 0.1f, new Color(0.3f, 0.95f, 0.3f));
  170. }
  171. else if (point.State == PointState.Persist)
  172. {
  173. // Persist
  174. DrawPoint(point.Position, 0.1f, new Color(0.3f, 0.3f, 0.95f));
  175. }
  176. if ((Flags & DebugViewFlags.ContactNormals) == DebugViewFlags.ContactNormals)
  177. {
  178. Vector2 p1 = point.Position;
  179. Vector2 p2 = p1 + axisScale * point.Normal;
  180. DrawSegment(p1, p2, new Color(0.4f, 0.9f, 0.4f));
  181. }
  182. }
  183. _pointCount = 0;
  184. }
  185. if ((Flags & DebugViewFlags.PolygonPoints) == DebugViewFlags.PolygonPoints)
  186. {
  187. foreach (Body body in World.BodyList)
  188. {
  189. foreach (Fixture f in body.FixtureList)
  190. {
  191. PolygonShape polygon = f.Shape as PolygonShape;
  192. if (polygon != null)
  193. {
  194. Transform xf;
  195. body.GetTransform(out xf);
  196. for (int i = 0; i < polygon.Vertices.Count; i++)
  197. {
  198. Vector2 tmp = MathUtils.Multiply(ref xf, polygon.Vertices[i]);
  199. DrawPoint(tmp, 0.1f, Color.Red);
  200. }
  201. }
  202. }
  203. }
  204. }
  205. if ((Flags & DebugViewFlags.Joint) == DebugViewFlags.Joint)
  206. {
  207. foreach (Joint j in World.JointList)
  208. {
  209. DrawJoint(j);
  210. }
  211. }
  212. if ((Flags & DebugViewFlags.Pair) == DebugViewFlags.Pair)
  213. {
  214. Color color = new Color(0.3f, 0.9f, 0.9f);
  215. for (int i = 0; i < World.ContactManager.ContactList.Count; i++)
  216. {
  217. Contact c = World.ContactManager.ContactList[i];
  218. Fixture fixtureA = c.FixtureA;
  219. Fixture fixtureB = c.FixtureB;
  220. AABB aabbA;
  221. fixtureA.GetAABB(out aabbA, 0);
  222. AABB aabbB;
  223. fixtureB.GetAABB(out aabbB, 0);
  224. Vector2 cA = aabbA.Center;
  225. Vector2 cB = aabbB.Center;
  226. DrawSegment(cA, cB, color);
  227. }
  228. }
  229. if ((Flags & DebugViewFlags.AABB) == DebugViewFlags.AABB)
  230. {
  231. Color color = new Color(0.9f, 0.3f, 0.9f);
  232. IBroadPhase bp = World.ContactManager.BroadPhase;
  233. foreach (Body b in World.BodyList)
  234. {
  235. if (b.Enabled == false)
  236. {
  237. continue;
  238. }
  239. foreach (Fixture f in b.FixtureList)
  240. {
  241. for (int t = 0; t < f.ProxyCount; ++t)
  242. {
  243. FixtureProxy proxy = f.Proxies[t];
  244. AABB aabb;
  245. bp.GetFatAABB(proxy.ProxyId, out aabb);
  246. DrawAABB(ref aabb, color);
  247. }
  248. }
  249. }
  250. }
  251. if ((Flags & DebugViewFlags.CenterOfMass) == DebugViewFlags.CenterOfMass)
  252. {
  253. foreach (Body b in World.BodyList)
  254. {
  255. Transform xf;
  256. b.GetTransform(out xf);
  257. xf.Position = b.WorldCenter;
  258. DrawTransform(ref xf);
  259. }
  260. }
  261. if ((Flags & DebugViewFlags.Controllers) == DebugViewFlags.Controllers)
  262. {
  263. for (int i = 0; i < World.ControllerList.Count; i++)
  264. {
  265. Controller controller = World.ControllerList[i];
  266. BuoyancyController buoyancy = controller as BuoyancyController;
  267. if (buoyancy != null)
  268. {
  269. AABB container = buoyancy.Container;
  270. DrawAABB(ref container, Color.LightBlue);
  271. }
  272. }
  273. }
  274. if ((Flags & DebugViewFlags.DebugPanel) == DebugViewFlags.DebugPanel)
  275. {
  276. DrawDebugPanel();
  277. }
  278. }
  279. private void DrawPerformanceGraph()
  280. {
  281. _graphValues.Add(World.UpdateTime);
  282. if (_graphValues.Count > ValuesToGraph + 1)
  283. _graphValues.RemoveAt(0);
  284. float x = PerformancePanelBounds.X;
  285. float deltaX = PerformancePanelBounds.Width / (float)ValuesToGraph;
  286. float yScale = PerformancePanelBounds.Bottom - (float)PerformancePanelBounds.Top;
  287. // we must have at least 2 values to start rendering
  288. if (_graphValues.Count > 2)
  289. {
  290. _max = (int)_graphValues.Max();
  291. _avg = (int)_graphValues.Average();
  292. _min = (int)_graphValues.Min();
  293. if (AdaptiveLimits)
  294. {
  295. MaximumValue = _max;
  296. MinimumValue = 0;
  297. }
  298. // start at last value (newest value added)
  299. // continue until no values are left
  300. for (int i = _graphValues.Count - 1; i > 0; i--)
  301. {
  302. float y1 = PerformancePanelBounds.Bottom -
  303. ((_graphValues[i] / (MaximumValue - MinimumValue)) * yScale);
  304. float y2 = PerformancePanelBounds.Bottom -
  305. ((_graphValues[i - 1] / (MaximumValue - MinimumValue)) * yScale);
  306. Vector2 x1 =
  307. new Vector2(MathHelper.Clamp(x, PerformancePanelBounds.Left, PerformancePanelBounds.Right),
  308. MathHelper.Clamp(y1, PerformancePanelBounds.Top, PerformancePanelBounds.Bottom));
  309. Vector2 x2 =
  310. new Vector2(
  311. MathHelper.Clamp(x + deltaX, PerformancePanelBounds.Left, PerformancePanelBounds.Right),
  312. MathHelper.Clamp(y2, PerformancePanelBounds.Top, PerformancePanelBounds.Bottom));
  313. DrawSegment(x1, x2, Color.LightGreen);
  314. x += deltaX;
  315. }
  316. }
  317. DrawString(PerformancePanelBounds.Right + 10, PerformancePanelBounds.Top, "Max: " + _max);
  318. DrawString(PerformancePanelBounds.Right + 10, PerformancePanelBounds.Center.Y - 7, "Avg: " + _avg);
  319. DrawString(PerformancePanelBounds.Right + 10, PerformancePanelBounds.Bottom - 15, "Min: " + _min);
  320. //Draw background.
  321. _background[0] = new Vector2(PerformancePanelBounds.X, PerformancePanelBounds.Y);
  322. _background[1] = new Vector2(PerformancePanelBounds.X,
  323. PerformancePanelBounds.Y + PerformancePanelBounds.Height);
  324. _background[2] = new Vector2(PerformancePanelBounds.X + PerformancePanelBounds.Width,
  325. PerformancePanelBounds.Y + PerformancePanelBounds.Height);
  326. _background[3] = new Vector2(PerformancePanelBounds.X + PerformancePanelBounds.Width,
  327. PerformancePanelBounds.Y);
  328. DrawSolidPolygon(_background, 4, Color.DarkGray, true);
  329. }
  330. private void DrawDebugPanel()
  331. {
  332. int fixtures = 0;
  333. for (int i = 0; i < World.BodyList.Count; i++)
  334. {
  335. fixtures += World.BodyList[i].FixtureList.Count;
  336. }
  337. int x = (int)DebugPanelPosition.X;
  338. int y = (int)DebugPanelPosition.Y;
  339. DrawString(x, y, "Objects:" +
  340. "\n- Bodies: " + World.BodyList.Count +
  341. "\n- Fixtures: " + fixtures +
  342. "\n- Contacts: " + World.ContactList.Count +
  343. "\n- Joints: " + World.JointList.Count +
  344. "\n- Controllers: " + World.ControllerList.Count +
  345. "\n- Proxies: " + World.ProxyCount);
  346. DrawString(x + 110, y, "Update time:" +
  347. "\n- Body: " + World.SolveUpdateTime +
  348. "\n- Contact: " + World.ContactsUpdateTime +
  349. "\n- CCD: " + World.ContinuousPhysicsTime +
  350. "\n- Joint: " + World.Island.JointUpdateTime +
  351. "\n- Controller: " + World.ControllersUpdateTime +
  352. "\n- Total: " + World.UpdateTime);
  353. }
  354. public void DrawAABB(ref AABB aabb, Color color)
  355. {
  356. Vector2[] verts = new Vector2[4];
  357. verts[0] = new Vector2(aabb.LowerBound.X, aabb.LowerBound.Y);
  358. verts[1] = new Vector2(aabb.UpperBound.X, aabb.LowerBound.Y);
  359. verts[2] = new Vector2(aabb.UpperBound.X, aabb.UpperBound.Y);
  360. verts[3] = new Vector2(aabb.LowerBound.X, aabb.UpperBound.Y);
  361. DrawPolygon(verts, 4, color);
  362. }
  363. private void DrawJoint(Joint joint)
  364. {
  365. if (!joint.Enabled)
  366. return;
  367. Body b1 = joint.BodyA;
  368. Body b2 = joint.BodyB;
  369. Transform xf1, xf2;
  370. b1.GetTransform(out xf1);
  371. Vector2 x2 = Vector2.Zero;
  372. // WIP David
  373. if (!joint.IsFixedType())
  374. {
  375. b2.GetTransform(out xf2);
  376. x2 = xf2.Position;
  377. }
  378. Vector2 p1 = joint.WorldAnchorA;
  379. Vector2 p2 = joint.WorldAnchorB;
  380. Vector2 x1 = xf1.Position;
  381. Color color = new Color(0.5f, 0.8f, 0.8f);
  382. switch (joint.JointType)
  383. {
  384. case JointType.Distance:
  385. DrawSegment(p1, p2, color);
  386. break;
  387. case JointType.Pulley:
  388. PulleyJoint pulley = (PulleyJoint)joint;
  389. Vector2 s1 = pulley.GroundAnchorA;
  390. Vector2 s2 = pulley.GroundAnchorB;
  391. DrawSegment(s1, p1, color);
  392. DrawSegment(s2, p2, color);
  393. DrawSegment(s1, s2, color);
  394. break;
  395. case JointType.FixedMouse:
  396. DrawPoint(p1, 0.5f, new Color(0.0f, 1.0f, 0.0f));
  397. DrawSegment(p1, p2, new Color(0.8f, 0.8f, 0.8f));
  398. break;
  399. case JointType.Revolute:
  400. //DrawSegment(x2, p1, color);
  401. DrawSegment(p2, p1, color);
  402. DrawSolidCircle(p2, 0.1f, Vector2.Zero, Color.Red);
  403. DrawSolidCircle(p1, 0.1f, Vector2.Zero, Color.Blue);
  404. break;
  405. case JointType.FixedAngle:
  406. //Should not draw anything.
  407. break;
  408. case JointType.FixedRevolute:
  409. DrawSegment(x1, p1, color);
  410. DrawSolidCircle(p1, 0.1f, Vector2.Zero, Color.Pink);
  411. break;
  412. case JointType.FixedLine:
  413. DrawSegment(x1, p1, color);
  414. DrawSegment(p1, p2, color);
  415. break;
  416. case JointType.FixedDistance:
  417. DrawSegment(x1, p1, color);
  418. DrawSegment(p1, p2, color);
  419. break;
  420. case JointType.FixedPrismatic:
  421. DrawSegment(x1, p1, color);
  422. DrawSegment(p1, p2, color);
  423. break;
  424. case JointType.Gear:
  425. DrawSegment(x1, x2, color);
  426. break;
  427. //case JointType.Weld:
  428. // break;
  429. default:
  430. DrawSegment(x1, p1, color);
  431. DrawSegment(p1, p2, color);
  432. DrawSegment(x2, p2, color);
  433. break;
  434. }
  435. }
  436. public void DrawShape(Fixture fixture, Transform xf, Color color)
  437. {
  438. switch (fixture.ShapeType)
  439. {
  440. case ShapeType.Circle:
  441. {
  442. CircleShape circle = (CircleShape)fixture.Shape;
  443. Vector2 center = MathUtils.Multiply(ref xf, circle.Position);
  444. float radius = circle.Radius;
  445. Vector2 axis = xf.R.Col1;
  446. DrawSolidCircle(center, radius, axis, color);
  447. }
  448. break;
  449. case ShapeType.Polygon:
  450. {
  451. PolygonShape poly = (PolygonShape)fixture.Shape;
  452. int vertexCount = poly.Vertices.Count;
  453. Debug.Assert(vertexCount <= Settings.MaxPolygonVertices);
  454. for (int i = 0; i < vertexCount; ++i)
  455. {
  456. _tempVertices[i] = MathUtils.Multiply(ref xf, poly.Vertices[i]);
  457. }
  458. DrawSolidPolygon(_tempVertices, vertexCount, color);
  459. }
  460. break;
  461. case ShapeType.Edge:
  462. {
  463. EdgeShape edge = (EdgeShape)fixture.Shape;
  464. Vector2 v1 = MathUtils.Multiply(ref xf, edge.Vertex1);
  465. Vector2 v2 = MathUtils.Multiply(ref xf, edge.Vertex2);
  466. DrawSegment(v1, v2, color);
  467. }
  468. break;
  469. case ShapeType.Loop:
  470. {
  471. LoopShape loop = (LoopShape)fixture.Shape;
  472. int count = loop.Vertices.Count;
  473. Vector2 v1 = MathUtils.Multiply(ref xf, loop.Vertices[count - 1]);
  474. DrawCircle(v1, 0.05f, color);
  475. for (int i = 0; i < count; ++i)
  476. {
  477. Vector2 v2 = MathUtils.Multiply(ref xf, loop.Vertices[i]);
  478. DrawSegment(v1, v2, color);
  479. v1 = v2;
  480. }
  481. }
  482. break;
  483. }
  484. }
  485. public override void DrawPolygon(Vector2[] vertices, int count, float red, float green, float blue)
  486. {
  487. DrawPolygon(vertices, count, new Color(red, green, blue));
  488. }
  489. public void DrawPolygon(Vector2[] vertices, int count, Color color)
  490. {
  491. if (!_primitiveBatch.IsReady())
  492. {
  493. throw new InvalidOperationException("BeginCustomDraw must be called before drawing anything.");
  494. }
  495. for (int i = 0; i < count - 1; i++)
  496. {
  497. _primitiveBatch.AddVertex(vertices[i], color, PrimitiveType.LineList);
  498. _primitiveBatch.AddVertex(vertices[i + 1], color, PrimitiveType.LineList);
  499. }
  500. _primitiveBatch.AddVertex(vertices[count - 1], color, PrimitiveType.LineList);
  501. _primitiveBatch.AddVertex(vertices[0], color, PrimitiveType.LineList);
  502. }
  503. public override void DrawSolidPolygon(Vector2[] vertices, int count, float red, float green, float blue)
  504. {
  505. DrawSolidPolygon(vertices, count, new Color(red, green, blue), true);
  506. }
  507. public void DrawSolidPolygon(Vector2[] vertices, int count, Color color)
  508. {
  509. DrawSolidPolygon(vertices, count, color, true);
  510. }
  511. public void DrawSolidPolygon(Vector2[] vertices, int count, Color color, bool outline)
  512. {
  513. if (!_primitiveBatch.IsReady())
  514. {
  515. throw new InvalidOperationException("BeginCustomDraw must be called before drawing anything.");
  516. }
  517. if (count == 2)
  518. {
  519. DrawPolygon(vertices, count, color);
  520. return;
  521. }
  522. Color colorFill = color * (outline ? 0.5f : 1.0f);
  523. for (int i = 1; i < count - 1; i++)
  524. {
  525. _primitiveBatch.AddVertex(vertices[0], colorFill, PrimitiveType.TriangleList);
  526. _primitiveBatch.AddVertex(vertices[i], colorFill, PrimitiveType.TriangleList);
  527. _primitiveBatch.AddVertex(vertices[i + 1], colorFill, PrimitiveType.TriangleList);
  528. }
  529. if (outline)
  530. {
  531. DrawPolygon(vertices, count, color);
  532. }
  533. }
  534. public override void DrawCircle(Vector2 center, float radius, float red, float green, float blue)
  535. {
  536. DrawCircle(center, radius, new Color(red, green, blue));
  537. }
  538. public void DrawCircle(Vector2 center, float radius, Color color)
  539. {
  540. if (!_primitiveBatch.IsReady())
  541. {
  542. throw new InvalidOperationException("BeginCustomDraw must be called before drawing anything.");
  543. }
  544. const double increment = Math.PI * 2.0 / CircleSegments;
  545. double theta = 0.0;
  546. for (int i = 0; i < CircleSegments; i++)
  547. {
  548. Vector2 v1 = center + radius * new Vector2((float)Math.Cos(theta), (float)Math.Sin(theta));
  549. Vector2 v2 = center +
  550. radius *
  551. new Vector2((float)Math.Cos(theta + increment), (float)Math.Sin(theta + increment));
  552. _primitiveBatch.AddVertex(v1, color, PrimitiveType.LineList);
  553. _primitiveBatch.AddVertex(v2, color, PrimitiveType.LineList);
  554. theta += increment;
  555. }
  556. }
  557. public override void DrawSolidCircle(Vector2 center, float radius, Vector2 axis, float red, float green,
  558. float blue)
  559. {
  560. DrawSolidCircle(center, radius, axis, new Color(red, green, blue));
  561. }
  562. public void DrawSolidCircle(Vector2 center, float radius, Vector2 axis, Color color)
  563. {
  564. if (!_primitiveBatch.IsReady())
  565. {
  566. throw new InvalidOperationException("BeginCustomDraw must be called before drawing anything.");
  567. }
  568. const double increment = Math.PI * 2.0 / CircleSegments;
  569. double theta = 0.0;
  570. Color colorFill = color * 0.5f;
  571. Vector2 v0 = center + radius * new Vector2((float)Math.Cos(theta), (float)Math.Sin(theta));
  572. theta += increment;
  573. for (int i = 1; i < CircleSegments - 1; i++)
  574. {
  575. Vector2 v1 = center + radius * new Vector2((float)Math.Cos(theta), (float)Math.Sin(theta));
  576. Vector2 v2 = center +
  577. radius *
  578. new Vector2((float)Math.Cos(theta + increment), (float)Math.Sin(theta + increment));
  579. _primitiveBatch.AddVertex(v0, colorFill, PrimitiveType.TriangleList);
  580. _primitiveBatch.AddVertex(v1, colorFill, PrimitiveType.TriangleList);
  581. _primitiveBatch.AddVertex(v2, colorFill, PrimitiveType.TriangleList);
  582. theta += increment;
  583. }
  584. DrawCircle(center, radius, color);
  585. DrawSegment(center, center + axis * radius, color);
  586. }
  587. public override void DrawSegment(Vector2 start, Vector2 end, float red, float green, float blue)
  588. {
  589. DrawSegment(start, end, new Color(red, green, blue));
  590. }
  591. public void DrawSegment(Vector2 start, Vector2 end, Color color)
  592. {
  593. if (!_primitiveBatch.IsReady())
  594. {
  595. throw new InvalidOperationException("BeginCustomDraw must be called before drawing anything.");
  596. }
  597. _primitiveBatch.AddVertex(start, color, PrimitiveType.LineList);
  598. _primitiveBatch.AddVertex(end, color, PrimitiveType.LineList);
  599. }
  600. public override void DrawTransform(ref Transform transform)
  601. {
  602. const float axisScale = 0.4f;
  603. Vector2 p1 = transform.Position;
  604. Vector2 p2 = p1 + axisScale * transform.R.Col1;
  605. DrawSegment(p1, p2, Color.Red);
  606. p2 = p1 + axisScale * transform.R.Col2;
  607. DrawSegment(p1, p2, Color.Green);
  608. }
  609. public void DrawPoint(Vector2 p, float size, Color color)
  610. {
  611. Vector2[] verts = new Vector2[4];
  612. float hs = size / 2.0f;
  613. verts[0] = p + new Vector2(-hs, -hs);
  614. verts[1] = p + new Vector2(hs, -hs);
  615. verts[2] = p + new Vector2(hs, hs);
  616. verts[3] = p + new Vector2(-hs, hs);
  617. DrawSolidPolygon(verts, 4, color, true);
  618. }
  619. public void DrawString(int x, int y, string s, params object[] args)
  620. {
  621. _stringData.Add(new StringData(x, y, s, args, TextColor));
  622. }
  623. public void DrawArrow(Vector2 start, Vector2 end, float length, float width, bool drawStartIndicator,
  624. Color color)
  625. {
  626. // Draw connection segment between start- and end-point
  627. DrawSegment(start, end, color);
  628. // Precalculate halfwidth
  629. float halfWidth = width / 2;
  630. // Create directional reference
  631. Vector2 rotation = (start - end);
  632. rotation.Normalize();
  633. // Calculate angle of directional vector
  634. float angle = (float)Math.Atan2(rotation.X, -rotation.Y);
  635. // Create matrix for rotation
  636. Matrix rotMatrix = Matrix.CreateRotationZ(angle);
  637. // Create translation matrix for end-point
  638. Matrix endMatrix = Matrix.CreateTranslation(end.X, end.Y, 0);
  639. // Setup arrow end shape
  640. Vector2[] verts = new Vector2[3];
  641. verts[0] = new Vector2(0, 0);
  642. verts[1] = new Vector2(-halfWidth, -length);
  643. verts[2] = new Vector2(halfWidth, -length);
  644. // Rotate end shape
  645. Vector2.Transform(verts, ref rotMatrix, verts);
  646. // Translate end shape
  647. Vector2.Transform(verts, ref endMatrix, verts);
  648. // Draw arrow end shape
  649. DrawSolidPolygon(verts, 3, color, false);
  650. if (drawStartIndicator)
  651. {
  652. // Create translation matrix for start
  653. Matrix startMatrix = Matrix.CreateTranslation(start.X, start.Y, 0);
  654. // Setup arrow start shape
  655. Vector2[] baseVerts = new Vector2[4];
  656. baseVerts[0] = new Vector2(-halfWidth, length / 4);
  657. baseVerts[1] = new Vector2(halfWidth, length / 4);
  658. baseVerts[2] = new Vector2(halfWidth, 0);
  659. baseVerts[3] = new Vector2(-halfWidth, 0);
  660. // Rotate start shape
  661. Vector2.Transform(baseVerts, ref rotMatrix, baseVerts);
  662. // Translate start shape
  663. Vector2.Transform(baseVerts, ref startMatrix, baseVerts);
  664. // Draw start shape
  665. DrawSolidPolygon(baseVerts, 4, color, false);
  666. }
  667. }
  668. public void RenderDebugData(ref Matrix projection, ref Matrix view)
  669. {
  670. if (!Enabled)
  671. {
  672. return;
  673. }
  674. //Nothing is enabled - don't draw the debug view.
  675. if (Flags == 0)
  676. return;
  677. _device.RasterizerState = RasterizerState.CullNone;
  678. _device.DepthStencilState = DepthStencilState.Default;
  679. _primitiveBatch.Begin(ref projection, ref view);
  680. DrawDebugData();
  681. _primitiveBatch.End();
  682. if ((Flags & DebugViewFlags.PerformanceGraph) == DebugViewFlags.PerformanceGraph)
  683. {
  684. _primitiveBatch.Begin(ref _localProjection, ref _localView);
  685. DrawPerformanceGraph();
  686. _primitiveBatch.End();
  687. }
  688. // begin the sprite batch effect
  689. _batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
  690. // draw any strings we have
  691. for (int i = 0; i < _stringData.Count; i++)
  692. {
  693. _batch.DrawString(_font, string.Format(_stringData[i].S, _stringData[i].Args),
  694. new Vector2(_stringData[i].X + 1f, _stringData[i].Y + 1f), Color.Black);
  695. _batch.DrawString(_font, string.Format(_stringData[i].S, _stringData[i].Args),
  696. new Vector2(_stringData[i].X, _stringData[i].Y), _stringData[i].Color);
  697. }
  698. // end the sprite batch effect
  699. _batch.End();
  700. _stringData.Clear();
  701. }
  702. public void RenderDebugData(ref Matrix projection)
  703. {
  704. if (!Enabled)
  705. {
  706. return;
  707. }
  708. Matrix view = Matrix.Identity;
  709. RenderDebugData(ref projection, ref view);
  710. }
  711. public void LoadContent(GraphicsDevice device, ContentManager content)
  712. {
  713. // Create a new SpriteBatch, which can be used to draw textures.
  714. _device = device;
  715. _batch = new SpriteBatch(_device);
  716. _primitiveBatch = new PrimitiveBatch(_device, 1000);
  717. _font = content.Load<SpriteFont>("font");
  718. _stringData = new List<StringData>();
  719. _localProjection = Matrix.CreateOrthographicOffCenter(0f, _device.Viewport.Width, _device.Viewport.Height,
  720. 0f, 0f, 1f);
  721. _localView = Matrix.Identity;
  722. }
  723. #region Nested type: ContactPoint
  724. private struct ContactPoint
  725. {
  726. public Vector2 Normal;
  727. public Vector2 Position;
  728. public PointState State;
  729. }
  730. #endregion
  731. #region Nested type: StringData
  732. private struct StringData
  733. {
  734. public object[] Args;
  735. public Color Color;
  736. public string S;
  737. public int X, Y;
  738. public StringData(int x, int y, string s, object[] args, Color color)
  739. {
  740. X = x;
  741. Y = y;
  742. S = s;
  743. Args = args;
  744. Color = color;
  745. }
  746. }
  747. #endregion
  748. }
  749. }