Fixed issue with multiple GLControls becoming invisible. Simplified GLControl, the platform dependent code now resides in GLContext and WindowInfo - GLControl itself is platform independent, just like GameWindow. This allowed to remove IGLControl.cs, WinGLControl.cs, X11GLControl.cs and DummyGLControl.cs

This commit is contained in:
the_fiddler 2007-10-05 06:52:40 +00:00
parent de5df88e8c
commit 5f9a8921b2
6 changed files with 195 additions and 646 deletions

View file

@ -1,6 +1,4 @@
using System; namespace OpenTK
namespace OpenTK
{ {
partial class GLControl partial class GLControl
{ {
@ -32,12 +30,12 @@ namespace OpenTK
{ {
this.SuspendLayout(); this.SuspendLayout();
// //
// GLControl // NewGLControl
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Black; this.BackColor = System.Drawing.Color.Black;
this.Name = "GLControl"; this.Name = "NewGLControl";
this.ResumeLayout(false); this.ResumeLayout(false);
} }

View file

@ -4,115 +4,140 @@
*/ */
#endregion #endregion
#region --- Using Directives ---
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Drawing; using System.Drawing;
using System.Data;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using System.Diagnostics;
using OpenTK.Platform; using OpenTK.Platform;
using OpenTK.OpenGL;
#endregion
namespace OpenTK namespace OpenTK
{ {
// TODO: Document the GLControl class.
/// <summary> /// <summary>
/// Defines a UserControl with opengl rendering capabilities. /// Defines a UserControl with OpenGL rendering capabilities.
/// </summary> /// </summary>
public partial class GLControl : UserControl, IGLControl public partial class GLControl : UserControl
{ {
#region --- Private Fields --- IGLContext context;
IPlatformIdle idle;
private IGLControl glControl; #region --- Constructor ---
#endregion
#region --- Contructors ---
/// <summary>
/// Constructs a new GLControl.
/// </summary>
public GLControl() public GLControl()
:this(new DisplayMode())
{
}
/// <summary>
/// Constructs a new GLControl, with the specified DisplayMode.
/// </summary>
/// <param name="mode">The DisplayMode of the control.</param>
public GLControl(DisplayMode mode)
{ {
InitializeComponent(); InitializeComponent();
this.Visible = false;
this.Fullscreen = mode.Fullscreen;
this.SetStyle(ControlStyles.UserPaint, true); this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
//this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
} }
#endregion #endregion
#region --- Context Setup ---
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// For maximum compatibility we do not set a specific depth for the DisplayMode.
// The driver is free to find the best match.
WindowInfo info = new WindowInfo(this);
if (!this.DesignMode)
{
context = new GLContext(new DisplayMode(), info);
context.CreateContext();
idle = new PlatformIdle(info);
}
else
{
context = new DummyGLContext();
idle = new DummyPlatformIdle();
}
}
protected override void OnHandleDestroyed(EventArgs e)
{
base.OnHandleDestroyed(e);
context.Dispose();
}
#endregion
#region --- Public Properties ---
#region public bool IsIdle
/// <summary>
/// Gets a value indicating whether the current thread contains pending system messages.
/// </summary>
public bool IsIdle
{
get { return idle.IsIdle; }
}
#endregion
#region public IGLContext Context
/// <summary>
/// Gets an interface to the underlying GLContext used by this GLControl.
/// </summary>
public IGLContext Context
{
get { return context; }
}
#endregion
#region public float AspectRatio
/// <summary>
/// Gets the aspect ratio of this GLControl.
/// </summary>
public float AspectRatio
{
get
{
return this.ClientSize.Width / (float)this.ClientSize.Height;
}
}
#endregion
#region public bool VSync
/// <summary>
/// Gets or sets a value indicating whether vsync is active for this GLControl.
/// </summary>
public bool VSync
{
get
{
if (Context != null)
return Context.VSync;
return false;
}
set
{
if (Context != null)
Context.VSync = value;
}
}
#endregion
#endregion
#region --- Public Methods --- #region --- Public Methods ---
#region public void CreateContext()
/// <summary>
/// Forces the creation of the opengl rendering context.
/// </summary>
public void CreateContext()
{
if (glControl != null)
{
throw new ApplicationException("Attempted to create GLControl more than once.");
}
if (this.DesignMode)
{
glControl = new DummyGLControl();
}
else
{
switch (Environment.OSVersion.Platform)
{
case PlatformID.Win32NT:
case PlatformID.Win32Windows:
glControl = new OpenTK.Platform.Windows.WinGLControl(this, new DisplayMode(Width, Height));
break;
case PlatformID.Unix:
case (PlatformID)128: // some older versions of Mono reported 128.
glControl = new OpenTK.Platform.X11.X11GLControl(this);
break;
default:
throw new PlatformNotSupportedException("Your operating system is not currently supported. We are sorry for the inconvenience.");
}
}
this.Visible = true;
this.CreateControl();
GL.LoadAll();
Glu.LoadAll();
this.OnResize(EventArgs.Empty);
}
#endregion
#region public void SwapBuffers() #region public void SwapBuffers()
/// <summary> /// <summary>
/// Swaps the front and back buffers, and presents the rendered scene to the screen. /// Swaps the front and back buffers, presenting the rendered scene to the screen.
/// </summary> /// </summary>
public void SwapBuffers() public void SwapBuffers()
{ {
@ -124,8 +149,8 @@ namespace OpenTK
#region public void MakeCurrent() #region public void MakeCurrent()
/// <summary> /// <summary>
/// Makes the underlying GLContext of this GLControl current. All OpenGL commands issued /// Makes the underlying this GLControl current in the calling thread.
/// from this point are interpreted by this GLContext. /// All OpenGL commands issued are hereafter interpreted by this GLControl.
/// </summary> /// </summary>
public void MakeCurrent() public void MakeCurrent()
{ {
@ -135,147 +160,114 @@ namespace OpenTK
#endregion #endregion
#endregion #endregion
}
#region --- Public Properties --- #region internal interface IPlatformIdle
/// <summary> internal interface IPlatformIdle
/// Gets the AspectRatio of the control this GLContext object {
/// renders to. This is usually used in a call to Glu.Perspective. bool IsIdle { get; }
/// </summary> }
public double AspectRatio
internal class WinPlatformIdle : IPlatformIdle
{
OpenTK.Platform.Windows.MSG msg = new OpenTK.Platform.Windows.MSG();
object get_lock = new object();
IntPtr handle;
public WinPlatformIdle(IWindowInfo info)
{ {
get handle = info.Handle;
{
return this.Width / (double)this.Height;
}
} }
/// <summary> #region IPlatformIdle Members
/// Gets or sets the display mode of the control.
/// </summary> public bool IsIdle
public bool Fullscreen
{ {
get get
{ {
return false; lock (get_lock)
//throw new NotImplementedException(); {
} return !OpenTK.Platform.Windows.Functions.PeekMessage(ref msg, IntPtr.Zero, 0, 0, 0);
set }
{
//throw new NotImplementedException();
} }
} }
#endregion #endregion
}
#region --- IGLControl Members --- internal class X11PlatformIdle : IPlatformIdle
{
object get_lock = new object();
IntPtr display;
#region public bool IsIdle public X11PlatformIdle(IWindowInfo info)
{
display = (info as OpenTK.Platform.X11.WindowInfo).Display;
}
#region IPlatformIdle Members
/// <summary>
/// Gets the idle status of the control.
/// </summary>
public bool IsIdle public bool IsIdle
{ {
get get
{ {
if (glControl == null) lock (get_lock)
this.CreateContext(); {
return OpenTK.Platform.X11.Functions.XPending(display) == 0;
return glControl.IsIdle; }
} }
} }
#endregion #endregion
#region public IGLContext Context
/// <summary>
/// Gets the opengl context associated with this control.
/// </summary>
public IGLContext Context
{
get
{
if (glControl == null)
this.CreateContext();
return glControl.Context;
}
}
#endregion
#region DisplayMode changes
/// <summary>
/// Selects the fullscreen DisplayMode closest to the DisplayMode requested.
/// </summary>
/// <param name="mode">
/// The fullscreen DisplayMode to match, or null to get the current screen DisplayMode.
/// </param>
/// <returns>The DisplayMode closest to the requested one, or null if no DisplayModes are available.</returns>
/// <remarks>
/// <see cref="SetDisplayMode">SetDisplayMode</see>
/// </remarks>
public DisplayMode SelectDisplayMode(DisplayMode mode)
{
throw new NotImplementedException();
//return glWindow.SelectDisplayMode(mode);
}
/// <summary>
/// Selects the fullscreen DisplayMode closest to the DisplayMode requested, accoriding to the specified
/// parameters.
/// </summary>
/// <param name="mode">
/// The fullscreen DisplayMode to match, or null to get the current screen DisplayMode.
/// </param>
/// <param name="options">
/// The DisplayModeMatchOptions flags that indicate how to search for the requested DisplayMode.
/// </param>
/// <returns>
/// The DisplayMode closest to the requested one, or null if no DisplayModes are available or
/// DisplayModeMatchOptions.ExactMatch was passed.
/// </returns>
/// <remarks>
/// <see cref="SetDisplayMode">SetDisplayMode</see>
/// </remarks>
public DisplayMode SelectDisplayMode(DisplayMode mode, DisplayModeMatchOptions options)
{
throw new NotImplementedException();
//return glWindow.SelectDisplayMode(mode, options);
}
/// <summary>
/// Sets the requested DisplayMode.
/// </summary>
/// <param name="mode">
/// The fulscreen DisplayMode to set. Passing null will return the application to windowed
/// mode.
/// </param>
/// <remarks>
/// Use SelectDisplayMode to select one of the available fullscreen modes.
/// <para>
/// If the mode requested is not available, this function will throw a
/// <exception cref="DisplayModeNotAvailable">DisplayModeNotAvailable</exception> exception.
/// </para>
/// <para>
/// Pass null to return to windowed mode. The previous desktop DisplayMode will be automatically reset by this
/// function. This function cannot be used to permanently change the user's desktop DisplayMode.
/// </para>
/// <see cref="SelectDisplayMode(DisplayMode mode)">SelectDisplayMode</see>
/// <seealso cref="DisplayModeNotAvailable">DisplayModeNotAvailable exception</seealso>
/// </remarks>
public void SetDisplayMode(DisplayMode mode)
{
throw new NotImplementedException();
//glWindow.SetDisplayMode(mode);
}
#endregion
#endregion
} }
internal class PlatformIdle : IPlatformIdle
{
IPlatformIdle implementation;
public PlatformIdle(IWindowInfo info)
{
switch (System.Environment.OSVersion.Platform)
{
case PlatformID.Unix:
case (PlatformID)128:
implementation = new X11PlatformIdle(info);
break;
case PlatformID.Win32NT:
case PlatformID.Win32S:
case PlatformID.Win32Windows:
case PlatformID.WinCE:
implementation = new WinPlatformIdle(info);
break;
default:
throw new PlatformNotSupportedException();
}
}
#region IPlatformIdle Members
public bool IsIdle
{
get { return implementation.IsIdle; }
}
#endregion
}
internal class DummyPlatformIdle : IPlatformIdle
{
#region IPlatformIdle Members
public bool IsIdle
{
get { return false; }
}
#endregion
}
#endregion
} }

View file

@ -1,53 +0,0 @@
#region --- License ---
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
* See license.txt for license info
*/
#endregion
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenTK.Platform
{
/// <summary>
/// An IGLControl implementation to be used inside the Visual Studio designer.
/// </summary>
internal sealed class DummyGLControl : IGLControl
{
bool fullscreen;
IGLContext glContext = new DummyGLContext();
#region --- IGLControl Members ---
public bool IsIdle
{
get
{
return false;
}
}
public bool Fullscreen
{
get
{
return fullscreen;
}
set
{
fullscreen = value;
}
}
public IGLContext Context
{
get
{
return glContext;
}
}
#endregion
}
}

View file

@ -1,21 +0,0 @@
#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.OpenGL;
namespace OpenTK.Platform
{
public interface IGLControl
{
bool IsIdle { get; }
bool Fullscreen { get; set; }
IGLContext Context { get; }
}
}

View file

@ -1,144 +0,0 @@
#region --- License ---
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
* Contributions from Erik Ylvisaker
* See license.txt for license info
*/
#endregion
#region --- Using directives ---
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
#endregion
namespace OpenTK.Platform.Windows
{
sealed class WinGLControl : IGLControl, IDisposable
{
private WinGLContext glContext;
private bool fullscreen;
private ResizeEventArgs resizeEventArgs = new ResizeEventArgs();
private DisplayMode mode;
private bool disposed;
private MSG msg; // Used only by the IsIdle event.
#region --- Constructors ---
public WinGLControl(UserControl c, DisplayMode mode)
{
this.mode = mode;
c.HandleCreated += new EventHandler(c_HandleCreated);
c.HandleDestroyed += new EventHandler(c_HandleDestroyed);
}
#endregion
void c_HandleCreated(object sender, EventArgs e)
{
Debug.Print("GLControl handle created, creating WinGLContext.");
Debug.Indent();
try
{
if (glContext != null)
glContext.Dispose();
glContext = new WinGLContext(mode, new WindowInfo(sender as Control));
glContext.CreateContext();
glContext.MakeCurrent();
}
catch (ApplicationException expt)
{
Debug.Print(expt.ToString());
throw;
}
finally
{
Debug.Unindent();
}
}
void c_HandleDestroyed(object sender, EventArgs e)
{
glContext.Dispose();
}
#region --- IGLControl members ---
#region public bool IsIdle
public bool IsIdle
{
get
{
return !Functions.PeekMessage(ref msg, IntPtr.Zero, 0, 0, 0);
}
}
#endregion
#region public bool Fullscreen
public bool Fullscreen
{
get
{
return fullscreen;
}
set
{
fullscreen = false;
//throw new NotImplementedException();
}
}
#endregion
#region public IGLContext Context
public IGLContext Context
{
get { return glContext; }
}
#endregion
#endregion
#region --- IDisposable Members ---
public void Dispose()
{
this.Dispose(true);
//GC.SuppressFinalize(this);
}
private void Dispose(bool calledManually)
{
if (!disposed)
{
// Clean unmanaged resources here:
if (calledManually)
{
// Safe to clean managed resources
glContext.Dispose();
}
disposed = true;
}
}
/*
~WinGLControl()
{
Dispose(false);
}
*/
#endregion
}
}

View file

@ -1,223 +0,0 @@
#region --- License ---
/* Copyright (c) 2007 Stefanos Apostolopoulos
* See license.txt for license info
*/
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;
namespace OpenTK.Platform.X11
{
sealed class X11GLControl : IGLControl
{
WindowInfo info = new WindowInfo();
//DisplayMode mode;
private Type xplatui;
IGLContext glContext;
private bool disposed;
private bool fullscreen;
#region --- Contructors ---
#region public X11GLControl(UserControl c)
public X11GLControl(UserControl c)
{
Debug.WriteLine("Creating opengl control (X11GLControl driver)");
Debug.Indent();
Utilities.ThrowOnX11Error = true;
if (c == null/* || c.TopLevelControl == null*/)
{
throw new ArgumentException("UserControl c may not be null.");
}
c.HandleCreated += new EventHandler(c_HandleCreated);
c.HandleDestroyed += new EventHandler(c_HandleDestroyed);
xplatui = Type.GetType("System.Windows.Forms.XplatUIX11, System.Windows.Forms");
if (xplatui == null)
throw new ApplicationException("Could not get System.Windows.Forms.XplatUIX11 through reflection. Unsupported platform or Mono runtime version, aborting.");
info.Display = (IntPtr)xplatui.GetField("DisplayHandle",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(null);
info.RootWindow = (IntPtr)xplatui.GetField("RootWindow",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(null);
info.Screen = (int)xplatui.GetField("ScreenNo",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(null);
Debug.Print("Data read from System.Windows.Forms.XplatUIX11: {0}", info.ToString());
//this.mode = mode;
glContext = new GLContext(null, info);
//glContext.PrepareContext(info);
info.VisualInfo = (glContext.Info as X11.WindowInfo).VisualInfo;
Debug.Print("Setting XplatUIX11.CustomVisual");
xplatui.GetField("CustomVisual", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)
.SetValue(null, info.VisualInfo.visual);
Debug.Print("Setting XplatUIX11.CustomColormap");
xplatui.GetField("CustomColormap", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)
.SetValue(null, API.CreateColormap(info.Display, info.RootWindow, info.VisualInfo.visual, 0));
Debug.Unindent();
}
#endregion
#region void c_HandleCreated(object sender, EventArgs e)
void c_HandleCreated(object sender, EventArgs e)
{
UserControl c = (sender as UserControl);
Debug.Print("GLControl handle created, creating X11GLContext.");
Debug.Indent();
try
{
(glContext.Info as X11.WindowInfo).Handle = info.Handle = (sender as UserControl).Handle;
glContext.CreateContext(true, null);
glContext.MakeCurrent();
}
catch (ApplicationException expt)
{
Debug.Print(expt.ToString());
throw;
}
finally
{
Debug.Unindent();
}
}
#endregion
#region void c_HandleDestroyed(object sender, EventArgs e)
void c_HandleDestroyed(object sender, EventArgs e)
{
Debug.Print("X11GLControl handle destroyed, disposing X11GLContext.");
glContext.Dispose();
}
#endregion
#region private IntPtr FindColormap()
/// <summary>
/// Finds a colormap suitable for use with the GLControl.
/// </summary>
/// <returns>A pointer to the colormap</returns>
/// <remarks>
/// If the visual of the GLControl matches the default visual, the function returns
/// the default colormap (i.e. the colormap of the root window). Otherwise, it creates
/// a new, private colormap.
/// </remarks>
private IntPtr FindColormap()
{
if (info.VisualInfo.visual == Functions.XDefaultVisual(info.Display, info.Screen))
{
return Functions.XDefaultColormap(info.Display, info.Screen);
}
return API.CreateColormap(info.Display, info.RootWindow,
(glContext.Info as X11.WindowInfo).VisualInfo.visual, 0/*AllocNone*/);
}
#endregion
#endregion
#region --- IGLControl Members ---
public event CreateEvent Create;
private void OnCreate(object sender, EventArgs e)
{
if (this.Create != null)
this.Create(sender, e);
}
#region public bool IsIdle
public bool IsIdle
{
get
{
return API.Pending(info.Display) == 0;
}
}
#endregion
#region public bool Fullscreen
public bool Fullscreen
{
get
{
return fullscreen;
}
set
{
//throw new Exception("The method or operation is not implemented.");
fullscreen = false;
}
}
#endregion
#region public IGLContext Context
public IGLContext Context
{
get
{
return glContext;
}
}
#endregion
#endregion
#region --- IDisposable Members ---
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool manuallyCalled)
{
if (!disposed)
{
// Clean unmanaged resources:
// Nothing
if (manuallyCalled)
{
// Clean managed resources, too
glContext.Dispose();
}
}
disposed = true;
}
~X11GLControl()
{
this.Dispose(false);
}
#endregion
}
}