// Project: XnaGraphicEngine, File: LineManager2D.cs
// Namespace: XnaGraphicEngine.Graphics, Class: LineManager2D
// Path: C:\code\XnaBook\XnaGraphicEngine\Graphics, Author: Abi
// Code lines: 408, Size of file: 11,36 KB
// Creation date: 07.09.2006 05:56
// Last modified: 07.11.2006 03:08
// Generated with Commenter by abi.exDream.com
#region Unit Testing
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using XnaGraphicEngine.Graphics;
using XnaGraphicEngine.Helpers;
using XnaGraphicEngine.Shaders;
using XnaGraphicEngine.Game;
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace XnaGraphicEngine.Graphics
{
///
/// LineManager class, used for drawing lines. We can't simply draw
/// lines like in OpenGL (glLine) because we need to do everything with
/// vertex buffers, which is a bit more work (and using DrawPrimitives
/// directly produces way worse code).
///
public class LineManager2D : IDisposable
{
#region Variables
///
/// Number of lines used this frame, will be set to 0 when rendering.
///
private int numOfLines = 0;
///
/// The actual list for all the lines, it will NOT be reseted each
/// frame like numOfLines! We will remember the last lines and
/// only change this list when anything changes (new line, old
/// line missing, changing line data).
/// When this happens buildVertexBuffer will be set to true.
///
private List lines = new List();
///
/// Struct for a line, instances of this struct will be added to lines.
///
struct Line
{
#region Variables
///
/// Positions
///
public Point startPoint, endPoint;
///
/// Color
///
public Color color;
#endregion
#region Constructor
///
/// Create line
///
/// Set start point
/// Set end point
/// Set color
public Line(Point setStartPoint,
Point setEndPoint, Color setColor)
{
startPoint = setStartPoint;
endPoint = setEndPoint;
color = setColor;
} // Line(setStartPoint, setEndPoint, setColor)
#endregion
#region Equals operators
///
/// Are these two Lines equal?
///
public static bool operator ==(Line a, Line b)
{
return a.startPoint == b.startPoint &&
a.endPoint == b.endPoint &&
a.color == b.color;
} // ==(a, b)
///
/// Are these two Lines not equal?
///
public static bool operator !=(Line a, Line b)
{
return a.startPoint != b.startPoint ||
a.endPoint != b.endPoint ||
a.color != b.color;
} // !=(a, b)
///
/// Support Equals(.) to keep the compiler happy
/// (because we used == and !=)
///
public override bool Equals(object a)
{
if (a.GetType() == typeof(Line))
return (Line)a == this;
else
return false; // Object is not a Line
} // Equals(a)
///
/// Support GetHashCode() to keep the compiler happy
/// (because we used == and !=)
///
public override int GetHashCode()
{
return 0; // Not supported or nessescary
} // GetHashCode()
#endregion
} // struct Line
///
/// Build vertex buffer this frame because the line list was changed?
///
private bool buildVertexBuffer = false;
///
/// Vertex buffer for all lines
///
VertexPositionColor[] lineVertices =
new VertexPositionColor[MaxNumOfLines * 2];
///
/// Real number of primitives currently used.
///
private int numOfPrimitives = 0;
///
/// Max. number of lines allowed.
///
private const int MaxNumOfLines = 64;
///
/// Vertex declaration for our lines.
///
VertexDeclaration decl = null;
#endregion
#region Constructor
///
/// Create LineManager
///
public LineManager2D()
{
decl = new VertexDeclaration(
BaseGame.Device, VertexPositionColor.VertexElements);
} // LineManager2D()
#endregion
#region Dispose
///
/// Dispose
///
public void Dispose()
{
if (decl != null)
decl.Dispose();
decl = null;
} // Dispose()
#endregion
#region Vertex buffer stuff
///
/// Update vertex buffer
///
private void UpdateVertexBuffer()
{
// Don't do anything if we got no lines.
if (numOfLines == 0 ||
// Or if some data is invalid
lines.Count < numOfLines)
{
numOfPrimitives = 0;
return;
} // if (numOfLines)
#if LOG_STUFF
Log.Write("LineManager.UpdateVertexBuffer() numOfLines=" +
numOfLines + ", buildVertexBuffer=" + buildVertexBuffer);
#endif
// Set all lines
for (int lineNum = 0; lineNum < numOfLines; lineNum++)
{
Line line = (Line)lines[lineNum];
lineVertices[lineNum * 2 + 0] = new VertexPositionColor(
new Vector3(
-1.0f + 2.0f * line.startPoint.X / BaseGame.Width,
-(-1.0f + 2.0f * line.startPoint.Y / BaseGame.Height), 0),
line.color);
lineVertices[lineNum * 2 + 1] = new VertexPositionColor(
new Vector3(
-1.0f + 2.0f * line.endPoint.X / BaseGame.Width,
-(-1.0f + 2.0f * line.endPoint.Y / BaseGame.Height), 0),
line.color);
} // for (lineNum)
numOfPrimitives = numOfLines;
// Vertex buffer was build
buildVertexBuffer = false;
} // UpdateVertexBuffer()
#endregion
#region Add line
///
/// Add line
///
public void AddLine(Point startPoint, Point endPoint, Color color)
{
// Don't add new lines if limit is reached
if (numOfLines >= MaxNumOfLines)
{
Log.Write("Too many lines requested in LineManager2D. " +
"Max lines = " + MaxNumOfLines);
return;
} // if (numOfLines)
// Build line
Line line = new Line(startPoint, endPoint, color);
// Check if this exact line exists at the current lines position.
if (lines.Count > numOfLines)
{
if ((Line)lines[numOfLines] != line)
{
// overwrite old line, otherwise just increase numOfLines
lines[numOfLines] = line;
// Remember to build vertex buffer in Render()
buildVertexBuffer = true;
} // if (Line)
} // if (lines.Count)
else
{
// Then just add new line
lines.Add(line);
// Remember to build vertex buffer in Render()
buildVertexBuffer = true;
} // else
// nextUpValue line
numOfLines++;
} // AddLine(startPoint, endPoint, color)
///
/// Add line with shadow
///
/// Start point
/// End point
/// Color
public void AddLineWithShadow(Point startPoint, Point endPoint,
Color color)
{
AddLine(new Point(startPoint.X, startPoint.Y+1),
new Point(endPoint.X, endPoint.Y+1), Color.Black);
AddLine(startPoint, endPoint, color);
} // AddLineWithShadow(startPoint, endPoint, color)
#endregion
#region Render
///
/// Render all lines added this frame
///
public virtual void Render()
{
// Need to build vertex buffer?
if (buildVertexBuffer ||
numOfPrimitives != numOfLines)
{
UpdateVertexBuffer();
} // if (buildVertexBuffer)
// Render lines if we got any lines to render
if (numOfPrimitives > 0)
{
try
{
BaseGame.AlphaBlending = true;
BaseGame.WorldMatrix = Matrix.Identity;
BaseGame.Device.VertexDeclaration = decl;
ShaderEffect.lineRendering.Render(
"LineRendering2D",
delegate
{
BaseGame.Device.DrawUserPrimitives(
PrimitiveType.LineList, lineVertices, 0, numOfPrimitives);
});
} // try
catch (Exception ex)
{
Log.Write(
"LineManager.Render failed. numOfPrimitives=" + numOfPrimitives +
", numOfLines=" + numOfLines + ". Error: " + ex.ToString());
} // catch (ex)
} // if (numOfVertices)
// Ok, finally reset numOfLines for next frame
numOfLines = 0;
} // Render()
#endregion
#region Unit Testing
#if DEBUG
#region TestRenderLines
///
/// Test render
///
public static void TestRenderLines()
{
TestGame.Start(
delegate
{
BaseGame.DrawLine(new Point(-100, 0), new Point(50, 100),
Color.White);
BaseGame.DrawLine(new Point(0, 100), new Point(100, 0),
Color.Gray);
BaseGame.DrawLine(new Point(400, 0), new Point(100, 0),
Color.Red);
BaseGame.DrawLine(new Point(10, 50), new Point(100, +150),
new Color(255, 0, 0, 64));
});
} // TestRenderLines()
#endregion
#endif
#endregion
} // class LineManager2D
} // namespace XnaGraphicEngine.Graphics