//-----------------------------------------------------------------------------
// LineManager2D.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RacingGame.Graphics;
using RacingGame.Helpers;
using System;
using System.Collections.Generic;
using System.Text;
using RacingGame.Shaders;
namespace RacingGame.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
{
///
/// 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
{
///
/// Positions
///
public Point startPoint, endPoint;
///
/// Color
///
public Color color;
///
/// Create line
///
/// Set start point
/// Set end point
/// Set color
public Line(Point setStartPoint,
Point setEndPoint, Color setColor)
{
startPoint = setStartPoint;
endPoint = setEndPoint;
color = setColor;
}
///
/// 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;
}
///
/// 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;
}
///
/// Support Equals(.) to keep the compiler happy
/// (because we used == and !=)
///
public override bool Equals(object a)
{
if (a is Line)
return (Line)a == this;
return false;
}
///
/// Support GetHashCode() to keep the compiler happy
/// (because we used == and !=)
///
public override int GetHashCode()
{
return 0; // Not supported or nessescary
}
}
///
/// Build vertex buffer this frame because the line list was changed?
/// Note: The vertex buffer implementation was removed some time ago,
/// but this variable is still used to check for updates to lineVertices!
///
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;
///
/// Create LineManager
///
public LineManager2D()
{
}
///
/// Dispose
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Dispose
///
/// Disposing
protected virtual void Dispose(bool disposing)
{
}
///
/// 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 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);
}
numOfPrimitives = numOfLines;
// Vertex buffer was build
buildVertexBuffer = false;
}
///
/// 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;
}
// 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;
}
}
else
{
// Then just add new line
lines.Add(line);
// Remember to build vertex buffer in Render()
buildVertexBuffer = true;
}
// nextUpValue line
numOfLines++;
}
///
/// 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);
}
///
/// Render all lines added this frame
///
public virtual void Render()
{
// Need to build vertex buffer?
if (buildVertexBuffer ||
numOfPrimitives != numOfLines)
{
UpdateVertexBuffer();
}
// Render lines if we got any lines to render
if (numOfPrimitives > 0)
{
BaseGame.SetAlphaBlendingEnabled(true);
BaseGame.WorldMatrix = Matrix.Identity;
ShaderEffect.lineRendering.Render(
"LineRendering2D",
delegate
{
BaseGame.Device.DrawUserPrimitives(
PrimitiveType.LineList, lineVertices, 0, numOfPrimitives);
});
}
// Ok, finally reset numOfLines for next frame
numOfLines = 0;
}
}
}