#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 functions = new SortedDictionary(); #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 in order to load all GL methods (GL.LoadAll() is called automatically.) using (GLControl control = new GLControl(GraphicsMode.Default, 3, 0, GraphicsContextFlags.Default)) { 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))) { // Only show a function as supported when all relevant overloads are supported. if (!functions.ContainsKey(f)) functions.Add(f, (bool)delegates.GetField(f.EntryPoint).GetValue(null)); else functions[f] &= (bool)delegates.GetField(f.EntryPoint).GetValue(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 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 args = new List(); 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 Size(2000, Height)); } #endregion #region public static void Main() /// /// Entry point of this example. /// [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, IComparable { #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 Members public bool Equals(Function other) { return Category == other.Category && Name == other.Name; } #endregion #region IComparable Members public int CompareTo(Function other) { int order = Category.CompareTo(other.Category); if (order == 0) order = Name.CompareTo(other.Name); return order; } #endregion } #endregion }