#region --- License --- /* Copyright (c) 2006, 2007 Stefanos Apostolopoulos * See license.txt for license info */ #endregion using System; using System.Collections.Generic; using System.Text; using OpenTK.Platform; namespace OpenTK { /// /// Represents and provides methods to manipulate an OpenGL render context. /// public sealed class GLContext : IGLContext, IGLContextInternal, IGLContextCreationHack { IGLContext implementation; // The actual render context implementation for the underlying platform. List dispose_queue = new List(); bool disposed; static bool share_contexts = true; static object context_lock = new object(); static Dictionary available_contexts = new Dictionary(); // Contains all available OpenGL contexts. //delegate IntPtr GetCurrentContextDelegate(); //static GetCurrentContextDelegate StaticGetCurrentContext; #region public GLContext(DisplayMode mode, IWindowInfo window) /// /// Constructs a new GLContext with the specified DisplayMode, and bound to the specified IWindowInfo. /// /// /// public GLContext(DisplayMode mode, IWindowInfo window) { //if (available_contexts.Count == 0) // available_contexts.Add(IntPtr.Zero, new WeakReference(null)); switch (Environment.OSVersion.Platform) { case PlatformID.Unix: case (PlatformID)128: implementation = new OpenTK.Platform.X11.X11GLContext(); break; case PlatformID.Win32NT: case PlatformID.Win32S: case PlatformID.Win32Windows: case PlatformID.WinCE: implementation = new OpenTK.Platform.Windows.WinGLContext(); break; default: throw new PlatformNotSupportedException("Your platform is not supported currently. Please, refer to http://www.opentk.com for more information."); } (this as IGLContextCreationHack).SetWindowHandle(window.Handle); (this as IGLContextCreationHack).SelectDisplayMode(mode, window); if (GLContext.ShareContexts) { lock (context_lock) { // A small hack to create a shared context with the first available context. foreach (WeakReference r in GLContext.available_contexts.Values) { this.CreateContext(true, (GLContext)r.Target); return; } } } // Only reached if a shared context was not created above, or if this is the first // context ever constructed. this.CreateContext(true, null); } #endregion #region void ContextDestroyed(IGLContext context, EventArgs e) /// /// Handles the Destroy event. /// /// The OpenTK.Platform.IGLContext that was destroyed. /// Not used. void ContextDestroyed(IGLContext context, EventArgs e) { this.Destroy -= ContextDestroyed; available_contexts.Remove(((IGLContextInternal)this).Context); } #endregion #region --- Public Members --- #region public static IGLContext CurrentContext internal delegate ContextHandle GetCurrentContextDelegate(); internal static GetCurrentContextDelegate GetCurrentContext; /// /// Returns the context which is current in the calling thread. /// public static GLContext CurrentContext { get { if (available_contexts.Count > 0) return (GLContext)available_contexts[GetCurrentContext()].Target; //return (GLContext)available_contexts[((IGLContextInternal)available_contexts[IntPtr.Zero].Target).GetCurrentContext()].Target; return null; //return (GLContext)available_contexts[StaticGetCurrentContext().ToInt64()].Target; } } #endregion #region public static bool ShareContexts /// Gets or sets a System.Boolean, indicating whether GLContexts are shared /// /// If ShareContexts is true, new GLContexts will share resources. If this value is /// false, new GLContexts will not share resources. /// Changing this value will not affect already created GLContexts. /// public static bool ShareContexts { get { return share_contexts; } set { share_contexts = value; } } #endregion #endregion #region --- IGLContext Members --- /// /// Creates an OpenGL context. /// public void CreateContext() { CreateContext(true, null); } /// /// Creates an OpenGL context with a direct or indirect rendering mode. This parameter is ignored /// on Windows platforms (direct mode only). /// /// Set to true for direct rendering or false otherwise. /// /// /// Direct rendering is the default rendering mode for OpenTK, since it can provide higher performance /// in some circumastances. /// /// /// The 'direct' parameter is a hint, and will ignored if the specified mode is not supported (e.g. setting /// indirect rendering on Windows platforms). /// /// public void CreateContext(bool direct) { CreateContext(direct, null); } /// /// Creates an OpenGL context with the specified direct/indirect rendering mode and sharing state with the /// specified IGLContext. /// /// Set to true for direct rendering or false otherwise. /// The source IGLContext to share state from.. /// public void CreateContext(bool direct, IGLContext source) { implementation.CreateContext(direct, source); this.Destroy += ContextDestroyed; available_contexts.Add((this as IGLContextInternal).Context, new WeakReference(this)); //if (StaticGetCurrentContext == null) // StaticGetCurrentContext = implementation.GetCurrentContext; } /// /// Swaps buffers on a context. This presents the rendered scene to the user. /// public void SwapBuffers() { implementation.SwapBuffers(); } /// /// Makes this context the current rendering target. /// public void MakeCurrent() { implementation.MakeCurrent(); } /// /// Gets a System.Boolean indicating whether this Context is current in the calling thread. /// public bool IsCurrent { get { return implementation.IsCurrent; } } /// /// Raised when a Context is destroyed. /// public event DestroyEvent Destroy { add { implementation.Destroy += value; } remove { implementation.Destroy -= value; } } /// /// Gets or sets a value indicating whether VSync is enabled. /// public bool VSync { get { return implementation.VSync; } set { implementation.VSync = value; } } #endregion #region --- IGLContextInternal Members --- /// /// Gets a handle to the OpenGL rendering context. /// ContextHandle IGLContextInternal.Context { get { return ((IGLContextInternal)implementation).Context; } } /// /// Gets the IWindowInfo describing the window associated with this context. /// IWindowInfo IGLContextInternal.Info { get { return (implementation as IGLContextInternal).Info; } //internal set { (implementation as IGLContextInternal).Info = value; } } /// /// Gets the DisplayMode of the context. /// DisplayMode IGLContextInternal.Mode { get { return (implementation as IGLContextInternal).Mode; } } /// /// Gets a System.IntPtr containing the handle to the OpenGL context which is current in the /// calling thread, or IntPtr.Zero if no OpenGL context is current. /// /// A System.IntPtr that holds the handle to the current OpenGL context. ContextHandle IGLContextInternal.GetCurrentContext() { return (implementation as IGLContextInternal).GetCurrentContext(); } /// /// Registers an OpenGL resource for disposal. /// /// The OpenGL resource to dispose. void IGLContextInternal.RegisterForDisposal(IDisposable resource) { GC.KeepAlive(resource); dispose_queue.Add(resource); } /// /// Disposes all registered OpenGL resources. /// void IGLContextInternal.DisposeResources() { foreach (IDisposable resource in dispose_queue) resource.Dispose(); dispose_queue.Clear(); } /// /// Returns the display modes supported by the current opengl context. /// /// An IEnumerable containing all supported display modes. IEnumerable IGLContextInternal.GetDisplayModes() { return (implementation as IGLContextInternal).GetDisplayModes(); } /// /// Gets the address of an OpenGL extension function. /// /// The name of the OpenGL function (e.g. "glGetString") /// /// A pointer to the specified function or IntPtr.Zero if the function isn't /// available in the current opengl context. /// /// IntPtr IGLContextInternal.GetAddress(string function) { return (implementation as IGLContextInternal).GetAddress(function); } #endregion #region --- IGLContextCreationHack Members --- bool IGLContextCreationHack.SelectDisplayMode(DisplayMode mode, IWindowInfo info) { return (implementation as IGLContextCreationHack).SelectDisplayMode(mode, info); } void IGLContextCreationHack.SetWindowHandle(IntPtr handle) { (implementation as IGLContextCreationHack).SetWindowHandle(handle); } #endregion #region --- IDisposable Members --- /// /// Disposes of the GLContext. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } void Dispose(bool manual) { if (!disposed) { // TODO: Check if this is safe //if (manual) { implementation.Dispose(); } disposed = true; } } ~GLContext() { this.Dispose(false); } #endregion } }