GLWidget/GLWidget/GraphicsContext.cs
2020-09-07 18:10:41 +00:00

160 lines
5.1 KiB
C#

using System;
using System.Runtime.InteropServices;
using OpenGL;
using static OpenTK.GTKBindingHelper;
namespace OpenTK
{
public interface IGraphicsContext
{
void MakeCurrent();
void SwapBuffers();
void ClearCurrent();
void SwapInterval(int interval);
}
public abstract class GraphicsContext : IGraphicsContext
{
public static IntPtr Display{ get; set; }
public abstract void MakeCurrent();
public abstract void SwapBuffers();
public static void InitializeDefaults(IntPtr handle)
{
if (CurrentPlatform == OSPlatform.Windows)
{
IntPtr deviceContext = Wgl.GetDC(UnsafeNativeMethods.gdk_win32_window_get_handle(handle));
Wgl.PIXELFORMATDESCRIPTOR pfd = new Wgl.PIXELFORMATDESCRIPTOR(24);
pfd.dwFlags |= Wgl.PixelFormatDescriptorFlags.DepthDontCare | Wgl.PixelFormatDescriptorFlags.DoublebufferDontCare | Wgl.PixelFormatDescriptorFlags.StereoDontCare;
int pFormat = Wgl.ChoosePixelFormat(deviceContext, ref pfd);
bool res = Wgl.DescribePixelFormat(deviceContext, pFormat, (uint)pfd.nSize, ref pfd) != 0;
res = Wgl.SetPixelFormat(deviceContext, pFormat, ref pfd);
}
}
public static IGraphicsContext GetCurrentContext(IntPtr handle)
{
var currentPlatform = CurrentPlatform;
if(currentPlatform == OSPlatform.Windows){
return WglGraphicsContext.GetCurrent(handle);
}
else if(currentPlatform == OSPlatform.Linux){
if (Display == null || Display == IntPtr.Zero)
{
throw new InvalidOperationException("No Display set");
}
return GlxGraphicsContext.GetCurrent(handle, Display);
}
return null;
}
public abstract void ClearCurrent();
public abstract void SwapInterval(int interval);
}
public class WglGraphicsContext : GraphicsContext
{
private delegate int wglSwapIntervalExtDelegate(int interval);
private static wglSwapIntervalExtDelegate wglSwapIntervalExt = null;
private IntPtr _windowHandle;
private IntPtr _deviceContext;
public WglGraphicsContext(IntPtr deviceContext, IntPtr graphicsContext, IntPtr windowHandle = default)
{
_deviceContext = deviceContext;
_graphicsContext = graphicsContext;
_windowHandle = windowHandle;
IntPtr swapIntervalPointer = UnsafeNativeMethods.wglGetProcAddress("wglSwapIntervalEXT");
if(swapIntervalPointer != null && swapIntervalPointer != IntPtr.Zero)
{
wglSwapIntervalExt = (wglSwapIntervalExtDelegate)Marshal.GetDelegateForFunctionPointer(
swapIntervalPointer, typeof(wglSwapIntervalExtDelegate));
}
}
private IntPtr _graphicsContext;
public static WglGraphicsContext GetCurrent(IntPtr windowHandle)
{
IntPtr dc = UnsafeNativeMethods.wglGetCurrentDC();
IntPtr gc = UnsafeNativeMethods.wglGetCurrentContext();
return new WglGraphicsContext(dc, gc, windowHandle);
}
public override void MakeCurrent()
{
UnsafeNativeMethods.WglMakeCurrent(_deviceContext, _graphicsContext);
}
public override void SwapBuffers()
{
UnsafeNativeMethods.wglSwapBuffers(_deviceContext);
}
public override void ClearCurrent()
{
UnsafeNativeMethods.WglMakeCurrent(_deviceContext, IntPtr.Zero);
}
public override void SwapInterval(int interval)
{
wglSwapIntervalExt?.Invoke(interval);
}
}
public class GlxGraphicsContext : GraphicsContext
{
private IntPtr _windowHandle;
public static GlxGraphicsContext GetCurrent(IntPtr windowHandle, IntPtr display)
{
var gc = UnsafeNativeMethods.glXGetCurrentContext();
return new GlxGraphicsContext(windowHandle, gc, display);
}
public GlxGraphicsContext(IntPtr windowHandle, IntPtr graphicsContext, IntPtr display)
{
_windowHandle = UnsafeNativeMethods.gdk_x11_window_get_xid(windowHandle);
_display = UnsafeNativeMethods.gdk_x11_display_get_xdisplay(display);
_graphicsContext = graphicsContext;
}
private IntPtr _graphicsContext;
private IntPtr _display;
public override void MakeCurrent()
{
UnsafeNativeMethods.glXMakeCurrent(_display, _windowHandle, _graphicsContext);
}
public override void SwapBuffers()
{
UnsafeNativeMethods.glXSwapBuffers(_display, _windowHandle);
}
public override void ClearCurrent()
{
UnsafeNativeMethods.glXMakeCurrent(_display, _windowHandle, IntPtr.Zero);
}
public override void SwapInterval(int interval)
{
UnsafeNativeMethods.glXSwapIntervalEXT(interval);
}
}
}