General progress on getting OpenGL based rendering.

This commit is contained in:
Harrison Deng 2020-06-01 01:27:38 -05:00
parent 5e85eb5de1
commit e59e78e08c
40 changed files with 995 additions and 501 deletions

View File

@ -1,7 +0,0 @@
namespace SlatedGameToolkit.Framework.DataTypes
{
public struct Colour {
public volatile float r, g, b;
}
}

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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) {
}
/// <summary>
/// Checks the current context for OpenGL errors that has occurred and throws an exception if there is one.
/// </summary>
public static void CheckGLErrorStatus() {
uint errorCode = WindowContextsManager.CurrentWindowContext.GetGLStatus();
if (errorCode != (uint) GLEnums.GL_NO_ERROR) {
throw new OpenGLErrorException(errorCode, "OpenGL error: " + errorCode.ToString());
}
}
}
}

View File

@ -1,4 +1,6 @@
using System;
using SlatedGameToolkit.Framework.Graphics;
using SlatedGameToolkit.Framework.Graphics.Window;
namespace SlatedGameToolkit.Framework.Exceptions
{

View File

@ -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();

View File

@ -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,
}
}

View File

@ -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<T>(string functionName) where T : Delegate {
IntPtr functionAddress = SDL.SDL_GL_GetProcAddress(functionName);
if (functionAddress == null) throw new FrameworkSDLException();
return Marshal.GetDelegateForFunctionPointer<T>(functionAddress);
}
}
}

View File

@ -1,8 +1,20 @@
using System;
using System.Numerics;
namespace SlatedGameToolkit.Framework.Graphics.Meshes
{
public interface IMeshable
{
float[] Vertices { get; }
float[] Elements { get; }
/// <summary>
/// Each value in the array represents a 3D coordinate for the vertex, as well as a 2D texture coordinate.
/// </summary>
/// <value></value>
ValueTuple<Vector3, Vector2>[] Vertices { get; }
uint[] Elements { get; }
Vector3 Rotation { get; set; }
Vector3 Translation { get; set; }
Vector3 Scale { get; set; }
}
}

View File

@ -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<Vector3, Vector2>[] vertices = new ValueTuple<Vector3, Vector2>[4];
private uint[] indices = new uint[] {0, 1, 3, 1, 2, 3};
public ValueTuple<Vector3, Vector2>[] 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, Vector2>(Vector3.Transform(baseVerts[i], transform), texCoords[i]);
}
changed = false;
}
}
}

View File

@ -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();
}

View File

@ -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<GLCreateProgram>(SDL.SDL_GL_GetProcAddress("glCreateProgram"));
if (createProgram == null) throw new FrameworkSDLException();
deleteProgram = Marshal.GetDelegateForFunctionPointer<GLDeleteProgram>(SDL.SDL_GL_GetProcAddress("glDeleteProgram"));
if (deleteProgram == null) throw new FrameworkSDLException();
linkProgram = Marshal.GetDelegateForFunctionPointer<GLLinkProgram>(SDL.SDL_GL_GetProcAddress("glLinkProgram"));
if (linkProgram == null) throw new FrameworkSDLException();
getProgramInfoLog = Marshal.GetDelegateForFunctionPointer<GLGetProgramInfoLog>(SDL.SDL_GL_GetProcAddress("glGetProgramInfoLog"));
if (getProgramInfoLog == null) throw new FrameworkSDLException();
programParameter = Marshal.GetDelegateForFunctionPointer<GLProgramParameter>(SDL.SDL_GL_GetProcAddress("glProgramParameter"));
if (programParameter == null) throw new FrameworkSDLException();
useProgram = Marshal.GetDelegateForFunctionPointer<GLUseProgram>(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();
}
}
}

View File

@ -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<GLGenProgramPipelines>(SDL.SDL_GL_GetProcAddress("glGenProgramPipelines"));
if (genProgramPipelines == null) throw new FrameworkSDLException();
useProgramStages = Marshal.GetDelegateForFunctionPointer<GLUseProgramStages>(SDL.SDL_GL_GetProcAddress("glUseProgramStages"));
if (useProgramStages == null) throw new FrameworkSDLException();
useProgram = Marshal.GetDelegateForFunctionPointer<GLUseProgram>(SDL.SDL_GL_GetProcAddress("glUseProgram"));
if (useProgram == null) throw new FrameworkSDLException();
bindProgramPipeline = Marshal.GetDelegateForFunctionPointer<GLBindProgramPipeline>(SDL.SDL_GL_GetProcAddress("glBindProgramPipeline"));
if (bindProgramPipeline == null) throw new FrameworkSDLException();
deleteProgramPipelines = Marshal.GetDelegateForFunctionPointer<GLDeleteProgramPipelines>(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();
}
}
}

