#region License // // The Open Toolkit Library License // // Copyright (c) 2006 - 2009 the Open Toolkit library, except where noted. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do // so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // #endregion using System; using System.Threading; using System.ComponentModel; using OpenTK.Graphics; using OpenTK.Platform; using Gtk; using OpenTK.OSX; using OpenTK.Win; using OpenTK.X11; namespace OpenTK { /// /// The is a GTK widget for which an OpenGL context can be used to draw arbitrary graphics. /// [ToolboxItem(true)] public class GLWidget: DrawingArea { #region Static attrs. private static int _GraphicsContextCount; private static bool _SharedContextInitialized = false; #endregion #region Attributes private IGraphicsContext _GraphicsContext; private IWindowInfo _WindowInfo; private GraphicsContextFlags _GraphicsContextFlags; private bool _Initialized = false; #endregion #region Properties /// /// Use a single buffer versus a double buffer. /// [Browsable(true)] public bool SingleBuffer { get; set; } /// /// Color Buffer Bits-Per-Pixel /// public int ColorBPP { get; set; } /// /// Accumulation Buffer Bits-Per-Pixel /// public int AccumulatorBPP { get; set; } /// /// Depth Buffer Bits-Per-Pixel /// public int DepthBPP { get; set; } /// /// Stencil Buffer Bits-Per-Pixel /// public int StencilBPP { get; set; } /// /// Number of samples /// public int Samples { get; set; } /// /// Indicates if steropic renderering is enabled /// public bool Stereo { get; set; } /// /// The major version of OpenGL to use. /// public int GlVersionMajor { get; set; } /// /// The minor version of OpenGL to use. /// public int GlVersionMinor { get; set; } /// /// The set for this widget. /// public GraphicsContextFlags GraphicsContextFlags { get { return _GraphicsContextFlags; } set { _GraphicsContextFlags = value; } } #endregion #region Construction/Destruction /// /// Initializes a new instance of the class. /// public GLWidget() : this(GraphicsMode.Default) { } /// Constructs a new GLWidget using a given GraphicsMode public GLWidget(GraphicsMode graphicsMode) : this(graphicsMode, 1, 0, GraphicsContextFlags.Default) { } /// /// Initializes a new instance of the class. /// /// The which the widget should be constructed with. /// The major OpenGL version to attempt to initialize. /// The minor OpenGL version to attempt to initialize. /// /// Any flags which should be used during initialization of the . /// public GLWidget(GraphicsMode graphicsMode, int glVersionMajor, int glVersionMinor, GraphicsContextFlags graphicsContextFlags) { this.DoubleBuffered = false; SingleBuffer = graphicsMode.Buffers == 1; ColorBPP = graphicsMode.ColorFormat.BitsPerPixel; AccumulatorBPP = graphicsMode.AccumulatorFormat.BitsPerPixel; DepthBPP = graphicsMode.Depth; StencilBPP = graphicsMode.Stencil; Samples = graphicsMode.Samples; Stereo = graphicsMode.Stereo; GlVersionMajor = glVersionMajor; GlVersionMinor = glVersionMinor; GraphicsContextFlags = graphicsContextFlags; } /// /// Destructs this object. /// ~GLWidget() { Dispose(false); } /// /// Destroys this , disposing it and destroying it in the context of GTK. /// public override void Destroy() { GC.SuppressFinalize(this); Dispose(true); base.Destroy(); } #if !GTK3 /// /// Disposes the current object, releasing any native resources it was using. /// /// public override void Dispose() { GC.SuppressFinalize(this); Dispose(true); base.Dispose(); } #endif #if GTK3 /// /// Disposes the current object, releasing any native resources it was using. /// /// protected override void Dispose(bool disposing) { base.Dispose(disposing); #else /// /// Disposes the current object, releasing any native resources it was using. /// /// public virtual void Dispose(bool disposing) { #endif if (disposing) { _GraphicsContext.MakeCurrent(_WindowInfo); OnShuttingDown(); if (GraphicsContext.ShareContexts && (Interlocked.Decrement(ref _GraphicsContextCount) == 0)) { OnGraphicsContextShuttingDown(); _SharedContextInitialized = false; } _GraphicsContext.Dispose(); } } #endregion #region New Events /// /// Called when the first is created in the case where /// GraphicsContext.ShareContexts == true; /// public static event EventHandler GraphicsContextInitialized; /// /// Invokes the event. /// private static void OnGraphicsContextInitialized() { if (GraphicsContextInitialized != null) GraphicsContextInitialized(null, EventArgs.Empty); } /// /// Called when the first is being destroyed in the case where /// GraphicsContext.ShareContext == true; /// public static event EventHandler GraphicsContextShuttingDown; /// /// Invokes the event. /// private static void OnGraphicsContextShuttingDown() { if (GraphicsContextShuttingDown != null) GraphicsContextShuttingDown(null, EventArgs.Empty); } /// /// Called when this has finished initializing and has a valid /// . /// public event EventHandler Initialized; /// /// Invokes the event. /// protected virtual void OnInitialized() { if (Initialized != null) Initialized(this, EventArgs.Empty); } /// /// Called when this needs to render a frame. /// public event EventHandler RenderFrame; /// /// Invokes the event. /// protected virtual void OnRenderFrame() { if (RenderFrame != null) RenderFrame(this, EventArgs.Empty); } /// /// Called when this is being disposed. /// public event EventHandler ShuttingDown; /// /// Invokes the event. /// protected virtual void OnShuttingDown() { if (ShuttingDown != null) ShuttingDown(this, EventArgs.Empty); } #endregion #if GTK3 /// /// Called when the widget needs to be (fully or partially) redrawn. /// /// /// protected override bool OnDrawn(Cairo.Context cr) #else /// /// Called when the widget is exposed. /// /// /// protected override bool OnExposeEvent(Gdk.EventExpose evnt) #endif { if (!_Initialized) Initialize(); else _GraphicsContext.MakeCurrent(_WindowInfo); #if GTK3 var result = base.OnDrawn(cr); #else bool result = base.OnExposeEvent(evnt); #endif OnRenderFrame(); #if !GTK3 evnt.Window.Display.Sync(); // Add Sync call to fix resize rendering problem (Jay L. T. Cornwall) - How does this affect VSync? #endif _GraphicsContext.SwapBuffers(); return result; } /// /// Called whenever the widget is resized. /// /// /// protected override bool OnConfigureEvent(Gdk.EventConfigure evnt) { bool result = base.OnConfigureEvent(evnt); if (_GraphicsContext != null) _GraphicsContext.Update(_WindowInfo); return result; } /// /// Initializes the with its given values and creates a . /// private void Initialize() { _Initialized = true; // If this looks uninitialized... initialize. if (ColorBPP == 0) { ColorBPP = 32; if (DepthBPP == 0) DepthBPP = 16; } ColorFormat colorBufferColorFormat = new ColorFormat(ColorBPP); ColorFormat accumulationColorFormat = new ColorFormat(AccumulatorBPP); int buffers = 2; if (SingleBuffer) buffers--; GraphicsMode graphicsMode = new GraphicsMode(colorBufferColorFormat, DepthBPP, StencilBPP, Samples, accumulationColorFormat, buffers, Stereo); if (Configuration.RunningOnWindows) Console.WriteLine("OpenTK running on windows"); else if (Configuration.RunningOnMacOS) Console.WriteLine("OpenTK running on OSX"); else Console.WriteLine("OpenTK running on X11"); // IWindowInfo if (Configuration.RunningOnWindows) _WindowInfo = WinWindowsInfoInitializer.Initialize(this.Window.Handle); else if (Configuration.RunningOnMacOS) _WindowInfo = OSXWindowInfoInitializer.Initialize(this.Window.Handle); else _WindowInfo = XWindowInfoInitializer.Initialize(graphicsMode, this.Display.Handle, this.Screen.Number, this.Window.Handle, this.RootWindow.Handle); // GraphicsContext _GraphicsContext = new GraphicsContext(graphicsMode, _WindowInfo, GlVersionMajor, GlVersionMinor, _GraphicsContextFlags); _GraphicsContext.MakeCurrent(_WindowInfo); if (GraphicsContext.ShareContexts) { Interlocked.Increment(ref _GraphicsContextCount); if (!_SharedContextInitialized) { _SharedContextInitialized = true; ((IGraphicsContextInternal)_GraphicsContext).LoadAll(); OnGraphicsContextInitialized(); } } else { ((IGraphicsContextInternal)_GraphicsContext).LoadAll(); OnGraphicsContextInitialized(); } OnInitialized(); } } }