250 lines
No EOL
8.6 KiB
C#
250 lines
No EOL
8.6 KiB
C#
#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", Visible = false)]
|
|
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
|
|
} |