View File

@ -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);
}
}
}

View File

@ -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<GLCreateShader>(SDL.SDL_GL_GetProcAddress("glCreateShader"));
if (createShader == null) throw new FrameworkSDLException();
shaderSource = Marshal.GetDelegateForFunctionPointer<GLShaderSource>(SDL.SDL_GL_GetProcAddress("glShaderSource"));
if (shaderSource == null) throw new FrameworkSDLException();
compileShader = Marshal.GetDelegateForFunctionPointer<GLCompileShader>(SDL.SDL_GL_GetProcAddress("glCompileShader"));
if (compileShader == null) throw new FrameworkSDLException();
getShaderLogInfo = Marshal.GetDelegateForFunctionPointer<GLGetShaderLogInfo>(SDL.SDL_GL_GetProcAddress("glGetShaderLogInfo"));
if(getShaderLogInfo == null) throw new FrameworkSDLException();
deleteShader = Marshal.GetDelegateForFunctionPointer<GLDeleteShader>(SDL.SDL_GL_GetProcAddress("glDeleteShader"));
if (deleteShader == null) throw new FrameworkSDLException();
}
public virtual void Dispose()
{
}
~GLShader() {
Dispose();
}
}
}

View File

@ -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;
/// <summary>
/// Creates an OpenGL program.
///
/// This is bound to the current context.
/// </summary>
internal GLProgram() {
this.context = WindowContextsManager.CurrentWindowContext;
createProgram = GLFunctionUtils.RetrieveGLDelegate<GLCreateProgram>("glCreateProgram");
deleteProgram = GLFunctionUtils.RetrieveGLDelegate<GLDeleteProgram>("glDeleteProgram");
linkProgram = GLFunctionUtils.RetrieveGLDelegate<GLLinkProgram>("glLinkProgram");
getProgramInfoLog = GLFunctionUtils.RetrieveGLDelegate<GLGetProgramInfoLog>("glGetProgramInfoLog");
programParameter = GLFunctionUtils.RetrieveGLDelegate<GLProgramParameter>("glProgramParameteri");
useProgram = GLFunctionUtils.RetrieveGLDelegate<GLUseProgram>("glUseProgram");
handle = createProgram();
}
/// <summary>
/// Binds this program.
/// </summary>
public virtual void Use() {
useProgram(handle);
}
/// <summary>
/// Disposes of the program.
/// </summary>
public virtual void Dispose()
{
deleteProgram(handle);
OpenGLErrorException.CheckGLErrorStatus();
}
~GLProgram() {
Dispose();
}
}
}

View File

@ -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<GLAttachShader>(SDL.SDL_GL_GetProcAddress("glAttachShader"));
if (attachShader == null) throw new FrameworkSDLException();
bindAttribLocation = Marshal.GetDelegateForFunctionPointer<GLBindAttribLocation>(SDL.SDL_GL_GetProcAddress("glBindAttribLocation"));
if (bindAttribLocation == null) throw new FrameworkSDLException();
detachShader = Marshal.GetDelegateForFunctionPointer<GLDetachShader>(SDL.SDL_GL_GetProcAddress("glDetachShader"));
if (detachShader == null) throw new FrameworkSDLException();
attachShader = GLFunctionUtils.RetrieveGLDelegate<GLAttachShader>("glAttachShader");
bindAttribLocation = GLFunctionUtils.RetrieveGLDelegate<GLBindAttribLocation>("glBindAttribLocation");
detachShader = GLFunctionUtils.RetrieveGLDelegate<GLDetachShader>("glDetachShader");
foreach (GLShader shader in shaders)
{
@ -43,6 +38,9 @@ namespace SlatedGameToolkit.Framework.Graphics.OpenGL.Programs
}
}
/// <summary>
/// Disposes of the shaders and this program.
/// </summary>
public override void Dispose() {
foreach (GLShader shader in shaders)
{

View File

@ -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<GLMultiDrawElements>("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<Vector3, Vector2>[] 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);
}
}
}

View File

@ -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; }
}
}

View File

@ -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();
}
}
}

View File

