From 0889c5f4df4a31a137921c4ad958fa5ee070a631 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 31 May 2015 12:59:03 +1000 Subject: [PATCH] Use dynamic VBOs instead of immediate mode. --- Entities/ParticleManager.cs | 9 ++++- Game/Game.cs | 3 ++ GraphicsAPI/IGraphicsApi.cs | 28 +++++++++++----- GraphicsAPI/OpenGLApi.cs | 65 +++++++++++++++--------------------- Launcher/WebUtility.cs | 15 +++------ Model/BlockModel.cs | 7 ++-- Rendering/PickingRenderer.cs | 8 ++++- Rendering/WeatherRenderer.cs | 4 ++- 8 files changed, 78 insertions(+), 61 deletions(-) diff --git a/Entities/ParticleManager.cs b/Entities/ParticleManager.cs index ee7bd3e0f..3fecca7c5 100644 --- a/Entities/ParticleManager.cs +++ b/Entities/ParticleManager.cs @@ -10,10 +10,12 @@ namespace ClassicalSharp.Particles { List particles = new List(); public Game Window; public IGraphicsApi Graphics; + int vb; public ParticleManager( Game window ) { Window = window; Graphics = window.Graphics; + vb = Graphics.CreateDynamicVb( VertexFormat.VertexPos3fTex2f, 1000 ); } VertexPos3fTex2f[] vertices = new VertexPos3fTex2f[0]; @@ -32,7 +34,8 @@ namespace ClassicalSharp.Particles { Graphics.Texturing = true; Graphics.Bind2DTexture( Window.TerrainAtlas.TexId ); Graphics.AlphaTest = true; - Graphics.DrawVertices( DrawMode.Triangles, vertices, count ); + count = Math.Min( count, 1000 ); + Graphics.DrawDynamicVb( DrawMode.Triangles, vb, vertices, VertexFormat.VertexPos3fTex2f, count ); Graphics.AlphaTest = false; Graphics.Texturing = false; } @@ -48,6 +51,10 @@ namespace ClassicalSharp.Particles { } } + public void Dispose() { + Graphics.DeleteDynamicVb( vb ); + } + int particleId = 0; public void BreakBlockEffect( Vector3I position, byte block ) { Vector3 startPos = new Vector3( position.X, position.Y, position.Z ); diff --git a/Game/Game.cs b/Game/Game.cs index fad390219..833551bc0 100644 --- a/Game/Game.cs +++ b/Game/Game.cs @@ -278,6 +278,8 @@ namespace ClassicalSharp { TerrainAtlas.Dispose(); TerrainAtlas1D.Dispose(); ModelCache.Dispose(); + Picking.Dispose(); + ParticleManager.Dispose(); for( int i = 0; i < NetPlayers.Length; i++ ) { if( NetPlayers[i] != null ) { NetPlayers[i].Despawn(); @@ -289,6 +291,7 @@ namespace ClassicalSharp { if( writer != null ) { writer.Close(); } + Graphics.Dispose(); Utils2D.Dispose(); base.Dispose(); } diff --git a/GraphicsAPI/IGraphicsApi.cs b/GraphicsAPI/IGraphicsApi.cs index 7ce051de2..c759c2d95 100644 --- a/GraphicsAPI/IGraphicsApi.cs +++ b/GraphicsAPI/IGraphicsApi.cs @@ -98,14 +98,12 @@ namespace ClassicalSharp.GraphicsAPI { /// Whether writing to the depth buffer is enabled. public abstract bool DepthWrite { set; } - public abstract void DrawVertices( DrawMode mode, VertexPos3fCol4b[] vertices, int count ); - - public abstract void DrawVertices( DrawMode mode, VertexPos3fTex2f[] vertices, int count ); - - public abstract void DrawVertices( DrawMode mode, VertexPos3fTex2fCol4b[] vertices, int count ); - public abstract void SetFillType( FillType type ); + public abstract int CreateDynamicVb( VertexFormat format, int maxVertices ); + + public abstract void DrawDynamicVb( DrawMode mode, int vb, T[] vertices, VertexFormat format, int count ) where T : struct; + public virtual int InitVb( T[] vertices, VertexFormat format ) where T : struct { return InitVb( vertices, format, vertices.Length ); } @@ -118,6 +116,8 @@ namespace ClassicalSharp.GraphicsAPI { public abstract bool IsValidIb( int ib ); + public abstract void DeleteDynamicVb( int id ); + public abstract void DeleteVb( int id ); public abstract void DeleteIb( int ib ); @@ -197,16 +197,28 @@ namespace ClassicalSharp.GraphicsAPI { public abstract void OnWindowResize( int newWidth, int newHeight ); + protected void InitDynamicBuffers() { + quadVb = CreateDynamicVb( VertexFormat.VertexPos3fCol4b, 4 ); + texVb = CreateDynamicVb( VertexFormat.VertexPos3fTex2f, 4 ); + } + + public virtual void Dispose() { + DeleteDynamicVb( quadVb ); + DeleteDynamicVb( texVb ); + } + VertexPos3fCol4b[] quadVertices = new VertexPos3fCol4b[4]; + int quadVb; public virtual void Draw2DQuad( float x, float y, float width, float height, FastColour col ) { quadVertices[0] = new VertexPos3fCol4b( x + width, y, 0, col ); quadVertices[1] = new VertexPos3fCol4b( x + width, y + height, 0, col ); quadVertices[2] = new VertexPos3fCol4b( x, y, 0, col ); quadVertices[3] = new VertexPos3fCol4b( x, y + height, 0, col ); - DrawVertices( DrawMode.TriangleStrip, quadVertices, 4 ); + DrawDynamicVb( DrawMode.TriangleStrip, quadVb, quadVertices, VertexFormat.VertexPos3fCol4b, 4 ); } VertexPos3fTex2f[] texVertices = new VertexPos3fTex2f[4]; + int texVb; public virtual void Draw2DTexture( ref Texture tex ) { float x1 = tex.X1, y1 = tex.Y1, x2 = tex.X2, y2 = tex.Y2; // Have to order them this way because it's a triangle strip. @@ -214,7 +226,7 @@ namespace ClassicalSharp.GraphicsAPI { texVertices[1] = new VertexPos3fTex2f( x2, y2, 0, tex.U2, tex.V2 ); texVertices[2] = new VertexPos3fTex2f( x1, y1, 0, tex.U1, tex.V1 ); texVertices[3] = new VertexPos3fTex2f( x1, y2, 0, tex.U1, tex.V2 ); - DrawVertices( DrawMode.TriangleStrip, texVertices, 4 ); + DrawDynamicVb( DrawMode.TriangleStrip, texVb, texVertices, VertexFormat.VertexPos3fTex2f, 4 ); } public void Mode2D( float width, float height ) { diff --git a/GraphicsAPI/OpenGLApi.cs b/GraphicsAPI/OpenGLApi.cs index 28b60dd84..e8ddd2859 100644 --- a/GraphicsAPI/OpenGLApi.cs +++ b/GraphicsAPI/OpenGLApi.cs @@ -27,6 +27,7 @@ namespace ClassicalSharp.GraphicsAPI { Utils.LogWarning( "Alternatively, you can download the 'DLCompatibility build." ); throw new InvalidOperationException( "Cannot use OpenGL vbos." ); } + base.InitDynamicBuffers(); drawBatchFuncCol4b = DrawVbPos3fCol4bFast; drawBatchFuncTex2f = DrawVbPos3fTex2fFast; drawBatchFuncTex2fCol4b = DrawVbPos3fTex2fCol4bFast; @@ -179,44 +180,6 @@ namespace ClassicalSharp.GraphicsAPI { set { GL.DepthMask( value ); } } - public override void DrawVertices( DrawMode mode, VertexPos3fCol4b[] vertices, int count ) { - //GL.DrawArrays( BeginMode.Triangles, 0, vertices.Length ); - // We can't just use GL.DrawArrays since we'd have to pin the array to prevent it from being moved around in memory. - // Feasible alternatives: - // - Use a dynamically updated VBO, and resize it (i.e. create a new bigger VBO) if required. - // - Immediate mode. - GL.Begin( modeMappings[(int)mode] ); - for( int i = 0; i < count; i++ ) { - VertexPos3fCol4b vertex = vertices[i]; - GL.Color4( vertex.R, vertex.G, vertex.B, vertex.A ); - GL.Vertex3( vertex.X, vertex.Y, vertex.Z ); - } - GL.Color4( 1f, 1f, 1f, 1f ); - GL.End(); - } - - public override void DrawVertices( DrawMode mode, VertexPos3fTex2f[] vertices, int count ) { - GL.Begin( modeMappings[(int)mode] ); - for( int i = 0; i < count; i++ ) { - VertexPos3fTex2f vertex = vertices[i]; - GL.TexCoord2( vertex.U, vertex.V ); - GL.Vertex3( vertex.X, vertex.Y, vertex.Z ); - } - GL.End(); - } - - public override void DrawVertices( DrawMode mode, VertexPos3fTex2fCol4b[] vertices, int count ) { - GL.Begin( modeMappings[(int)mode] ); - for( int i = 0; i < count; i++ ) { - VertexPos3fTex2fCol4b vertex = vertices[i]; - GL.TexCoord2( vertex.U, vertex.V ); - GL.Color4( vertex.R, vertex.G, vertex.B, vertex.A ); - GL.Vertex3( vertex.X, vertex.Y, vertex.Z ); - } - GL.Color4( 1f, 1f, 1f, 1f ); - GL.End(); - } - PolygonMode[] fillModes = { PolygonMode.Point, PolygonMode.Line, PolygonMode.Fill }; public override void SetFillType( FillType type ) { GL.PolygonMode( MaterialFace.FrontAndBack, fillModes[(int)type] ); @@ -232,6 +195,17 @@ namespace ClassicalSharp.GraphicsAPI { Action drawBatchFuncCol4b; Action drawBatchFuncTex2fCol4b; + + public override int CreateDynamicVb( VertexFormat format, int maxVertices ) { + int id = 0; + GL.Arb.GenBuffers( 1, out id ); + int sizeInBytes = GetSizeInBytes( maxVertices, format ); + GL.Arb.BindBuffer( BufferTargetArb.ArrayBuffer, id ); + GL.Arb.BufferData( BufferTargetArb.ArrayBuffer, new IntPtr( sizeInBytes ), IntPtr.Zero, BufferUsageArb.DynamicDraw ); + GL.Arb.BindBuffer( BufferTargetArb.ArrayBuffer, 0 ); + return id; + } + public override int InitVb( T[] vertices, VertexFormat format, int count ) { int id = 0; GL.Arb.GenBuffers( 1, out id ); @@ -255,6 +229,21 @@ namespace ClassicalSharp.GraphicsAPI { return id; } + public override void DrawDynamicVb( DrawMode mode, int vb, T[] vertices, VertexFormat format, int count ) { + int sizeInBytes = GetSizeInBytes( count, format ); + GL.Arb.BindBuffer( BufferTargetArb.ArrayBuffer, vb ); + GL.Arb.BufferSubData( BufferTargetArb.ArrayBuffer, IntPtr.Zero, new IntPtr( sizeInBytes ), vertices ); + + BeginVbBatch( format ); + DrawVbBatch( mode, vb, count ); + EndVbBatch(); + } + + public override void DeleteDynamicVb( int id ) { + if( id <= 0 ) return; + GL.Arb.DeleteBuffers( 1, ref id ); + } + public override void DeleteVb( int id ) { if( id <= 0 ) return; #if TRACK_RESOURCES diff --git a/Launcher/WebUtility.cs b/Launcher/WebUtility.cs index 5f0d82333..4ed30e8c1 100644 --- a/Launcher/WebUtility.cs +++ b/Launcher/WebUtility.cs @@ -1,8 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; namespace Launcher { @@ -75,10 +74,6 @@ namespace Launcher { { "diams", '\x2666' }, }; - static bool Lookup( string entity, out char decoded ) { - return _lookupTable.TryGetValue( entity, out decoded ); - } - public static string HtmlDecode( string value ) { value = value.Replace( "hellip;", "\x2026" ); // minecraft.net doesn't escape this at the end properly. if( String.IsNullOrEmpty( value ) || value.IndexOf( '&' ) < 0 ) { @@ -119,7 +114,7 @@ namespace Launcher { } else { i = entityEnd; char decodedEntity; - if( Lookup( entity, out decodedEntity ) ) { + if( _lookupTable.TryGetValue( entity, out decodedEntity ) ) { output.Append( decodedEntity ); } else { // Invalid token. output.Append( '&' ); diff --git a/Model/BlockModel.cs b/Model/BlockModel.cs index 39bad297e..7e164af91 100644 --- a/Model/BlockModel.cs +++ b/Model/BlockModel.cs @@ -9,8 +9,10 @@ namespace ClassicalSharp.Model { public class BlockModel : IModel { byte block = (byte)Block.Air; + int vb; public BlockModel( Game window ) : base( window ) { vertices = new VertexPos3fTex2fCol4b[6 * 6]; + vb = window.Graphics.CreateDynamicVb( VertexFormat.VertexPos3fTex2fCol4b, 6 * 6 ); } public override float NameYOffset { @@ -34,7 +36,7 @@ namespace ClassicalSharp.Model { if( BlockInfo.IsSprite( block ) ) { DrawXFace( 0f, TileSide.Right, false ); DrawZFace( 0f, TileSide.Back, false ); - graphics.DrawVertices( DrawMode.Triangles, vertices, 6 * 2 ); + graphics.DrawDynamicVb( DrawMode.Triangles, vb, vertices, VertexFormat.VertexPos3fTex2fCol4b, 6 * 2 ); } else { DrawYFace( blockHeight, TileSide.Top ); DrawXFace( -0.5f, TileSide.Right, false ); @@ -42,7 +44,7 @@ namespace ClassicalSharp.Model { DrawZFace( -0.5f, TileSide.Front, true ); DrawZFace( 0.5f, TileSide.Back, false ); DrawYFace( 0f, TileSide.Bottom ); - graphics.DrawVertices( DrawMode.Triangles, vertices, 6 * 6 ); + graphics.DrawDynamicVb( DrawMode.Triangles, vb, vertices, VertexFormat.VertexPos3fTex2fCol4b, 6 * 6 ); } } float blockHeight; @@ -50,6 +52,7 @@ namespace ClassicalSharp.Model { BlockInfo BlockInfo; public override void Dispose() { + graphics.DeleteDynamicVb( vb ); } void DrawYFace( float y, int side ) { diff --git a/Rendering/PickingRenderer.cs b/Rendering/PickingRenderer.cs index 3268de29d..07830d64e 100644 --- a/Rendering/PickingRenderer.cs +++ b/Rendering/PickingRenderer.cs @@ -8,10 +8,12 @@ namespace ClassicalSharp.Renderers { Game window; IGraphicsApi graphics; + int vb; public PickingRenderer( Game window ) { this.window = window; graphics = window.Graphics; + vb = graphics.CreateDynamicVb( VertexFormat.VertexPos3fCol4b, verticesCount ); } FastColour col = FastColour.White; @@ -59,10 +61,14 @@ namespace ClassicalSharp.Renderers { DrawZPlane( p2.Z, p2.X, p1.Y, p2.X - size, p2.Y ); DrawZPlane( p2.Z, p1.X, p1.Y, p2.X, p1.Y + size ); DrawZPlane( p2.Z, p1.X, p2.Y, p2.X, p2.Y - size ); - graphics.DrawVertices( DrawMode.Triangles, vertices, verticesCount ); + graphics.DrawDynamicVb( DrawMode.Triangles, vb, vertices, VertexFormat.VertexPos3fCol4b, verticesCount ); } } + public void Dispose() { + graphics.DeleteDynamicVb( vb ); + } + void DrawXPlane( float x, float z1, float y1, float z2, float y2 ) { vertices[index++] = new VertexPos3fCol4b( x, y1, z1, col ); vertices[index++] = new VertexPos3fCol4b( x, y2, z1, col ); diff --git a/Rendering/WeatherRenderer.cs b/Rendering/WeatherRenderer.cs index df4a57531..ab6b94b1f 100644 --- a/Rendering/WeatherRenderer.cs +++ b/Rendering/WeatherRenderer.cs @@ -15,8 +15,10 @@ namespace ClassicalSharp { map = Window.Map; graphics = window.Graphics; info = Window.BlockInfo; + weatherVb = graphics.CreateDynamicVb( VertexFormat.VertexPos3fTex2fCol4b, 12 * 9 * 9 ); } + int weatherVb; int rainTexture, snowTexture; short[] heightmap; float vOffset; @@ -44,7 +46,7 @@ namespace ClassicalSharp { MakeRainForSquare( pos.X + dx, rainY, height, pos.Z + dz, col, ref index ); } } - graphics.DrawVertices( DrawMode.Triangles, vertices, index ); + graphics.DrawDynamicVb( DrawMode.Triangles, weatherVb, vertices, VertexFormat.VertexPos3fTex2fCol4b, index ); graphics.AlphaBlending = false; graphics.Texturing = false; }