123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- //-----------------------------------------------------------------------------
- // DebugDraw.cs
- //
- // Microsoft XNA Community Game Platform
- // Copyright (C) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- using System;
- using System.Diagnostics;
- using System.Collections.Generic;
- using Microsoft.Xna.Framework;
- using Microsoft.Xna.Framework.Graphics;
- namespace CollisionSample
- {
- /// <summary>
- /// Debug drawing routines for common collision shapes. These are not designed to be the most
- /// efficent way to submit geometry to the graphics device as they are intended for use in
- /// visualizing collision for debugging purposes.
- /// </summary>
- public class DebugDraw : IDisposable
- {
- #region Constants
- public const int MAX_VERTS = 2000;
- public const int MAX_INDICES = 2000;
- // Indices for drawing the edges of a cube, given the vertex ordering
- // used by Bounding(Frustum|Box|OrientedBox).GetCorners()
- static ushort[] cubeIndices = new ushort[] { 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 };
-
- #endregion
- #region Fields
- BasicEffect basicEffect;
- DynamicVertexBuffer vertexBuffer;
- DynamicIndexBuffer indexBuffer;
- ushort[] Indices = new ushort[MAX_INDICES];
- VertexPositionColor[] Vertices = new VertexPositionColor[MAX_VERTS];
- int IndexCount;
- int VertexCount;
- #endregion
- #region Initialization
- public DebugDraw(GraphicsDevice device)
- {
- vertexBuffer = new DynamicVertexBuffer(device, typeof(VertexPositionColor), MAX_VERTS, BufferUsage.WriteOnly);
- indexBuffer = new DynamicIndexBuffer(device, typeof(ushort), MAX_INDICES, BufferUsage.WriteOnly);
- basicEffect = new BasicEffect(device); //(device, null);
- basicEffect.LightingEnabled = false;
- basicEffect.VertexColorEnabled = true;
- basicEffect.TextureEnabled = false;
- }
- #endregion
- #region Dispose
- ~DebugDraw()
- {
- Dispose(false);
- }
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (vertexBuffer != null)
- vertexBuffer.Dispose();
- if (indexBuffer != null)
- indexBuffer.Dispose();
- if (basicEffect != null)
- basicEffect.Dispose();
- }
- }
- #endregion
- #region Draw
- /// <summary>
- /// Starts debug drawing by setting the required render states and camera information
- /// </summary>
- public void Begin(Matrix view, Matrix projection)
- {
- basicEffect.World = Matrix.Identity;
- basicEffect.View = view;
- basicEffect.Projection = projection;
- VertexCount = 0;
- IndexCount = 0;
- }
- /// <summary>
- /// Ends debug drawing and restores standard render states
- /// </summary>
- public void End()
- {
- FlushDrawing();
- }
- public void DrawWireShape(Vector3[] positionArray, ushort[] indexArray, Color color)
- {
- if (Reserve(positionArray.Length, indexArray.Length))
- {
- for (int i = 0; i < indexArray.Length; i++)
- Indices[IndexCount++] = (ushort)(VertexCount + indexArray[i]);
- for (int i = 0; i < positionArray.Length; i++)
- Vertices[VertexCount++] = new VertexPositionColor(positionArray[i], color);
- }
- }
- // Draw any queued objects and reset our line buffers
- private void FlushDrawing()
- {
- if (IndexCount > 0)
- {
- vertexBuffer.SetData(Vertices, 0, VertexCount, SetDataOptions.Discard);
- indexBuffer.SetData(Indices, 0, IndexCount, SetDataOptions.Discard);
- GraphicsDevice device = basicEffect.GraphicsDevice;
- device.SetVertexBuffer(vertexBuffer);
- device.Indices = indexBuffer;
- foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
- {
- pass.Apply();
- device.DrawIndexedPrimitives(PrimitiveType.LineList, 0, 0, VertexCount, 0, IndexCount / 2);
- }
- device.SetVertexBuffer(null);
- device.Indices = null;
- }
- IndexCount = 0;
- VertexCount = 0;
- }
- // Check if there's enough space to draw an object with the given vertex/index counts.
- // If necessary, call FlushDrawing() to make room.
- private bool Reserve(int numVerts, int numIndices)
- {
- if(numVerts > MAX_VERTS || numIndices > MAX_INDICES)
- {
- // Whatever it is, we can't draw it
- return false;
- }
- if (VertexCount + numVerts > MAX_VERTS || IndexCount + numIndices >= MAX_INDICES)
- {
- // We can draw it, but we need to make room first
- FlushDrawing();
- }
- return true;
- }
- /// <summary>
- /// Renders a 2D grid (must be called within a Begin/End pair)
- /// </summary>
- /// <param name="xAxis">Vector direction for the local X-axis direction of the grid</param>
- /// <param name="yAxis">Vector direction for the local Y-axis of the grid</param>
- /// <param name="origin">3D starting anchor point for the grid</param>
- /// <param name="iXDivisions">Number of divisions in the local X-axis direction</param>
- /// <param name="iYDivisions">Number of divisions in the local Y-axis direction</param>
- /// <param name="color">Color of the grid lines</param>
- public void DrawWireGrid(Vector3 xAxis, Vector3 yAxis, Vector3 origin, int iXDivisions, int iYDivisions, Color color)
- {
- Vector3 pos, step;
- pos = origin;
- step = xAxis / iXDivisions;
- for (int i = 0; i <= iXDivisions; i++)
- {
- DrawLine(pos, pos + yAxis, color);
- pos += step;
- }
- pos = origin;
- step = yAxis / iYDivisions;
- for (int i = 0; i <= iYDivisions; i++)
- {
- DrawLine(pos, pos + xAxis, color);
- pos += step;
- }
- }
- /// <summary>
- /// Renders the outline of a bounding frustum
- /// </summary>
- /// <param name="frustum">Bounding frustum to render</param>
- /// <param name="color">Color of the frustum lines</param>
- public void DrawWireFrustum(BoundingFrustum frustum, Color color)
- {
- DrawWireShape(frustum.GetCorners(), cubeIndices, color);
- }
- /// <summary>
- /// Renders the outline of an axis-aligned bounding box
- /// </summary>
- /// <param name="box">Bounding box to render</param>
- /// <param name="color">Color of the box lines</param>
- public void DrawWireBox(BoundingBox box, Color color)
- {
- DrawWireShape(box.GetCorners(), cubeIndices, color);
- }
- /// <summary>
- /// Renders the outline of an oriented bounding box
- /// </summary>
- /// <param name="box">Oriented bounding box to render</param>
- /// <param name="color">Color of the box lines</param>
- public void DrawWireBox(BoundingOrientedBox box, Color color)
- {
- DrawWireShape(box.GetCorners(), cubeIndices, color);
- }
- /// <summary>
- /// Renders a circular ring (tessellated circle)
- /// </summary>
- /// <param name="origin">Center point for the ring</param>
- /// <param name="majorAxis">Direction of the major-axis of the circle</param>
- /// <param name="minorAxis">Direction of hte minor-axis of the circle</param>
- /// <param name="color">Color of the ring lines</param>
- public void DrawRing(Vector3 origin, Vector3 majorAxis, Vector3 minorAxis, Color color)
- {
- const int RING_SEGMENTS = 32;
- const float fAngleDelta = 2.0F * (float)Math.PI / RING_SEGMENTS;
- if (Reserve(RING_SEGMENTS, RING_SEGMENTS * 2))
- {
- for (int i = 0; i < RING_SEGMENTS; i++)
- {
- Indices[IndexCount++] = (ushort)(VertexCount + i);
- Indices[IndexCount++] = (ushort)(VertexCount + (i + 1) % RING_SEGMENTS);
- }
- float cosDelta = (float)Math.Cos(fAngleDelta);
- float sinDelta = (float)Math.Sin(fAngleDelta);
- float cosAcc = 1;
- float sinAcc = 0;
- for (int i = 0; i < RING_SEGMENTS; ++i)
- {
- Vector3 pos = new Vector3(majorAxis.X * cosAcc + minorAxis.X * sinAcc + origin.X,
- majorAxis.Y * cosAcc + minorAxis.Y * sinAcc + origin.Y,
- majorAxis.Z * cosAcc + minorAxis.Z * sinAcc + origin.Z);
- Vertices[VertexCount++] = new VertexPositionColor(pos, color);
- float newCos = cosAcc * cosDelta - sinAcc * sinDelta;
- float newSin = cosAcc * sinDelta + sinAcc * cosDelta;
- cosAcc = newCos;
- sinAcc = newSin;
- }
- }
- }
- /// <summary>
- /// Renders the outline of a bounding sphere.
- ///
- /// This code assumes that the model and view matrices contain only rigid motion.
- /// </summary>
- /// <param name="sphere">Bounding sphere to render</param>
- /// <param name="color">Color of the outline lines</param>
- public void DrawWireSphere(BoundingSphere sphere, Color color)
- {
- // Invert the modelview matrix to get direction vectors
- // in screen space, so we can draw a circle that always
- // faces the camera.
- Matrix view = basicEffect.World * basicEffect.View;
- Matrix.Transpose(ref view, out view);
- DrawRing(sphere.Center, view.Right * sphere.Radius, view.Up * sphere.Radius, color);
- }
- /// <summary>
- /// Draw a ray of the given length
- /// </summary>
- /// <param name="ray"></param>
- /// <param name="color"></param>
- /// <param name="length"></param>
- public void DrawRay(Ray ray, Color color, float length)
- {
- DrawLine(ray.Position, ray.Position + ray.Direction * length, color);
- }
- public void DrawLine(Vector3 v0, Vector3 v1, Color color)
- {
- if(Reserve(2, 2))
- {
- Indices[IndexCount++] = (ushort)VertexCount;
- Indices[IndexCount++] = (ushort)(VertexCount+1);
- Vertices[VertexCount++] = new VertexPositionColor(v0, color);
- Vertices[VertexCount++] = new VertexPositionColor(v1, color);
- }
- }
- public void DrawWireTriangle(Vector3 v0, Vector3 v1, Vector3 v2, Color color)
- {
- if(Reserve(3, 6))
- {
- Indices[IndexCount++] = (ushort)(VertexCount+0);
- Indices[IndexCount++] = (ushort)(VertexCount+1);
- Indices[IndexCount++] = (ushort)(VertexCount+1);
- Indices[IndexCount++] = (ushort)(VertexCount+2);
- Indices[IndexCount++] = (ushort)(VertexCount+2);
- Indices[IndexCount++] = (ushort)(VertexCount+0);
- Vertices[VertexCount++] = new VertexPositionColor(v0, color);
- Vertices[VertexCount++] = new VertexPositionColor(v1, color);
- Vertices[VertexCount++] = new VertexPositionColor(v2, color);
- }
- }
- public void DrawWireTriangle(Triangle t, Color color)
- {
- DrawWireTriangle(t.V0, t.V1, t.V2, color);
- }
- #endregion
- }
- }
|