@ -0,0 +1,6 @@
namespace SlatedGameToolkit.Framework.Graphics.Render
{
public class Sprite2D
{
}
}

View File

@ -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 {
/// <summary>
/// Creates an OpenGL fragment shader.
/// </summary>
/// <param name="shader">A string representing the GLSL code to run.</param>
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();
}
}
}

View File

@ -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>("glCreateShader");
shaderSource = GLFunctionUtils.RetrieveGLDelegate<GLShaderSource>("glShaderSource");
compileShader = GLFunctionUtils.RetrieveGLDelegate<GLCompileShader>("glCompileShader");
getShaderLogInfo = GLFunctionUtils.RetrieveGLDelegate<GLGetShaderLogInfo>("glGetShaderLogInfo");
deleteShader = GLFunctionUtils.RetrieveGLDelegate<GLDeleteShader>("glDeleteShader");
getAttribLocation = GLFunctionUtils.RetrieveGLDelegate<GLGetAttribLocation>("glGetAttribLocation");
}
/// <summary>
/// Gets the attribute location.
/// </summary>
/// <param name="attributeName">The name of the attribute.</param>
/// <returns>The attribute location index.</returns>
public int GetAttributeLocation(string attributeName) {
int index = getAttribLocation(Handle, attributeName);
OpenGLErrorException.CheckGLErrorStatus();
return index;
}
/// <summary>
/// Disposes of the shader at the handle.
/// </summary>
public virtual void Dispose()
{
deleteShader(Handle);
OpenGLErrorException.CheckGLErrorStatus();
}
~GLShader() {
Dispose();
}
}
}

View File

@ -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>("glGenBuffers");
deleteBuffers = GLFunctionUtils.RetrieveGLDelegate<GLDeleteBuffers>("glDeleteBuffers");
bindBuffer = GLFunctionUtils.RetrieveGLDelegate<GLBindBuffer>("glBindBuffer");
genVertexArrays = GLFunctionUtils.RetrieveGLDelegate<GLGenVertexArrays>("glGenVertexArrays");
bindVertexArray = GLFunctionUtils.RetrieveGLDelegate<GLBindVertexArray>("glBindVertexArray");
deleteVertexArrays = GLFunctionUtils.RetrieveGLDelegate<GLDeleteVertexArrays>("glDeleteVertexArrays");
vertexAttribPointer = GLFunctionUtils.RetrieveGLDelegate<GLVertexAttribPointer>("glVertexAttribPointer");
enableVertexAttribArray = GLFunctionUtils.RetrieveGLDelegate<GLEnableVertexAttribArray>("glEnableVertexAttribArray");
disableVertexAttribArray = GLFunctionUtils.RetrieveGLDelegate<GLDisableVertexAttribArray>("glDisableVertexAttribArray");
bufferData = GLFunctionUtils.RetrieveGLDelegate<GLBufferData>("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();
}
/// <summary>
/// Defines the vertex attributes in an OpenGL vertex array object.
/// Sends as floats.
/// </summary>
/// <param name="bufferIndex">The buffer in this set to affect.</param>
/// <param name="enableAttributes">Whether or not to automatically enable the attributes that are being defined. Defaults to true.</param>
/// <param name="definitions">The definitions for the vertex array object.</param>
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);
}
}
/// <summary>
/// Enaables the vertex array object's definitions at the given attribute indices.
/// </summary>
/// <param name="bufferIndex">The buffer index in this set this should affect.</param>
/// <param name="attributeIndices">The attribute indices to be enabled.</param>
public void EnableAttributes(uint bufferIndex, params uint[] attributeIndices) {
Use(bufferIndex);
foreach (uint attrib in attributeIndices)
{
enableVertexAttribArray(attrib);
}
}
/// <summary>
/// Disables the vertex array object's definitions at the given attribute indices.
/// </summary>
/// <param name="bufferIndex">The buffer index in this set that should be affected.</param>
/// <param name="attributeIndices">The attribute indices to be disabled.</param>
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;
}
}
}

View File

@ -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 {
/// <summary>
/// Creates an OpenGL vertex shader.
/// </summary>
/// <param name="shader">A string representing the GLSL code.</param>
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();
}
}
}

View File

