2007-07-23 02:15:18 +02:00
#region - - - License - - -
/ * Copyright ( c ) 2006 , 2007 Stefanos Apostolopoulos
* Contributions from Erik Ylvisaker
* See license . txt for license info
* /
#endregion
2007-09-09 17:10:21 +02:00
#region - - - Using Directives - - -
2007-07-23 02:15:18 +02:00
using System ;
using System.Collections.Generic ;
using System.Text ;
using System.Runtime.InteropServices ;
2007-09-09 17:10:21 +02:00
using System.Diagnostics ;
2007-07-23 02:15:18 +02:00
using OpenTK.OpenGL ;
2007-09-09 17:10:21 +02:00
#endregion
2007-07-23 02:15:18 +02:00
namespace OpenTK.Platform.Windows
{
2007-09-09 13:52:09 +02:00
/// <summary>
/// Provides methods to create and control an opengl context on the Windows platform.
2007-12-09 19:15:51 +01:00
/// This class supports OpenTK, and is not intended for use by OpenTK programs.
2007-09-09 13:52:09 +02:00
/// </summary>
2008-01-11 21:24:48 +01:00
internal sealed class WinGLContext : IGLContext , IGLContextInternal , IGLContextCreationHack
2007-07-23 02:15:18 +02:00
{
private IntPtr deviceContext ;
2008-01-11 21:24:48 +01:00
private ContextHandle renderContext ;
2007-07-23 02:15:18 +02:00
static private IntPtr opengl32Handle ;
2007-09-09 17:10:21 +02:00
private const string opengl32Name = "OPENGL32.DLL" ;
2008-01-11 21:24:48 +01:00
private WindowInfo windowInfo = new WindowInfo ( ) ;
2007-07-23 02:15:18 +02:00
2008-01-20 20:00:03 +01:00
private DisplayMode mode = null ;
2007-09-29 17:24:55 +02:00
private bool vsync_supported ;
2007-08-20 14:25:48 +02:00
2007-07-23 02:15:18 +02:00
private bool disposed ;
#region - - - Contructors - - -
2008-01-11 21:24:48 +01:00
/// <summary>
/// Constructs a new WinGLContext object.
/// </summary>
public WinGLContext ( )
2007-09-09 13:52:09 +02:00
{
2008-01-11 21:24:48 +01:00
if ( GLContext . GetCurrentContext = = null )
GLContext . GetCurrentContext = this . GetCurrentContext ;
2007-08-20 14:25:48 +02:00
}
2007-07-23 02:15:18 +02:00
2007-09-09 17:10:21 +02:00
#endregion
2007-12-09 19:15:51 +01:00
2007-09-09 17:10:21 +02:00
#region - - - IGLContext Members - - -
2007-08-20 14:25:48 +02:00
#region public void CreateContext ( )
public void CreateContext ( )
2007-09-09 17:10:21 +02:00
{
this . CreateContext ( true , null ) ;
}
#endregion
#region public void CreateContext ( bool direct )
public void CreateContext ( bool direct )
{
this . CreateContext ( direct , null ) ;
}
#endregion
#region public void CreateContext ( bool direct , IGLContext source )
public void CreateContext ( bool direct , IGLContext source )
2007-08-20 14:25:48 +02:00
{
2008-01-11 21:24:48 +01:00
Debug . WriteLine ( String . Format ( "OpenGL context is bound to handle: {0}" , this . windowInfo . Handle ) ) ;
2007-09-09 13:52:09 +02:00
2007-08-20 14:25:48 +02:00
Debug . Write ( "Creating render context... " ) ;
// Do not rely on OpenTK.Platform.Windows.Wgl - the context is not ready yet,
// and Wgl extensions will fail to load.
2008-01-11 21:24:48 +01:00
renderContext = new ContextHandle ( Wgl . Imports . CreateContext ( deviceContext ) ) ;
2007-12-09 19:15:51 +01:00
if ( renderContext = = IntPtr . Zero )
2007-09-09 17:10:21 +02:00
throw new ApplicationException ( "Could not create OpenGL render context (Wgl.CreateContext() return 0)." ) ;
2007-12-09 19:15:51 +01:00
Debug . WriteLine ( String . Format ( "done! (id: {0})" , renderContext ) ) ;
2007-08-20 14:25:48 +02:00
Wgl . Imports . MakeCurrent ( deviceContext , renderContext ) ;
Wgl . LoadAll ( ) ;
2007-10-15 13:14:41 +02:00
GL . LoadAll ( ) ;
Glu . LoadAll ( ) ;
2007-09-09 17:10:21 +02:00
2008-01-23 01:19:22 +01:00
vsync_supported = Wgl . Arb . SupportsExtension ( this , "WGL_EXT_swap_control" ) & &
2007-09-29 17:24:55 +02:00
Wgl . Load ( "wglGetSwapIntervalEXT" ) & & Wgl . Load ( "wglSwapIntervalEXT" ) ;
2007-09-09 17:10:21 +02:00
if ( source ! = null )
{
2008-01-11 21:24:48 +01:00
Debug . Print ( "Sharing state with context {0}" , ( source as IGLContextInternal ) . Context ) ;
Wgl . Imports . ShareLists ( renderContext , ( source as IGLContextInternal ) . Context ) ;
2007-09-09 17:10:21 +02:00
}
2007-07-23 02:15:18 +02:00
}
2007-08-20 14:25:48 +02:00
#endregion
2007-07-23 02:15:18 +02:00
#region public void SwapBuffers ( )
public void SwapBuffers ( )
{
2007-09-26 13:55:24 +02:00
Functions . SwapBuffers ( deviceContext ) ;
2007-07-23 02:15:18 +02:00
}
#endregion
#region public void MakeCurrent ( )
public void MakeCurrent ( )
{
2007-09-03 23:47:34 +02:00
if ( ! Wgl . Imports . MakeCurrent ( deviceContext , renderContext ) )
{
Debug . Print ( "WinGLContext.MakeCurrent() call failed. Error: {0}" , Marshal . GetLastWin32Error ( ) ) ;
}
2007-07-23 02:15:18 +02:00
}
#endregion
2007-12-09 19:15:51 +01:00
#region public bool IsCurrent
public bool IsCurrent
{
get { return Wgl . GetCurrentContext ( ) = = this . renderContext ; }
}
#endregion
2008-01-11 21:24:48 +01:00
#region public ContextHandle GetCurrentContext ( )
2007-12-09 19:15:51 +01:00
2008-01-11 21:24:48 +01:00
public ContextHandle GetCurrentContext ( )
2007-12-09 19:15:51 +01:00
{
return Wgl . GetCurrentContext ( ) ;
}
#endregion
2008-01-11 21:24:48 +01:00
#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
2007-12-09 19:15:51 +01:00
public event DestroyEvent < IGLContext > Destroy ;
2008-01-11 21:24:48 +01:00
#endregion
#region - - - IGLContextInternal Members - - -
#region public IntPtr Context
ContextHandle IGLContextInternal . Context
2007-12-09 19:15:51 +01:00
{
2008-01-11 21:24:48 +01:00
get { return renderContext ; }
2007-12-09 19:15:51 +01:00
}
2008-01-11 21:24:48 +01:00
#endregion
#region public IWindowInfo Info
IWindowInfo IGLContextInternal . Info
2007-12-09 19:15:51 +01:00
{
2008-01-11 21:24:48 +01:00
get { return windowInfo ; }
}
#endregion
#region public DisplayMode Mode
2008-01-20 20:00:03 +01:00
[Obsolete]
2008-01-11 21:24:48 +01:00
DisplayMode IGLContextInternal . Mode
{
get { return new DisplayMode ( mode ) ; }
}
#endregion
#region public IntPtr GetAddress ( string function_string )
public IntPtr GetAddress ( string function_string )
{
return Wgl . Imports . GetProcAddress ( function_string ) ;
2007-12-09 19:15:51 +01:00
}
2008-01-11 21:24:48 +01:00
#endregion
2007-07-23 02:15:18 +02:00
#region public DisplayMode [ ] GetDisplayModes ( )
public IEnumerable < DisplayMode > GetDisplayModes ( )
{
2008-01-24 10:14:24 +01:00
throw new NotSupportedException ( "See OpenTK.Graphics.DisplayDevice.AvailableModes instead." ) ;
2007-07-23 02:15:18 +02:00
}
#endregion
2008-01-20 20:29:42 +01:00
#region void IGLContextInternal . RegisterForDisposal ( IDisposable resource )
2008-01-11 21:24:48 +01:00
void IGLContextInternal . RegisterForDisposal ( IDisposable resource )
2007-09-29 17:24:55 +02:00
{
2008-01-20 20:29:42 +01:00
throw new NotSupportedException ( "Use OpenTK.GLContext instead." ) ;
2008-01-11 21:24:48 +01:00
}
2008-01-20 20:29:42 +01:00
#endregion
#region void IGLContextInternal . DisposeResources ( )
2008-01-11 21:24:48 +01:00
void IGLContextInternal . DisposeResources ( )
{
2008-01-20 20:29:42 +01:00
throw new NotSupportedException ( "Use OpenTK.GLContext instead." ) ;
2008-01-11 21:24:48 +01:00
}
2008-01-20 20:29:42 +01:00
#endregion
2008-01-11 21:24:48 +01:00
#endregion
#region - - - IGLContextCreationHack Members - - -
#region bool IGLContextCreationHack . SelectDisplayMode ( DisplayMode mode , IWindowInfo info )
/// <summary>
/// HACK! This function will be removed in 0.3.15
/// Checks if the specified OpenTK.Platform.DisplayMode is available, and selects it if it is.
/// </summary>
/// <param name="mode">The OpenTK.Platform.DisplayMode to select.</param>
/// <param name="info">The OpenTK.Platform.IWindowInfo that describes the display to use. Note: a window handle is not necessary for this function!</param>
/// <returns>True if the DisplayMode is available, false otherwise.</returns>
bool IGLContextCreationHack . SelectDisplayMode ( DisplayMode mode , IWindowInfo info )
{
// Dynamically load the OpenGL32.dll in order to use the extension loading capabilities of Wgl.
if ( opengl32Handle = = IntPtr . Zero )
2007-09-29 17:24:55 +02:00
{
2008-01-11 21:24:48 +01:00
opengl32Handle = Functions . LoadLibrary ( opengl32Name ) ;
if ( opengl32Handle = = IntPtr . Zero )
{
//System.Diagnostics.Debug.WriteLine("LoadLibrary({0}) set error code: {1}. Will not load extensions.", _dll_name, error_code);
throw new ApplicationException ( String . Format ( "LoadLibrary(\"{0}\") call failed with code {1}" ,
opengl32Name , Marshal . GetLastWin32Error ( ) ) ) ;
}
Debug . WriteLine ( String . Format ( "Loaded opengl32.dll: {0}" , opengl32Handle ) ) ;
2007-09-29 17:24:55 +02:00
}
2008-01-11 21:24:48 +01:00
deviceContext = Functions . GetDC ( this . windowInfo . Handle ) ;
Debug . WriteLine ( String . Format ( "Device context: {0}" , deviceContext ) ) ;
Debug . Write ( "Setting pixel format... " ) ;
PixelFormatDescriptor pixelFormat = new PixelFormatDescriptor ( ) ;
pixelFormat . Size = API . PixelFormatDescriptorSize ;
pixelFormat . Version = API . PixelFormatDescriptorVersion ;
pixelFormat . Flags =
PixelFormatDescriptorFlags . SUPPORT_OPENGL |
PixelFormatDescriptorFlags . DRAW_TO_WINDOW ;
pixelFormat . ColorBits = ( byte ) ( mode . Color . Red + mode . Color . Green + mode . Color . Blue ) ;
if ( mode . Color . IsIndexed )
2007-09-29 17:24:55 +02:00
{
2008-01-11 21:24:48 +01:00
pixelFormat . PixelType = PixelType . INDEXED ;
}
else
{
pixelFormat . PixelType = PixelType . RGBA ;
pixelFormat . RedBits = ( byte ) mode . Color . Red ;
pixelFormat . GreenBits = ( byte ) mode . Color . Green ;
pixelFormat . BlueBits = ( byte ) mode . Color . Blue ;
pixelFormat . AlphaBits = ( byte ) mode . Color . Alpha ;
}
/ *
if ( accum ! = null )
{
pixelFormat . AccumBits = ( byte ) ( accum . Red + accum . Green + accum . Blue ) ;
pixelFormat . AccumRedBits = ( byte ) accum . Red ;
pixelFormat . AccumGreenBits = ( byte ) accum . Green ;
pixelFormat . AccumBlueBits = ( byte ) accum . Blue ;
pixelFormat . AccumAlphaBits = ( byte ) accum . Alpha ;
}
* /
2008-01-23 15:17:09 +01:00
pixelFormat . DepthBits = ( byte ) mode . Depth ;
pixelFormat . StencilBits = ( byte ) mode . Stencil ;
2008-01-11 21:24:48 +01:00
2008-01-23 15:17:09 +01:00
if ( mode . Depth < = 0 )
2008-01-11 21:24:48 +01:00
{
pixelFormat . Flags | = PixelFormatDescriptorFlags . DEPTH_DONTCARE ;
}
if ( mode . Stereo )
{
pixelFormat . Flags | = PixelFormatDescriptorFlags . STEREO ;
2007-09-29 17:24:55 +02:00
}
2008-01-11 21:24:48 +01:00
if ( mode . Buffers > 1 )
{
pixelFormat . Flags | = PixelFormatDescriptorFlags . DOUBLEBUFFER ;
}
// TODO: More elaborate mode setting, using DescribePixelFormat.
/ *
unsafe
{
int pixel = Wgl . Imports . ChoosePixelFormat ( deviceContext , & pixelFormat ) ;
if ( pixel = = 0 )
{
throw new ApplicationException ( "The requested pixel format is not supported by the hardware configuration." ) ;
}
Wgl . Imports . SetPixelFormat ( deviceContext , pixel , & pixelFormat ) ;
Debug . WriteLine ( String . Format ( "done! (format: {0})" , pixel ) ) ;
}
* /
int pixel = Functions . ChoosePixelFormat ( deviceContext , ref pixelFormat ) ;
if ( pixel = = 0 )
{
Debug . Print ( "format not available..." ) ;
return false ;
}
Functions . SetPixelFormat ( deviceContext , pixel , ref pixelFormat ) ;
Debug . Print ( "done! (format: {0})" , pixel ) ;
return true ;
}
#endregion
void IGLContextCreationHack . SetWindowHandle ( IntPtr handle )
{
this . windowInfo . Handle = handle ;
2007-09-29 17:24:55 +02:00
}
2007-07-23 02:15:18 +02:00
#endregion
2008-01-23 01:19:22 +01:00
#region - - - Internal Members - - -
#region internal IntPtr Device
internal IntPtr Device { get { return deviceContext ; } }
#endregion
#endregion
2007-07-23 02:15:18 +02:00
#region - - - IDisposable Members - - -
public void Dispose ( )
{
2007-08-10 18:55:24 +02:00
Dispose ( true ) ;
2007-07-23 02:15:18 +02:00
GC . SuppressFinalize ( this ) ;
}
private void Dispose ( bool calledManually )
{
if ( ! disposed )
{
2007-12-09 19:15:51 +01:00
DestroyContext ( ) ;
2007-07-23 02:15:18 +02:00
if ( calledManually )
{
// Safe to clean managed resources
}
disposed = true ;
}
}
~ WinGLContext ( )
{
Dispose ( false ) ;
}
2007-12-09 19:15:51 +01:00
#region private void DestroyContext ( )
2007-07-23 02:15:18 +02:00
2007-12-09 19:15:51 +01:00
private void DestroyContext ( )
2007-07-23 02:15:18 +02:00
{
2007-12-09 19:15:51 +01:00
if ( Destroy ! = null )
Destroy ( this , EventArgs . Empty ) ;
2007-07-23 02:15:18 +02:00
if ( renderContext ! = IntPtr . Zero )
{
2007-08-20 14:25:48 +02:00
Wgl . Imports . MakeCurrent ( IntPtr . Zero , IntPtr . Zero ) ;
if ( ! Wgl . Imports . DeleteContext ( renderContext ) )
2007-07-23 02:15:18 +02:00
{
2007-09-02 02:16:22 +02:00
//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());
2007-07-23 02:15:18 +02:00
}
2008-01-11 21:24:48 +01:00
renderContext = null ;
2007-07-23 02:15:18 +02:00
}
2007-08-20 14:25:48 +02:00
if ( deviceContext ! = IntPtr . Zero )
{
2007-09-26 13:55:24 +02:00
if ( ! Functions . ReleaseDC ( this . windowInfo . Handle , deviceContext ) )
2007-08-20 14:25:48 +02:00
{
2007-09-02 02:16:22 +02:00
//throw new ApplicationException("Could not release device context. Error: " + Marshal.GetLastWin32Error());
//Debug.Print("Could not destroy the device context. Error: {0}", Marshal.GetLastWin32Error());
2007-08-20 14:25:48 +02:00
}
}
2007-12-09 19:15:51 +01:00
/ *
2007-07-23 02:15:18 +02:00
if ( opengl32Handle ! = IntPtr . Zero )
{
2007-09-26 13:55:24 +02:00
if ( ! Functions . FreeLibrary ( opengl32Handle ) )
2007-07-23 02:15:18 +02:00
{
2007-09-02 02:16:22 +02:00
//throw new ApplicationException("FreeLibray call failed ('opengl32.dll'), Error: " + Marshal.GetLastWin32Error());
//Debug.Print("Could not release {0}. Error: {1}", opengl32Name, Marshal.GetLastWin32Error());
2007-07-23 02:15:18 +02:00
}
opengl32Handle = IntPtr . Zero ;
}
2007-12-09 19:15:51 +01:00
* /
2007-07-23 02:15:18 +02:00
}
#endregion
#endregion
}
}