#region --- License --- /* Licensed under the MIT/X11 license. * Copyright (c) 2006-2008 the OpenTK Team. * This notice may not be removed from any source distribution. * See license.txt for licensing detailed licensing details. */ #endregion using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using OpenTK.Platform; namespace OpenTK.Graphics { /// /// Represents and provides methods to manipulate an OpenGL render context. /// public sealed class GraphicsContext : IGraphicsContext, IGraphicsContextInternal { IGraphicsContext implementation; // The actual render context implementation for the underlying platform. List dispose_queue = new List(); bool disposed; // Indicates that this context was created through external means, e.g. Tao.Sdl or GLWidget#. // In this case, We'll assume that the external program will manage the lifetime of this // context - we'll not destroy it manually. bool is_external; static bool share_contexts = true; static bool direct_rendering = true; static object context_lock = new object(); // Maps OS-specific context handles to GraphicsContext weak references. static Dictionary available_contexts = new Dictionary(); #region public GraphicsContext(GraphicsMode format, IWindowInfo window) /// /// Constructs a new GraphicsContext with the specified format, and attaches it to the specified window. /// /// The OpenTK.Graphics.GraphicsMode of the GraphicsContext. /// The OpenTK.Platform.IWindowInfo to attach the GraphicsContext to. public GraphicsContext(GraphicsMode mode, IWindowInfo window) { bool designMode = false; if (mode == null && window == null) designMode = true; else if (mode == null) throw new ArgumentNullException("mode", "Must be a valid GraphicsMode."); else if (window == null) throw new ArgumentNullException("window", "Must point to a valid window."); Debug.Print("Creating GraphicsContext."); try { Debug.Indent(); Debug.Print("GraphicsMode: {0}", mode); Debug.Print("IWindowInfo: {0}", window); IGraphicsContext shareContext = null; if (GraphicsContext.ShareContexts) { lock (context_lock) { // A small hack to create a shared context with the first available context. foreach (WeakReference r in GraphicsContext.available_contexts.Values) { shareContext = (IGraphicsContext)r.Target; break; } } } if (designMode) implementation = new Platform.Dummy.DummyGLContext(mode); else implementation = Factory.CreateGLContext(mode, window, shareContext, DirectRendering); lock (context_lock) { available_contexts.Add((this as IGraphicsContextInternal).Context, new WeakReference(this)); } //(implementation as IGraphicsContextInternal).LoadAll(); } finally { Debug.Unindent(); } } #endregion #region private GraphicsContext() private GraphicsContext() { } #endregion /// /// Attempts to create a GraphicsContext object from an existing OpenGL context. /// /// The window this context is bound to. /// A new GraphicsContext object, describing the current OpenGL context. /// /// Use this function to interoperate with OpenGL contexts created outside of OpenTK. /// The new GraphicsContext is added to the list of available OpenTK contexts. /// Make sure to call the Dispose() method once this context is destroyed. /// You may not call this method more than once on the same context. Doing so will throw an exception. /// public static GraphicsContext CreateFromCurrentThread(IWindowInfo window) { Debug.Print("Creating context from current thread."); GraphicsContext context = new GraphicsContext(); context.is_external = true; if (Configuration.RunningOnWindows) context.implementation = new OpenTK.Platform.Windows.WinGLContext(window); else if (Configuration.RunningOnX11) context.implementation = new OpenTK.Platform.X11.X11GLContext(window); else throw new PlatformNotSupportedException("Please, refer to http://www.opentk.com for more information."); lock (context_lock) { available_contexts.Add((context as IGraphicsContextInternal).Context, new WeakReference(context)); } return context; } #region void ContextDestroyed(IGraphicsContext context, EventArgs e) /// /// Handles the Destroy event. /// /// The OpenTK.Platform.IGraphicsContext that was destroyed. /// Not used. void ContextDestroyed(IGraphicsContext context, EventArgs e) { this.Destroy -= ContextDestroyed; //available_contexts.Remove(((IGraphicsContextInternal)this).Context); } #endregion #region --- Public Members --- #region public static IGraphicsContext CurrentContext internal delegate ContextHandle GetCurrentContextDelegate(); internal static GetCurrentContextDelegate GetCurrentContext; /// /// Gets or sets the current GraphicsContext in the calling thread. /// public static GraphicsContext CurrentContext { get { lock (context_lock) { if (available_contexts.Count > 0) { ContextHandle handle = GetCurrentContext(); if (handle.Handle != IntPtr.Zero) return (GraphicsContext)available_contexts[handle].Target; } return null; } } //set //{ // if (value != null) // value.MakeCurrent(); // else if (CurrentContext != null) // CurrentContext.IsCurrent = false; //} } #endregion #region public static bool ShareContexts /// Gets or sets a System.Boolean, indicating whether GraphicsContext resources 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 #region public static bool DirectRendering /// Gets or sets a System.Boolean, indicating whether GraphicsContexts will perform direct rendering. /// /// /// If DirectRendering is true, new contexts will be constructed with direct rendering capabilities, if possible. /// If DirectRendering is false, new contexts will be constructed with indirect rendering capabilities. /// /// This property does not affect existing GraphicsContexts, unless they are recreated. /// /// This property is ignored on Operating Systems without support for indirect rendering, like Windows and OS X. /// /// public static bool DirectRendering { get { return direct_rendering; } set { direct_rendering = value; } } #endregion #region public static AvailableDisplayFormats #endregion #region public static void Assert() /// /// Checks if a GraphicsContext exists in the calling thread and throws a GraphicsContextException if it doesn't. /// public static void Assert() { if (GraphicsContext.CurrentContext == null) throw new GraphicsContextException(); } #endregion #endregion internal IGraphicsContext Implementation { get { return implementation; } } #region --- IGraphicsContext Members --- /// /// Creates an OpenGL context with the specified direct/indirect rendering mode and sharing state with the /// specified IGraphicsContext. /// /// Set to true for direct rendering or false otherwise. /// The source IGraphicsContext to share state from.. /// /// /// 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). /// /// void CreateContext(bool direct, IGraphicsContext source) { this.Destroy += ContextDestroyed; lock (context_lock) { available_contexts.Add((this as IGraphicsContextInternal).Context, new WeakReference(this)); } //OpenTK.Graphics.OpenGL.GL.Clear(OpenTK.Graphics.OpenGL.ClearBufferMask.ColorBufferBit); //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 the GraphicsContext the current rendering target. /// /// A System.Platform.IWindowInfo structure for the window this context is bound to. /// /// You can use this method to bind the GraphicsContext to a different window than the one it was created from. /// public void MakeCurrent(IWindowInfo info) { implementation.MakeCurrent(info); } /// /// Gets a System.Boolean indicating whether this Context is current in the calling thread. /// public bool IsCurrent { get { return implementation.IsCurrent; } //set { implementation.IsCurrent = value; } } /// /// 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; } } /// /// Updates the graphics context. This must be called when the render target /// is resized for proper behavior on Mac OS X. /// /// public void Update(IWindowInfo window) { implementation.Update(window); } #endregion #region --- IGraphicsContextInternal Members --- #region void LoadAll() void IGraphicsContextInternal.LoadAll() { (implementation as IGraphicsContextInternal).LoadAll(); } #endregion /// /// Gets a handle to the OpenGL rendering context. ContextHandle IGraphicsContextInternal.Context { get { return ((IGraphicsContextInternal)implementation).Context; } } /* /// /// Gets the IWindowInfo describing the window associated with this context. /// IWindowInfo IGraphicsContextInternal.Info { get { return (implementation as IGraphicsContextInternal).Info; } //internal set { (implementation as IGLContextInternal).Info = value; } } */ /// /// Gets the GraphicsMode of the context. /// public GraphicsMode GraphicsMode { get { return (implementation as IGraphicsContextInternal).GraphicsMode; } } ///// ///// 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 IGraphicsContextInternal.RegisterForDisposal(IDisposable resource) { GC.KeepAlive(resource); dispose_queue.Add(resource); } /// /// Disposes all registered OpenGL resources. /// void IGraphicsContextInternal.DisposeResources() { foreach (IDisposable resource in dispose_queue) resource.Dispose(); dispose_queue.Clear(); } /// /// 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 IGraphicsContextInternal.GetAddress(string function) { return (implementation as IGraphicsContextInternal).GetAddress(function); } #endregion #region --- IDisposable Members --- /// /// Disposes of the GraphicsContext. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } void Dispose(bool manual) { if (!disposed) { Debug.WriteLine("Disposing context {0}.", (this as IGraphicsContextInternal).Context.ToString()); lock (context_lock) { available_contexts.Remove((this as IGraphicsContextInternal).Context); } if (manual && !is_external) { if (implementation != null) implementation.Dispose(); } disposed = true; } } //~GraphicsContext() //{ // this.Dispose(false); //} #endregion } #region public class GraphicsException : Exception /// Represents errors related to Graphics operations. public class GraphicsException : Exception { /// Constructs a new GraphicsException. public GraphicsException() : base() { } /// Constructs a new GraphicsException with the specified excpetion message. /// public GraphicsException(string message) : base(message) { } } #endregion }