@ -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);
}
/// <summary>
/// Defines the vertex attributes in an OpenGL vertex array object.
/// Sends as floats.
/// </summary>
/// <param name="enableAttributes">Whether or not to automatically enable the attributes that are being defined. Defaults to true.</param>
/// <param name="definitions">The definitions for the vertex array object.</param>
public void defineVertexAttributes(bool enableAttributes = true, params VertexAttributeDefinition[] definitions) {
this.glVertexArraySet.defineVertexAttributes(index, enableAttributes, definitions);
}
/// <summary>
/// Enaables the vertex array object's definitions at the given attribute indices.
/// </summary>
/// <param name="attributeIndices">The attribute indices to be enabled.</param>
public void EnableAttributes(params uint[] attributeIndices) {
glVertexArraySet.EnableAttributes(index, attributeIndices);
}
/// <summary>
/// Disables the vertex array object's definitions at the given attribute indices.
/// </summary>
/// <param name="attributeIndices">The attribute indices to be disabled.</param>
public void DisableAttributes(params uint[] attributeIndices) {
glVertexArraySet.DisableAttributes(index, attributeIndices);
}
public void Use() {
glVertexArraySet.Use(index);
}
public void Dispose()
{
this.glVertexArraySet.Dispose();
}
}
}

View File

@ -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>("glGenTextures");
deleteTextures = GLFunctionUtils.RetrieveGLDelegate<GLDeleteTextures>("glDeleteTextures");
bindTexture = GLFunctionUtils.RetrieveGLDelegate<GLBindTexture>("glBindTexture");
texParameteri = GLFunctionUtils.RetrieveGLDelegate<GLTexParameteri>("glTexParameteri");
texParameterfv = GLFunctionUtils.RetrieveGLDelegate<GLTexParameterfv>("glTexParameterfv");
texImage2D = GLFunctionUtils.RetrieveGLDelegate<GLTexImage2D>("glTexImage2D");
generateMipMap = GLFunctionUtils.RetrieveGLDelegate<GLGenerateMipMap>("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);
}
}
}

View File

@ -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();
}
}
}

View File

@ -0,0 +1,9 @@
namespace SlatedGameToolkit.Framework.Graphics.Textures
{
public struct TextureData
{
public byte[] data;
public uint width;
public uint height;
}
}

View File

