// Project: XnaShooter, File: LineManager3D.cs // Namespace: XnaShooter.Graphic, Class: LineManager3D // Creation date: 18.02.2005 11:35 // Last modified: 01.03.2005 16:36 // Generated with Commenter by abi.exDream.com #region Using directives using System; using System.Collections; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System.Collections.Generic; using XnaShooter; using XnaShooter.Helpers; using XnaShooter.Shaders; using XnaShooter.Game; #endregion namespace XnaShooter.Graphics { /// /// Helper class for game for rendering lines. /// This class will collect all line calls, then build a new vertex buffer /// if any line has changed or the line number changed and finally will /// render all lines in the vertex buffer at the end of the frame (so this /// class is obviously only for 2D lines directly on screen, no z buffer /// and no stuff will be in front of the lines, because everything is /// rendered at the end of the frame). /// internal class LineManager3D : IGraphicContent { #region Line struct /// /// Struct for a line, instances of this class will be added to lines. /// struct Line { // Positions public Vector3 startPoint, endPoint; // Colors public Color startColor, endColor; /// /// Constructor /// public Line( Vector3 setStartPoint, Color setStartColor, Vector3 setEndPoint, Color setEndColor) { startPoint = setStartPoint; startColor = setStartColor; endPoint = setEndPoint; endColor = setEndColor; } // Line(setStartPoint, setStartColor, setEndPoint) /// /// Are these two Lines equal? /// public static bool operator ==(Line a, Line b) { return a.startPoint == b.startPoint && a.endPoint == b.endPoint && a.startColor == b.startColor && a.endColor == b.endColor; } // ==(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.startColor != b.startColor || a.endColor != b.endColor; } // !=(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() } // struct Line #endregion #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(); /// /// 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 to prevent to big buffer, will never /// be reached, but in case something goes wrong or numOfLines is not /// reseted each frame, we won't add unlimited lines (all new lines /// will be ignored if this max. number is reached). /// protected const int MaxNumOfLines = 4096;//40096;//512;//256; // more than in 2D /// /// Vertex declaration for our lines. /// VertexDeclaration decl = null; #endregion #region Initialization /// /// Init LineManager /// public LineManager3D() { if (BaseGame.Device == null) throw new NullReferenceException( "XNA device is not initialized, can't init line manager."); Load(); BaseGame.RegisterGraphicContentObject(this); } // LineManager() #endregion #region Load public void Load() { if (decl == null) decl = new VertexDeclaration( BaseGame.Device, VertexPositionColor.VertexElements); } // Load() #endregion #region Dispose public void Dispose() { if (decl != null) decl.Dispose(); decl = null; } // Dispose() #endregion #region Reset, AddLine and Rendering /// /// Add line /// public void AddLine( Vector3 startPoint, Color startColor, Vector3 endPoint, Color endColor) { // Don't add new lines if limit is reached if (numOfLines >= MaxNumOfLines) { /*ignore Log.Write("Too many lines requested in LineManager3D. " + "Max lines = " + MaxNumOfLines); */ return; } // if (numOfLines) // Build line Line line = new Line(startPoint, startColor, endPoint, endColor); // 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 if } // if else { // Then just add new line lines.Add(line); // Remember to build vertex buffer in Render() buildVertexBuffer = true; } // else // nextUpValue line numOfLines++; } // AddLine(startPoint, startColor, endPoint) /// /// Add line (only 1 color for start and end version) /// public void AddLine(Vector3 startPoint, Vector3 endPoint, Color color) { AddLine(startPoint, color, endPoint, color); } // AddLine(startPoint, endPoint, color) protected 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) // Set all lines for (int lineNum = 0; lineNum < numOfLines; lineNum++) { Line line = (Line)lines[lineNum]; lineVertices[lineNum * 2 + 0] = new VertexPositionColor( line.startPoint, line.startColor); lineVertices[lineNum * 2 + 1] = new VertexPositionColor( line.endPoint, line.endColor); } // for (lineNum) numOfPrimitives = numOfLines; // Vertex buffer was build buildVertexBuffer = false; } // UpdateVertexBuffer() /// /// Render all lines added this frame /// public 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.WorldMatrix = Matrix.Identity; BaseGame.AlphaBlending = true; BaseGame.Device.VertexDeclaration = decl; BaseGame.Device.RenderState.DepthBufferEnable = true; ShaderEffect.lineRendering.Render( "LineRendering3D", delegate { BaseGame.Device.DrawUserPrimitives( PrimitiveType.LineList, lineVertices, 0, numOfPrimitives); }); } // try catch (Exception ex) { Log.Write( "LineManager3D.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 lines /// public static void TestRenderLines() { TestGame.Start( delegate // 3d render code { for (int num = 0; num < 200; num++) { BaseGame.DrawLine( new Vector3(-12.0f + num / 4.0f, 13.0f, 0), new Vector3(-17.0f + num / 4.0f, -13.0f, 0), new Color((byte)(255-num), 14, (byte)num)); } // for TextureFont.WriteText(2, 30, "cam pos="+BaseGame.CameraPos); }); } // TestRenderLines() #endregion #endif #endregion } // class LineManager3D } // namespace XnaShooter.Graphic