#region --- License ---
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
* Contributions by Andy Gill.
* See license.txt for license info
*/
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Reflection.Emit;
using OpenTK.Platform;
namespace OpenTK.Graphics
{
///
/// Provides access to the OpenGL Utilities library.
/// Methods i this library are considered deprecated and should be avoided.
///
[Obsolete("Use OpenTK math functions instead.")]
public static partial class Glu
{
private const string Library = "glu32.dll";
private static Dictionary AvailableExtensions = new Dictionary();
private static bool rebuildExtensionList = true;
private static Type importsClass = typeof(Imports);
static Glu()
{
// Glu doesn't have any extensions, so this is safe to call once and be done with it.
LoadAll();
}
#region private static Delegate LoadDelegate(string name, Type signature)
///
/// Creates a System.Delegate that can be used to call a GLU function, core or extension.
///
/// The name of the GLU function (eg. "gluBuild2DMipmaps")
/// The signature of the GLU function.
///
/// A System.Delegate that can be used to call this GLU function, or null if the specified
/// function name did not correspond to an GLU function.
///
private static Delegate LoadDelegate(string name, Type signature)
{
MethodInfo m = importsClass.GetMethod(name.Substring(3), BindingFlags.Static | BindingFlags.NonPublic);
return
GL.GetExtensionDelegate(name, signature) ??
(m != null ? Delegate.CreateDelegate(signature, m) : null);
}
#endregion
#region public static void LoadAll()
///
/// Loads all GLU functions (core and extensions).
///
///
///
/// Call this function manually whenever you need to update GLU entry points.
/// This need will never arise under normal usage patterns.
///
///
public static void LoadAll()
{
int supported = 0;
Type extensions_class = typeof(Glu).GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (extensions_class == null)
throw new InvalidOperationException("The specified type does not have any loadable extensions.");
FieldInfo[] delegates = extensions_class.GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (delegates == null)
throw new InvalidOperationException("The specified type does not have any loadable extensions.");
foreach (FieldInfo f in delegates)
{
Delegate d = LoadDelegate(f.Name, f.FieldType);
if (d != null)
++supported;
f.SetValue(null, d);
}
rebuildExtensionList = true;
}
#endregion
#region public static bool Load(string function)
///
/// Tries to reload the given GLU function (core or extension).
///
/// The name of the GLU function.
/// True if the function was found and reloaded, false otherwise.
///
///
/// While the automatic initialisation will load all GLU entry points, in some cases
/// the initialization can take place before a render context has been established.
/// In this case, use this function to load the entry points for the GLU functions
/// you will need, or use LoadAll() to load all available entry points.
///
///
/// This function returns true if the given GLU function is supported, false otherwise.
///
///
/// To query for supported extensions use the IsExtensionSupported() function instead.
///
///
public static bool Load(string function)
{
// Glu does not contain any extensions - this method does nothing.
return true;
}
#endregion
#region public static bool SupportsExtension(string name)
///
/// Determines whether the specified GLU extension is available in
/// the current GLU context.
///
/// The string for the GLU extension.
/// True if the specified extension is available, false otherwise.
public static bool SupportsExtension(string name)
{
if (rebuildExtensionList)
{
BuildExtensionList();
}
// Search the cache for the string. Note that the cache substitutes
// strings "1.0" to "2.1" with "GL_VERSION_1_0" to "GL_VERSION_2_1"
if (AvailableExtensions.ContainsKey(name))
{
return AvailableExtensions[name];
}
return false;
}
#endregion
#region private static void BuildExtensionList()
///
/// Builds a cache of the supported extensions to speed up searches.
///
private static void BuildExtensionList()
{
// Assumes there is an opengl context current.
AvailableExtensions.Clear();
string version_string = Glu.GetString(GluStringName.Version);
if (String.IsNullOrEmpty(version_string))
{
throw new ApplicationException("Failed to build extension list. Is there an opengl context current?");
}
string version = version_string.Trim(' ');
if (version.StartsWith("1.0"))
{
AvailableExtensions.Add("VERSION_1_0", true);
}
else if (version.StartsWith("1.1"))
{
AvailableExtensions.Add("VERSION_1_0", true);
AvailableExtensions.Add("VERSION_1_1", true);
}
else if (version.StartsWith("1.2"))
{
AvailableExtensions.Add("VERSION_1_0", true);
AvailableExtensions.Add("VERSION_1_1", true);
AvailableExtensions.Add("VERSION_1_2", true);
}
else if (version.StartsWith("1.3"))
{
AvailableExtensions.Add("VERSION_1_0", true);
AvailableExtensions.Add("VERSION_1_1", true);
AvailableExtensions.Add("VERSION_1_2", true);
AvailableExtensions.Add("VERSION_1_3", true);
}
string extension_string = Glu.GetString(GluStringName.Extensions);
if (String.IsNullOrEmpty(extension_string))
{ // no extensions are available
return;
}
string[] extensions = extension_string.Split(' ');
foreach (string ext in extensions)
{
AvailableExtensions.Add(ext, true);
}
rebuildExtensionList = false;
}
#endregion
#region Overloads
public static void LookAt(Vector3 eye, Vector3 center, Vector3 up)
{
Delegates.gluLookAt((double)eye.X, (double)eye.Y, (double)eye.Z, (double)center.X, (double)center.Y, (double)center.Z, (double)up.X, (double)up.Y, (double)up.Z);
}
// One token Project overload, I picked this one because it's CLS compliant, and it
// makes reasonably clear which args are inputs and which are outputs.
public static Int32 Project(Vector3 obj, double[] model, double[] proj, Int32[] view, out Vector3 win)
{
unsafe
{
double winX, winY, winZ;
double* winX_ptr = &winX;
double* winY_ptr = &winY;
double* winZ_ptr = &winZ;
fixed (double* model_ptr = model)
fixed (double* proj_ptr = proj)
fixed (Int32* view_ptr = view)
{
Int32 retval = Delegates.gluProject((double)obj.X, (double)obj.Y, (double)obj.Z, (double*)model_ptr, (double*)proj_ptr, (Int32*)view_ptr, (double*)winX_ptr, (double*)winY_ptr, (double*)winZ_ptr);
win = new Vector3((float)*winX_ptr, (float)*winY_ptr, (float)*winZ_ptr);
return retval;
}
}
}
public static void TessNormal(IntPtr tess, Vector3 normal)
{
Delegates.gluTessNormal(tess, (double)normal.X, (double)normal.Y, (double)normal.Z);
}
public static Int32 UnProject(Vector3 win, double[] model, double[] proj, Int32[] view, out Vector3 obj)
{
unsafe
{
double objX, objY, objZ;
double* objX_ptr = &objX;
double* objY_ptr = &objY;
double* objZ_ptr = &objZ;
fixed (double* model_ptr = model)
fixed (double* proj_ptr = proj)
fixed (Int32* view_ptr = view)
{
Int32 retval = Delegates.gluUnProject((double)win.X, (double)win.Y, (double)win.Z, (double*)model_ptr, (double*)proj_ptr, (Int32*)view_ptr, (double*)objX_ptr, (double*)objY_ptr, (double*)objZ_ptr);
obj = new Vector3((float)*objX_ptr, (float)*objY_ptr, (float)*objZ_ptr);
return retval;
}
}
}
public static Int32 UnProject4(Vector4 win, double[] model, double[] proj, Int32[] view, double near, double far, out Vector4 obj)
{
unsafe
{
double objX, objY, objZ, objW;
double* objX_ptr = &objX;
double* objY_ptr = &objY;
double* objZ_ptr = &objZ;
double* objW_ptr = &objW;
fixed (double* model_ptr = model)
fixed (double* proj_ptr = proj)
fixed (Int32* view_ptr = view)
{
Int32 retval = Delegates.gluUnProject4((double)win.X, (double)win.Y, (double)win.Z, (double)win.W, (double*)model_ptr, (double*)proj_ptr, (Int32*)view_ptr, (double)near, (double)far, (double*)objX_ptr, (double*)objY_ptr, (double*)objZ_ptr, (double*)objW_ptr);
obj = new Vector4((float)*objX_ptr, (float)*objY_ptr, (float)*objZ_ptr, (float)*objW_ptr);
return retval;
}
}
}
public static string ErrorString(ErrorCode error)
{
return ErrorString((GluErrorCode)error);
}
public static void TessWindingRuleProperty(IntPtr tess, TessWinding property)
{
Glu.TessProperty(tess, TessParameter.TessWindingRule, (double)property);
}
#endregion
}
#if false
//public delegate object
public delegate void FastVoidInvokeHandler(object target, object[] paramters);
public delegate object FastInvokeHandler(object target, object[] paramters);
public static class FastInvoker
{
///
/// Use this one instead of MethodInfo.Invoke, this way it is 50 times quicker.
///
///
/// string Filter = "FirstName = 'Ton'"
/// MethodInfo mi = typeof(Person).GetMethod("GetAll");
/// snoei.net.Reflection.FastInvoker.FastInvokeHandler fi = snoei.net.Reflection.FastInvoker.GetMethodInvoker( mi );
// return fi.Invoke( Person, new object[]{Filter} );
/// //Calls Person.GetAll(string Filter);
///
///
///
///
public static Delegate GetMethodInvoker(MethodInfo methodInfo)
{
DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, methodInfo.ReturnType, new Type[] { typeof(object), typeof(object[]) }, methodInfo.DeclaringType.Module);
ILGenerator il = dynamicMethod.GetILGenerator();
ParameterInfo[] ps = methodInfo.GetParameters();
Type[] paramTypes = new Type[ps.Length];
for (int i = 0; i < paramTypes.Length; i++)
{
if (ps[i].ParameterType.IsByRef)
paramTypes[i] = ps[i].ParameterType.GetElementType();
else
paramTypes[i] = ps[i].ParameterType;
}
LocalBuilder[] locals = new LocalBuilder[paramTypes.Length];
for (int i = 0; i < paramTypes.Length; i++)
locals[i] = il.DeclareLocal(paramTypes[i], true);
for (int i = 0; i < paramTypes.Length; i++)
{
il.Emit(OpCodes.Ldarg_1);
EmitFastInt(il, i);
il.Emit(OpCodes.Ldelem_Ref);
EmitCastToReference(il, paramTypes[i]);
il.Emit(OpCodes.Stloc, locals[i]);
}
if (!methodInfo.IsStatic)
il.Emit(OpCodes.Ldarg_0);
for (int i = 0; i < paramTypes.Length; i++)
{
if (ps[i].ParameterType.IsByRef)
il.Emit(OpCodes.Ldloca_S, locals[i]);
else
il.Emit(OpCodes.Ldloc, locals[i]);
}
if (methodInfo.IsStatic)
il.EmitCall(OpCodes.Call, methodInfo, null);
else
il.EmitCall(OpCodes.Callvirt, methodInfo, null);
if (methodInfo.ReturnType == typeof(void))
il.Emit(OpCodes.Ldnull);
else
EmitBoxIfNeeded(il, methodInfo.ReturnType);
for (int i = 0; i < paramTypes.Length; i++)
{
if (ps[i].ParameterType.IsByRef)
{
il.Emit(OpCodes.Ldarg_1);
EmitFastInt(il, i);
il.Emit(OpCodes.Ldloc, locals[i]);
if (locals[i].LocalType.IsValueType)
il.Emit(OpCodes.Box, locals[i].LocalType);
il.Emit(OpCodes.Stelem_Ref);
}
}
il.Emit(OpCodes.Ret);
if (methodInfo.ReturnType == typeof(void))
return dynamicMethod.CreateDelegate(typeof(FastVoidInvokeHandler));
else
return dynamicMethod.CreateDelegate(typeof(FastInvokeHandler));
}
private static void EmitCastToReference(ILGenerator il, System.Type type)
{
if (type.IsValueType)
il.Emit(OpCodes.Unbox_Any, type);
else
il.Emit(OpCodes.Castclass, type);
}
private static void EmitBoxIfNeeded(ILGenerator il, System.Type type)
{
if (type.IsValueType)
il.Emit(OpCodes.Box, type);
}
private static void EmitFastInt(ILGenerator il, int value)
{
switch (value)
{
case -1:
il.Emit(OpCodes.Ldc_I4_M1);
return;
case 0:
il.Emit(OpCodes.Ldc_I4_0);
return;
case 1:
il.Emit(OpCodes.Ldc_I4_1);
return;
case 2:
il.Emit(OpCodes.Ldc_I4_2);
return;
case 3:
il.Emit(OpCodes.Ldc_I4_3);
return;
case 4:
il.Emit(OpCodes.Ldc_I4_4);
return;
case 5:
il.Emit(OpCodes.Ldc_I4_5);
return;
case 6:
il.Emit(OpCodes.Ldc_I4_6);
return;
case 7:
il.Emit(OpCodes.Ldc_I4_7);
return;
case 8:
il.Emit(OpCodes.Ldc_I4_8);
return;
}
if (value > -129 && value < 128)
il.Emit(OpCodes.Ldc_I4_S, (SByte)value);
else
il.Emit(OpCodes.Ldc_I4, value);
}
}
#endif
}