using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace OpenGL
{
static class GL
{
public static unsafe class Private
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void glCullFace(int mode);
public static glCullFace CullFace;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void glFrontFace(int mode);
public static glFrontFace FrontFace;
}
}
static class Loader
{
static IntPtr opengl;
public static void Load()
{
opengl = Native.LoadLibrary("opengl32.dll");
foreach (var field in typeof(OpenGL.GL.Private).GetFields())
{
Type type = field.FieldType;
string name = type.Name;
IntPtr ptr = Native.wglGetProcAddress(name);
if (ptr == IntPtr.Zero)
{
ptr = Native.GetProcAddress(opengl, name);
}
field.SetValue(null, GetDelegate(ptr, type));
}
}
public static void Unload()
{
foreach (var field in typeof(OpenGL.GL.Private).GetFields())
{
field.SetValue(null, null);
}
Native.FreeLibrary(opengl);
}
static object GetDelegate(IntPtr ptr, Type type)
{
//return Convert.ChangeType(Marshal.GetDelegateForFunctionPointer(ptr, type), type);
var invoke = type.GetMethod("Invoke");
var retType = invoke.ReturnType;
var parameters = invoke.GetParameters();
var argCount = parameters.Length;
var argTypes = new Type[argCount];
for (int i = 0; i < argCount; i++)
{
argTypes[i] = parameters[i].ParameterType;
}
var method = new DynamicMethod(type.Name + "_Method", retType, argTypes, typeof(Loader), true);
var il = method.GetILGenerator();
if (argCount > 0) il.Emit(OpCodes.Ldarg_0);
if (argCount > 1) il.Emit(OpCodes.Ldarg_1);
if (argCount > 2) il.Emit(OpCodes.Ldarg_2);
if (argCount > 3) il.Emit(OpCodes.Ldarg_3);
for (int i = 4; i < argCount; i++)
{
il.Emit(OpCodes.Ldarg_S, i);
}
if (sizeof(int) == IntPtr.Size)
{
il.Emit(OpCodes.Ldc_I4, ptr.ToInt32());
}
else
{
il.Emit(OpCodes.Ldc_I8, ptr.ToInt64());
}
il.EmitCalli(OpCodes.Calli, CallingConvention.Cdecl, retType, argTypes);
#if DEBUG
if (type != typeof(OpenGL.GL.Private.glGetError))
{
var check = typeof(Loader).GetMethod("CheckGLErrors", BindingFlags.Static | BindingFlags.NonPublic);
il.EmitCall(OpCodes.Call, check, null);
}
#endif
il.Emit(OpCodes.Ret);
return method.CreateDelegate(type);
}
static void CheckGLErrors()
{
var err = OpenGL.GL.GetError();
if (err != OpenGL.GL.ErrorCode.NoError)
{
var errors = new List<string>(1);
while (err != OpenGL.GL.ErrorCode.NoError)
{
errors.Add(err.ToString());
err = OpenGL.GL.GetError();
}
throw new ApplicationException("OpenGL error(s): " + String.Join(", ", errors.ToArray()));
}
}
}
}