diff --git a/ClassicalSharp/GraphicsAPI/OpenGLApi.cs b/ClassicalSharp/GraphicsAPI/OpenGLApi.cs
index 4f968ef08..2fc04e668 100644
--- a/ClassicalSharp/GraphicsAPI/OpenGLApi.cs
+++ b/ClassicalSharp/GraphicsAPI/OpenGLApi.cs
@@ -1,440 +1,448 @@
-// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
-#if !USE_DX && !ANDROID
-using System;
-using System.Drawing;
-using System.Drawing.Imaging;
-using OpenTK;
-using OpenTK.Graphics.OpenGL;
-using BmpPixelFormat = System.Drawing.Imaging.PixelFormat;
-using GlPixelFormat = OpenTK.Graphics.OpenGL.PixelFormat;
-
-namespace ClassicalSharp.GraphicsAPI {
-
- /// Implements IGraphicsAPI using OpenGL 1.5,
- /// or 1.2 with the GL_ARB_vertex_buffer_object extension.
- public unsafe class OpenGLApi : IGraphicsApi {
-
- BeginMode[] modeMappings;
- public OpenGLApi() {
- InitFields();
- int texDims;
- GL.GetIntegerv( GetPName.MaxTextureSize, &texDims );
- texDimensions = texDims;
- CheckVboSupport();
- base.InitDynamicBuffers();
-
- setupBatchFuncCol4b = SetupVbPos3fCol4b;
- setupBatchFuncTex2fCol4b = SetupVbPos3fTex2fCol4b;
- GL.EnableClientState( ArrayCap.VertexArray );
- GL.EnableClientState( ArrayCap.ColorArray );
- }
-
- void CheckVboSupport() {
- string extensions = new String( (sbyte*)GL.GetString( StringName.Extensions ) );
- string version = new String( (sbyte*)GL.GetString( StringName.Version ) );
- int major = (int)(version[0] - '0'); // x.y. (and so forth)
- int minor = (int)(version[2] - '0');
- if( (major > 1) || (major == 1 && minor >= 5) ) return; // Supported in core since 1.5
-
- Utils.LogDebug( "Using ARB vertex buffer objects" );
- if( !extensions.Contains( "GL_ARB_vertex_buffer_object" ) ) {
- ErrorHandler.LogError( "OpenGL VBO support check",
- "Driver does not support OpenGL VBOs, which are required for the OpenGL build." +
- Environment.NewLine + "You may need to install and/or update video card drivers." +
- Environment.NewLine + "Alternatively, you can download the Direct3D 9 build." );
- throw new InvalidOperationException( "VBO support required for OpenGL build" );
- }
- GL.UseArbVboAddresses();
- }
-
- public override bool AlphaTest { set { Toggle( EnableCap.AlphaTest, value ); } }
-
- public override bool AlphaBlending { set { Toggle( EnableCap.Blend, value ); } }
-
- Compare[] compareFuncs;
- public override void AlphaTestFunc( CompareFunc func, float value ) {
- GL.AlphaFunc( compareFuncs[(int)func], value );
- }
-
- BlendingFactor[] blendFuncs;
- public override void AlphaBlendFunc( BlendFunc srcFunc, BlendFunc dstFunc ) {
- GL.BlendFunc( blendFuncs[(int)srcFunc], blendFuncs[(int)dstFunc] );
- }
-
- public override bool Fog { set { Toggle( EnableCap.Fog, value ); } }
-
- FastColour lastFogCol = FastColour.Black;
- public override void SetFogColour( FastColour col ) {
- if( col != lastFogCol ) {
- Vector4 colRGBA = new Vector4( col.R / 255f, col.G / 255f, col.B / 255f, col.A / 255f );
- GL.Fogfv( FogParameter.FogColor, &colRGBA.X );
- lastFogCol = col;
- }
- }
-
- float lastFogStart = -1, lastFogEnd = -1, lastFogDensity = -1;
- public override void SetFogDensity( float value ) {
- FogParam( FogParameter.FogDensity, value, ref lastFogDensity );
- }
-
- public override void SetFogStart( float value ) {
- FogParam( FogParameter.FogStart, value, ref lastFogStart );
- }
-
- public override void SetFogEnd( float value ) {
- FogParam( FogParameter.FogEnd, value, ref lastFogEnd );
- }
-
- static void FogParam( FogParameter param, float value, ref float last ) {
- if( value != last ) {
- GL.Fogf( param, value );
- last = value;
- }
- }
-
- Fog lastFogMode = (Fog)999;
- FogMode[] fogModes;
- public override void SetFogMode( Fog mode ) {
- if( mode != lastFogMode ) {
- GL.Fogi( FogParameter.FogMode, (int)fogModes[(int)mode] );
- lastFogMode = mode;
- }
- }
-
- public override bool FaceCulling {
- set {
- if( value ) GL.Enable( EnableCap.CullFace );
- else GL.Disable( EnableCap.CullFace );
- }
- }
-
- public override void Clear() {
- GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
- }
-
- FastColour lastClearCol;
- public override void ClearColour( FastColour col ) {
- if( col != lastClearCol ) {
- GL.ClearColor( col.R / 255f, col.G / 255f, col.B / 255f, col.A / 255f );
- lastClearCol = col;
- }
- }
-
- public override bool ColourWrite { set { GL.ColorMask( value, value, value, value ); } }
-
- public override void DepthTestFunc( CompareFunc func ) {
- GL.DepthFunc( compareFuncs[(int)func] );
- }
-
- public override bool DepthTest { set { Toggle( EnableCap.DepthTest, value ); } }
-
- public override bool DepthWrite { set { GL.DepthMask( value ); } }
-
- public override bool AlphaArgBlend { set { } }
-
- #region Texturing
-
- int texDimensions;
- public override int MaxTextureDimensions { get { return texDimensions; } }
-
- public override bool Texturing { set { Toggle( EnableCap.Texture2D, value ); } }
-
- public override int CreateTexture( int width, int height, IntPtr scan0 ) {
- if( !Utils.IsPowerOf2( width ) || !Utils.IsPowerOf2( height ) )
- Utils.LogDebug( "Creating a non power of two texture." );
-
- int texId = 0;
- GL.GenTextures( 1, &texId );
- GL.BindTexture( TextureTarget.Texture2D, texId );
- GL.TexParameteri( TextureTarget.Texture2D, TextureParameterName.MinFilter, (int)TextureFilter.Nearest );
- GL.TexParameteri( TextureTarget.Texture2D, TextureParameterName.MagFilter, (int)TextureFilter.Nearest );
-
- GL.TexImage2D( TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height,
- GlPixelFormat.Bgra, PixelType.UnsignedByte, scan0 );
- return texId;
- }
-
- public override void BindTexture( int texture ) {
- GL.BindTexture( TextureTarget.Texture2D, texture );
- }
-
- public override void UpdateTexturePart( int texId, int texX, int texY, FastBitmap part ) {
- GL.BindTexture( TextureTarget.Texture2D, texId );
- GL.TexSubImage2D( TextureTarget.Texture2D, 0, texX, texY, part.Width, part.Height,
- GlPixelFormat.Bgra, PixelType.UnsignedByte, part.Scan0 );
- }
-
- public override void DeleteTexture( ref int texId ) {
- if( texId <= 0 ) return;
- int id = texId;
- GL.DeleteTextures( 1, &id );
- texId = -1;
- }
- #endregion
-
- #region Vertex/index buffers
- Action setupBatchFunc, setupBatchFuncCol4b, setupBatchFuncTex2fCol4b;
-
- public override int CreateDynamicVb( VertexFormat format, int maxVertices ) {
- int id = GenAndBind( BufferTarget.ArrayBuffer );
- int sizeInBytes = maxVertices * strideSizes[(int)format];
- GL.BufferData( BufferTarget.ArrayBuffer, new IntPtr( sizeInBytes ), IntPtr.Zero, BufferUsage.DynamicDraw );
- return id;
- }
-
- public override int CreateVb( T[] vertices, VertexFormat format, int count ) {
- int id = GenAndBind( BufferTarget.ArrayBuffer );
- int sizeInBytes = count * strideSizes[(int)format];
- GL.BufferData( BufferTarget.ArrayBuffer, new IntPtr( sizeInBytes ), vertices, BufferUsage.StaticDraw );
- return id;
- }
-
- public override int CreateVb( IntPtr vertices, VertexFormat format, int count ) {
- int id = GenAndBind( BufferTarget.ArrayBuffer );
- int sizeInBytes = count * strideSizes[(int)format];
- GL.BufferData( BufferTarget.ArrayBuffer, new IntPtr( sizeInBytes ), vertices, BufferUsage.StaticDraw );
- return id;
- }
-
- public override int CreateIb( ushort[] indices, int indicesCount ) {
- int id = GenAndBind( BufferTarget.ElementArrayBuffer );
- int sizeInBytes = indicesCount * sizeof( ushort );
- GL.BufferData( BufferTarget.ElementArrayBuffer, new IntPtr( sizeInBytes ), indices, BufferUsage.StaticDraw );
- return id;
- }
-
- public override int CreateIb( IntPtr indices, int indicesCount ) {
- int id = GenAndBind( BufferTarget.ElementArrayBuffer );
- int sizeInBytes = indicesCount * sizeof( ushort );
- GL.BufferData( BufferTarget.ElementArrayBuffer, new IntPtr( sizeInBytes ), indices, BufferUsage.StaticDraw );
- return id;
- }
-
- static int GenAndBind( BufferTarget target ) {
- int id = 0;
- GL.GenBuffers( 1, &id );
- GL.BindBuffer( target, id );
- return id;
- }
-
- int batchStride;
- public override void UpdateDynamicVb( DrawMode mode, int id, T[] vertices, int count ) {
- GL.BindBuffer( BufferTarget.ArrayBuffer, id );
- GL.BufferSubData( BufferTarget.ArrayBuffer, IntPtr.Zero, new IntPtr( count * batchStride ), vertices );
-
- setupBatchFunc();
- GL.DrawArrays( modeMappings[(int)mode], 0, count );
- }
-
- public override void UpdateDynamicIndexedVb( DrawMode mode, int id, T[] vertices, int vCount, int indicesCount ) {
- GL.BindBuffer( BufferTarget.ArrayBuffer, id );
- GL.BufferSubData( BufferTarget.ArrayBuffer, IntPtr.Zero, new IntPtr( vCount * batchStride ), vertices );
-
- setupBatchFunc();
- GL.DrawElements( modeMappings[(int)mode], indicesCount, indexType, zero );
- }
-
- public override void SetDynamicVbData( DrawMode mode, int id, T[] vertices, int count ) {
- GL.BindBuffer( BufferTarget.ArrayBuffer, id );
- GL.BufferSubData( BufferTarget.ArrayBuffer, IntPtr.Zero, new IntPtr( count * batchStride ), vertices );
- }
-
- public override void DeleteDynamicVb( int id ) {
- if( id <= 0 ) return;
- GL.DeleteBuffers( 1, &id );
- }
-
- public override void DeleteVb( int vb ) {
- if( vb <= 0 ) return;
- GL.DeleteBuffers( 1, &vb );
- }
-
- public override void DeleteIb( int ib ) {
- if( ib <= 0 ) return;
- GL.DeleteBuffers( 1, &ib );
- }
-
- VertexFormat batchFormat = (VertexFormat)999;
- public override void SetBatchFormat( VertexFormat format ) {
- if( format == batchFormat ) return;
-
- if( batchFormat == VertexFormat.P3fT2fC4b ) {
- GL.DisableClientState( ArrayCap.TextureCoordArray );
- }
-
- batchFormat = format;
- if( format == VertexFormat.P3fT2fC4b ) {
- GL.EnableClientState( ArrayCap.TextureCoordArray );
- setupBatchFunc = setupBatchFuncTex2fCol4b;
- batchStride = VertexP3fT2fC4b.Size;
- } else {
- setupBatchFunc = setupBatchFuncCol4b;
- batchStride = VertexP3fC4b.Size;
- }
- }
-
- public override void BindVb( int vb ) {
- GL.BindBuffer( BufferTarget.ArrayBuffer, vb );
- }
-
- public override void BindIb( int ib ) {
- GL.BindBuffer( BufferTarget.ElementArrayBuffer, ib );
- }
-
- const DrawElementsType indexType = DrawElementsType.UnsignedShort;
- public override void DrawVb( DrawMode mode, int startVertex, int verticesCount ) {
- setupBatchFunc();
- GL.DrawArrays( modeMappings[(int)mode], startVertex, verticesCount );
- }
-
- public override void DrawIndexedVb( DrawMode mode, int indicesCount, int startIndex ) {
- setupBatchFunc();
- GL.DrawElements( modeMappings[(int)mode], indicesCount, indexType, new IntPtr( startIndex * 2 ) );
- }
-
- internal override void DrawIndexedVb_TrisT2fC4b( int indicesCount, int startIndex ) {
- GL.VertexPointer( 3, PointerType.Float, 24, zero );
- GL.ColorPointer( 4, PointerType.UnsignedByte, 24, twelve );
- GL.TexCoordPointer( 2, PointerType.Float, 24, sixteen );
- GL.DrawElements( BeginMode.Triangles, indicesCount, indexType, new IntPtr( startIndex * 2 ) );
- }
-
- internal override void DrawIndexedVb_TrisT2fC4b( int indicesCount, int startVertex, int startIndex ) {
- int offset = startVertex * VertexP3fT2fC4b.Size;
- GL.VertexPointer( 3, PointerType.Float, 24, new IntPtr( offset ) );
- GL.ColorPointer( 4, PointerType.UnsignedByte, 24, new IntPtr( offset + 12 ) );
- GL.TexCoordPointer( 2, PointerType.Float, 24, new IntPtr( offset + 16 ) );
- GL.DrawElements( BeginMode.Triangles, indicesCount, indexType, new IntPtr( startIndex * 2 ) );
- }
-
- IntPtr zero = new IntPtr( 0 ), twelve = new IntPtr( 12 ), sixteen = new IntPtr( 16 );
-
- void SetupVbPos3fCol4b() {
- GL.VertexPointer( 3, PointerType.Float, VertexP3fC4b.Size, zero );
- GL.ColorPointer( 4, PointerType.UnsignedByte, VertexP3fC4b.Size, twelve );
- }
-
- void SetupVbPos3fTex2fCol4b() {
- GL.VertexPointer( 3, PointerType.Float, VertexP3fT2fC4b.Size, zero );
- GL.ColorPointer( 4, PointerType.UnsignedByte, VertexP3fT2fC4b.Size, twelve );
- GL.TexCoordPointer( 2, PointerType.Float, VertexP3fT2fC4b.Size, sixteen );
- }
- #endregion
-
- #region Matrix manipulation
- MatrixMode lastMode = 0;
- MatrixMode[] matrixModes;
- public override void SetMatrixMode( MatrixType mode ) {
- MatrixMode glMode = matrixModes[(int)mode];
- if( glMode != lastMode ) {
- GL.MatrixMode( glMode );
- lastMode = glMode;
- }
- }
-
- public override void LoadMatrix( ref Matrix4 matrix ) {
- fixed( Single* ptr = &matrix.Row0.X )
- GL.LoadMatrixf( ptr );
- }
-
- public override void LoadIdentityMatrix() {
- GL.LoadIdentity();
- }
-
- public override void PushMatrix() {
- GL.PushMatrix();
- }
-
- public override void PopMatrix() {
- GL.PopMatrix();
- }
-
- public override void MultiplyMatrix( ref Matrix4 matrix ) {
- fixed( Single* ptr = &matrix.Row0.X )
- GL.MultMatrixf( ptr );
- }
-
- #endregion
-
- public override void BeginFrame( Game game ) {
- }
-
- public override void EndFrame( Game game ) {
- game.window.SwapBuffers();
- }
-
- public override void SetVSync( Game game, bool value ) {
- game.VSync = value;
- }
-
- bool isIntelRenderer;
- protected override void MakeApiInfo() {
- string vendor = new String( (sbyte*)GL.GetString( StringName.Vendor ) );
- string renderer = new String( (sbyte*)GL.GetString( StringName.Renderer ) );
- string version = new String( (sbyte*)GL.GetString( StringName.Version ) );
- int depthBits = 0;
- GL.GetIntegerv( GetPName.DepthBits, &depthBits );
-
- ApiInfo = new string[] {
- "--Using OpenGL api--",
- "Vendor: " + vendor,
- "Renderer: " + renderer,
- "GL version: " + version,
- "Max 2D texture dimensions: " + MaxTextureDimensions,
- "Depth buffer bits: " + depthBits,
- };
- isIntelRenderer = renderer.Contains( "Intel" );
- }
-
- public override bool WarnIfNecessary( Chat chat ) {
- if( !isIntelRenderer ) return false;
-
- chat.Add( "&cIntel graphics cards are known to have issues with the OpenGL build." );
- chat.Add( "&cVSync may not work, and you may see disappearing clouds and map edges." );
- chat.Add( "&cFor Windows, try downloading the Direct3D 9 build instead.");
- return true;
- }
-
- // Based on http://www.opentk.com/doc/graphics/save-opengl-rendering-to-disk
- public override void TakeScreenshot( string output, int width, int height ) {
- using( Bitmap bmp = new Bitmap( width, height, BmpPixelFormat.Format32bppRgb ) ) { // ignore alpha component
- using( FastBitmap fastBmp = new FastBitmap( bmp, true, false ) )
- GL.ReadPixels( 0, 0, width, height, GlPixelFormat.Bgra, PixelType.UnsignedByte, fastBmp.Scan0 );
- bmp.RotateFlip( RotateFlipType.RotateNoneFlipY );
- bmp.Save( output, ImageFormat.Png );
- }
- }
-
- public override void OnWindowResize( Game game ) {
- GL.Viewport( 0, 0, game.Width, game.Height );
- }
-
- static void Toggle( EnableCap cap, bool value ) {
- if( value ) GL.Enable( cap );
- else GL.Disable( cap );
- }
-
- void InitFields() {
- // See comment in Game() constructor for why this is necessary.
- blendFuncs = new BlendingFactor[6];
- blendFuncs[0] = BlendingFactor.Zero; blendFuncs[1] = BlendingFactor.One;
- blendFuncs[2] = BlendingFactor.SrcAlpha; blendFuncs[3] = BlendingFactor.OneMinusSrcAlpha;
- blendFuncs[4] = BlendingFactor.DstAlpha; blendFuncs[5] = BlendingFactor.OneMinusDstAlpha;
- compareFuncs = new Compare[8];
- compareFuncs[0] = Compare.Always; compareFuncs[1] = Compare.Notequal;
- compareFuncs[2] = Compare.Never; compareFuncs[3] = Compare.Less;
- compareFuncs[4] = Compare.Lequal; compareFuncs[5] = Compare.Equal;
- compareFuncs[6] = Compare.Gequal; compareFuncs[7] = Compare.Greater;
-
- modeMappings = new BeginMode[2];
- modeMappings[0] = BeginMode.Triangles; modeMappings[1] = BeginMode.Lines;
- fogModes = new FogMode[3];
- fogModes[0] = FogMode.Linear; fogModes[1] = FogMode.Exp;
- fogModes[2] = FogMode.Exp2;
- matrixModes = new MatrixMode[3];
- matrixModes[0] = MatrixMode.Projection; matrixModes[1] = MatrixMode.Modelview;
- matrixModes[2] = MatrixMode.Texture;
- }
- }
-}
+// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
+#if !USE_DX && !ANDROID
+using System;
+using System.Drawing;
+using System.Drawing.Imaging;
+using OpenTK;
+using OpenTK.Graphics.OpenGL;
+using BmpPixelFormat = System.Drawing.Imaging.PixelFormat;
+using GlPixelFormat = OpenTK.Graphics.OpenGL.PixelFormat;
+
+namespace ClassicalSharp.GraphicsAPI {
+
+ /// Implements IGraphicsAPI using OpenGL 1.5,
+ /// or 1.2 with the GL_ARB_vertex_buffer_object extension.
+ public unsafe class OpenGLApi : IGraphicsApi {
+
+ BeginMode[] modeMappings;
+ public OpenGLApi() {
+ InitFields();
+ int texDims;
+ GL.GetIntegerv( GetPName.MaxTextureSize, &texDims );
+ texDimensions = texDims;
+ CheckVboSupport();
+ base.InitDynamicBuffers();
+
+ setupBatchFuncCol4b = SetupVbPos3fCol4b;
+ setupBatchFuncTex2fCol4b = SetupVbPos3fTex2fCol4b;
+ GL.EnableClientState( ArrayCap.VertexArray );
+ GL.EnableClientState( ArrayCap.ColorArray );
+ }
+
+ void CheckVboSupport() {
+ string extensions = new String( (sbyte*)GL.GetString( StringName.Extensions ) );
+ string version = new String( (sbyte*)GL.GetString( StringName.Version ) );
+ int major = (int)(version[0] - '0'); // x.y. (and so forth)
+ int minor = (int)(version[2] - '0');
+ if( (major > 1) || (major == 1 && minor >= 5) ) return; // Supported in core since 1.5
+
+ Utils.LogDebug( "Using ARB vertex buffer objects" );
+ if( !extensions.Contains( "GL_ARB_vertex_buffer_object" ) ) {
+ ErrorHandler.LogError( "OpenGL VBO support check",
+ "Driver does not support OpenGL VBOs, which are required for the OpenGL build." +
+ Environment.NewLine + "You may need to install and/or update video card drivers." +
+ Environment.NewLine + "Alternatively, you can download the Direct3D 9 build." );
+ throw new InvalidOperationException( "VBO support required for OpenGL build" );
+ }
+ GL.UseArbVboAddresses();
+ }
+
+ public override bool AlphaTest {
+ set { if( value ) GL.Enable( EnableCap.AlphaTest );
+ else GL.Disable( EnableCap.AlphaTest ); }
+ }
+
+ public override bool AlphaBlending {
+ set { if( value ) GL.Enable( EnableCap.Blend );
+ else GL.Disable( EnableCap.Blend ); }
+ }
+
+ Compare[] compareFuncs;
+ public override void AlphaTestFunc( CompareFunc func, float value ) {
+ GL.AlphaFunc( compareFuncs[(int)func], value );
+ }
+
+ BlendingFactor[] blendFuncs;
+ public override void AlphaBlendFunc( BlendFunc srcFunc, BlendFunc dstFunc ) {
+ GL.BlendFunc( blendFuncs[(int)srcFunc], blendFuncs[(int)dstFunc] );
+ }
+
+ public override bool Fog {
+ set { if( value ) GL.Enable( EnableCap.Fog );
+ else GL.Disable( EnableCap.Fog ); }
+ }
+
+ FastColour lastFogCol = FastColour.Black;
+ public override void SetFogColour( FastColour col ) {
+ if( col != lastFogCol ) {
+ Vector4 colRGBA = new Vector4( col.R / 255f, col.G / 255f, col.B / 255f, col.A / 255f );
+ GL.Fogfv( FogParameter.FogColor, &colRGBA.X );
+ lastFogCol = col;
+ }
+ }
+
+ float lastFogStart = -1, lastFogEnd = -1, lastFogDensity = -1;
+ public override void SetFogDensity( float value ) {
+ FogParam( FogParameter.FogDensity, value, ref lastFogDensity );
+ }
+
+ public override void SetFogStart( float value ) {
+ FogParam( FogParameter.FogStart, value, ref lastFogStart );
+ }
+
+ public override void SetFogEnd( float value ) {
+ FogParam( FogParameter.FogEnd, value, ref lastFogEnd );
+ }
+
+ static void FogParam( FogParameter param, float value, ref float last ) {
+ if( value != last ) {
+ GL.Fogf( param, value );
+ last = value;
+ }
+ }
+
+ Fog lastFogMode = (Fog)999;
+ FogMode[] fogModes;
+ public override void SetFogMode( Fog mode ) {
+ if( mode != lastFogMode ) {
+ GL.Fogi( FogParameter.FogMode, (int)fogModes[(int)mode] );
+ lastFogMode = mode;
+ }
+ }
+
+ public override bool FaceCulling {
+ set { if( value ) GL.Enable( EnableCap.CullFace );
+ else GL.Disable( EnableCap.CullFace ); }
+ }
+
+ public override void Clear() {
+ GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
+ }
+
+ FastColour lastClearCol;
+ public override void ClearColour( FastColour col ) {
+ if( col != lastClearCol ) {
+ GL.ClearColor( col.R / 255f, col.G / 255f, col.B / 255f, col.A / 255f );
+ lastClearCol = col;
+ }
+ }
+
+ public override bool ColourWrite { set { GL.ColorMask( value, value, value, value ); } }
+
+ public override void DepthTestFunc( CompareFunc func ) {
+ GL.DepthFunc( compareFuncs[(int)func] );
+ }
+
+ public override bool DepthTest {
+ set { if( value ) GL.Enable( EnableCap.DepthTest );
+ else GL.Disable( EnableCap.DepthTest ); }
+ }
+
+ public override bool DepthWrite { set { GL.DepthMask( value ); } }
+
+ public override bool AlphaArgBlend { set { } }
+
+ #region Texturing
+
+ int texDimensions;
+ public override int MaxTextureDimensions { get { return texDimensions; } }
+
+ public override bool Texturing {
+ set { if( value ) GL.Enable( EnableCap.Texture2D );
+ else GL.Disable( EnableCap.Texture2D ); }
+ }
+
+ public override int CreateTexture( int width, int height, IntPtr scan0 ) {
+ if( !Utils.IsPowerOf2( width ) || !Utils.IsPowerOf2( height ) )
+ Utils.LogDebug( "Creating a non power of two texture." );
+
+ int texId = 0;
+ GL.GenTextures( 1, &texId );
+ GL.BindTexture( TextureTarget.Texture2D, texId );
+ GL.TexParameteri( TextureTarget.Texture2D, TextureParameterName.MinFilter, (int)TextureFilter.Nearest );
+ GL.TexParameteri( TextureTarget.Texture2D, TextureParameterName.MagFilter, (int)TextureFilter.Nearest );
+
+ GL.TexImage2D( TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height,
+ GlPixelFormat.Bgra, PixelType.UnsignedByte, scan0 );
+ return texId;
+ }
+
+ public override void BindTexture( int texture ) {
+ GL.BindTexture( TextureTarget.Texture2D, texture );
+ }
+
+ public override void UpdateTexturePart( int texId, int texX, int texY, FastBitmap part ) {
+ GL.BindTexture( TextureTarget.Texture2D, texId );
+ GL.TexSubImage2D( TextureTarget.Texture2D, 0, texX, texY, part.Width, part.Height,
+ GlPixelFormat.Bgra, PixelType.UnsignedByte, part.Scan0 );
+ }
+
+ public override void DeleteTexture( ref int texId ) {
+ if( texId <= 0 ) return;
+ int id = texId;
+ GL.DeleteTextures( 1, &id );
+ texId = -1;
+ }
+ #endregion
+
+ #region Vertex/index buffers
+ Action setupBatchFunc, setupBatchFuncCol4b, setupBatchFuncTex2fCol4b;
+
+ public override int CreateDynamicVb( VertexFormat format, int maxVertices ) {
+ int id = GenAndBind( BufferTarget.ArrayBuffer );
+ int sizeInBytes = maxVertices * strideSizes[(int)format];
+ GL.BufferData( BufferTarget.ArrayBuffer, new IntPtr( sizeInBytes ), IntPtr.Zero, BufferUsage.DynamicDraw );
+ return id;
+ }
+
+ public override int CreateVb( T[] vertices, VertexFormat format, int count ) {
+ int id = GenAndBind( BufferTarget.ArrayBuffer );
+ int sizeInBytes = count * strideSizes[(int)format];
+ GL.BufferData( BufferTarget.ArrayBuffer, new IntPtr( sizeInBytes ), vertices, BufferUsage.StaticDraw );
+ return id;
+ }
+
+ public override int CreateVb( IntPtr vertices, VertexFormat format, int count ) {
+ int id = GenAndBind( BufferTarget.ArrayBuffer );
+ int sizeInBytes = count * strideSizes[(int)format];
+ GL.BufferData( BufferTarget.ArrayBuffer, new IntPtr( sizeInBytes ), vertices, BufferUsage.StaticDraw );
+ return id;
+ }
+
+ public override int CreateIb( ushort[] indices, int indicesCount ) {
+ int id = GenAndBind( BufferTarget.ElementArrayBuffer );
+ int sizeInBytes = indicesCount * sizeof( ushort );
+ GL.BufferData( BufferTarget.ElementArrayBuffer, new IntPtr( sizeInBytes ), indices, BufferUsage.StaticDraw );
+ return id;
+ }
+
+ public override int CreateIb( IntPtr indices, int indicesCount ) {
+ int id = GenAndBind( BufferTarget.ElementArrayBuffer );
+ int sizeInBytes = indicesCount * sizeof( ushort );
+ GL.BufferData( BufferTarget.ElementArrayBuffer, new IntPtr( sizeInBytes ), indices, BufferUsage.StaticDraw );
+ return id;
+ }
+
+ static int GenAndBind( BufferTarget target ) {
+ int id = 0;
+ GL.GenBuffers( 1, &id );
+ GL.BindBuffer( target, id );
+ return id;
+ }
+
+ int batchStride;
+ public override void UpdateDynamicVb( DrawMode mode, int id, T[] vertices, int count ) {
+ GL.BindBuffer( BufferTarget.ArrayBuffer, id );
+ GL.BufferSubData( BufferTarget.ArrayBuffer, IntPtr.Zero, new IntPtr( count * batchStride ), vertices );
+
+ setupBatchFunc();
+ GL.DrawArrays( modeMappings[(int)mode], 0, count );
+ }
+
+ public override void UpdateDynamicIndexedVb( DrawMode mode, int id, T[] vertices, int vCount, int indicesCount ) {
+ GL.BindBuffer( BufferTarget.ArrayBuffer, id );
+ GL.BufferSubData( BufferTarget.ArrayBuffer, IntPtr.Zero, new IntPtr( vCount * batchStride ), vertices );
+
+ setupBatchFunc();
+ GL.DrawElements( modeMappings[(int)mode], indicesCount, indexType, zero );
+ }
+
+ public override void SetDynamicVbData( DrawMode mode, int id, T[] vertices, int count ) {
+ GL.BindBuffer( BufferTarget.ArrayBuffer, id );
+ GL.BufferSubData( BufferTarget.ArrayBuffer, IntPtr.Zero, new IntPtr( count * batchStride ), vertices );
+ }
+
+ public override void DeleteDynamicVb( int id ) {
+ if( id <= 0 ) return;
+ GL.DeleteBuffers( 1, &id );
+ }
+
+ public override void DeleteVb( int vb ) {
+ if( vb <= 0 ) return;
+ GL.DeleteBuffers( 1, &vb );
+ }
+
+ public override void DeleteIb( int ib ) {
+ if( ib <= 0 ) return;
+ GL.DeleteBuffers( 1, &ib );
+ }
+
+ VertexFormat batchFormat = (VertexFormat)999;
+ public override void SetBatchFormat( VertexFormat format ) {
+ if( format == batchFormat ) return;
+
+ if( batchFormat == VertexFormat.P3fT2fC4b ) {
+ GL.DisableClientState( ArrayCap.TextureCoordArray );
+ }
+
+ batchFormat = format;
+ if( format == VertexFormat.P3fT2fC4b ) {
+ GL.EnableClientState( ArrayCap.TextureCoordArray );
+ setupBatchFunc = setupBatchFuncTex2fCol4b;
+ batchStride = VertexP3fT2fC4b.Size;
+ } else {
+ setupBatchFunc = setupBatchFuncCol4b;
+ batchStride = VertexP3fC4b.Size;
+ }
+ }
+
+ public override void BindVb( int vb ) {
+ GL.BindBuffer( BufferTarget.ArrayBuffer, vb );
+ }
+
+ public override void BindIb( int ib ) {
+ GL.BindBuffer( BufferTarget.ElementArrayBuffer, ib );
+ }
+
+ const DrawElementsType indexType = DrawElementsType.UnsignedShort;
+ public override void DrawVb( DrawMode mode, int startVertex, int verticesCount ) {
+ setupBatchFunc();
+ GL.DrawArrays( modeMappings[(int)mode], startVertex, verticesCount );
+ }
+
+ public override void DrawIndexedVb( DrawMode mode, int indicesCount, int startIndex ) {
+ setupBatchFunc();
+ GL.DrawElements( modeMappings[(int)mode], indicesCount, indexType, new IntPtr( startIndex * 2 ) );
+ }
+
+ internal override void DrawIndexedVb_TrisT2fC4b( int indicesCount, int startIndex ) {
+ GL.VertexPointer( 3, PointerType.Float, 24, zero );
+ GL.ColorPointer( 4, PointerType.UnsignedByte, 24, twelve );
+ GL.TexCoordPointer( 2, PointerType.Float, 24, sixteen );
+ GL.DrawElements( BeginMode.Triangles, indicesCount, indexType, new IntPtr( startIndex * 2 ) );
+ }
+
+ internal override void DrawIndexedVb_TrisT2fC4b( int indicesCount, int startVertex, int startIndex ) {
+ int offset = startVertex * VertexP3fT2fC4b.Size;
+ GL.VertexPointer( 3, PointerType.Float, 24, new IntPtr( offset ) );
+ GL.ColorPointer( 4, PointerType.UnsignedByte, 24, new IntPtr( offset + 12 ) );
+ GL.TexCoordPointer( 2, PointerType.Float, 24, new IntPtr( offset + 16 ) );
+ GL.DrawElements( BeginMode.Triangles, indicesCount, indexType, new IntPtr( startIndex * 2 ) );
+ }
+
+ IntPtr zero = new IntPtr( 0 ), twelve = new IntPtr( 12 ), sixteen = new IntPtr( 16 );
+
+ void SetupVbPos3fCol4b() {
+ GL.VertexPointer( 3, PointerType.Float, VertexP3fC4b.Size, zero );
+ GL.ColorPointer( 4, PointerType.UnsignedByte, VertexP3fC4b.Size, twelve );
+ }
+
+ void SetupVbPos3fTex2fCol4b() {
+ GL.VertexPointer( 3, PointerType.Float, VertexP3fT2fC4b.Size, zero );
+ GL.ColorPointer( 4, PointerType.UnsignedByte, VertexP3fT2fC4b.Size, twelve );
+ GL.TexCoordPointer( 2, PointerType.Float, VertexP3fT2fC4b.Size, sixteen );
+ }
+ #endregion
+
+ #region Matrix manipulation
+ MatrixMode lastMode = 0;
+ MatrixMode[] matrixModes;
+ public override void SetMatrixMode( MatrixType mode ) {
+ MatrixMode glMode = matrixModes[(int)mode];
+ if( glMode != lastMode ) {
+ GL.MatrixMode( glMode );
+ lastMode = glMode;
+ }
+ }
+
+ public override void LoadMatrix( ref Matrix4 matrix ) {
+ fixed( Single* ptr = &matrix.Row0.X )
+ GL.LoadMatrixf( ptr );
+ }
+
+ public override void LoadIdentityMatrix() {
+ GL.LoadIdentity();
+ }
+
+ public override void PushMatrix() {
+ GL.PushMatrix();
+ }
+
+ public override void PopMatrix() {
+ GL.PopMatrix();
+ }
+
+ public override void MultiplyMatrix( ref Matrix4 matrix ) {
+ fixed( Single* ptr = &matrix.Row0.X )
+ GL.MultMatrixf( ptr );
+ }
+
+ #endregion
+
+ public override void BeginFrame( Game game ) {
+ }
+
+ public override void EndFrame( Game game ) {
+ game.window.SwapBuffers();
+ }
+
+ public override void SetVSync( Game game, bool value ) {
+ game.VSync = value;
+ }
+
+ bool isIntelRenderer;
+ protected override void MakeApiInfo() {
+ string vendor = new String( (sbyte*)GL.GetString( StringName.Vendor ) );
+ string renderer = new String( (sbyte*)GL.GetString( StringName.Renderer ) );
+ string version = new String( (sbyte*)GL.GetString( StringName.Version ) );
+ int depthBits = 0;
+ GL.GetIntegerv( GetPName.DepthBits, &depthBits );
+
+ ApiInfo = new string[] {
+ "--Using OpenGL api--",
+ "Vendor: " + vendor,
+ "Renderer: " + renderer,
+ "GL version: " + version,
+ "Max 2D texture dimensions: " + MaxTextureDimensions,
+ "Depth buffer bits: " + depthBits,
+ };
+ isIntelRenderer = renderer.Contains( "Intel" );
+ }
+
+ public override bool WarnIfNecessary( Chat chat ) {
+ if( !isIntelRenderer ) return false;
+
+ chat.Add( "&cIntel graphics cards are known to have issues with the OpenGL build." );
+ chat.Add( "&cVSync may not work, and you may see disappearing clouds and map edges." );
+ chat.Add( "&cFor Windows, try downloading the Direct3D 9 build instead.");
+ return true;
+ }
+
+ // Based on http://www.opentk.com/doc/graphics/save-opengl-rendering-to-disk
+ public override void TakeScreenshot( string output, int width, int height ) {
+ using( Bitmap bmp = new Bitmap( width, height, BmpPixelFormat.Format32bppRgb ) ) { // ignore alpha component
+ using( FastBitmap fastBmp = new FastBitmap( bmp, true, false ) )
+ GL.ReadPixels( 0, 0, width, height, GlPixelFormat.Bgra, PixelType.UnsignedByte, fastBmp.Scan0 );
+ bmp.RotateFlip( RotateFlipType.RotateNoneFlipY );
+ bmp.Save( output, ImageFormat.Png );
+ }
+ }
+
+ public override void OnWindowResize( Game game ) {
+ GL.Viewport( 0, 0, game.Width, game.Height );
+ }
+
+ void InitFields() {
+ // See comment in Game() constructor for why this is necessary.
+ blendFuncs = new BlendingFactor[6];
+ blendFuncs[0] = BlendingFactor.Zero; blendFuncs[1] = BlendingFactor.One;
+ blendFuncs[2] = BlendingFactor.SrcAlpha; blendFuncs[3] = BlendingFactor.OneMinusSrcAlpha;
+ blendFuncs[4] = BlendingFactor.DstAlpha; blendFuncs[5] = BlendingFactor.OneMinusDstAlpha;
+ compareFuncs = new Compare[8];
+ compareFuncs[0] = Compare.Always; compareFuncs[1] = Compare.Notequal;
+ compareFuncs[2] = Compare.Never; compareFuncs[3] = Compare.Less;
+ compareFuncs[4] = Compare.Lequal; compareFuncs[5] = Compare.Equal;
+ compareFuncs[6] = Compare.Gequal; compareFuncs[7] = Compare.Greater;
+
+ modeMappings = new BeginMode[2];
+ modeMappings[0] = BeginMode.Triangles; modeMappings[1] = BeginMode.Lines;
+ fogModes = new FogMode[3];
+ fogModes[0] = FogMode.Linear; fogModes[1] = FogMode.Exp;
+ fogModes[2] = FogMode.Exp2;
+ matrixModes = new MatrixMode[3];
+ matrixModes[0] = MatrixMode.Projection; matrixModes[1] = MatrixMode.Modelview;
+ matrixModes[2] = MatrixMode.Texture;
+ }
+ }
+}
#endif
\ No newline at end of file
diff --git a/ClassicalSharp/Model/IModel.cs b/ClassicalSharp/Model/IModel.cs
index e67b2b714..183d4f6c5 100644
--- a/ClassicalSharp/Model/IModel.cs
+++ b/ClassicalSharp/Model/IModel.cs
@@ -100,17 +100,17 @@ namespace ClassicalSharp.Model {
protected void DrawPart( ModelPart part ) {
float vScale = _64x64 ? 64f : 32f;
for( int i = 0; i < part.Count; i++ ) {
- ModelVertex model = vertices[part.Offset + i];
- Utils.RotateY( ref model.X, ref model.Z, cosYaw, sinYaw );
- model.X += pos.X; model.Y += pos.Y; model.Z += pos.Z;
+ ModelVertex v = vertices[part.Offset + i];
+ float t = cosYaw * v.X - sinYaw * v.Z; v.Z = sinYaw * v.X + cosYaw * v.Z; v.X = t; // Inlined RotY
+ v.X += pos.X; v.Y += pos.Y; v.Z += pos.Z;
FastColour col = part.Count == boxVertices ?
cols[i >> 2] : FastColour.Scale( this.col, 0.7f );
VertexP3fT2fC4b vertex = default( VertexP3fT2fC4b );
- vertex.X = model.X; vertex.Y = model.Y; vertex.Z = model.Z;
+ vertex.X = v.X; vertex.Y = v.Y; vertex.Z = v.Z;
vertex.R = col.R; vertex.G = col.G; vertex.B = col.B; vertex.A = 255;
- vertex.U = model.U / 64f; vertex.V = model.V / vScale;
+ vertex.U = v.U / 64f; vertex.V = v.V / vScale;
int quadI = i % 4;
if( quadI == 0 || quadI == 3 ) vertex.V -= 0.01f / vScale;
if( quadI == 2 || quadI == 3 ) vertex.U -= 0.01f / 64f;
@@ -126,46 +126,48 @@ namespace ClassicalSharp.Model {
DrawRotated( part.RotX, part.RotY, part.RotZ, angleX, angleY, angleZ, part, true );
}
- protected void DrawRotated( float x, float y, float z, float angleX, float angleY, float angleZ, ModelPart part, bool head ) {
+ protected void DrawRotated( float x, float y, float z,
+ float angleX, float angleY, float angleZ, ModelPart part, bool head ) {
float cosX = (float)Math.Cos( -angleX ), sinX = (float)Math.Sin( -angleX );
float cosY = (float)Math.Cos( -angleY ), sinY = (float)Math.Sin( -angleY );
float cosZ = (float)Math.Cos( -angleZ ), sinZ = (float)Math.Sin( -angleZ );
float vScale = _64x64 ? 64f : 32f;
for( int i = 0; i < part.Count; i++ ) {
- ModelVertex model = vertices[part.Offset + i];
- model.X -= x; model.Y -= y; model.Z -= z;
+ ModelVertex v = vertices[part.Offset + i];
+ v.X -= x; v.Y -= y; v.Z -= z;
+ float t = 0;
// Rotate locally
if( Rotate == RotateOrder.ZYX ) {
- Utils.RotateZ( ref model.X, ref model.Y, cosZ, sinZ );
- Utils.RotateY( ref model.X, ref model.Z, cosY, sinY );
- Utils.RotateX( ref model.Y, ref model.Z, cosX, sinX );
+ t = cosZ * v.X + sinZ * v.Y; v.Y = -sinZ * v.X + cosZ * v.Y; v.X = t; // Inlined RotZ
+ t = cosY * v.X - sinY * v.Z; v.Z = sinY * v.X + cosY * v.Z; v.X = t; // Inlined RotY
+ t = cosX * v.Y + sinX * v.Z; v.Z = -sinX * v.Y + cosX * v.Z; v.Y = t; // Inlined RotX
} else if( Rotate == RotateOrder.XZY ) {
- Utils.RotateX( ref model.Y, ref model.Z, cosX, sinX );
- Utils.RotateZ( ref model.X, ref model.Y, cosZ, sinZ );
- Utils.RotateY( ref model.X, ref model.Z, cosY, sinY );
+ t = cosX * v.Y + sinX * v.Z; v.Z = -sinX * v.Y + cosX * v.Z; v.Y = t; // Inlined RotX
+ t = cosZ * v.X + sinZ * v.Y; v.Y = -sinZ * v.X + cosZ * v.Y; v.X = t; // Inlined RotZ
+ t = cosY * v.X - sinY * v.Z; v.Z = sinY * v.X + cosY * v.Z; v.X = t; // Inlined RotY
}
// Rotate globally
- if( !head) {
- model.X += x; model.Y += y; model.Z += z;
- Utils.RotateY( ref model.X, ref model.Z, cosYaw, sinYaw );
+ if( !head ) {
+ v.X += x; v.Y += y; v.Z += z;
+ t = cosYaw * v.X - sinYaw * v.Z; v.Z = sinYaw * v.X + cosYaw * v.Z; v.X = t; // Inlined RotY
} else {
- Utils.RotateY( ref model.X, ref model.Z, cosHead, sinHead );
- float tempX = x, tempZ = z;
- Utils.RotateY( ref tempX, ref tempZ, cosYaw, sinYaw );
- model.X += tempX; model.Y += y; model.Z += tempZ;
+ t = cosHead * v.X - sinHead * v.Z; v.Z = sinHead * v.X + cosHead * v.Z; v.X = t; // Inlined RotY
+ float tX = x, tZ = z;
+ t = cosYaw * tX - sinYaw * tZ; tZ = sinYaw * tX + cosYaw * tZ; tX = t; // Inlined RotY
+ v.X += tX; v.Y += y; v.Z += tZ;
}
- model.X += pos.X; model.Y += pos.Y; model.Z += pos.Z;
+ v.X += pos.X; v.Y += pos.Y; v.Z += pos.Z;
FastColour col = part.Count == boxVertices ?
cols[i >> 2] : FastColour.Scale( this.col, 0.7f );
VertexP3fT2fC4b vertex = default( VertexP3fT2fC4b );
- vertex.X = model.X; vertex.Y = model.Y; vertex.Z = model.Z;
+ vertex.X = v.X; vertex.Y = v.Y; vertex.Z = v.Z;
vertex.R = col.R; vertex.G = col.G; vertex.B = col.B; vertex.A = 255;
- vertex.U = model.U / 64f; vertex.V = model.V / vScale;
+ vertex.U = v.U / 64f; vertex.V = v.V / vScale;
int quadI = i % 4;
if( quadI == 0 || quadI == 3 ) vertex.V -= 0.01f / vScale;
if( quadI == 2 || quadI == 3 ) vertex.U -= 0.01f / 64f;