#region --- License --- /* Copyright (c) 2006, 2007 Stefanos Apostolopoulos * See license.txt for license info */ #endregion using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Text; using System.Windows.Forms; using OpenTK.Platform; namespace OpenTK { /// /// Defines a UserControl with OpenGL rendering capabilities. /// public partial class GLControl : UserControl { IGLContext context; IPlatformIdle idle; DisplayMode display_mode; #region --- Constructor --- /// /// Constructs a new GLControl. /// public GLControl() : this(null) { } /// /// Constructs a new GLControl with the specified DisplayMode. /// /// public GLControl(DisplayMode mode) { InitializeComponent(); this.SetStyle(ControlStyles.Opaque, true); this.SetStyle(ControlStyles.UserPaint, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); DoubleBuffered = false; this.display_mode = mode; this.CreateControl(); } #endregion #region --- Context Setup --- protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); this.CreateContext(); } protected override void OnHandleDestroyed(EventArgs e) { base.OnHandleDestroyed(e); this.DestroyContext(); } #endregion #region --- Public Properties --- #region public bool IsIdle /// /// Gets a value indicating whether the current thread contains pending system messages. /// [Browsable(false)] public bool IsIdle { get { return idle.IsIdle; } } #endregion #region public IGLContext Context /// /// Gets an interface to the underlying GLContext used by this GLControl. /// [Browsable(false)] public IGLContext Context { get { return context; } private set { context = value; } } #endregion #region public float AspectRatio /// /// Gets the aspect ratio of this GLControl. /// [Description("The aspect ratio of the client area of this GLControl.")] public float AspectRatio { get { return this.ClientSize.Width / (float)this.ClientSize.Height; } } #endregion #region public bool VSync /// /// Gets or sets a value indicating whether vsync is active for this GLControl. /// [Description("Indicates whether GLControl updates are synced to the monitor's refresh.")] public bool VSync { get { if (Context != null) return Context.VSync; return false; } set { if (Context != null) Context.VSync = value; } } #endregion #region public DisplayMode Mode /// /// Gets the DisplayMode of the GLContext attached to this GLControl. /// /// /// You cannot change the DisplayMode of an existing GLContext. /// public DisplayMode Mode { get { return Context.Mode; } } #endregion #endregion #region --- Public Methods --- #region public void SwapBuffers() /// /// Swaps the front and back buffers, presenting the rendered scene to the screen. /// public void SwapBuffers() { Context.SwapBuffers(); } #endregion #region public void MakeCurrent() /// /// Makes the underlying this GLControl current in the calling thread. /// All OpenGL commands issued are hereafter interpreted by this GLControl. /// public void MakeCurrent() { Context.MakeCurrent(); } #endregion #region public void CreateContext() /// /// Creates a GLContext and attaches it to this GLControl. /// public void CreateContext() { if (display_mode == null) display_mode = new DisplayMode(); WindowInfo info = new WindowInfo(this); if (!this.DesignMode) { // Mono's implementation of Windows.Forms on X11 does not allow the context to // have a different colordepth from the parent. To combat this, we do not set a // specific depth for the DisplayMode - we let the driver select one instead. display_mode.Color = new ColorMode(0); context = new GLContext(display_mode, info); context.CreateContext(true, null); idle = new PlatformIdle(info); } else { context = new DummyGLContext(display_mode); idle = new DummyPlatformIdle(); } } #endregion #region public void DestroyContext() /// /// Destroys the GLContext attached to this GLControl. /// /// Occurs when no GLContext is attached. public void DestroyContext() { Context.Dispose(); Context = null; } #endregion #endregion } #region internal interface IPlatformIdle internal interface IPlatformIdle { bool IsIdle { get; } } internal class WinPlatformIdle : IPlatformIdle { OpenTK.Platform.Windows.MSG msg = new OpenTK.Platform.Windows.MSG(); object get_lock = new object(); //IntPtr handle; public WinPlatformIdle(WindowInfo info) { //handle = info.Handle; } #region IPlatformIdle Members public bool IsIdle { get { lock (get_lock) { return !OpenTK.Platform.Windows.Functions.PeekMessage(ref msg, IntPtr.Zero, 0, 0, 0); } } } #endregion } internal class X11PlatformIdle : IPlatformIdle { object get_lock = new object(); IntPtr display; public X11PlatformIdle(WindowInfo info) { display = ((OpenTK.Platform.X11.WindowInfo)info).Display; } #region IPlatformIdle Members public bool IsIdle { get { lock (get_lock) { return OpenTK.Platform.X11.Functions.XPending(display) == 0; } } } #endregion } internal class PlatformIdle : IPlatformIdle { IPlatformIdle implementation; public PlatformIdle(WindowInfo 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 }