Dashboard/Dashboard.Drawing.OpenGL/ContextExecutor.cs

135 lines
3.8 KiB
C#

using System.Drawing;
using OpenTK.Graphics.OpenGL;
namespace Dashboard.Drawing.OpenGL
{
public class ContextExecutor : IDisposable
{
public GLEngine Engine { get; }
public IGLContext Context { get; }
public ContextResourcePool ResourcePool { get; }
protected bool IsDisposed { get; private set; } = false;
public bool IsInitialized { get; private set; } = false;
private int _program = 0;
public ContextExecutor(GLEngine engine, IGLContext context)
{
Engine = engine;
Context = context;
ResourcePool = Engine.ResourcePoolManager.Get(context);
ResourcePool.IncrementReference();
}
~ContextExecutor()
{
DisposeInvoker(false);
}
public void Initialize()
{
if (IsInitialized)
return;
IsInitialized = true;
LoadShaders();
}
private void LoadShaders()
{
using Stream vsource = FetchEmbeddedResource("Dashboard.Drawing.OpenGL.default.vert");
using Stream fsource = FetchEmbeddedResource("Dashboard.Drawing.OpenGL.default.frag");
int vs = CompileShader(ShaderType.VertexShader, vsource);
int fs = CompileShader(ShaderType.FragmentShader, fsource);
_program = LinkProgram(vs, fs);
GL.DeleteShader(vs);
GL.DeleteShader(fs);
}
public void Draw(DrawQueue drawqueue) => Draw(drawqueue, new RectangleF(new PointF(0f,0f), Context.FramebufferSize));
public virtual void Draw(DrawQueue drawQueue, RectangleF bounds)
{
}
public virtual void EndFrame()
{
}
private void DisposeInvoker(bool disposing)
{
if (!IsDisposed)
return;
IsDisposed = true;
if (disposing)
GC.SuppressFinalize(this);
Dispose(disposing);
}
protected virtual void Dispose(bool disposing)
{
ContextCollector.Global.DeleteProgram(_program);
}
public void Dispose() => DisposeInvoker(true);
private static int CompileShader(ShaderType type, string source)
{
int shader = GL.CreateShader(type);
GL.ShaderSource(shader, source);
GL.CompileShader(shader);
int compileStatus = 0;
GL.GetShaderi(shader, ShaderParameterName.CompileStatus, out compileStatus);
if (compileStatus == 0)
{
GL.GetShaderInfoLog(shader, out string log);
GL.DeleteShader(shader);
throw new Exception($"{type} Shader compilation failed: " + log);
}
return shader;
}
private static int CompileShader(ShaderType type, Stream stream)
{
using StreamReader reader = new StreamReader(stream, leaveOpen: true);
return CompileShader(type, reader.ReadToEnd());
}
private static int LinkProgram(int s1, int s2)
{
int program = GL.CreateProgram();
GL.AttachShader(program, s1);
GL.AttachShader(program, s2);
GL.LinkProgram(program);
int linkStatus = 0;
GL.GetProgrami(program, ProgramProperty.LinkStatus, out linkStatus);
if (linkStatus == 0)
{
GL.GetProgramInfoLog(program, out string log);
GL.DeleteProgram(program);
throw new Exception("Shader program linking failed: " + log);
}
return program;
}
private static Stream FetchEmbeddedResource(string name)
{
return typeof(ContextExecutor).Assembly.GetManifestResourceStream(name)!;
}
}
}