From e59e78e08c6e80d99b6522a22f4b01cb58b453ab Mon Sep 17 00:00:00 2001 From: Harrison Date: Mon, 1 Jun 2020 01:27:38 -0500 Subject: [PATCH] General progress on getting OpenGL based rendering. --- .../DataTypes/Colour.cs | 7 - .../DataTypes/FloatRectangle.cs | 67 ------ .../DataTypes/FloatVector2.cs | 11 - .../Exceptions/OpenGLErrorException.cs | 29 +++ .../Exceptions/OpenGLException.cs | 2 + src/SlatedGameToolkit.Framework/GameEngine.cs | 20 +- .../Graphics/{OpenGL => }/GLEnums.cs | 6 +- .../Graphics/GLFunctionDelegates.cs | 62 +++++ .../Graphics/Meshes/IMeshable.cs | 16 +- .../Graphics/Meshes/RectangleMesh.cs | 130 ++++++++++ .../Graphics/OpenGL/GLFunctionDelegates.cs | 27 --- .../Graphics/OpenGL/Programs/GLProgram.cs | 54 ----- .../OpenGL/Programs/GLProgramPipeline.cs | 49 ---- .../Programs/GLShaderProgramPipeline.cs | 18 -- .../Graphics/OpenGL/Shaders/GLShader.cs | 42 ---- .../Graphics/Programs/GLProgram.cs | 57 +++++ .../{OpenGL => }/Programs/GLShaderProgram.cs | 22 +- .../Graphics/Render/Batch.cs | 99 ++++++++ .../Graphics/Render/IRenderable.cs | 10 + .../Graphics/Render/Renderer.cs | 25 ++ .../Graphics/Render/Sprite2D.cs | 6 + .../{OpenGL => }/Shaders/GLFragmentShader.cs | 21 +- .../Graphics/Shaders/GLShader.cs | 54 +++++ .../Graphics/Shaders/GLVertexArraySet.cs | 141 +++++++++++ .../{OpenGL => }/Shaders/GLVertexShader.cs | 21 +- .../Graphics/Shaders/VertexArray.cs | 63 +++++ .../Graphics/Textures/GLTexture2DSet.cs | 67 ++++++ .../Graphics/Textures/Texture.cs | 30 +++ .../Graphics/Textures/TextureData.cs | 9 + .../Graphics/Window/WindowContext.cs | 227 ++++++++++-------- .../Graphics/Window/WindowContextsManager.cs | 25 +- .../Loaders/ILoadable.cs | 8 + .../SDL2-bindings/SDL2.cs | 2 +- .../SlatedGameToolkit.Framework.csproj | 2 +- .../StateSystem/Manager.cs | 24 +- .../StateSystem/States/IState.cs | 2 - .../SlatedGameToolkit.Tools.csproj | 2 + .../GraphicalPlayground/MainState.cs | 6 +- tests/UnitTest1.cs | 18 -- tests/tests.csproj | 15 -- 40 files changed, 995 insertions(+), 501 deletions(-) delete mode 100644 src/SlatedGameToolkit.Framework/DataTypes/Colour.cs delete mode 100644 src/SlatedGameToolkit.Framework/DataTypes/FloatRectangle.cs delete mode 100644 src/SlatedGameToolkit.Framework/DataTypes/FloatVector2.cs create mode 100644 src/SlatedGameToolkit.Framework/Exceptions/OpenGLErrorException.cs rename src/SlatedGameToolkit.Framework/Graphics/{OpenGL => }/GLEnums.cs (99%) create mode 100644 src/SlatedGameToolkit.Framework/Graphics/GLFunctionDelegates.cs create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Meshes/RectangleMesh.cs delete mode 100644 src/SlatedGameToolkit.Framework/Graphics/OpenGL/GLFunctionDelegates.cs delete mode 100644 src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLProgram.cs delete mode 100644 src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLProgramPipeline.cs delete mode 100644 src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLShaderProgramPipeline.cs delete mode 100644 src/SlatedGameToolkit.Framework/Graphics/OpenGL/Shaders/GLShader.cs create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Programs/GLProgram.cs rename src/SlatedGameToolkit.Framework/Graphics/{OpenGL => }/Programs/GLShaderProgram.cs (60%) create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Render/Batch.cs create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Render/IRenderable.cs create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Render/Renderer.cs create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Render/Sprite2D.cs rename src/SlatedGameToolkit.Framework/Graphics/{OpenGL => }/Shaders/GLFragmentShader.cs (63%) create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Shaders/GLShader.cs create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Shaders/GLVertexArraySet.cs rename src/SlatedGameToolkit.Framework/Graphics/{OpenGL => }/Shaders/GLVertexShader.cs (63%) create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Shaders/VertexArray.cs create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Textures/GLTexture2DSet.cs create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Textures/Texture.cs create mode 100644 src/SlatedGameToolkit.Framework/Graphics/Textures/TextureData.cs create mode 100644 src/SlatedGameToolkit.Framework/Loaders/ILoadable.cs delete mode 100644 tests/UnitTest1.cs delete mode 100644 tests/tests.csproj diff --git a/src/SlatedGameToolkit.Framework/DataTypes/Colour.cs b/src/SlatedGameToolkit.Framework/DataTypes/Colour.cs deleted file mode 100644 index cc2a00f..0000000 --- a/src/SlatedGameToolkit.Framework/DataTypes/Colour.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace SlatedGameToolkit.Framework.DataTypes -{ - public struct Colour { - public volatile float r, g, b; - - } -} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/DataTypes/FloatRectangle.cs b/src/SlatedGameToolkit.Framework/DataTypes/FloatRectangle.cs deleted file mode 100644 index 147f18a..0000000 --- a/src/SlatedGameToolkit.Framework/DataTypes/FloatRectangle.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; - -namespace SlatedGameToolkit.Framework.DataTypes -{ - public struct FloatRectangle { - public FloatVector2 BottomLeft, TopRight; - - public float Width { - get { - return Math.Abs(BottomLeft.x - TopRight.x); - } - set { - TopRight.x = BottomLeft.x + value; - } - } - - public float Height { - get { - return Math.Abs(BottomLeft.y - TopRight.y); - } - set { - TopRight.y = BottomLeft.y + value; - } - } - - public float X1 { - get { - return BottomLeft.x; - } - - set { - BottomLeft.x = value; - } - } - - public float X2 { - get { - return TopRight.x; - } - - set { - TopRight.x = value; - } - } - - public float Y1 { - get { - return BottomLeft.y; - } - - set { - BottomLeft.y = value; - } - } - - public float Y2 { - get { - return TopRight.y; - } - - set { - TopRight.y = value; - } - } - - } -} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/DataTypes/FloatVector2.cs b/src/SlatedGameToolkit.Framework/DataTypes/FloatVector2.cs deleted file mode 100644 index fd72c0d..0000000 --- a/src/SlatedGameToolkit.Framework/DataTypes/FloatVector2.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace SlatedGameToolkit.Framework.DataTypes -{ - public struct FloatVector2 { - public volatile float x, y; - - public FloatVector2(float x, float y) { - this.x = x; - this.y = y; - } - } -} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Exceptions/OpenGLErrorException.cs b/src/SlatedGameToolkit.Framework/Exceptions/OpenGLErrorException.cs new file mode 100644 index 0000000..110fdbd --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Exceptions/OpenGLErrorException.cs @@ -0,0 +1,29 @@ +using System; +using SlatedGameToolkit.Framework.Graphics; +using SlatedGameToolkit.Framework.Graphics.Window; + +namespace SlatedGameToolkit.Framework.Exceptions +{ + public class OpenGLErrorException : OpenGLException { + public uint ErrorCode { get; private set; } + public OpenGLErrorException(uint errorCode) : base() { + } + + public OpenGLErrorException(uint errorCode, string message) : base(message) { + + } + + public OpenGLErrorException(uint errorCode, string message, Exception inner) : base(message, inner) { + } + + /// + /// Checks the current context for OpenGL errors that has occurred and throws an exception if there is one. + /// + public static void CheckGLErrorStatus() { + uint errorCode = WindowContextsManager.CurrentWindowContext.GetGLStatus(); + if (errorCode != (uint) GLEnums.GL_NO_ERROR) { + throw new OpenGLErrorException(errorCode, "OpenGL error: " + errorCode.ToString()); + } + } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Exceptions/OpenGLException.cs b/src/SlatedGameToolkit.Framework/Exceptions/OpenGLException.cs index efaff0b..e7b18ab 100644 --- a/src/SlatedGameToolkit.Framework/Exceptions/OpenGLException.cs +++ b/src/SlatedGameToolkit.Framework/Exceptions/OpenGLException.cs @@ -1,4 +1,6 @@ using System; +using SlatedGameToolkit.Framework.Graphics; +using SlatedGameToolkit.Framework.Graphics.Window; namespace SlatedGameToolkit.Framework.Exceptions { diff --git a/src/SlatedGameToolkit.Framework/GameEngine.cs b/src/SlatedGameToolkit.Framework/GameEngine.cs index b62eda1..e0c2801 100644 --- a/src/SlatedGameToolkit.Framework/GameEngine.cs +++ b/src/SlatedGameToolkit.Framework/GameEngine.cs @@ -78,10 +78,10 @@ namespace SlatedGameToolkit.Framework { IState initialState = (IState) o; Manager manager = new Manager(initialState); DateTime currentTime = DateTime.Now; - TimeSpan timePassedFromLastUpdate; - TimeSpan timePassedFromLastRender; - TimeSpan updateDeltaTime; - TimeSpan frameDeltaTime; + TimeSpan timePassedFromLastUpdate = TimeSpan.Zero; + TimeSpan timePassedFromLastRender = TimeSpan.Zero; + TimeSpan updateDeltaTime = GameEngine.updateDeltaTime; + TimeSpan frameDeltaTime = GameEngine.frameDeltaTime; deltaChanged = true; stopped = false; Logger.Information("Game engine initiated."); @@ -95,11 +95,6 @@ namespace SlatedGameToolkit.Framework { } deltaChanged = false; } - - DateTime frameStart = DateTime.Now; - TimeSpan difference = frameStart - currentTime; - currentTime = frameStart; - //Events SDL.SDL_Event SDL_Event; while (SDL.SDL_PollEvent(out SDL_Event) != 0) { @@ -154,7 +149,10 @@ namespace SlatedGameToolkit.Framework { break; } } - + DateTime frameStart = DateTime.Now; + TimeSpan difference = frameStart - currentTime; + currentTime = frameStart; + timePassedFromLastUpdate += difference; while (timePassedFromLastUpdate > updateDeltaTime) { //Updates. @@ -226,7 +224,7 @@ namespace SlatedGameToolkit.Framework { throw new FrameworkSDLException(); } - if (SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, 4) < 0) throw new FrameworkSDLException(); + if (SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, 3) < 0) throw new FrameworkSDLException(); if (SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 1) < 0) throw new FrameworkSDLException(); if (SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE) < 0) throw new FrameworkSDLException(); diff --git a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/GLEnums.cs b/src/SlatedGameToolkit.Framework/Graphics/GLEnums.cs similarity index 99% rename from src/SlatedGameToolkit.Framework/Graphics/OpenGL/GLEnums.cs rename to src/SlatedGameToolkit.Framework/Graphics/GLEnums.cs index 5a01f1a..a8a131c 100644 --- a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/GLEnums.cs +++ b/src/SlatedGameToolkit.Framework/Graphics/GLEnums.cs @@ -1,4 +1,4 @@ -namespace SlatedGameToolkit.Framework.Graphics.OpenGL +namespace SlatedGameToolkit.Framework.Graphics { internal enum GLEnums: uint { GL_DEPTH_BUFFER_BIT = 0x00000100, @@ -807,9 +807,5 @@ namespace SlatedGameToolkit.Framework.Graphics.OpenGL GL_MAX_COLOR_TEXTURE_SAMPLES = 0x910E, GL_MAX_DEPTH_TEXTURE_SAMPLES = 0x910F, GL_MAX_INTEGER_SAMPLES = 0x9110, - // - GL_PROGRAM_SEPARABLE = 0x8258, - GL_FRAGMENT_SHADER_BIT = 0x00000002, - GL_VERTEX_SHADER_BIT = 0x00000001, } } \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/GLFunctionDelegates.cs b/src/SlatedGameToolkit.Framework/Graphics/GLFunctionDelegates.cs new file mode 100644 index 0000000..5c02247 --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/GLFunctionDelegates.cs @@ -0,0 +1,62 @@ +using System; +using System.Runtime.InteropServices; +using SDL2; +using SlatedGameToolkit.Framework.Exceptions; + +namespace SlatedGameToolkit.Framework.Graphics +{ + internal delegate void GLClearColour(float r, float g, float b); + internal delegate void GLClear(GLEnums flags); + internal delegate void GLViewport(int x, int y, int width, int height); + internal delegate UIntPtr GLCreateShader(GLEnums type); + internal delegate UIntPtr GLShaderSource(UIntPtr shaderHandle, uint count, string program, int[] length); + internal delegate void GLCompileShader(UIntPtr shaderHandle); + internal delegate void GLGetShaderLogInfo(UIntPtr shader, uint maxLength, out uint writtenLength, out string output); + internal delegate UIntPtr GLCreateProgram(); + internal delegate UIntPtr GLDeleteProgram(UIntPtr program); + internal delegate void GLAttachShader(UIntPtr program, UIntPtr shader); + internal delegate void GLDetachShader(UIntPtr program, UIntPtr shader); + internal delegate void GLDeleteShader(UIntPtr shader); + internal delegate void GLBindAttribLocation(UIntPtr program, uint index, string name); + internal delegate void GLGetProgramInfoLog(UIntPtr program, uint maxLength, out uint writtenLength, out string output); + internal delegate void GLLinkProgram(UIntPtr program); + internal delegate void GLProgramParameter(UIntPtr program, GLEnums parameterName, int value); + internal delegate void GLUseProgram(UIntPtr program); + internal delegate void GLGenProgramPipelines(uint size, out UIntPtr[] pipelines); + internal delegate void GLDeleteProgramPipelines(uint size, UIntPtr[] pipelines); + internal delegate void GLBindProgramPipeline(UIntPtr pipeline); + internal delegate void GLUseProgramStages(UIntPtr pipeline, GLEnums bitField, UIntPtr program); + internal delegate uint GLGetError(); + internal delegate int GLGetAttribLocation(UIntPtr program, string attribName); + internal delegate void GLBindBuffer(GLEnums target, UIntPtr buffer); + internal delegate void GLGenBuffers(uint size, UIntPtr[] buffers); + internal unsafe delegate void GLBufferData(GLEnums target, uint size, void* data, GLEnums usage); + internal delegate void GLDeleteBuffers(uint size, UIntPtr[] buffers); + internal delegate void GLVertexAttribPointer(uint index, int size, GLEnums type, bool normalized, uint stride, uint offset); + internal delegate void GLGenVertexArrays(uint amount, UIntPtr[] arrays); + internal delegate void GLDeleteVertexArrays(uint amount, UIntPtr[] arrays); + internal delegate void GLBindVertexArray(UIntPtr array); + internal delegate void GLEnableVertexAttribArray(uint attribIndex); + internal delegate void GLDisableVertexAttribArray(uint attribIndex); + internal delegate void GLDrawArrays(GLEnums mode, int first, uint count); + internal delegate void GLDrawElements(GLEnums mode, uint count, int offset); + internal delegate void GLMultiDrawArrays(GLEnums mode, int[] first, uint[] count, uint primout); + internal delegate void GLMultiDrawElements(GLEnums mode, uint[] count, GLEnums type, uint[] indices); + internal delegate void GLGenTextures(uint n, UIntPtr[] textureHandles); + internal delegate void GLBindTexture(GLEnums target, UIntPtr texture); + internal delegate void GLDeleteTextures(uint n, UIntPtr[] textureHandles); + internal delegate void GLTexParameteri(GLEnums target, GLEnums pname, int value); + internal delegate void GLTexParameterf(GLEnums target, GLEnums pname, float value); + internal delegate void GLTexParameteriv(GLEnums target, GLEnums pname, int[] values); + internal delegate void GLTexParameterfv(GLEnums target, GLEnums pname, float[] values); + internal delegate void GLTexImage2D(GLEnums target, int level, int internalFormat, uint width, uint height, int border, GLEnums format, GLEnums type, byte[] data); + internal delegate void GLGenerateMipMap(GLEnums target); + + internal static class GLFunctionUtils { + public static T RetrieveGLDelegate(string functionName) where T : Delegate { + IntPtr functionAddress = SDL.SDL_GL_GetProcAddress(functionName); + if (functionAddress == null) throw new FrameworkSDLException(); + return Marshal.GetDelegateForFunctionPointer(functionAddress); + } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Meshes/IMeshable.cs b/src/SlatedGameToolkit.Framework/Graphics/Meshes/IMeshable.cs index 8456221..87773c0 100644 --- a/src/SlatedGameToolkit.Framework/Graphics/Meshes/IMeshable.cs +++ b/src/SlatedGameToolkit.Framework/Graphics/Meshes/IMeshable.cs @@ -1,8 +1,20 @@ + +using System; +using System.Numerics; + namespace SlatedGameToolkit.Framework.Graphics.Meshes { public interface IMeshable { - float[] Vertices { get; } - float[] Elements { get; } + + /// + /// Each value in the array represents a 3D coordinate for the vertex, as well as a 2D texture coordinate. + /// + /// + ValueTuple[] Vertices { get; } + uint[] Elements { get; } + Vector3 Rotation { get; set; } + Vector3 Translation { get; set; } + Vector3 Scale { get; set; } } } \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Meshes/RectangleMesh.cs b/src/SlatedGameToolkit.Framework/Graphics/Meshes/RectangleMesh.cs new file mode 100644 index 0000000..04f85f4 --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Meshes/RectangleMesh.cs @@ -0,0 +1,130 @@ +using System; +using System.Drawing; +using System.Numerics; + +namespace SlatedGameToolkit.Framework.Graphics.Meshes +{ + public class RectangleMesh : IMeshable + { + private bool changed = true; + private Matrix4x4 matRot, matTrans, matScale; + private Vector3 rotation, translation, scale; + private Vector2 origin, dimensions; + public readonly Vector2[] texCoords = new Vector2[4]; + private ValueTuple[] vertices = new ValueTuple[4]; + private uint[] indices = new uint[] {0, 1, 3, 1, 2, 3}; + + public ValueTuple[] Vertices + { + get { + if (changed) CalculateVertices(); + return vertices; + } + } + + public float X { + get + { + return origin.X; + } + + set + { + origin.X = X; + } + } + + public float Y { + get + { + return origin.Y; + } + + set + { + origin.Y = value; + } + } + + public float Width + { + get + { + return dimensions.X; + } + + set { + dimensions.X = value; + } + } + + public float Height + { + get + { + return dimensions.Y; + } + + set + { + dimensions.Y = value; + } + } + + public uint[] Elements { get {return indices; } } + + public Vector3 Translation + { + get { + return rotation; + } + set { + changed = true; + translation = value; + matTrans = Matrix4x4.CreateTranslation(value); + } + } + + public Vector3 Scale + { + get { + return scale; + } + + set { + changed = true; + scale = value; + matScale = Matrix4x4.CreateScale(value); + } + } + + public Vector3 Rotation + { + get + { + return rotation; + } + + set + { + changed = true; + rotation = value; + matRot = Matrix4x4.CreateFromYawPitchRoll(value.X, value.Y, value.Z); + } + } + private void CalculateVertices() { + Vector3[] baseVerts = new Vector3[4]; + baseVerts[0] = new Vector3(this.origin, 0); + baseVerts[1] = new Vector3(this.origin.X + this.dimensions.X, this.origin.Y, 0); + baseVerts[2] = new Vector3(baseVerts[1].X, this.origin.Y + this.dimensions.Y, 0); + baseVerts[3] = new Vector3(this.origin.X, baseVerts[2].Y, 0); + + Matrix4x4 transform = matTrans * matRot * matScale; + for (int i = 0; i < vertices.Length; i++) + { + vertices[i] = new ValueTuple(Vector3.Transform(baseVerts[i], transform), texCoords[i]); + } + changed = false; + } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/GLFunctionDelegates.cs b/src/SlatedGameToolkit.Framework/Graphics/OpenGL/GLFunctionDelegates.cs deleted file mode 100644 index be93cf4..0000000 --- a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/GLFunctionDelegates.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; - -namespace SlatedGameToolkit.Framework.Graphics.OpenGL -{ - internal delegate void GLClearColour(float r, float g, float b); - internal delegate void GLClear(GLEnums flags); - internal delegate void GLViewport(int x, int y, int width, int height); - internal delegate UIntPtr GLCreateShader(GLEnums type); - internal delegate UIntPtr GLShaderSource(UIntPtr shaderHandle, uint count, string program, int[] length); - internal delegate void GLCompileShader(UIntPtr shaderHandle); - internal delegate void GLGetShaderLogInfo(UIntPtr shader, uint maxLength, out uint writtenLength, out string output); - internal delegate UIntPtr GLCreateProgram(); - internal delegate UIntPtr GLDeleteProgram(UIntPtr program); - internal delegate void GLAttachShader(UIntPtr program, UIntPtr shader); - internal delegate void GLDetachShader(UIntPtr program, UIntPtr shader); - internal delegate void GLDeleteShader(UIntPtr shader); - internal delegate void GLBindAttribLocation(UIntPtr program, uint index, string name); - internal delegate void GLGetProgramInfoLog(UIntPtr program, uint maxLength, out uint writtenLength, out string output); - internal delegate void GLLinkProgram(UIntPtr program); - internal delegate void GLProgramParameter(UIntPtr program, GLEnums parameterName, int value); - internal delegate void GLUseProgram(UIntPtr program); - internal delegate void GLGenProgramPipelines(uint size, out UIntPtr[] pipelines); - internal delegate void GLDeleteProgramPipelines(uint size, UIntPtr[] pipelines); - internal delegate void GLBindProgramPipeline(UIntPtr pipeline); - internal delegate void GLUseProgramStages(UIntPtr pipeline, GLEnums bitField, UIntPtr program); - internal delegate uint GLGetError(); -} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLProgram.cs b/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLProgram.cs deleted file mode 100644 index 168023d..0000000 --- a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLProgram.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using SDL2; -using SlatedGameToolkit.Framework.Exceptions; -using SlatedGameToolkit.Framework.Graphics.Window; - -namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Programs -{ - public abstract class GLProgram : IDisposable - { - private WindowContext context; - internal readonly UIntPtr handle; - private protected GLCreateProgram createProgram; - private protected GLDeleteProgram deleteProgram; - private protected GLLinkProgram linkProgram; - private protected GLGetProgramInfoLog getProgramInfoLog; - private protected GLProgramParameter programParameter; - private protected GLUseProgram useProgram; - - public GLProgram(bool separable = true) { - this.context = WindowContextsManager.CurrentWindowContext(); - createProgram = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glCreateProgram")); - if (createProgram == null) throw new FrameworkSDLException(); - deleteProgram = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glDeleteProgram")); - if (deleteProgram == null) throw new FrameworkSDLException(); - linkProgram = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glLinkProgram")); - if (linkProgram == null) throw new FrameworkSDLException(); - getProgramInfoLog = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glGetProgramInfoLog")); - if (getProgramInfoLog == null) throw new FrameworkSDLException(); - programParameter = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glProgramParameter")); - if (programParameter == null) throw new FrameworkSDLException(); - useProgram = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glUseProgram")); - if (useProgram == null) throw new FrameworkSDLException(); - - handle = createProgram(); - if (separable) { - programParameter(handle, GLEnums.GL_PROGRAM_SEPARABLE, (int) GLEnums.GL_TRUE); - } - } - - public virtual void Use() { - useProgram(handle); - } - - public virtual void Dispose() - { - deleteProgram(handle); - } - - ~GLProgram() { - Dispose(); - } - } -} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLProgramPipeline.cs b/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLProgramPipeline.cs deleted file mode 100644 index 5448dbd..0000000 --- a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLProgramPipeline.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using SDL2; -using SlatedGameToolkit.Framework.Exceptions; -using SlatedGameToolkit.Framework.Graphics.OpenGL.Shaders; -using SlatedGameToolkit.Framework.Graphics.Window; - -namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Programs -{ - public abstract class GLProgramPipeline : IDisposable { - private readonly WindowContext associatedContext; - private UIntPtr[] pipelines; - private protected UIntPtr PipelineHandle { get {return pipelines[0]; } } - private protected GLGenProgramPipelines genProgramPipelines; - private protected GLDeleteProgramPipelines deleteProgramPipelines; - private protected GLBindProgramPipeline bindProgramPipeline; - private protected GLUseProgramStages useProgramStages; - private protected GLUseProgram useProgram; - public GLProgramPipeline() { - associatedContext = WindowContextsManager.CurrentWindowContext(); - genProgramPipelines = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glGenProgramPipelines")); - if (genProgramPipelines == null) throw new FrameworkSDLException(); - useProgramStages = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glUseProgramStages")); - if (useProgramStages == null) throw new FrameworkSDLException(); - useProgram = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glUseProgram")); - if (useProgram == null) throw new FrameworkSDLException(); - bindProgramPipeline = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glBindProgramPipeline")); - if (bindProgramPipeline == null) throw new FrameworkSDLException(); - deleteProgramPipelines = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glDeleteProgramPipelines")); - if (deleteProgramPipelines == null) throw new FrameworkSDLException(); - - genProgramPipelines(1, out pipelines); - - } - - public virtual void Use() { - useProgram(UIntPtr.Zero); - } - - public virtual void Dispose() - { - deleteProgramPipelines((uint) pipelines.Length, pipelines); - } - - ~GLProgramPipeline() { - Dispose(); - } - } -} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLShaderProgramPipeline.cs b/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLShaderProgramPipeline.cs deleted file mode 100644 index b261967..0000000 --- a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLShaderProgramPipeline.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Programs -{ - public class GLShaderProgramPipeline : GLProgramPipeline { - private GLShaderProgram fragmentShader; - private GLShaderProgram vertexShader; - public GLShaderProgram FragmentShader { get { return fragmentShader; } set { fragmentShader = value; useProgramStages(PipelineHandle, GLEnums.GL_FRAGMENT_SHADER_BIT, value.handle); } } - public GLShaderProgram VertexShader { get { return vertexShader; } set { vertexShader = value; useProgramStages(PipelineHandle, GLEnums.GL_VERTEX_SHADER_BIT, value.handle); } } - - public GLShaderProgramPipeline() : base() { - - } - - public override void Use() { - base.Use(); - bindProgramPipeline(PipelineHandle); - } - } -} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Shaders/GLShader.cs b/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Shaders/GLShader.cs deleted file mode 100644 index 526da9d..0000000 --- a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Shaders/GLShader.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using SDL2; -using SlatedGameToolkit.Framework.Exceptions; -using SlatedGameToolkit.Framework.Graphics.Window; - -namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Shaders -{ - public abstract class GLShader : IDisposable { - private WindowContext context; - public UIntPtr Handle { get; private protected set; } - - private protected GLCreateShader createShader; - private protected GLShaderSource shaderSource; - private protected GLCompileShader compileShader; - private protected GLGetShaderLogInfo getShaderLogInfo; - private protected GLDeleteShader deleteShader; - - public GLShader() { - context = WindowContextsManager.CurrentWindowContext(); - createShader = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glCreateShader")); - if (createShader == null) throw new FrameworkSDLException(); - shaderSource = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glShaderSource")); - if (shaderSource == null) throw new FrameworkSDLException(); - compileShader = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glCompileShader")); - if (compileShader == null) throw new FrameworkSDLException(); - getShaderLogInfo = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glGetShaderLogInfo")); - if(getShaderLogInfo == null) throw new FrameworkSDLException(); - deleteShader = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glDeleteShader")); - if (deleteShader == null) throw new FrameworkSDLException(); - - } - - public virtual void Dispose() - { - } - - ~GLShader() { - Dispose(); - } - } -} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Programs/GLProgram.cs b/src/SlatedGameToolkit.Framework/Graphics/Programs/GLProgram.cs new file mode 100644 index 0000000..da8dbce --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Programs/GLProgram.cs @@ -0,0 +1,57 @@ +using System; +using System.Runtime.InteropServices; +using SDL2; +using SlatedGameToolkit.Framework.Exceptions; +using SlatedGameToolkit.Framework.Graphics.Window; + +namespace SlatedGameToolkit.Framework.Graphics.Programs +{ + public abstract class GLProgram : IDisposable + { + private WindowContext context; + private protected readonly UIntPtr handle; + private protected GLCreateProgram createProgram; + private protected GLDeleteProgram deleteProgram; + private protected GLLinkProgram linkProgram; + private protected GLGetProgramInfoLog getProgramInfoLog; + private protected GLProgramParameter programParameter; + private protected GLUseProgram useProgram; + + /// + /// Creates an OpenGL program. + /// + /// This is bound to the current context. + /// + internal GLProgram() { + this.context = WindowContextsManager.CurrentWindowContext; + createProgram = GLFunctionUtils.RetrieveGLDelegate("glCreateProgram"); + deleteProgram = GLFunctionUtils.RetrieveGLDelegate("glDeleteProgram"); + linkProgram = GLFunctionUtils.RetrieveGLDelegate("glLinkProgram"); + getProgramInfoLog = GLFunctionUtils.RetrieveGLDelegate("glGetProgramInfoLog"); + programParameter = GLFunctionUtils.RetrieveGLDelegate("glProgramParameteri"); + useProgram = GLFunctionUtils.RetrieveGLDelegate("glUseProgram"); + + handle = createProgram(); + } + + /// + /// Binds this program. + /// + public virtual void Use() { + useProgram(handle); + } + + /// + /// Disposes of the program. + /// + public virtual void Dispose() + { + deleteProgram(handle); + OpenGLErrorException.CheckGLErrorStatus(); + } + + ~GLProgram() { + Dispose(); + } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLShaderProgram.cs b/src/SlatedGameToolkit.Framework/Graphics/Programs/GLShaderProgram.cs similarity index 60% rename from src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLShaderProgram.cs rename to src/SlatedGameToolkit.Framework/Graphics/Programs/GLShaderProgram.cs index a6b4823..286d78c 100644 --- a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Programs/GLShaderProgram.cs +++ b/src/SlatedGameToolkit.Framework/Graphics/Programs/GLShaderProgram.cs @@ -1,11 +1,8 @@ using System; -using System.Runtime.InteropServices; -using SDL2; using SlatedGameToolkit.Framework.Exceptions; -using SlatedGameToolkit.Framework.Graphics.OpenGL.Shaders; -using SlatedGameToolkit.Framework.Graphics.Window; +using SlatedGameToolkit.Framework.Graphics.Shaders; -namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Programs +namespace SlatedGameToolkit.Framework.Graphics.Programs { public class GLShaderProgram : GLProgram { @@ -13,15 +10,13 @@ namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Programs private readonly GLAttachShader attachShader; private readonly GLDetachShader detachShader; private GLBindAttribLocation bindAttribLocation; - public GLShaderProgram(bool separable = true, params GLShader[] shaders) : base(separable) { + public GLShaderProgram(bool separable = true, params GLShader[] shaders) : base() { if (shaders.Length == 0) throw new ArgumentException("Requires at least one shader for shader program."); this.shaders = shaders; - attachShader = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glAttachShader")); - if (attachShader == null) throw new FrameworkSDLException(); - bindAttribLocation = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glBindAttribLocation")); - if (bindAttribLocation == null) throw new FrameworkSDLException(); - detachShader = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glDetachShader")); - if (detachShader == null) throw new FrameworkSDLException(); + + attachShader = GLFunctionUtils.RetrieveGLDelegate("glAttachShader"); + bindAttribLocation = GLFunctionUtils.RetrieveGLDelegate("glBindAttribLocation"); + detachShader = GLFunctionUtils.RetrieveGLDelegate("glDetachShader"); foreach (GLShader shader in shaders) { @@ -43,6 +38,9 @@ namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Programs } } + /// + /// Disposes of the shaders and this program. + /// public override void Dispose() { foreach (GLShader shader in shaders) { diff --git a/src/SlatedGameToolkit.Framework/Graphics/Render/Batch.cs b/src/SlatedGameToolkit.Framework/Graphics/Render/Batch.cs new file mode 100644 index 0000000..97d7018 --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Render/Batch.cs @@ -0,0 +1,99 @@ +using System; +using System.Drawing; +using System.Numerics; +using SlatedGameToolkit.Framework.Graphics.Meshes; +using SlatedGameToolkit.Framework.Graphics; +using SlatedGameToolkit.Framework.Graphics.Textures; +using SlatedGameToolkit.Framework.Graphics.Shaders; + +namespace SlatedGameToolkit.Framework.Graphics.Render +{ + public class Batch : IDisposable { + private Texture texture; + private bool disposed; + private VertexArray vertexArray; + private const int VERTEX_LENGTH = 6; + private GLMultiDrawElements multiDrawElements; + public bool Batching { get; private set; } + private float[] data; + private uint[] indices; + private uint[] lengths; + private uint[] offsets; + private uint dataIndex, indicesIndex, lengthsIndex; + + public Batch(uint BatchVertexSize = 4096) { + multiDrawElements = GLFunctionUtils.RetrieveGLDelegate("glMultDrawElements"); + indices = new uint[BatchVertexSize]; + lengths = new uint[BatchVertexSize]; + offsets = new uint[BatchVertexSize]; + data = new float[BatchVertexSize * VERTEX_LENGTH]; + + vertexArray = new VertexArray(); + + VertexAttributeDefinition[] definitions = new VertexAttributeDefinition[3]; + definitions[0] = new VertexAttributeDefinition(0, 3, 3 * sizeof(float), 0); + definitions[1] = new VertexAttributeDefinition(1, 4, 1 * sizeof(float), 3 * sizeof(float)); + definitions[2] = new VertexAttributeDefinition(2, 2, 2 * sizeof(float), 4 * sizeof(float)); + vertexArray.defineVertexAttributes(definitions: definitions); + } + + public virtual void Begin(Texture texture) { + if (Batching) throw new InvalidOperationException("This batch is already started."); + this.texture = texture ?? throw new ArgumentNullException("texture"); + this.Batching = true; + } + + public virtual void Dispose() + { + if (disposed) return; + disposed = true; + vertexArray.Dispose(); + } + + public virtual void Draw(IMeshable meshable, Color color) { + ValueTuple[] vertices = meshable.Vertices; + uint[] indices = meshable.Elements; + if (vertices.Length * VERTEX_LENGTH + dataIndex >= data.Length || indices.Length + indicesIndex >= indicesIndex) Flush(); + for (int i = 0; i < vertices.Length; i++) { + data[dataIndex] = vertices[i].Item1.X; + dataIndex++; + data[dataIndex] = vertices[i].Item1.Y; + dataIndex++; + data[dataIndex] = vertices[i].Item1.Z; + dataIndex++; + + data[dataIndex] = color.ToArgb(); + dataIndex++; + + data[dataIndex] = vertices[i].Item2.X; + dataIndex++; + data[dataIndex] = vertices[i].Item2.Y; + dataIndex++; + + uint elementsCount = (uint)indices.Length; + Array.Copy(indices, indices, elementsCount); + indicesIndex += elementsCount; + + lengths[lengthsIndex] = elementsCount; + lengthsIndex ++; + } + } + + public virtual void End() { + if (!Batching) throw new InvalidOperationException("This batch was never started."); + this.Batching = false; + Flush(); + } + + protected virtual void Flush() { + texture.Use(); + vertexArray.Use(); + vertexArray.BufferVertices(data); + vertexArray.BufferIndices(indices); + dataIndex = 0; + indicesIndex = 0; + lengthsIndex = 0; + multiDrawElements(GLEnums.GL_TRIANGLE_STRIP, lengths, GLEnums.GL_UNSIGNED_INT, offsets); + } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Render/IRenderable.cs b/src/SlatedGameToolkit.Framework/Graphics/Render/IRenderable.cs new file mode 100644 index 0000000..77de1ca --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Render/IRenderable.cs @@ -0,0 +1,10 @@ +using SlatedGameToolkit.Framework.Graphics.Meshes; +using SlatedGameToolkit.Framework.Graphics.Textures; + +namespace SlatedGameToolkit.Framework.Graphics.Render +{ + public interface IRenderable : IMeshable + { + Texture Texture { get; } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Render/Renderer.cs b/src/SlatedGameToolkit.Framework/Graphics/Render/Renderer.cs new file mode 100644 index 0000000..98022eb --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Render/Renderer.cs @@ -0,0 +1,25 @@ +using System.Drawing; +using SlatedGameToolkit.Framework.Graphics.Textures; + +namespace SlatedGameToolkit.Framework.Graphics.Render +{ + public class Renderer + { + private Batch batch; + private Texture currentTexture; + + public void Queue(IRenderable renderable, Color color) { + if (renderable.Texture != currentTexture) { + if (batch.Batching) batch.End(); + currentTexture = renderable.Texture; + currentTexture.Use(); + batch.Begin(currentTexture); + } + batch.Draw(renderable, color); + } + + public void Render() { + if (batch.Batching) batch.End(); + } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Render/Sprite2D.cs b/src/SlatedGameToolkit.Framework/Graphics/Render/Sprite2D.cs new file mode 100644 index 0000000..54716d7 --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Render/Sprite2D.cs @@ -0,0 +1,6 @@ +namespace SlatedGameToolkit.Framework.Graphics.Render +{ + public class Sprite2D + { + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Shaders/GLFragmentShader.cs b/src/SlatedGameToolkit.Framework/Graphics/Shaders/GLFragmentShader.cs similarity index 63% rename from src/SlatedGameToolkit.Framework/Graphics/OpenGL/Shaders/GLFragmentShader.cs rename to src/SlatedGameToolkit.Framework/Graphics/Shaders/GLFragmentShader.cs index 0e50b8b..432dd41 100644 --- a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Shaders/GLFragmentShader.cs +++ b/src/SlatedGameToolkit.Framework/Graphics/Shaders/GLFragmentShader.cs @@ -1,12 +1,13 @@ -using System; -using System.Runtime.InteropServices; -using SDL2; using SlatedGameToolkit.Framework.Exceptions; -using SlatedGameToolkit.Framework.Graphics.Window; -namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Shaders +namespace SlatedGameToolkit.Framework.Graphics.Shaders { public class GLFragmentShader : GLShader { + + /// + /// Creates an OpenGL fragment shader. + /// + /// A string representing the GLSL code to run. public GLFragmentShader(string shader) : base() { Handle = createShader(GLEnums.GL_FRAGMENT_SHADER); shaderSource(Handle, 1, shader, null); @@ -18,15 +19,7 @@ namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Shaders Dispose(); throw new OpenGLException(shaderLog); } - } - - public override void Dispose() - { - deleteShader(Handle); - } - - ~GLFragmentShader() { - Dispose(); + OpenGLErrorException.CheckGLErrorStatus(); } } } \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Shaders/GLShader.cs b/src/SlatedGameToolkit.Framework/Graphics/Shaders/GLShader.cs new file mode 100644 index 0000000..a9d141a --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Shaders/GLShader.cs @@ -0,0 +1,54 @@ +using System; +using System.Runtime.InteropServices; +using SDL2; +using SlatedGameToolkit.Framework.Exceptions; +using SlatedGameToolkit.Framework.Graphics.Window; + +namespace SlatedGameToolkit.Framework.Graphics.Shaders +{ + public abstract class GLShader : IDisposable { + private WindowContext context; + public UIntPtr Handle { get; private protected set; } + + private protected GLCreateShader createShader; + private protected GLShaderSource shaderSource; + private protected GLCompileShader compileShader; + private protected GLGetShaderLogInfo getShaderLogInfo; + private protected GLGetAttribLocation getAttribLocation; + private GLDeleteShader deleteShader; + + internal GLShader() { + context = WindowContextsManager.CurrentWindowContext; + createShader = GLFunctionUtils.RetrieveGLDelegate("glCreateShader"); + shaderSource = GLFunctionUtils.RetrieveGLDelegate("glShaderSource"); + compileShader = GLFunctionUtils.RetrieveGLDelegate("glCompileShader"); + getShaderLogInfo = GLFunctionUtils.RetrieveGLDelegate("glGetShaderLogInfo"); + deleteShader = GLFunctionUtils.RetrieveGLDelegate("glDeleteShader"); + getAttribLocation = GLFunctionUtils.RetrieveGLDelegate("glGetAttribLocation"); + } + + /// + /// Gets the attribute location. + /// + /// The name of the attribute. + /// The attribute location index. + public int GetAttributeLocation(string attributeName) { + int index = getAttribLocation(Handle, attributeName); + OpenGLErrorException.CheckGLErrorStatus(); + return index; + } + + /// + /// Disposes of the shader at the handle. + /// + public virtual void Dispose() + { + deleteShader(Handle); + OpenGLErrorException.CheckGLErrorStatus(); + } + + ~GLShader() { + Dispose(); + } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Shaders/GLVertexArraySet.cs b/src/SlatedGameToolkit.Framework/Graphics/Shaders/GLVertexArraySet.cs new file mode 100644 index 0000000..5202eb3 --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Shaders/GLVertexArraySet.cs @@ -0,0 +1,141 @@ +using System; +using System.Runtime.InteropServices; +using SlatedGameToolkit.Framework.Exceptions; + +namespace SlatedGameToolkit.Framework.Graphics.Shaders +{ + public class GLVertexArraySet : IDisposable { + private bool disposed; + public int Count { get; private set; } + private UIntPtr[] arrayBufferHandles; + private UIntPtr[] vertexArrayHandles; + private UIntPtr[] indexArrayHandles; + private GLBindBuffer bindBuffer; + private GLGenBuffers genBuffers; + private GLDeleteBuffers deleteBuffers; + private GLGenVertexArrays genVertexArrays; + private GLBindVertexArray bindVertexArray; + private GLDeleteVertexArrays deleteVertexArrays; + private GLVertexAttribPointer vertexAttribPointer; + private GLEnableVertexAttribArray enableVertexAttribArray; + private GLDisableVertexAttribArray disableVertexAttribArray; + private GLBufferData bufferData; + + public GLVertexArraySet(uint amount) { + if (amount > int.MaxValue) throw new ArgumentOutOfRangeException("amount"); + this.Count = (int)amount; + genBuffers = GLFunctionUtils.RetrieveGLDelegate("glGenBuffers"); + deleteBuffers = GLFunctionUtils.RetrieveGLDelegate("glDeleteBuffers"); + bindBuffer = GLFunctionUtils.RetrieveGLDelegate("glBindBuffer"); + genVertexArrays = GLFunctionUtils.RetrieveGLDelegate("glGenVertexArrays"); + bindVertexArray = GLFunctionUtils.RetrieveGLDelegate("glBindVertexArray"); + deleteVertexArrays = GLFunctionUtils.RetrieveGLDelegate("glDeleteVertexArrays"); + vertexAttribPointer = GLFunctionUtils.RetrieveGLDelegate("glVertexAttribPointer"); + enableVertexAttribArray = GLFunctionUtils.RetrieveGLDelegate("glEnableVertexAttribArray"); + disableVertexAttribArray = GLFunctionUtils.RetrieveGLDelegate("glDisableVertexAttribArray"); + bufferData = GLFunctionUtils.RetrieveGLDelegate("glBufferData"); + + genBuffers(amount, arrayBufferHandles); + OpenGLErrorException.CheckGLErrorStatus(); + genVertexArrays(amount, vertexArrayHandles); + OpenGLErrorException.CheckGLErrorStatus(); + genBuffers(amount, indexArrayHandles); + } + + public void Use(uint index) { + bindVertexArray(vertexArrayHandles[index]); + OpenGLErrorException.CheckGLErrorStatus(); + bindBuffer(GLEnums.GL_ELEMENT_ARRAY_BUFFER, indexArrayHandles[index]); + bindBuffer(GLEnums.GL_ARRAY_BUFFER, arrayBufferHandles[index]); + OpenGLErrorException.CheckGLErrorStatus(); + } + + public unsafe void BufferVertices(uint index, float[] data, bool dynamic) { + Use(index); + fixed (void* arrayData = &data[0]) { + bufferData(GLEnums.GL_ARRAY_BUFFER, (uint) (sizeof(float) * data.Length), arrayData, dynamic ? GLEnums.GL_DYNAMIC_DRAW : GLEnums.GL_STATIC_DRAW); + } + OpenGLErrorException.CheckGLErrorStatus(); + } + + public unsafe void BufferIndices(uint index, uint[] data, bool dynamic) { + Use(index); + fixed (void* arrayData = &data[0]) { + bufferData(GLEnums.GL_ELEMENT_ARRAY_BUFFER, (uint) (sizeof(float) * data.Length), arrayData, dynamic ? GLEnums.GL_DYNAMIC_DRAW : GLEnums.GL_STATIC_DRAW); + } + OpenGLErrorException.CheckGLErrorStatus(); + } + + /// + /// Defines the vertex attributes in an OpenGL vertex array object. + /// Sends as floats. + /// + /// The buffer in this set to affect. + /// Whether or not to automatically enable the attributes that are being defined. Defaults to true. + /// The definitions for the vertex array object. + public void defineVertexAttributes(uint bufferIndex, bool enableAttributes = true, params VertexAttributeDefinition[] definitions) { + Use(bufferIndex); + foreach (VertexAttributeDefinition definition in definitions) + { + vertexAttribPointer(definition.attributeIndex, definition.size, GLEnums.GL_FLOAT, false, definition.stride, definition.offset); + OpenGLErrorException.CheckGLErrorStatus(); + if (enableAttributes) enableVertexAttribArray(definition.attributeIndex); + } + } + + /// + /// Enaables the vertex array object's definitions at the given attribute indices. + /// + /// The buffer index in this set this should affect. + /// The attribute indices to be enabled. + public void EnableAttributes(uint bufferIndex, params uint[] attributeIndices) { + Use(bufferIndex); + foreach (uint attrib in attributeIndices) + { + enableVertexAttribArray(attrib); + } + } + + /// + /// Disables the vertex array object's definitions at the given attribute indices. + /// + /// The buffer index in this set that should be affected. + /// The attribute indices to be disabled. + public void DisableAttributes(uint bufferIndex, params uint[] attributeIndices) { + Use(bufferIndex); + foreach (uint attrib in attributeIndices) + { + disableVertexAttribArray(attrib); + } + } + + public void Dispose() + { + if (this.disposed) return; + this.disposed = true; + deleteBuffers((uint)arrayBufferHandles.Length, arrayBufferHandles); + OpenGLErrorException.CheckGLErrorStatus(); + deleteVertexArrays((uint)vertexArrayHandles.Length, vertexArrayHandles); + OpenGLErrorException.CheckGLErrorStatus(); + GC.SuppressFinalize(this); + } + + ~GLVertexArraySet() { + Dispose(); + } + } + + public struct VertexAttributeDefinition { + public uint attributeIndex; + public int size; + public uint stride; + public uint offset; + + public VertexAttributeDefinition(uint attributeIndex, int size, uint stride, uint offset) { + this.attributeIndex = attributeIndex; + this.size = size; + this.stride = stride; + this.offset = offset; + } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Shaders/GLVertexShader.cs b/src/SlatedGameToolkit.Framework/Graphics/Shaders/GLVertexShader.cs similarity index 63% rename from src/SlatedGameToolkit.Framework/Graphics/OpenGL/Shaders/GLVertexShader.cs rename to src/SlatedGameToolkit.Framework/Graphics/Shaders/GLVertexShader.cs index 2c7b832..5967752 100644 --- a/src/SlatedGameToolkit.Framework/Graphics/OpenGL/Shaders/GLVertexShader.cs +++ b/src/SlatedGameToolkit.Framework/Graphics/Shaders/GLVertexShader.cs @@ -1,12 +1,13 @@ -using System; -using System.Runtime.InteropServices; -using SDL2; using SlatedGameToolkit.Framework.Exceptions; -using SlatedGameToolkit.Framework.Graphics.Window; -namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Shaders +namespace SlatedGameToolkit.Framework.Graphics.Shaders { public class GLVertexShader : GLShader { + + /// + /// Creates an OpenGL vertex shader. + /// + /// A string representing the GLSL code. public GLVertexShader(string shader) : base() { Handle = createShader(GLEnums.GL_VERTEX_SHADER); shaderSource(Handle, 1, shader, null); @@ -18,15 +19,7 @@ namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Shaders Dispose(); throw new OpenGLException(shaderLog); } - } - - public override void Dispose() - { - deleteShader(Handle); - } - - ~GLVertexShader() { - Dispose(); + OpenGLErrorException.CheckGLErrorStatus(); } } } \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Shaders/VertexArray.cs b/src/SlatedGameToolkit.Framework/Graphics/Shaders/VertexArray.cs new file mode 100644 index 0000000..5a5547c --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Shaders/VertexArray.cs @@ -0,0 +1,63 @@ +using System; + +namespace SlatedGameToolkit.Framework.Graphics.Shaders +{ + public class VertexArray : IDisposable + { + private GLVertexArraySet glVertexArraySet; + private uint index; + + public VertexArray(GLVertexArraySet gLVertexArraySet, uint index) { + this.glVertexArraySet = gLVertexArraySet; + this.index = index; + } + + public VertexArray() { + this.glVertexArraySet = new GLVertexArraySet(1); + this.index = 0; + } + + public unsafe void BufferVertices(float[] data, bool dynamic = true) { + glVertexArraySet.BufferVertices(index, data, dynamic); + } + + public unsafe void BufferIndices(uint[] data, bool dynamic = true) { + glVertexArraySet.BufferIndices(index, data, dynamic); + } + + /// + /// Defines the vertex attributes in an OpenGL vertex array object. + /// Sends as floats. + /// + /// Whether or not to automatically enable the attributes that are being defined. Defaults to true. + /// The definitions for the vertex array object. + public void defineVertexAttributes(bool enableAttributes = true, params VertexAttributeDefinition[] definitions) { + this.glVertexArraySet.defineVertexAttributes(index, enableAttributes, definitions); + } + + /// + /// Enaables the vertex array object's definitions at the given attribute indices. + /// + /// The attribute indices to be enabled. + public void EnableAttributes(params uint[] attributeIndices) { + glVertexArraySet.EnableAttributes(index, attributeIndices); + } + + /// + /// Disables the vertex array object's definitions at the given attribute indices. + /// + /// The attribute indices to be disabled. + public void DisableAttributes(params uint[] attributeIndices) { + glVertexArraySet.DisableAttributes(index, attributeIndices); + } + + public void Use() { + glVertexArraySet.Use(index); + } + + public void Dispose() + { + this.glVertexArraySet.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Textures/GLTexture2DSet.cs b/src/SlatedGameToolkit.Framework/Graphics/Textures/GLTexture2DSet.cs new file mode 100644 index 0000000..1e7da56 --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Textures/GLTexture2DSet.cs @@ -0,0 +1,67 @@ +using System; +using SlatedGameToolkit.Framework.Exceptions; +using SlatedGameToolkit.Framework.Graphics; +using SlatedGameToolkit.Framework.Graphics.Textures; + +namespace SlatedGameToolkit.Framework.Graphics +{ + public class GLTexture2DSet : IDisposable + { + private bool disposed; + public int Count { get; private set; } + private GLGenTextures genTextures; + private GLTexParameteri texParameteri; + private GLTexParameterfv texParameterfv; + private GLDeleteTextures deleteTextures; + private GLTexImage2D texImage2D; + private GLBindTexture bindTexture; + private GLGenerateMipMap generateMipMap; + private readonly UIntPtr[] handle; + private readonly bool linear, mipmap; + + public GLTexture2DSet(TextureData[] textureDatas, bool linear = false, bool mipmap = false) + { + this.linear = linear; + genTextures = GLFunctionUtils.RetrieveGLDelegate("glGenTextures"); + deleteTextures = GLFunctionUtils.RetrieveGLDelegate("glDeleteTextures"); + bindTexture = GLFunctionUtils.RetrieveGLDelegate("glBindTexture"); + texParameteri = GLFunctionUtils.RetrieveGLDelegate("glTexParameteri"); + texParameterfv = GLFunctionUtils.RetrieveGLDelegate("glTexParameterfv"); + texImage2D = GLFunctionUtils.RetrieveGLDelegate("glTexImage2D"); + generateMipMap = GLFunctionUtils.RetrieveGLDelegate("glGenerateMipMap"); + + genTextures((uint)textureDatas.Length, handle); + for (uint i = 0; i < textureDatas.Length; i++) { + Setup(i, textureDatas[i]); + } + bindTexture(GLEnums.GL_TEXTURE_2D, UIntPtr.Zero); + OpenGLErrorException.CheckGLErrorStatus(); + + this.Count = textureDatas.Length; + } + + private void Setup(uint index, TextureData textureData) { + bindTexture(GLEnums.GL_TEXTURE_2D, handle[index]); + texParameteri(GLEnums.GL_TEXTURE_2D, GLEnums.GL_TEXTURE_WRAP_S, (int)GLEnums.GL_CLAMP_TO_EDGE); + texParameteri(GLEnums.GL_TEXTURE_2D, GLEnums.GL_TEXTURE_WRAP_S, (int)GLEnums.GL_CLAMP_TO_EDGE); + texParameteri(GLEnums.GL_TEXTURE_2D, GLEnums.GL_TEXTURE_MIN_FILTER, (int)(linear ? (mipmap ? GLEnums.GL_LINEAR_MIPMAP_LINEAR : GLEnums.GL_LINEAR) : (mipmap ? GLEnums.GL_NEAREST_MIPMAP_LINEAR : GLEnums.GL_NEAREST))); + texParameteri(GLEnums.GL_TEXTURE_2D, GLEnums.GL_TEXTURE_MAG_FILTER, (int)(linear ? GLEnums.GL_LINEAR : GLEnums.GL_NEAREST)); + texImage2D(GLEnums.GL_TEXTURE_2D, 0, (int)GLEnums.GL_RGBA, textureData.width, textureData.height, 0, GLEnums.GL_RGBA, GLEnums.GL_UNSIGNED_BYTE, textureData.data); + generateMipMap(GLEnums.GL_TEXTURE_2D); + } + + public void Bind(uint index) { + bindTexture(GLEnums.GL_TEXTURE_2D, handle[index]); + + } + + public void Dispose() + { + if (disposed) return; + this.disposed = true; + deleteTextures((uint)handle.Length, handle); + OpenGLErrorException.CheckGLErrorStatus(); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Textures/Texture.cs b/src/SlatedGameToolkit.Framework/Graphics/Textures/Texture.cs new file mode 100644 index 0000000..5074052 --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Textures/Texture.cs @@ -0,0 +1,30 @@ +using System; + +namespace SlatedGameToolkit.Framework.Graphics.Textures +{ + public class Texture : IDisposable + { + private readonly GLTexture2DSet glTexture2DSet; + private readonly uint index; + + public Texture(GLTexture2DSet set, uint index) { + this.glTexture2DSet = set; + this.index = index; + } + + public Texture(TextureData textureData, bool linear = true, bool mipmap = true) { + TextureData[] textureDatas = new TextureData[] {textureData}; + this.glTexture2DSet = new GLTexture2DSet(textureDatas, linear, mipmap); + this.index = 0; + } + + public void Use() { + this.glTexture2DSet.Bind(index); + } + + public void Dispose() + { + this.glTexture2DSet.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Textures/TextureData.cs b/src/SlatedGameToolkit.Framework/Graphics/Textures/TextureData.cs new file mode 100644 index 0000000..be23a4d --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Graphics/Textures/TextureData.cs @@ -0,0 +1,9 @@ +namespace SlatedGameToolkit.Framework.Graphics.Textures +{ + public struct TextureData + { + public byte[] data; + public uint width; + public uint height; + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Graphics/Window/WindowContext.cs b/src/SlatedGameToolkit.Framework/Graphics/Window/WindowContext.cs index 2e72ffb..b05c621 100644 --- a/src/SlatedGameToolkit.Framework/Graphics/Window/WindowContext.cs +++ b/src/SlatedGameToolkit.Framework/Graphics/Window/WindowContext.cs @@ -1,9 +1,10 @@ using System; +using System.Drawing; +using System.Numerics; using System.Runtime.InteropServices; using SDL2; -using SlatedGameToolkit.Framework.DataTypes; using SlatedGameToolkit.Framework.Exceptions; -using SlatedGameToolkit.Framework.Graphics.OpenGL; +using SlatedGameToolkit.Framework.Graphics; namespace SlatedGameToolkit.Framework.Graphics.Window { @@ -13,7 +14,7 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// /// The window coordinates that are being interacted with. /// The region type. - public delegate WindowRegion WindowRegionHit(FloatVector2 hitPoint); + public delegate WindowRegion WindowRegionHit(Vector2 hitPoint); /// /// A delegate that represents a function to be called on a window resize. @@ -36,12 +37,12 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// /// The pointer referencing the SDL window. /// - private readonly IntPtr window; + private readonly IntPtr windowHandle; /// /// The pointer referencing the OpenGL context. /// - private readonly IntPtr glContext; + private readonly IntPtr glContextHandle; public event WindowOperation focusGainedEvent, focusLostEvent; /// @@ -57,6 +58,7 @@ namespace SlatedGameToolkit.Framework.Graphics.Window internal readonly GLClearColour clearColour; internal readonly GLClear clear; internal readonly GLViewport viewport; + private readonly GLGetError getError; /// @@ -66,14 +68,14 @@ namespace SlatedGameToolkit.Framework.Graphics.Window public bool Shown { set { if (value) { - SDL.SDL_ShowWindow(window); + SDL.SDL_ShowWindow(windowHandle); } else { - SDL.SDL_HideWindow(window); + SDL.SDL_HideWindow(windowHandle); } } get { - return ((SDL.SDL_WindowFlags) Enum.Parse(typeof(SDL.SDL_WindowFlags), SDL.SDL_GetWindowFlags(window).ToString())).HasFlag(SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN); + return ((SDL.SDL_WindowFlags) Enum.Parse(typeof(SDL.SDL_WindowFlags), SDL.SDL_GetWindowFlags(windowHandle).ToString())).HasFlag(SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN); } } @@ -87,23 +89,21 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// public bool VSync { get { - IntPtr currentContext = SDL.SDL_GL_GetCurrentContext(); - IntPtr currentWindow = SDL.SDL_GL_GetCurrentWindow(); + WindowContext actual = WindowContextsManager.CurrentWindowContext; bool diff = false; - if (currentContext != glContext || currentWindow != window) { - MakeCurrent(); + if (actual != this) { + WindowContextsManager.CurrentWindowContext = this; diff = true; } bool vSync = SDL.SDL_GL_GetSwapInterval() != 0; - if (diff) SDL.SDL_GL_MakeCurrent(currentWindow, currentContext); + if (diff) WindowContextsManager.CurrentWindowContext = actual; return vSync; } set { - IntPtr currentContext = SDL.SDL_GL_GetCurrentContext(); - IntPtr currentWindow = SDL.SDL_GL_GetCurrentWindow(); + WindowContext actual = WindowContextsManager.CurrentWindowContext; bool diff = false; - if (currentContext != glContext || currentWindow != window) { - MakeCurrent(); + if (actual != this) { + WindowContextsManager.CurrentWindowContext = this; diff = true; } if (SDL.SDL_GL_SetSwapInterval(value ? -1 : 0) < 0) { @@ -111,7 +111,7 @@ namespace SlatedGameToolkit.Framework.Graphics.Window throw new OptionalSDLException(); } } - if (diff) SDL.SDL_GL_MakeCurrent(currentWindow, currentContext); + if (diff) WindowContextsManager.CurrentWindowContext = actual; } } @@ -121,11 +121,11 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// A string that represents whats to be displayed as the title of the window. public string WindowTitle { set { - SDL.SDL_SetWindowTitle(window, value); + SDL.SDL_SetWindowTitle(windowHandle, value); } get { - return SDL.SDL_GetWindowTitle(window); + return SDL.SDL_GetWindowTitle(windowHandle); } } @@ -135,12 +135,12 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// True if displaying borders. public bool WindowBordered { set { - SDL.SDL_SetWindowBordered(window, value ? SDL.SDL_bool.SDL_TRUE : SDL.SDL_bool.SDL_FALSE); + SDL.SDL_SetWindowBordered(windowHandle, value ? SDL.SDL_bool.SDL_TRUE : SDL.SDL_bool.SDL_FALSE); } get { int top, bottom, left, right; - int errorCode = SDL.SDL_GetWindowBordersSize(window, out top, out left, out bottom, out right); + int errorCode = SDL.SDL_GetWindowBordersSize(windowHandle, out top, out left, out bottom, out right); if (errorCode < 0) throw new OptionalSDLException(); return top > 0 || bottom > 0 || left > 0 || right > 0; } @@ -152,10 +152,10 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// True if resizeable. public bool WindowResizable { set { - SDL.SDL_SetWindowResizable(window, value ? SDL.SDL_bool.SDL_TRUE : SDL.SDL_bool.SDL_FALSE); + SDL.SDL_SetWindowResizable(windowHandle, value ? SDL.SDL_bool.SDL_TRUE : SDL.SDL_bool.SDL_FALSE); } get { - return ((SDL.SDL_WindowFlags) Enum.Parse(typeof(SDL.SDL_WindowFlags), SDL.SDL_GetWindowFlags(window).ToString())).HasFlag(SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE); + return ((SDL.SDL_WindowFlags) Enum.Parse(typeof(SDL.SDL_WindowFlags), SDL.SDL_GetWindowFlags(windowHandle).ToString())).HasFlag(SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE); } } @@ -164,21 +164,20 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// as well as the current width and height of this window. /// /// Rectangle representing the boundaries of the window. - public FloatRectangle WindowBoundaries { + public Rectangle WindowBoundaries { set { - SDL.SDL_SetWindowPosition(window, (int)value.X1, (int)value.Y1); - SDL.SDL_SetWindowSize(window, (int)value.Width, (int)value.Height); + SDL.SDL_SetWindowPosition(windowHandle, value.X, value.Y); + SDL.SDL_SetWindowSize(windowHandle, value.Width, value.Height); } get { int x, y, width, height; - SDL.SDL_GetWindowSize(window, out x, out y); - SDL.SDL_GetWindowPosition(window, out width, out height); - FloatRectangle rectangle = new FloatRectangle(); - rectangle.X1 = x; - rectangle.Y2 = y; + SDL.SDL_GetWindowSize(windowHandle, out x, out y); + SDL.SDL_GetWindowPosition(windowHandle, out width, out height); + Rectangle rectangle = new Rectangle(); + rectangle.X = x; + rectangle.Y = y; rectangle.Width = width; rectangle.Height = height; - return rectangle; } } @@ -187,16 +186,16 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// The maximum size the window can be at any given time. /// /// A vector that represents the maximum width and height of the window with the x and y components respectively. - public FloatVector2 MaximumSize { + public Vector2 MaximumSize { set { - SDL.SDL_SetWindowMaximumSize(window, (int)value.x, (int)value.y); + SDL.SDL_SetWindowMaximumSize(windowHandle, (int)value.X, (int)value.Y); } get { int width, height; - SDL.SDL_GetWindowMaximumSize(window, out width, out height); - FloatVector2 maxSize = new FloatVector2(); - maxSize.x = width; - maxSize.y = height; + SDL.SDL_GetWindowMaximumSize(windowHandle, out width, out height); + Vector2 maxSize = new Vector2(); + maxSize.X = width; + maxSize.Y = height; return maxSize; } } @@ -205,16 +204,16 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// The minimum size the window can be at any given time. /// /// A vector that represents the minimum width and height of the window with the x and y components respectively. - public FloatVector2 MinimumSize { + public Vector2 MinimumSize { set { - SDL.SDL_SetWindowMinimumSize(window, (int)value.x, (int)value.y); + SDL.SDL_SetWindowMinimumSize(windowHandle, (int)value.X, (int)value.Y); } get { int width, height; - SDL.SDL_GetWindowMinimumSize(window, out width, out height); - FloatVector2 maxSize = new FloatVector2(); - maxSize.x = width; - maxSize.y = height; + SDL.SDL_GetWindowMinimumSize(windowHandle, out width, out height); + Vector2 maxSize = new Vector2(); + maxSize.X = width; + maxSize.Y = height; return maxSize; } } @@ -226,12 +225,12 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// A float with bounds of [0, 1] representing the opacity of the window. public float Opacity { set { - int errorCode = SDL.SDL_SetWindowOpacity(window, value); + int errorCode = SDL.SDL_SetWindowOpacity(windowHandle, value); if (errorCode < 0) throw new OptionalSDLException(); } get { float value; - int errorCode = SDL.SDL_GetWindowOpacity(window, out value); + int errorCode = SDL.SDL_GetWindowOpacity(windowHandle, out value); if (errorCode < 0) throw new OptionalSDLException(); return value; } @@ -243,16 +242,16 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// True if grabbing. public bool GrabbingInput { set { - SDL.SDL_SetWindowGrab(window, value ? SDL.SDL_bool.SDL_TRUE : SDL.SDL_bool.SDL_FALSE); + SDL.SDL_SetWindowGrab(windowHandle, value ? SDL.SDL_bool.SDL_TRUE : SDL.SDL_bool.SDL_FALSE); } get { - return SDL.SDL_GetWindowGrab(window) == SDL.SDL_bool.SDL_TRUE ? true : false; + return SDL.SDL_GetWindowGrab(windowHandle) == SDL.SDL_bool.SDL_TRUE ? true : false; } } internal uint WindowID { get { - uint id = SDL.SDL_GetWindowID(window); + uint id = SDL.SDL_GetWindowID(windowHandle); if (id == 0) throw new FrameworkSDLException(); return id; } @@ -263,85 +262,45 @@ namespace SlatedGameToolkit.Framework.Graphics.Window /// public WindowContext(string title, int x = -1, int y = -1, int width = 640, int height = 480, bool specialRegions = false, WindowOption options = default(WindowOption)) { GameEngine.Logger.Information(String.Format("Starting openGL window with title \"{0}\"", title)); - window = SDL.SDL_CreateWindow(title, x < 0 ? SDL.SDL_WINDOWPOS_CENTERED : x, y < 0 ? SDL.SDL_WINDOWPOS_CENTERED : y, width, height, SDL.SDL_WindowFlags.SDL_WINDOW_INPUT_FOCUS | SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL.SDL_WindowFlags.SDL_WINDOW_MOUSE_FOCUS | (SDL.SDL_WindowFlags) options); - if (window == null) { + windowHandle = SDL.SDL_CreateWindow(title, x < 0 ? SDL.SDL_WINDOWPOS_CENTERED : x, y < 0 ? SDL.SDL_WINDOWPOS_CENTERED : y, width, height, SDL.SDL_WindowFlags.SDL_WINDOW_INPUT_FOCUS | SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL.SDL_WindowFlags.SDL_WINDOW_MOUSE_FOCUS | (SDL.SDL_WindowFlags) options); + if (windowHandle == null) { throw new FrameworkSDLException(); } - glContext = SDL.SDL_GL_CreateContext(window); - if (glContext == null) { + glContextHandle = SDL.SDL_GL_CreateContext(windowHandle); + if (glContextHandle == null) { throw new FrameworkSDLException(); } - clear = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glClear")); - if (clear == null) throw new FrameworkSDLException(); - clearColour = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glClearColor")); - if (clearColour == null) throw new FrameworkSDLException(); - viewport = Marshal.GetDelegateForFunctionPointer(SDL.SDL_GL_GetProcAddress("glViewport")); - if (viewport == null) throw new FrameworkSDLException(); - - + clear = GLFunctionUtils.RetrieveGLDelegate("glClear"); + clearColour = GLFunctionUtils.RetrieveGLDelegate("glClearColor"); + viewport = GLFunctionUtils.RetrieveGLDelegate("glViewport"); + getError = GLFunctionUtils.RetrieveGLDelegate("glGetError"); if (specialRegions) { - if (SDL.SDL_SetWindowHitTest(window, SpecialRegionHit, IntPtr.Zero) < 0) { + if (SDL.SDL_SetWindowHitTest(windowHandle, SpecialRegionHit, IntPtr.Zero) < 0) { throw new OptionalSDLException(); } } WindowContextsManager.RegisterWindow(this); - } + WindowContextsManager.CurrentWindowContext = this; - /// - /// Makes this window the window that is currently being drawn to. - /// More specifically, it sets the OpenGL Context associated with this window to be the one - /// that is actively receiving all OpenGL calls. - /// - /// If the current context is already of this window, nothing happens. - /// - internal void MakeCurrent() { - if (SDL.SDL_GL_GetCurrentContext() != glContext) { - SDL.SDL_GL_MakeCurrent(window, glContext); - } - } - - internal void SwapBuffer() { - SDL.SDL_GL_SwapWindow(window); - } - - /// - /// Attempts to raise the window to the top. - /// - public void RaiseToTop() { - SDL.SDL_RestoreWindow(window); - SDL.SDL_RaiseWindow(window); - } - - /// - /// Gets the index of the display that this window resides within. - /// - /// An integer representing the display this window resides within. - public int GetDisplayIndex() { - int index = SDL.SDL_GetWindowDisplayIndex(window); - if (index < 0) throw new FrameworkSDLException(); - return index; + Vector2 drawable = GetDrawableDimensions(); + viewport(0, 0, (int)drawable.X, (int)drawable.Y); } private SDL.SDL_HitTestResult SpecialRegionHit(IntPtr window, IntPtr hitPtr, IntPtr data) { SDL.SDL_Point SDLPoint = Marshal.PtrToStructure(hitPtr); - FloatVector2 point = new FloatVector2(SDLPoint.x, SDLPoint.y); + Vector2 point = new Vector2(SDLPoint.x, SDLPoint.y); WindowRegion region = windowRegionHitEvent.Invoke(point); return (SDL.SDL_HitTestResult) region; } - /// - /// Disposes of this window and it's associated handles. - /// - public void Dispose() - { - WindowContextsManager.DeregisterWindow(this); - SDL.SDL_GL_DeleteContext(glContext); - SDL.SDL_DestroyWindow(window); + internal void SwapBuffer() { + SDL.SDL_GL_SwapWindow(windowHandle); } + internal void OnResize(int width, int height) { resizeEvent?.Invoke(width, height); } @@ -354,6 +313,62 @@ namespace SlatedGameToolkit.Framework.Graphics.Window focusGainedEvent?.Invoke(); } + /// + /// Gets the current GL error code. + /// + /// The unsigned int representing the status of OpenGL. + public uint GetGLStatus() { + return getError(); + } + + /// + /// Gets the current drawable area of the window. + /// + /// A vector with x component representing the width and y component representing the height of the drawable area. + public Vector2 GetDrawableDimensions() { + int width, height; + SDL.SDL_GL_GetDrawableSize(windowHandle, out width, out height); + return new Vector2(width, height); + } + + /// + /// Makes this window context the active one. + /// There can only be one window context active at any given time. + /// + public void MakeCurrent() { + + SDL.SDL_GL_MakeCurrent(windowHandle, glContextHandle); + WindowContextsManager.CurrentWindowContext = this; + } + + /// + /// Attempts to raise the window to the top. + /// + public void RaiseToTop() { + SDL.SDL_RestoreWindow(windowHandle); + SDL.SDL_RaiseWindow(windowHandle); + } + + /// + /// Gets the index of the display that this window resides within. + /// + /// An integer representing the display this window resides within. + public int GetDisplayIndex() { + int index = SDL.SDL_GetWindowDisplayIndex(windowHandle); + if (index < 0) throw new FrameworkSDLException(); + return index; + } + + /// + /// Disposes of this window and it's associated handles. + /// + public void Dispose() + { + WindowContextsManager.DeregisterWindow(this); + SDL.SDL_GL_DeleteContext(glContextHandle); + SDL.SDL_DestroyWindow(windowHandle); + } + ~WindowContext() { Dispose(); } diff --git a/src/SlatedGameToolkit.Framework/Graphics/Window/WindowContextsManager.cs b/src/SlatedGameToolkit.Framework/Graphics/Window/WindowContextsManager.cs index 7507097..291bafb 100644 --- a/src/SlatedGameToolkit.Framework/Graphics/Window/WindowContextsManager.cs +++ b/src/SlatedGameToolkit.Framework/Graphics/Window/WindowContextsManager.cs @@ -1,9 +1,26 @@ using System.Collections.Generic; -using SDL2; namespace SlatedGameToolkit.Framework.Graphics.Window { - internal static class WindowContextsManager { + public static class WindowContextsManager { + private static WindowContext current; + + /// + /// The current window context. + /// + /// The currently active window context. + public static WindowContext CurrentWindowContext { + get { + return current; + } + + set { + if (current != value) { + current = value; + value.MakeCurrent(); + } + } + } private static Dictionary existingWindows = new Dictionary(); internal static void RegisterWindow(WindowContext windowHandle) { @@ -19,9 +36,5 @@ namespace SlatedGameToolkit.Framework.Graphics.Window public static WindowContext ContextFromWindowID(uint ID) { return existingWindows[ID]; } - - public static WindowContext CurrentWindowContext() { - return ContextFromWindowID(SDL.SDL_GetWindowID(SDL.SDL_GL_GetCurrentWindow())); - } } } \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/Loaders/ILoadable.cs b/src/SlatedGameToolkit.Framework/Loaders/ILoadable.cs new file mode 100644 index 0000000..9857d0c --- /dev/null +++ b/src/SlatedGameToolkit.Framework/Loaders/ILoadable.cs @@ -0,0 +1,8 @@ +namespace SlatedGameToolkit.Framework.Loaders +{ + public interface ILoadable + { + bool RequiresLoading { get; } + void Load(); + } +} \ No newline at end of file diff --git a/src/SlatedGameToolkit.Framework/SDL2-bindings/SDL2.cs b/src/SlatedGameToolkit.Framework/SDL2-bindings/SDL2.cs index b35d6a2..270526e 100644 --- a/src/SlatedGameToolkit.Framework/SDL2-bindings/SDL2.cs +++ b/src/SlatedGameToolkit.Framework/SDL2-bindings/SDL2.cs @@ -1097,7 +1097,7 @@ namespace SDL2 [StructLayout(LayoutKind.Sequential)] public struct SDL_MessageBoxColorScheme { - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = (int)SDL_MessageBoxColorType.SDL_MESSAGEBOX_COLOR_MAX)] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)SDL_MessageBoxColorType.SDL_MESSAGEBOX_COLOR_MAX)] public SDL_MessageBoxColor[] colors; } diff --git a/src/SlatedGameToolkit.Framework/SlatedGameToolkit.Framework.csproj b/src/SlatedGameToolkit.Framework/SlatedGameToolkit.Framework.csproj index 4cfed17..b926bd5 100644 --- a/src/SlatedGameToolkit.Framework/SlatedGameToolkit.Framework.csproj +++ b/src/SlatedGameToolkit.Framework/SlatedGameToolkit.Framework.csproj @@ -1,7 +1,7 @@ - netstandard2.0 + netstandard2.1 true diff --git a/src/SlatedGameToolkit.Framework/StateSystem/Manager.cs b/src/SlatedGameToolkit.Framework/StateSystem/Manager.cs index f70503c..15ea52c 100644 --- a/src/SlatedGameToolkit.Framework/StateSystem/Manager.cs +++ b/src/SlatedGameToolkit.Framework/StateSystem/Manager.cs @@ -1,18 +1,16 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Threading; -using SDL2; -using SlatedGameToolkit.Framework.DataTypes; -using SlatedGameToolkit.Framework.Graphics.OpenGL; +using SlatedGameToolkit.Framework.Graphics; using SlatedGameToolkit.Framework.Graphics.Window; using SlatedGameToolkit.Framework.StateSystem.States; namespace SlatedGameToolkit.Framework.StateSystem { public sealed class Manager : IDisposable { - public WindowContext CurrentWindow { get; private set; } public Thread thread; - public Colour backgroundColour; + public Color backgroundColour; private IState currentState; private IState nextState; private Dictionary states; @@ -25,9 +23,7 @@ namespace SlatedGameToolkit.Framework.StateSystem /// The name of the initial state. /// The initial set of game states to be added. internal Manager(IState initialState) { - backgroundColour.r = 0.5f; - backgroundColour.g = 0.5f; - backgroundColour.b = 0.5f; + backgroundColour = Color.Orange; if (initialState == null) throw new ArgumentNullException("initialState"); thread = Thread.CurrentThread; @@ -47,14 +43,11 @@ namespace SlatedGameToolkit.Framework.StateSystem } internal void render(double delta) { - if (CurrentWindow != currentState.CurrentWindow) { - CurrentWindow = currentState.CurrentWindow; - CurrentWindow.MakeCurrent(); - } - CurrentWindow.clearColour(backgroundColour.r, backgroundColour.g, backgroundColour.b); - CurrentWindow.clear(GLEnums.GL_COLOR_BUFFER_BIT | GLEnums.GL_DEPTH_STENCIL); + WindowContext windowContext = WindowContextsManager.CurrentWindowContext; + windowContext.clearColour(backgroundColour.R / 254f, backgroundColour.G / 254f, backgroundColour.B / 254f); + windowContext.clear(GLEnums.GL_COLOR_BUFFER_BIT | GLEnums.GL_DEPTH_STENCIL); currentState.Render(delta); - CurrentWindow.SwapBuffer(); + windowContext.SwapBuffer(); } /// @@ -134,6 +127,7 @@ namespace SlatedGameToolkit.Framework.StateSystem public void Dispose() { + if (currentState == null) return; currentState = null; removeAllStates(); } diff --git a/src/SlatedGameToolkit.Framework/StateSystem/States/IState.cs b/src/SlatedGameToolkit.Framework/StateSystem/States/IState.cs index 3e53871..f6f3260 100644 --- a/src/SlatedGameToolkit.Framework/StateSystem/States/IState.cs +++ b/src/SlatedGameToolkit.Framework/StateSystem/States/IState.cs @@ -5,8 +5,6 @@ namespace SlatedGameToolkit.Framework.StateSystem.States { public interface IState { - WindowContext CurrentWindow { get; } - /// /// Called when this state should be deactivated. /// Deactivate may be called multiple times: diff --git a/src/SlatedGameToolkit.Tools/SlatedGameToolkit.Tools.csproj b/src/SlatedGameToolkit.Tools/SlatedGameToolkit.Tools.csproj index b466f31..327b64e 100644 --- a/src/SlatedGameToolkit.Tools/SlatedGameToolkit.Tools.csproj +++ b/src/SlatedGameToolkit.Tools/SlatedGameToolkit.Tools.csproj @@ -7,6 +7,8 @@ Exe netcoreapp3.1 + 1.0.0.0 + A tool to help with developing a game using SlatedGameToolkit. diff --git a/src/SlatedGameToolkit.Tools/Utilities/GraphicalPlayground/MainState.cs b/src/SlatedGameToolkit.Tools/Utilities/GraphicalPlayground/MainState.cs index 7869dd4..9d5ab32 100644 --- a/src/SlatedGameToolkit.Tools/Utilities/GraphicalPlayground/MainState.cs +++ b/src/SlatedGameToolkit.Tools/Utilities/GraphicalPlayground/MainState.cs @@ -1,6 +1,6 @@ using System; -using SlatedGameToolkit.Framework.Graphics.OpenGL.Programs; -using SlatedGameToolkit.Framework.Graphics.OpenGL.Shaders; +using SlatedGameToolkit.Framework.Graphics.Programs; +using SlatedGameToolkit.Framework.Graphics.Shaders; using SlatedGameToolkit.Framework.Graphics.Window; using SlatedGameToolkit.Framework.StateSystem; using SlatedGameToolkit.Framework.StateSystem.States; @@ -10,7 +10,6 @@ namespace SlatedGameToolkit.Tools.Utilities.GraphicalPlayground public class MainState : IState { private WindowContext window; - private GLShaderProgram shader; public WindowContext CurrentWindow { get { return window;}} @@ -37,7 +36,6 @@ namespace SlatedGameToolkit.Tools.Utilities.GraphicalPlayground public void Initialize(Manager manager) { window = new WindowContext("SlatedGameToolkit Playground"); - shader = new GLShaderProgram(); window.RaiseToTop(); } diff --git a/tests/UnitTest1.cs b/tests/UnitTest1.cs deleted file mode 100644 index 2bc5a40..0000000 --- a/tests/UnitTest1.cs +++ /dev/null @@ -1,18 +0,0 @@ -using NUnit.Framework; - -namespace tests -{ - public class Tests - { - [SetUp] - public void Setup() - { - } - - [Test] - public void Test1() - { - Assert.Pass(); - } - } -} \ No newline at end of file diff --git a/tests/tests.csproj b/tests/tests.csproj deleted file mode 100644 index 43f0ccc..0000000 --- a/tests/tests.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp3.1 - - false - - - - - - - - -