#region --- License ---
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
* See license.txt for license info
*/
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using System.Text.RegularExpressions;
namespace Examples
.WinForms
{
[Example
("OpenGL Extensions", ExampleCategory
.OpenTK,
"Test", Documentation
="Extensions")]
public partial class Extensions
: Form
{
#region Fields
int supported_count, opengl_function_count
; // Number of supported extensions.
SortedDictionary
<Function,
bool> functions
= new SortedDictionary
<Function,
bool>();
#endregion
#region Constructors
public Extensions
()
{
this.Font = SystemFonts
.MessageBoxFont;
InitializeComponent
();
Application
.Idle += StartAsync
;
// Workaround for missing Idle event on Mono/Windows.
if (Configuration
.RunningOnMono && Configuration
.RunningOnWindows)
Application
.RaiseIdle(EventArgs
.Empty);
}
#endregion
#region Private Members
// Creates a context and starts processing the GL class.
// The processing takes place in the background to avoid hanging the GUI.
void StartAsync
(object sender, EventArgs e
)
{
Application
.Idle -= StartAsync
;
// Create a context to load all GL entry points.
// The loading part is handled automatically by OpenTK.
using (INativeWindow window
= new OpenTK
.NativeWindow())
using (IGraphicsContext context
= new GraphicsContext
(GraphicsMode
.Default, window
.WindowInfo,
3,
0, GraphicsContextFlags
.Default))
{
window
.ProcessEvents();
context
.MakeCurrent(window
.WindowInfo);
(context
as IGraphicsContextInternal
).LoadAll();
TextBoxVendor
.Text = GL
.GetString(StringName
.Vendor);
TextBoxRenderer
.Text = GL
.GetString(StringName
.Renderer);
TextBoxVersion
.Text = GL
.GetString(StringName
.Version);
}
backgroundWorker1
.RunWorkerAsync();
TextBoxSupport
.Text = "processing... (please be patient)";
}
void backgroundWorker1_DoWork
(object sender, DoWorkEventArgs e
)
{
Type delegates
= typeof(GL
).GetNestedType("Delegates", BindingFlags
.NonPublic | BindingFlags
.Static);
foreach (Function f
in LoadFunctionsFromType
(typeof(GL
)))
{
FieldInfo @
delegate = delegates
.GetField(f
.EntryPoint,
BindingFlags
.Public | BindingFlags
.NonPublic | BindingFlags
.Static | BindingFlags
.Instance);
// Only show a function as supported when all relevant overloads are supported.
if (!functions
.ContainsKey(f
))
functions
.Add(f, @
delegate != null && @
delegate.GetValue(null) != null);
else
functions
[f
] &= @
delegate != null && @
delegate.GetValue(null) != null;
}
// Count supported functions using the delegates directly.
foreach (FieldInfo f
in typeof(GL
).GetNestedType("Delegates", BindingFlags
.NonPublic)
.GetFields(BindingFlags
.Static | BindingFlags
.NonPublic))
{
if (f
.GetValue(null) != null)
supported_count
++;
opengl_function_count
++;
}
}
// Recursively load all functions marked with [AutoGenerated] in the specified Type.
IEnumerable
<Function
> LoadFunctionsFromType
(Type type
)
{
foreach (MethodInfo method
in type
.GetMethods(BindingFlags
.Public | BindingFlags
.Static))
{
// Functions in GLHelper.cs are not autogenerated and should be skipped.
AutoGeneratedAttribute
[] attr
= (AutoGeneratedAttribute
[])
method
.GetCustomAttributes(typeof(AutoGeneratedAttribute
),
false);
if (attr
.Length == 0)
continue;
string returnType
= method
.ReturnParameter.ToString();
List
<string> args
= new List
<string>();
foreach (ParameterInfo item
in method
.GetParameters())
{
args
.Add(item
.ToString());
}
string argsStr
= String.Join(", ", args
.ToArray());
string fullMethodName
= String.Format("{0} {1}({2})", returnType, method
.Name, argsStr
);
yield return new Function
(fullMethodName, type
.Name,
attr
[0].EntryPoint, attr
[0].Version, attr
[0].Category);
}
foreach (Type nested_type
in type
.GetNestedTypes(BindingFlags
.Public | BindingFlags
.Static))
foreach (Function f
in LoadFunctionsFromType
(nested_type
))
yield return f
;
}
// Update the DataGridView with our findings.
private void backgroundWorker1_RunWorkerCompleted
(object sender, RunWorkerCompletedEventArgs e
)
{
TextBoxSupport
.Text = String.Format("{0} of {1} functions supported.",
supported_count, opengl_function_count
);
foreach (Function f
in functions
.Keys)
{
dataGridView1
.Rows.Add(functions
[f
], f
.Name, f
.Category, f
.Version, f
.Extension, f
.EntryPoint);
int index
= dataGridView1
.Rows.Count - 1;
// Some simple coloring to make the GridView easier on the eyes.
// Supported functions are green, unsupported are redish.
dataGridView1
.Rows[index
].DefaultCellStyle.BackColor =
functions
[f
] ?
(index
% 2 != 0 ? Color
.FromArgb(128,
255,
192) : Color
.FromArgb(192,
255,
192)) :
(index
% 2 != 0 ? Color
.FromArgb(255,
192,
160) : Color
.FromArgb(255,
200,
160));
}
// Change the width of our Form to make every DataGridView column visible.
dataGridView1
.AutoResizeColumns(DataGridViewAutoSizeColumnsMode
.AllCellsExceptHeader);
dataGridView1
.Columns[1].Width = 450;
this.Size = dataGridView1
.GetPreferredSize(new System.Drawing.Size(2000, Height
));
}
#endregion
#region public static void Main()
/// <summary>
/// Entry point of this example.
/// </summary>
[STAThread
]
public static void Main
()
{
using (Extensions example
= new Extensions
())
{
Utilities
.SetWindowTitle(example
);
example
.ShowDialog();
}
}
#endregion
}
#region class Function
// A simple class where we store information from OpenTK.Graphics.GL.
sealed class Function
: IEquatable
<Function
>, IComparable
<Function
>
{
#region Fields
// We use these fields to distinguish between functions.
public readonly string Name
;
public readonly string Category
;
// These fields just provide some extra (cosmetic) information.
public readonly string EntryPoint
;
public readonly string Version
;
public readonly string Extension
;
#endregion
#region Constructors
public Function
(string name,
string category,
string entryPoint,
string version,
string extension
)
{
Name
= name
;
Category
= category
== "GL" ? String.Empty : category
;
EntryPoint
= entryPoint
;
Version
= version
;
Extension
= extension
;
}
#endregion
#region Public Members
public override bool Equals
(object obj
)
{
if (obj
is Function
)
return this.Equals((Function
)obj
);
return false;
}
public override int GetHashCode
()
{
return Name
.GetHashCode() ^ Category
.GetHashCode();
}
#endregion
#region IEquatable<Function> Members
public bool Equals
(Function other
)
{
return
Category
== other
.Category &&
Name
== other
.Name;
}
#endregion
#region IComparable<Function> Members
public int CompareTo
(Function other
)
{
int order
= Category
.CompareTo(other
.Category);
if (order
== 0)
order
= Name
.CompareTo(other
.Name);
return order
;
}
#endregion
}
#endregion
}