using
System;
using
Microsoft.Xna.Framework;
using
Microsoft.Xna.Framework.Graphics;
namespace
FarseerPhysics.DebugViews
{
public
class
PrimitiveBatch : IDisposable
{
private
const
int
DefaultBufferSize = 500;
private
BasicEffect _basicEffect;
private
GraphicsDevice _device;
private
bool
_hasBegun;
private
bool
_isDisposed;
private
VertexPositionColor[] _lineVertices;
private
int
_lineVertsCount;
private
VertexPositionColor[] _triangleVertices;
private
int
_triangleVertsCount;
/// <summary>
/// the constructor creates a new PrimitiveBatch and sets up all of the internals
/// that PrimitiveBatch will need.
/// </summary>
/// <param name="graphicsDevice">The graphics device.</param>
public
PrimitiveBatch(GraphicsDevice graphicsDevice)
:
this
(graphicsDevice, DefaultBufferSize)
{
}
public
PrimitiveBatch(GraphicsDevice graphicsDevice,
int
bufferSize)
{
if
(graphicsDevice ==
null
)
{
throw
new
ArgumentNullException(
"graphicsDevice"
);
}
_device = graphicsDevice;
_triangleVertices =
new
VertexPositionColor[bufferSize - bufferSize % 3];
_lineVertices =
new
VertexPositionColor[bufferSize - bufferSize % 2];
_basicEffect =
new
BasicEffect(graphicsDevice);
_basicEffect.VertexColorEnabled =
true
;
}
#region IDisposable Members
public
void
Dispose()
{
Dispose(
true
);
GC.SuppressFinalize(
this
);
}
#endregion
public
void
SetProjection(
ref
Matrix projection)
{
_basicEffect.Projection = projection;
}
protected
virtual
void
Dispose(
bool
disposing)
{
if
(disposing && !_isDisposed)
{
if
(_basicEffect !=
null
)
_basicEffect.Dispose();
_isDisposed =
true
;
}
}
/// <summary>
/// Begin is called to tell the PrimitiveBatch what kind of primitives will be
/// drawn, and to prepare the graphics card to render those primitives.
/// </summary>
/// <param name="projection">The projection.</param>
/// <param name="view">The view.</param>
public
void
Begin(
ref
Matrix projection,
ref
Matrix view)
{
if
(_hasBegun)
{
throw
new
InvalidOperationException(
"End must be called before Begin can be called again."
);
}
_basicEffect.Projection = projection;
_basicEffect.View = view;
_basicEffect.CurrentTechnique.Passes[0].Apply();
_hasBegun =
true
;
}
public
bool
IsReady()
{
return
_hasBegun;
}
public
void
AddVertex(Vector2 vertex, Color color, PrimitiveType primitiveType)
{
if
(!_hasBegun)
{
throw
new
InvalidOperationException(
"Begin must be called before AddVertex can be called."
);
}
if
(primitiveType == PrimitiveType.LineStrip ||
primitiveType == PrimitiveType.TriangleStrip)
{
throw
new
NotSupportedException(
"The specified primitiveType is not supported by PrimitiveBatch."
);
}
if
(primitiveType == PrimitiveType.TriangleList)
{
if
(_triangleVertsCount >= _triangleVertices.Length)
{
FlushTriangles();
}
_triangleVertices[_triangleVertsCount].Position =
new
Vector3(vertex, -0.1f);
_triangleVertices[_triangleVertsCount].Color = color;
_triangleVertsCount++;
}
if
(primitiveType == PrimitiveType.LineList)
{
if
(_lineVertsCount >= _lineVertices.Length)
{
FlushLines();
}
_lineVertices[_lineVertsCount].Position =
new
Vector3(vertex, 0f);
_lineVertices[_lineVertsCount].Color = color;
_lineVertsCount++;
}
}
/// <summary>
/// End is called once all the primitives have been drawn using AddVertex.
/// it will call Flush to actually submit the draw call to the graphics card, and
/// then tell the basic effect to end.
/// </summary>
public
void
End()
{
if
(!_hasBegun)
{
throw
new
InvalidOperationException(
"Begin must be called before End can be called."
);
}
FlushTriangles();
FlushLines();
_hasBegun =
false
;
}
private
void
FlushTriangles()
{
if
(!_hasBegun)
{
throw
new
InvalidOperationException(
"Begin must be called before Flush can be called."
);
}
if
(_triangleVertsCount >= 3)
{
int
primitiveCount = _triangleVertsCount / 3;
_device.SamplerStates[0] = SamplerState.AnisotropicClamp;
_device.DrawUserPrimitives(PrimitiveType.TriangleList, _triangleVertices, 0, primitiveCount);
_triangleVertsCount -= primitiveCount * 3;
}
}
private
void
FlushLines()
{
if
(!_hasBegun)
{
throw
new
InvalidOperationException(
"Begin must be called before Flush can be called."
);
}
if
(_lineVertsCount >= 2)
{
int
primitiveCount = _lineVertsCount / 2;
_device.SamplerStates[0] = SamplerState.AnisotropicClamp;
_device.DrawUserPrimitives(PrimitiveType.LineList, _lineVertices, 0, primitiveCount);
_lineVertsCount -= primitiveCount * 2;
}
}
}
}