135 lines
3.8 KiB
C#
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)!;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|