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