37c40f16eb
Update X11 stack to use System.Windows.Forms.XPlatUI for its Display, Screen and RootWindow. Fixed mode setting for X11GLControl. Fixed X11 shutdown (was generating X11 errors). Added DeviceContext getter to WinWindowInfo. Made IWindowInfo disposable. Added documentation to many public methods. Worked around a Mono 1.2.4 bug with Handle creation on Windows.Forms.Control. Updated GL.BuildExtensionList to correctly parse GL_VERSION when in indirect rendering mode. Fixed crash errors in X11GLContext.CreateContext and X11GraphicsMode. Added a ref overload to Glx.ChooseVisual() IGraphicsContext.MakeCurrent now takes an IWindowInfo parameter. This allows the user to change to window is context is bound to (untested). Renamed XyzWindowInfo.Handle to XyzWindowInfo.WindowHandle.
426 lines
13 KiB
C#
426 lines
13 KiB
C#
#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.Runtime.InteropServices;
|
|
using System.Diagnostics;
|
|
|
|
using OpenTK.Graphics.OpenGL;
|
|
using OpenTK.Graphics;
|
|
|
|
#endregion
|
|
|
|
namespace OpenTK.Platform.Windows
|
|
{
|
|
/// <summary>
|
|
/// Provides methods to create and control an opengl context on the Windows platform.
|
|
/// This class supports OpenTK, and is not intended for use by OpenTK programs.
|
|
/// </summary>
|
|
internal sealed class WinGLContext : IGraphicsContext, IGraphicsContextInternal//, IGLContextCreationHack
|
|
{
|
|
//IntPtr deviceContext;
|
|
WinWindowInfo currentWindow;
|
|
ContextHandle renderContext;
|
|
static IntPtr opengl32Handle;
|
|
const string opengl32Name = "OPENGL32.DLL";
|
|
//WinWindowInfo windowInfo = new WinWindowInfo();
|
|
|
|
GraphicsMode format;
|
|
//DisplayMode mode = null;
|
|
bool vsync_supported;
|
|
|
|
bool disposed;
|
|
|
|
#region --- Contructors ---
|
|
|
|
static WinGLContext()
|
|
{
|
|
// Set the GetCurrentContext implementation.
|
|
// TODO: Does this belong here?
|
|
if (GraphicsContext.GetCurrentContext == null)
|
|
GraphicsContext.GetCurrentContext = WinGLContext.GetCurrentContext;
|
|
|
|
// Dynamically load the OpenGL32.dll in order to use the extension loading capabilities of Wgl.
|
|
if (opengl32Handle == IntPtr.Zero)
|
|
{
|
|
opengl32Handle = Functions.LoadLibrary(opengl32Name);
|
|
if (opengl32Handle == IntPtr.Zero)
|
|
throw new ApplicationException(String.Format("LoadLibrary(\"{0}\") call failed with code {1}",
|
|
opengl32Name, Marshal.GetLastWin32Error()));
|
|
Debug.WriteLine(String.Format("Loaded opengl32.dll: {0}", opengl32Handle));
|
|
}
|
|
}
|
|
|
|
public WinGLContext(GraphicsMode format, IWindowInfo window, IGraphicsContext sharedContext)
|
|
{
|
|
if (window == null) throw new ArgumentNullException("window", "Must point to a valid window.");
|
|
|
|
currentWindow = (WinWindowInfo)window;
|
|
if (currentWindow.WindowHandle == IntPtr.Zero) throw new ArgumentException("window", "Must be a valid window.");
|
|
|
|
Debug.Print("OpenGL will be bound to handle: {0}", currentWindow.WindowHandle);
|
|
|
|
Debug.Print("Setting pixel format... ");
|
|
this.SetGraphicsModePFD(format, (WinWindowInfo)window);
|
|
|
|
// Do not rely on OpenTK.Platform.Windows.Wgl - the context is not ready yet,
|
|
// and Wgl extensions will fail to load.
|
|
Debug.Write("Creating render context... ");
|
|
renderContext = new ContextHandle(Wgl.Imports.CreateContext(currentWindow.DeviceContext));
|
|
if (renderContext == IntPtr.Zero)
|
|
renderContext = new ContextHandle(Wgl.Imports.CreateContext(currentWindow.DeviceContext));
|
|
if (renderContext == IntPtr.Zero)
|
|
throw new GraphicsContextException(String.Format("Context creation failed. Wgl.CreateContext() error: {0}.",
|
|
Marshal.GetLastWin32Error()));
|
|
|
|
Debug.WriteLine(String.Format("done! (id: {0})", renderContext));
|
|
|
|
if (sharedContext != null)
|
|
{
|
|
Debug.Print("Sharing state with context {0}", sharedContext.ToString());
|
|
Wgl.Imports.ShareLists(renderContext, (sharedContext as IGraphicsContextInternal).Context);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region --- IGraphicsContext Members ---
|
|
|
|
#region public void CreateContext()
|
|
|
|
public void CreateContext()
|
|
{
|
|
throw new NotSupportedException();
|
|
this.CreateContext(true, null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public void CreateContext(bool direct)
|
|
|
|
public void CreateContext(bool direct)
|
|
{
|
|
throw new NotSupportedException();
|
|
this.CreateContext(direct, null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public void CreateContext(bool direct, IGraphicsContext source)
|
|
|
|
public void CreateContext(bool direct, IGraphicsContext source)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public void SwapBuffers()
|
|
|
|
public void SwapBuffers()
|
|
{
|
|
|
|
Functions.SwapBuffers(currentWindow.DeviceContext);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public void MakeCurrent(IWindowInfo window)
|
|
|
|
public void MakeCurrent(IWindowInfo window)
|
|
{
|
|
bool success;
|
|
|
|
if (window != null)
|
|
{
|
|
if (((WinWindowInfo)window).WindowHandle == IntPtr.Zero)
|
|
throw new ArgumentException("window", "Must point to a valid window.");
|
|
|
|
currentWindow = (WinWindowInfo)window;
|
|
success = Wgl.Imports.MakeCurrent(((WinWindowInfo)window).DeviceContext, this.renderContext);
|
|
}
|
|
else
|
|
success = Wgl.Imports.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
|
|
|
|
if (!success)
|
|
throw new GraphicsContextException(String.Format(
|
|
"Failed to make context {0} current. Error: {1}", this, Marshal.GetLastWin32Error()));
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public bool IsCurrent
|
|
|
|
public bool IsCurrent
|
|
{
|
|
get { return Wgl.GetCurrentContext() == this.renderContext; }
|
|
/*
|
|
set
|
|
{
|
|
if (value)
|
|
Wgl.MakeCurrent(this.deviceContext, this.renderContext);
|
|
else
|
|
Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public bool VSync
|
|
|
|
/// <summary>
|
|
/// Gets or sets a System.Boolean indicating whether SwapBuffer calls are synced to the screen refresh rate.
|
|
/// </summary>
|
|
public bool VSync
|
|
{
|
|
get
|
|
{
|
|
return vsync_supported && Wgl.Ext.GetSwapInterval() != 0;
|
|
}
|
|
set
|
|
{
|
|
if (vsync_supported)
|
|
Wgl.Ext.SwapInterval(value ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public event DestroyEvent<IGraphicsContext> Destroy;
|
|
|
|
#endregion
|
|
|
|
#region --- IGLContextInternal Members ---
|
|
|
|
#region void LoadAll()
|
|
|
|
void IGraphicsContextInternal.LoadAll()
|
|
{
|
|
Wgl.LoadAll();
|
|
GL.LoadAll();
|
|
Glu.LoadAll();
|
|
|
|
vsync_supported = Wgl.Arb.SupportsExtension(this, "WGL_EXT_swap_control") &&
|
|
Wgl.Load("wglGetSwapIntervalEXT") && Wgl.Load("wglSwapIntervalEXT");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ContextHandle IGLContextInternal.Context
|
|
|
|
ContextHandle IGraphicsContextInternal.Context
|
|
{
|
|
get { return renderContext; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IWindowInfo IGLContextInternal.Info
|
|
/*
|
|
IWindowInfo IGraphicsContextInternal.Info
|
|
{
|
|
get { return (IWindowInfo)windowInfo; }
|
|
}
|
|
*/
|
|
#endregion
|
|
|
|
#region GraphicsMode IGLContextInternal.GraphicsMode
|
|
|
|
GraphicsMode IGraphicsContextInternal.GraphicsMode
|
|
{
|
|
get { return format; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public IntPtr GetAddress(string function_string)
|
|
|
|
public IntPtr GetAddress(string function_string)
|
|
{
|
|
return Wgl.Imports.GetProcAddress(function_string);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public DisplayMode[] GetDisplayModes()
|
|
|
|
public IEnumerable<DisplayMode> GetDisplayModes()
|
|
{
|
|
throw new NotSupportedException("See OpenTK.Graphics.DisplayDevice.AvailableModes instead.");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region void IGLContextInternal.RegisterForDisposal(IDisposable resource)
|
|
|
|
void IGraphicsContextInternal.RegisterForDisposal(IDisposable resource)
|
|
{
|
|
throw new NotSupportedException("Use OpenTK.GraphicsContext instead.");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region void IGLContextInternal.DisposeResources()
|
|
|
|
void IGraphicsContextInternal.DisposeResources()
|
|
{
|
|
throw new NotSupportedException("Use OpenTK.GraphicsContext instead.");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region --- Private Methods ---
|
|
|
|
#region void SetGraphicsModePFD(GraphicsMode format, WinWindowInfo window)
|
|
|
|
void SetGraphicsModePFD(GraphicsMode mode, WinWindowInfo window)
|
|
{
|
|
if (mode.Index == IntPtr.Zero) throw new ArgumentException(
|
|
"mode", "The Index (pixel format) of the GraphicsMode is not set.");
|
|
if (window == null) throw new ArgumentNullException("window", "Must point to a valid window.");
|
|
|
|
PixelFormatDescriptor pfd = new PixelFormatDescriptor();
|
|
Functions.DescribePixelFormat(window.DeviceContext, (int)mode.Index,
|
|
API.PixelFormatDescriptorSize, ref pfd);
|
|
Debug.WriteLine(mode.Index.ToString());
|
|
if (!Functions.SetPixelFormat(window.DeviceContext, (int)mode.Index, ref pfd))
|
|
throw new GraphicsContextException(String.Format(
|
|
"Requested GraphicsMode not available. SetPixelFormat error: {0}", Marshal.GetLastWin32Error()));
|
|
}
|
|
#endregion
|
|
|
|
#region void SetGraphicsModeARB(GraphicsMode format, IWindowInfo window)
|
|
|
|
void SetGraphicsModeARB(GraphicsMode format, IWindowInfo window)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region --- Internal Methods ---
|
|
|
|
#region internal IntPtr DeviceContext
|
|
|
|
internal IntPtr DeviceContext
|
|
{
|
|
get
|
|
{
|
|
if (currentWindow != null)
|
|
return currentWindow.DeviceContext;
|
|
return IntPtr.Zero;
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region static ContextHandle GetCurrentContext()
|
|
|
|
static ContextHandle GetCurrentContext()
|
|
{
|
|
return Wgl.GetCurrentContext();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region --- Overrides ---
|
|
|
|
/// <summary>Returns a System.String describing this OpenGL context.</summary>
|
|
/// <returns>A System.String describing this OpenGL context.</returns>
|
|
public override string ToString()
|
|
{
|
|
return (this as IGraphicsContextInternal).Context.ToString();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region --- IDisposable Members ---
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
private void Dispose(bool calledManually)
|
|
{
|
|
if (!disposed)
|
|
{
|
|
DestroyContext();
|
|
|
|
if (calledManually)
|
|
{
|
|
// Safe to clean managed resources
|
|
}
|
|
disposed = true;
|
|
}
|
|
}
|
|
|
|
~WinGLContext()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
#region private void DestroyContext()
|
|
|
|
private void DestroyContext()
|
|
{
|
|
if (Destroy != null)
|
|
Destroy(this, EventArgs.Empty);
|
|
|
|
if (renderContext != IntPtr.Zero)
|
|
{
|
|
Wgl.Imports.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
|
|
if (!Wgl.Imports.DeleteContext(renderContext))
|
|
{
|
|
//throw new ApplicationException("Could not destroy the OpenGL render context. Error: " + Marshal.GetLastWin32Error());
|
|
//Debug.Print("Could not destroy the OpenGL render context. Error: {0}", Marshal.GetLastWin32Error());
|
|
}
|
|
renderContext = null;
|
|
}
|
|
|
|
//if (deviceContext != IntPtr.Zero)
|
|
//{
|
|
// if (!Functions.ReleaseDC(this.windowInfo.Handle, deviceContext))
|
|
// {
|
|
// //throw new ApplicationException("Could not release device context. Error: " + Marshal.GetLastWin32Error());
|
|
// //Debug.Print("Could not destroy the device context. Error: {0}", Marshal.GetLastWin32Error());
|
|
// }
|
|
//}
|
|
|
|
/*
|
|
if (opengl32Handle != IntPtr.Zero)
|
|
{
|
|
if (!Functions.FreeLibrary(opengl32Handle))
|
|
{
|
|
//throw new ApplicationException("FreeLibray call failed ('opengl32.dll'), Error: " + Marshal.GetLastWin32Error());
|
|
//Debug.Print("Could not release {0}. Error: {1}", opengl32Name, Marshal.GetLastWin32Error());
|
|
}
|
|
opengl32Handle = IntPtr.Zero;
|
|
}
|
|
*/
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
}
|