@ -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
/// </summary>
/// <param name="hitPoint">The window coordinates that are being interacted with.</param>
/// <returns>The region type.</returns>
public delegate WindowRegion WindowRegionHit(FloatVector2 hitPoint);
public delegate WindowRegion WindowRegionHit(Vector2 hitPoint);
/// <summary>
/// A delegate that represents a function to be called on a window resize.
@ -36,12 +37,12 @@ namespace SlatedGameToolkit.Framework.Graphics.Window
/// <summary>
/// The pointer referencing the SDL window.
/// </summary>
private readonly IntPtr window;
private readonly IntPtr windowHandle;
/// <summary>
/// The pointer referencing the OpenGL context.
/// </summary>
private readonly IntPtr glContext;
private readonly IntPtr glContextHandle;
public event WindowOperation focusGainedEvent, focusLostEvent;
/// <summary>
@ -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;
/// <summary>
@ -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
/// <value></value>
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
/// <value>A string that represents whats to be displayed as the title of the window.</value>
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
/// <value>True if displaying borders.</value>
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
/// <value>True if resizeable.</value>
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.
/// </summary>
/// <value>Rectangle representing the boundaries of the window.</value>
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.
/// </summary>
/// <value>A vector that represents the maximum width and height of the window with the x and y components respectively.</value>
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.
/// </summary>
/// <value>A vector that represents the minimum width and height of the window with the x and y components respectively.</value>
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
/// <value>A float with bounds of [0, 1] representing the opacity of the window.</value>
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
/// <value>True if grabbing.</value>
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
/// </summary>
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<GLClear>(SDL.SDL_GL_GetProcAddress("glClear"));
if (clear == null) throw new FrameworkSDLException();
clearColour = Marshal.GetDelegateForFunctionPointer<GLClearColour>(SDL.SDL_GL_GetProcAddress("glClearColor"));
if (clearColour == null) throw new FrameworkSDLException();
viewport = Marshal.GetDelegateForFunctionPointer<GLViewport>(SDL.SDL_GL_GetProcAddress("glViewport"));
if (viewport == null) throw new FrameworkSDLException();
clear = GLFunctionUtils.RetrieveGLDelegate<GLClear>("glClear");
clearColour = GLFunctionUtils.RetrieveGLDelegate<GLClearColour>("glClearColor");
viewport = GLFunctionUtils.RetrieveGLDelegate<GLViewport>("glViewport");
getError = GLFunctionUtils.RetrieveGLDelegate<GLGetError>("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;
/// <summary>
/// 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.
/// </summary>
internal void MakeCurrent() {
if (SDL.SDL_GL_GetCurrentContext() != glContext) {
SDL.SDL_GL_MakeCurrent(window, glContext);
}
}
internal void SwapBuffer() {
SDL.SDL_GL_SwapWindow(window);
}
/// <summary>
/// Attempts to raise the window to the top.
/// </summary>
public void RaiseToTop() {
SDL.SDL_RestoreWindow(window);
SDL.SDL_RaiseWindow(window);
}
/// <summary>
/// Gets the index of the display that this window resides within.
/// </summary>
/// <returns>An integer representing the display this window resides within.</returns>
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<SDL.SDL_Point>(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;
}
/// <summary>
/// Disposes of this window and it's associated handles.
/// </summary>
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();
}
/// <summary>
/// Gets the current GL error code.
/// </summary>
/// <returns>The unsigned int representing the status of OpenGL.</returns>
public uint GetGLStatus() {
return getError();
}
/// <summary>
/// Gets the current drawable area of the window.
/// </summary>
/// <returns>A vector with x component representing the width and y component representing the height of the drawable area.</returns>
public Vector2 GetDrawableDimensions() {
int width, height;
SDL.SDL_GL_GetDrawableSize(windowHandle, out width, out height);
return new Vector2(width, height);
}
/// <summary>
/// Makes this window context the active one.
/// There can only be one window context active at any given time.
/// </summary>
public void MakeCurrent() {
SDL.SDL_GL_MakeCurrent(windowHandle, glContextHandle);
WindowContextsManager.CurrentWindowContext = this;
}
/// <summary>
/// Attempts to raise the window to the top.
/// </summary>
public void RaiseToTop() {
SDL.SDL_RestoreWindow(windowHandle);
SDL.SDL_RaiseWindow(windowHandle);
}
/// <summary>
/// Gets the index of the display that this window resides within.
/// </summary>
/// <returns>An integer representing the display this window resides within.</returns>
public int GetDisplayIndex() {
int index = SDL.SDL_GetWindowDisplayIndex(windowHandle);
if (index < 0) throw new FrameworkSDLException();
return index;
}
/// <summary>
/// Disposes of this window and it's associated handles.
/// </summary>
public void Dispose()
{
WindowContextsManager.DeregisterWindow(this);
SDL.SDL_GL_DeleteContext(glContextHandle);
SDL.SDL_DestroyWindow(windowHandle);
}
~WindowContext() {
Dispose();
}

View File

@ -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;
/// <summary>
/// The current window context.
/// </summary>
/// <value>The currently active window context.</value>
public static WindowContext CurrentWindowContext {
get {
return current;
}
set {
if (current != value) {
current = value;
value.MakeCurrent();
}
}
}
private static Dictionary<uint, WindowContext> existingWindows = new Dictionary<uint, WindowContext>();
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()));
}
}
}

View File

@ -0,0 +1,8 @@
namespace SlatedGameToolkit.Framework.Loaders
{
public interface ILoadable
{
bool RequiresLoading { get; }
void Load();
}
}

View File

@ -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;
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

View File

@ -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<string, IState> states;
@ -25,9 +23,7 @@ namespace SlatedGameToolkit.Framework.StateSystem
/// <param name="initialState">The name of the initial state.</param>
/// <param name="states">The initial set of game states to be added.</param>
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();
}
/// <summary>
@ -134,6 +127,7 @@ namespace SlatedGameToolkit.Framework.StateSystem
public void Dispose()
{
if (currentState == null) return;
currentState = null;
removeAllStates();
}

View File

@ -5,8 +5,6 @@ namespace SlatedGameToolkit.Framework.StateSystem.States
{
public interface IState
{
WindowContext CurrentWindow { get; }
/// <summary>
/// Called when this state should be deactivated.
/// Deactivate may be called multiple times:

View File

@ -7,6 +7,8 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<Description>A tool to help with developing a game using SlatedGameToolkit.</Description>
</PropertyGroup>
</Project>

View File

@ -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();
}

View File

@ -1,18 +0,0 @@
using NUnit.Framework;
namespace tests
{
public class Tests
{
[SetUp]
public void Setup()
{
}
[Test]
public void Test1()
{
Assert.Pass();
}
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0"/>
</ItemGroup>
</Project>