axiosengine/axios/DrawingSystem/LineBatch.cs

183 lines
6.4 KiB
C#

using System;
using FarseerPhysics.Collision.Shapes;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace FarseerPhysics.SamplesFramework
{
public class LineBatch : IDisposable
{
private const int DefaultBufferSize = 500;
// a basic effect, which contains the shaders that we will use to draw our
// primitives.
private BasicEffect _basicEffect;
// the device that we will issue draw calls to.
private GraphicsDevice _device;
// hasBegun is flipped to true once Begin is called, and is used to make
// sure users don't call End before Begin is called.
private bool _hasBegun;
private bool _isDisposed;
private VertexPositionColor[] _lineVertices;
private int _lineVertsCount;
public LineBatch(GraphicsDevice graphicsDevice)
: this(graphicsDevice, DefaultBufferSize)
{
}
public LineBatch(GraphicsDevice graphicsDevice, int bufferSize)
{
if (graphicsDevice == null)
{
throw new ArgumentNullException("graphicsDevice");
}
_device = graphicsDevice;
_lineVertices = new VertexPositionColor[bufferSize - bufferSize % 2];
// set up a new basic effect, and enable vertex colors.
_basicEffect = new BasicEffect(graphicsDevice);
_basicEffect.VertexColorEnabled = true;
}
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
protected virtual void Dispose(bool disposing)
{
if (disposing && !_isDisposed)
{
if (_basicEffect != null)
_basicEffect.Dispose();
_isDisposed = true;
}
}
public void Begin(Matrix projection, Matrix view)
{
if (_hasBegun)
{
throw new InvalidOperationException("End must be called before Begin can be called again.");
}
_device.SamplerStates[0] = SamplerState.AnisotropicClamp;
//tell our basic effect to begin.
_basicEffect.Projection = projection;
_basicEffect.View = view;
_basicEffect.CurrentTechnique.Passes[0].Apply();
// flip the error checking boolean. It's now ok to call DrawLineShape, Flush,
// and End.
_hasBegun = true;
}
public void DrawLineShape(Shape shape)
{
DrawLineShape(shape, Color.Black);
}
public void DrawLineShape(Shape shape, Color color)
{
if (!_hasBegun)
{
throw new InvalidOperationException("Begin must be called before DrawLineShape can be called.");
}
if (shape.ShapeType != ShapeType.Edge &&
shape.ShapeType != ShapeType.Loop)
{
throw new NotSupportedException("The specified shapeType is not supported by LineBatch.");
}
if (shape.ShapeType == ShapeType.Edge)
{
if (_lineVertsCount >= _lineVertices.Length)
{
Flush();
}
EdgeShape edge = (EdgeShape)shape;
_lineVertices[_lineVertsCount].Position = new Vector3(edge.Vertex1, 0f);
_lineVertices[_lineVertsCount + 1].Position = new Vector3(edge.Vertex2, 0f);
_lineVertices[_lineVertsCount].Color = _lineVertices[_lineVertsCount + 1].Color = color;
_lineVertsCount += 2;
}
else if (shape.ShapeType == ShapeType.Loop)
{
LoopShape loop = (LoopShape)shape;
for (int i = 0; i < loop.Vertices.Count; ++i)
{
if (_lineVertsCount >= _lineVertices.Length)
{
Flush();
}
_lineVertices[_lineVertsCount].Position = new Vector3(loop.Vertices[i], 0f);
_lineVertices[_lineVertsCount + 1].Position = new Vector3(loop.Vertices.NextVertex(i), 0f);
_lineVertices[_lineVertsCount].Color = _lineVertices[_lineVertsCount + 1].Color = color;
_lineVertsCount += 2;
}
}
}
public void DrawLine(Vector2 v1, Vector2 v2)
{
DrawLine(v1, v2, Color.Black);
}
public void DrawLine(Vector2 v1, Vector2 v2, Color color)
{
if (!_hasBegun)
{
throw new InvalidOperationException("Begin must be called before DrawLineShape can be called.");
}
if (_lineVertsCount >= _lineVertices.Length)
{
Flush();
}
_lineVertices[_lineVertsCount].Position = new Vector3(v1, 0f);
_lineVertices[_lineVertsCount + 1].Position = new Vector3(v2, 0f);
_lineVertices[_lineVertsCount].Color = _lineVertices[_lineVertsCount + 1].Color = color;
_lineVertsCount += 2;
}
// 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.
public void End()
{
if (!_hasBegun)
{
throw new InvalidOperationException("Begin must be called before End can be called.");
}
// Draw whatever the user wanted us to draw
Flush();
_hasBegun = false;
}
private void Flush()
{
if (!_hasBegun)
{
throw new InvalidOperationException("Begin must be called before Flush can be called.");
}
if (_lineVertsCount >= 2)
{
int primitiveCount = _lineVertsCount / 2;
// submit the draw call to the graphics card
_device.DrawUserPrimitives(PrimitiveType.LineList, _lineVertices, 0, primitiveCount);
_lineVertsCount -= primitiveCount * 2;
}
}
}
}