mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-10-05 20:15:26 -04:00

Managed pool places data in both video and system memory. By only using the default pool, we only store data in video memory (at the cost of needing to recreate vertex buffers whenever the context is lost). This also means the client will crash whenever it runs out of video memory.. but really if that happens, you are likely stuffed anyway. I think the tradeoff is worth it. I'll also unload far away chunks to reduce video memory usage.
406 lines
17 KiB
C#
406 lines
17 KiB
C#
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
|
|
using System;
|
|
using System.Drawing;
|
|
using OpenTK;
|
|
#if ANDROID
|
|
using Android.Graphics;
|
|
#else
|
|
using System.Drawing.Imaging;
|
|
#endif
|
|
|
|
namespace ClassicalSharp.GraphicsAPI {
|
|
|
|
/// <summary> Abstracts a 3D graphics rendering API. </summary>
|
|
public abstract class IGraphicsApi {
|
|
|
|
/// <summary> Maximum supported length of a dimension (width and height) of a 2D texture. </summary>
|
|
public abstract int MaxTextureDimensions { get; }
|
|
|
|
/// <summary> Sets whether texturing is applied when rasterizing primitives. </summary>
|
|
public abstract bool Texturing { set; }
|
|
|
|
internal float MinZNear = 0.1f;
|
|
readonly FastBitmap bmpBuffer = new FastBitmap();
|
|
|
|
/// <summary> Returns whether this graphics api had a valid context. </summary>
|
|
public bool LostContext;
|
|
|
|
/// <summary> Event raised when a context is destroyed after having been previously lost. </summary>
|
|
public event EventHandler ContextLost;
|
|
|
|
/// <summary> Event raised when a context is recreated after having been previously lost. </summary>
|
|
public event EventHandler ContextRecreated;
|
|
|
|
protected void RaiseContextLost() {
|
|
if( ContextLost != null ) ContextLost( null, null );
|
|
}
|
|
|
|
protected void RaiseContextRecreated() {
|
|
if( ContextRecreated != null ) ContextRecreated( null, null );
|
|
}
|
|
|
|
/// <summary> Delegate that is invoked when the current context is lost,
|
|
/// and is repeatedly invoked until the context can be retrieved. </summary>
|
|
public Action<ScheduledTask> LostContextFunction;
|
|
|
|
|
|
/// <summary> Creates a new native texture with the specified dimensions and using the
|
|
/// image data encapsulated by the Bitmap instance. </summary>
|
|
/// <remarks> Note that should make every effort you can to ensure that the dimensions of the bitmap
|
|
/// are powers of two, because otherwise they will not display properly on certain graphics cards. <br/>
|
|
/// This method returns -1 if the input image is not a 32bpp format. </remarks>
|
|
public int CreateTexture( Bitmap bmp ) {
|
|
if( !Platform.Is32Bpp( bmp ) ) {
|
|
string line2 = String.Format( "input bitmap was not 32bpp" );
|
|
ErrorHandler.LogError( "IGraphicsApi.CreateTexture()",
|
|
Environment.NewLine + line2 +
|
|
Environment.NewLine + Environment.StackTrace );
|
|
return -1;
|
|
}
|
|
bmpBuffer.SetData( bmp, false, true );
|
|
return CreateTexture( bmpBuffer );
|
|
}
|
|
|
|
/// <summary> Creates a new native texture with the specified dimensions and FastBitmap instance
|
|
/// that encapsulates the pointer to the 32bpp image data.</summary>
|
|
/// <remarks> Note that should make every effort you can to ensure that the dimensions are powers of two,
|
|
/// because otherwise they will not display properly on certain graphics cards. </remarks>
|
|
public int CreateTexture( FastBitmap bmp ) {
|
|
if( !bmp.IsLocked ) bmp.LockBits();
|
|
int texId = CreateTexture( bmp.Width, bmp.Height, bmp.Scan0 );
|
|
bmp.UnlockBits();
|
|
return texId;
|
|
}
|
|
|
|
/// <summary> Creates a new native texture with the specified dimensions and pointer to the 32bpp image data. </summary>
|
|
/// <remarks> Note that should make every effort you can to ensure that the dimensions are powers of two,
|
|
/// because otherwise they will not display properly on certain graphics cards. </remarks>
|
|
public abstract int CreateTexture( int width, int height, IntPtr scan0 );
|
|
|
|
/// <summary> Updates the sub-rectangle (texX, texY) -> (texX + part.Width, texY + part.Height)
|
|
/// of the native texture associated with the given ID, with the pixels encapsulated in the 'part' instance. </summary>
|
|
public abstract void UpdateTexturePart( int texId, int texX, int texY, FastBitmap part );
|
|
|
|
/// <summary> Binds the given texture id so that it can be used for rasterization. </summary>
|
|
public abstract void BindTexture( int texId );
|
|
|
|
/// <summary> Frees all native resources held for the given texture id. </summary>
|
|
public abstract void DeleteTexture( ref int texId );
|
|
|
|
/// <summary> Frees all native resources held for the given texture id. </summary>
|
|
public void DeleteTexture( ref Texture texture ) { DeleteTexture( ref texture.ID ); }
|
|
|
|
/// <summary> Sets whether fog is currently enabled. </summary>
|
|
public abstract bool Fog { set; }
|
|
|
|
/// <summary> Sets the fog colour that is blended with final primitive colours. </summary>
|
|
public abstract void SetFogColour( FastColour col );
|
|
|
|
/// <summary> Sets the density of exp and exp^2 fog </summary>
|
|
public abstract void SetFogDensity( float value );
|
|
|
|
/// <summary> Sets the start radius of fog for linear fog. </summary>
|
|
public abstract void SetFogStart( float value );
|
|
|
|
/// <summary> Sets the end radius of fog for for linear fog. </summary>
|
|
public abstract void SetFogEnd( float value );
|
|
|
|
/// <summary> Sets the current fog mode. (linear, exp, or exp^2) </summary>
|
|
public abstract void SetFogMode( Fog fogMode );
|
|
|
|
/// <summary> Whether back facing primitives should be culled by the 3D graphics api. </summary>
|
|
public abstract bool FaceCulling { set; }
|
|
|
|
|
|
/// <summary> Whether alpha testing is currently enabled. </summary>
|
|
public abstract bool AlphaTest { set; }
|
|
|
|
/// <summary> Sets the alpha test compare function that is used when alpha testing is enabled. </summary>
|
|
public abstract void AlphaTestFunc( CompareFunc func, float refValue );
|
|
|
|
/// <summary> Whether alpha blending is currently enabled. </summary>
|
|
public abstract bool AlphaBlending { set; }
|
|
|
|
/// <summary> Sets the alpha blend function that is used when alpha blending is enabled. </summary>
|
|
public abstract void AlphaBlendFunc( BlendFunc srcFunc, BlendFunc dstFunc );
|
|
|
|
/// <summary> Clears the underlying back and/or front buffer. </summary>
|
|
public abstract void Clear();
|
|
|
|
/// <summary> Sets the colour the screen is cleared to when Clear() is called. </summary>
|
|
public abstract void ClearColour( FastColour col );
|
|
|
|
/// <summary> Whether depth testing is currently enabled. </summary>
|
|
public abstract bool DepthTest { set; }
|
|
|
|
/// <summary> Sets the depth test compare function that is used when depth testing is enabled. </summary>
|
|
public abstract void DepthTestFunc( CompareFunc func );
|
|
|
|
/// <summary> Whether writing to the colour buffer is enabled. </summary>
|
|
public abstract bool ColourWrite { set; }
|
|
|
|
/// <summary> Whether writing to the depth buffer is enabled. </summary>
|
|
public abstract bool DepthWrite { set; }
|
|
|
|
/// <summary> Whether blending between the alpha components of the texture and colour are performed. </summary>
|
|
public abstract bool AlphaArgBlend { set; }
|
|
|
|
/// <summary> Creates a vertex buffer that can have its data dynamically updated. </summary>
|
|
public abstract int CreateDynamicVb( VertexFormat format, int maxVertices );
|
|
|
|
/// <summary> Creates a static vertex buffer that has its data set at creation,
|
|
/// but the vertex buffer's data cannot be updated after creation. </summary>
|
|
public abstract int CreateVb<T>( T[] vertices, VertexFormat format, int count ) where T : struct;
|
|
|
|
/// <summary> Creates a static vertex buffer that has its data set at creation,
|
|
/// but the vertex buffer's data cannot be updated after creation. </summary>
|
|
public abstract int CreateVb( IntPtr vertices, VertexFormat format, int count );
|
|
|
|
/// <summary> Creates a static index buffer that has its data set at creation,
|
|
/// but the index buffer's data cannot be updated after creation. </summary>
|
|
public abstract int CreateIb( ushort[] indices, int indicesCount );
|
|
|
|
/// <summary> Creates a static index buffer that has its data set at creation,
|
|
/// but the index buffer's data cannot be updated after creation. </summary>
|
|
public abstract int CreateIb( IntPtr indices, int indicesCount );
|
|
|
|
/// <summary> Sets the currently active vertex buffer to the given id. </summary>
|
|
public abstract void BindVb( int vb );
|
|
|
|
/// <summary> Sets the currently active index buffer to the given id. </summary>
|
|
public abstract void BindIb( int ib );
|
|
|
|
/// <summary> Frees all native resources held for the dynamic vertex buffer associated with the given id. </summary>
|
|
public abstract void DeleteDynamicVb( ref int vb );
|
|
|
|
/// <summary> Frees all native resources held for the vertex buffer associated with the given id. </summary>
|
|
public abstract void DeleteVb( ref int vb );
|
|
|
|
/// <summary> Frees all native resources held for the index buffer associated with the given id. </summary>
|
|
public abstract void DeleteIb( ref int ib );
|
|
|
|
/// <summary> Informs the graphics API that the format of the vertex data used in subsequent
|
|
/// draw calls will be in the given format. </summary>
|
|
public abstract void SetBatchFormat( VertexFormat format );
|
|
|
|
/// <summary> Binds and draws the specified subset of the vertices in the current dynamic vertex buffer<br/>
|
|
/// This method also replaces the dynamic vertex buffer's data first with the given vertices before drawing. </summary>
|
|
public abstract void UpdateDynamicVb<T>( DrawMode mode, int vb, T[] vertices, int count ) where T : struct;
|
|
|
|
/// <summary> Binds and draws the specified subset of the vertices in the current dynamic vertex buffer<br/>
|
|
/// This method also replaces the dynamic vertex buffer's data first with the given vertices before drawing. </summary>
|
|
public abstract void UpdateDynamicIndexedVb<T>( DrawMode mode, int vb, T[] vertices,
|
|
int vCount, int indicesCount ) where T : struct;
|
|
|
|
/// <summary> Binds and updates the data of the current dynamic vertex buffer's data.<br/>
|
|
/// This method also replaces the dynamic vertex buffer's data first with the given vertices before drawing. </summary>
|
|
public abstract void SetDynamicVbData<T>( int vb, T[] vertices, int count ) where T : struct;
|
|
|
|
/// <summary> Draws the specified subset of the vertices in the current vertex buffer. </summary>
|
|
public abstract void DrawVb( DrawMode mode, int startVertex, int verticesCount );
|
|
|
|
/// <summary> Draws the specified subset of the vertices in the current vertex buffer. </summary>
|
|
public abstract void DrawIndexedVb( DrawMode mode, int indicesCount, int startIndex );
|
|
|
|
/// <summary> Optimised version of DrawIndexedVb for VertexFormat.Pos3fTex2fCol4b </summary>
|
|
internal abstract void DrawIndexedVb_TrisT2fC4b( int indicesCount, int offsetVertex, int startIndex );
|
|
|
|
internal abstract void DrawIndexedVb_TrisT2fC4b( int indicesCount, int startIndex );
|
|
|
|
protected static int[] strideSizes = { 16, 24 };
|
|
|
|
|
|
/// <summary> Sets the matrix type that load/push/pop operations should be applied to. </summary>
|
|
public abstract void SetMatrixMode( MatrixType mode );
|
|
|
|
/// <summary> Sets the current matrix to the given matrix. </summary>
|
|
public abstract void LoadMatrix( ref Matrix4 matrix );
|
|
|
|
/// <summary> Sets the current matrix to the identity matrix. </summary>
|
|
public abstract void LoadIdentityMatrix();
|
|
|
|
/// <summary> Multplies the current matrix by the given matrix, then
|
|
/// sets the current matrix to the result of the multiplication. </summary>
|
|
public abstract void MultiplyMatrix( ref Matrix4 matrix );
|
|
|
|
/// <summary> Gets the top matrix the current matrix stack and pushes it to the stack. </summary>
|
|
public abstract void PushMatrix();
|
|
|
|
/// <summary> Removes the top matrix from the current matrix stack, then
|
|
/// sets the current matrix to the new top matrix of the stack. </summary>
|
|
public abstract void PopMatrix();
|
|
|
|
/// <summary> Outputs a .png screenshot of the backbuffer to the specified file. </summary>
|
|
public abstract void TakeScreenshot( string output, int width, int height );
|
|
|
|
/// <summary> Adds a warning to chat if this graphics API has problems with the current user's GPU. </summary>
|
|
public virtual bool WarnIfNecessary( Chat chat ) { return false; }
|
|
|
|
/// <summary> Informs the graphic api to update its state in preparation for a new frame. </summary>
|
|
public abstract void BeginFrame( Game game );
|
|
|
|
/// <summary> Informs the graphic api to update its state in preparation for the end of a frame,
|
|
/// and to prepare that frame for display on the monitor. </summary>
|
|
public abstract void EndFrame( Game game );
|
|
|
|
/// <summary> Sets whether the graphics api should tie frame rendering to the refresh rate of the monitor. </summary>
|
|
public abstract void SetVSync( Game game, bool value );
|
|
|
|
/// <summary> Raised when the dimensions of the game's window have changed. </summary>
|
|
public abstract void OnWindowResize( Game game );
|
|
|
|
internal abstract void MakeApiInfo();
|
|
public string[] ApiInfo;
|
|
|
|
|
|
protected void InitDynamicBuffers() {
|
|
quadVb = CreateDynamicVb( VertexFormat.P3fC4b, 4 );
|
|
texVb = CreateDynamicVb( VertexFormat.P3fT2fC4b, 4 );
|
|
}
|
|
|
|
public virtual void Dispose() {
|
|
DeleteDynamicVb( ref quadVb );
|
|
DeleteDynamicVb( ref texVb );
|
|
}
|
|
|
|
internal VertexP3fC4b[] quadVerts = new VertexP3fC4b[4];
|
|
internal int quadVb;
|
|
public virtual void Draw2DQuad( float x, float y, float width, float height,
|
|
FastColour col ) {
|
|
int c = col.Pack();
|
|
quadVerts[0] = new VertexP3fC4b( x, y, 0, c );
|
|
quadVerts[1] = new VertexP3fC4b( x + width, y, 0, c );
|
|
quadVerts[2] = new VertexP3fC4b( x + width, y + height, 0, c );
|
|
quadVerts[3] = new VertexP3fC4b( x, y + height, 0, c );
|
|
SetBatchFormat( VertexFormat.P3fC4b );
|
|
UpdateDynamicIndexedVb( DrawMode.Triangles, quadVb, quadVerts, 4, 6 );
|
|
}
|
|
|
|
public virtual void Draw2DQuad( float x, float y, float width, float height,
|
|
FastColour topCol, FastColour bottomCol ) {
|
|
int c = topCol.Pack();
|
|
quadVerts[0] = new VertexP3fC4b( x, y, 0, c );
|
|
quadVerts[1] = new VertexP3fC4b( x + width, y, 0, c );
|
|
c = bottomCol.Pack();
|
|
quadVerts[2] = new VertexP3fC4b( x + width, y + height, 0, c );
|
|
quadVerts[3] = new VertexP3fC4b( x, y + height, 0, c );
|
|
SetBatchFormat( VertexFormat.P3fC4b );
|
|
UpdateDynamicIndexedVb( DrawMode.Triangles, quadVb, quadVerts, 4, 6 );
|
|
}
|
|
|
|
internal VertexP3fT2fC4b[] texVerts = new VertexP3fT2fC4b[4];
|
|
internal int texVb;
|
|
public virtual void Draw2DTexture( ref Texture tex, FastColour col ) {
|
|
int index = 0;
|
|
Make2DQuad( ref tex, col, texVerts, ref index );
|
|
SetBatchFormat( VertexFormat.P3fT2fC4b );
|
|
UpdateDynamicIndexedVb( DrawMode.Triangles, texVb, texVerts, 4, 6 );
|
|
}
|
|
|
|
public static void Make2DQuad( ref Texture tex, FastColour col,
|
|
VertexP3fT2fC4b[] vertices, ref int index ) {
|
|
float x1 = tex.X, y1 = tex.Y, x2 = tex.X + tex.Width, y2 = tex.Y + tex.Height;
|
|
#if USE_DX
|
|
// NOTE: see "https://msdn.microsoft.com/en-us/library/windows/desktop/bb219690(v=vs.85).aspx",
|
|
// i.e. the msdn article called "Directly Mapping Texels to Pixels (Direct3D 9)" for why we have to do this.
|
|
x1 -= 0.5f; x2 -= 0.5f;
|
|
y1 -= 0.5f; y2 -= 0.5f;
|
|
#endif
|
|
int c = col.Pack();
|
|
vertices[index++] = new VertexP3fT2fC4b( x1, y1, 0, tex.U1, tex.V1, c );
|
|
vertices[index++] = new VertexP3fT2fC4b( x2, y1, 0, tex.U2, tex.V1, c );
|
|
vertices[index++] = new VertexP3fT2fC4b( x2, y2, 0, tex.U2, tex.V2, c );
|
|
vertices[index++] = new VertexP3fT2fC4b( x1, y2, 0, tex.U1, tex.V2, c );
|
|
}
|
|
|
|
/// <summary> Updates the various matrix stacks and properties so that the graphics API state
|
|
/// is suitable for rendering 2D quads and other 2D graphics to. </summary>
|
|
public void Mode2D( float width, float height, bool setFog ) {
|
|
SetMatrixMode( MatrixType.Projection );
|
|
PushMatrix();
|
|
LoadOrthoMatrix( width, height );
|
|
SetMatrixMode( MatrixType.Modelview );
|
|
PushMatrix();
|
|
LoadIdentityMatrix();
|
|
|
|
DepthTest = false;
|
|
AlphaBlending = true;
|
|
if( setFog ) Fog = false;
|
|
}
|
|
|
|
protected virtual void LoadOrthoMatrix( float width, float height ) {
|
|
Matrix4 matrix = Matrix4.CreateOrthographicOffCenter( 0, width, height, 0, -10000, 10000 );
|
|
LoadMatrix( ref matrix );
|
|
}
|
|
|
|
/// <summary> Updates the various matrix stacks and properties so that the graphics API state
|
|
/// is suitable for rendering 3D vertices. </summary>
|
|
public void Mode3D( bool setFog ) {
|
|
SetMatrixMode( MatrixType.Projection );
|
|
PopMatrix(); // Get rid of orthographic 2D matrix.
|
|
SetMatrixMode( MatrixType.Modelview );
|
|
PopMatrix();
|
|
|
|
DepthTest = true;
|
|
AlphaBlending = false;
|
|
if( setFog ) Fog = true;
|
|
}
|
|
|
|
internal unsafe int MakeDefaultIb() {
|
|
const int maxIndices = 65536 / 4 * 6;
|
|
int element = 0;
|
|
ushort* indices = stackalloc ushort[maxIndices];
|
|
IntPtr ptr = (IntPtr)indices;
|
|
|
|
for( int i = 0; i < maxIndices; i += 6 ) {
|
|
*indices = (ushort)(element + 0); indices++;
|
|
*indices = (ushort)(element + 1); indices++;
|
|
*indices = (ushort)(element + 2); indices++;
|
|
|
|
*indices = (ushort)(element + 2); indices++;
|
|
*indices = (ushort)(element + 3); indices++;
|
|
*indices = (ushort)(element + 0); indices++;
|
|
element += 4;
|
|
}
|
|
return CreateIb( ptr, maxIndices );
|
|
}
|
|
}
|
|
|
|
public enum VertexFormat {
|
|
P3fC4b = 0, P3fT2fC4b = 1,
|
|
}
|
|
|
|
public enum DrawMode {
|
|
Triangles = 0, Lines = 1,
|
|
}
|
|
|
|
public enum CompareFunc {
|
|
Always = 0,
|
|
NotEqual = 1,
|
|
Never = 2,
|
|
|
|
Less = 3,
|
|
LessEqual = 4,
|
|
Equal = 5,
|
|
GreaterEqual = 6,
|
|
Greater = 7,
|
|
}
|
|
|
|
public enum BlendFunc {
|
|
Zero = 0,
|
|
One = 1,
|
|
|
|
SourceAlpha = 2,
|
|
InvSourceAlpha = 3,
|
|
DestAlpha = 4,
|
|
InvDestAlpha = 5,
|
|
}
|
|
|
|
public enum Fog {
|
|
Linear = 0, Exp = 1, Exp2 = 2,
|
|
}
|
|
|
|
public enum MatrixType {
|
|
Projection = 0, Modelview = 1, Texture = 2,
|
|
}
|
|
} |