//----------------------------------------------------------------------------- // 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; } } }