using System; using System.Threading; using System.ComponentModel; using Gdk; using OpenTK.Graphics; using OpenTK.Platform; using Gtk; using OpenTK.OSX; using OpenTK.Platform.X11; 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. /// [CLSCompliant(false)] [ToolboxItem(true)] public class GLWidget: GLArea { private static int _GraphicsContextCount; private static bool _SharedContextInitialized = false; private IGraphicsContext _GraphicsContext; private IWindowInfo _WindowInfo; private bool _Initialized = false; /// /// The set for this widget. /// public GraphicsContextFlags GraphicsContextFlags { get; set; } /// /// 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; GraphicsContextFlags = graphicsContextFlags; SetRequiredVersion(glVersionMajor, glVersionMinor); if (graphicsMode.Depth > 0) { HasDepthBuffer = true; } if (graphicsMode.Stencil > 0) { HasStencilBuffer = true; } if (graphicsMode.ColorFormat.Alpha > 0) { HasAlpha = true; } } /// /// 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(); } } /// /// 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 is being disposed. /// public event EventHandler ShuttingDown; /// /// Invokes the event. /// protected virtual void OnShuttingDown() { if (ShuttingDown != null) { ShuttingDown(this, EventArgs.Empty); } } #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(); } #if GTK3 var result = base.OnDrawn(cr); #else bool result = base.OnExposeEvent(evnt); #endif #if !GTK3 evnt.Window.Display.Sync(); // Add Sync call to fix resize rendering problem (Jay L. T. Cornwall) - How does this affect VSync? #endif 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 (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"); } #if GTK3 IntPtr widgetWindowHandle = this.Window.Handle; #else IntPtr widgetWindowHandle = this.GdkWindow.Handle; #endif // IWindowInfo if (Configuration.RunningOnWindows) { _WindowInfo = WinWindowsInfoInitializer.Initialize(widgetWindowHandle); } else if (Configuration.RunningOnMacOS) { _WindowInfo = OSXWindowInfoInitializer.Initialize(widgetWindowHandle); } else { _WindowInfo = XWindowInfoInitializer.Initialize(this.Display.Handle, this.Screen.Number, widgetWindowHandle, this.Screen.RootWindow.Handle); } // Make the GDK GL context current MakeCurrent(); // Create an OpenTK graphics context using the GdkGLContext as a foreign context // Since the GDK context is already created and has been made current, we can retrieve its handle. var gdkContextHandle = Factory.Default.CreateGetCurrentGraphicsContext()(); GetRequiredVersion(out int glVersionMajor, out int glVersionMinor); _GraphicsContext = new GraphicsContext(gdkContextHandle, _WindowInfo, null, glVersionMajor, glVersionMinor, GraphicsContextFlags); MakeCurrent(); if (GraphicsContext.ShareContexts) { Interlocked.Increment(ref _GraphicsContextCount); if (!_SharedContextInitialized) { _SharedContextInitialized = true; ((IGraphicsContextInternal)_GraphicsContext).LoadAll(); OnGraphicsContextInitialized(); } } else { ((IGraphicsContextInternal)_GraphicsContext).LoadAll(); OnGraphicsContextInitialized(); } OnInitialized(); } } }