2007-07-23 00:15:18 +00:00
#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.Runtime.InteropServices ;
using System.Diagnostics ;
using OpenTK.OpenGL ;
namespace OpenTK.Platform.X11
{
2007-08-05 13:42:31 +00:00
/// <summary>
2007-09-09 11:52:09 +00:00
/// Provides methods to create and control an opengl context on the X11 platform.
2007-12-09 18:15:51 +00:00
/// This class supports OpenTK, and is not intended for use by OpenTK programs.
2007-08-05 13:42:31 +00:00
/// </summary>
2008-01-11 20:23:41 +00:00
internal sealed class X11GLContext : IGLContext , IGLContextCreationHack
2007-07-23 00:15:18 +00:00
{
2007-08-20 12:25:48 +00:00
private IntPtr context ;
2007-08-21 10:48:32 +00:00
private DisplayMode mode ;
2008-01-15 11:02:23 +00:00
private WindowInfo windowInfo = new WindowInfo ( ) ;
2007-09-09 11:52:09 +00:00
private IntPtr visual ;
2007-07-23 00:15:18 +00:00
private bool disposed ;
2007-09-09 11:52:09 +00:00
#region - - - Constructors - - -
2007-07-23 00:15:18 +00:00
2008-01-11 20:23:41 +00:00
/// <summary>
/// Constructs a new X11GLContext object.
/// </summary>
public X11GLContext ( ) { }
2007-09-09 11:52:09 +00:00
#endregion
2008-01-11 20:23:41 +00:00
#region - - - IGLContextCreationHack Members - - -
2007-08-20 12:25:48 +00:00
2008-01-11 20:23:41 +00:00
#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 )
2007-08-20 12:25:48 +00:00
{
List < int > visualAttributes = new List < int > ( ) ;
2007-08-21 10:48:32 +00:00
2007-11-04 15:37:41 +00:00
// TODO: Improve modesetting code.
if ( mode = = null | | mode . Color . BitsPerPixel = = 0 )
2007-08-21 10:48:32 +00:00
{
// Define the bare essentials - needed for compatibility with Mono's System.Windows.Forms
Debug . Print ( "Preparing visual for System.Windows.Forms (compatibility mode)" ) ;
2007-09-02 22:52:00 +00:00
2007-08-21 10:48:32 +00:00
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . RGBA ) ;
2007-11-11 19:28:55 +00:00
/ * visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . RED_SIZE ) ;
2007-11-04 15:37:41 +00:00
visualAttributes . Add ( ( int ) 1 ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . GREEN_SIZE ) ;
visualAttributes . Add ( ( int ) 1 ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . BLUE_SIZE ) ;
2007-11-11 19:28:55 +00:00
visualAttributes . Add ( ( int ) 1 ) ; * /
2007-08-21 10:48:32 +00:00
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . DEPTH_SIZE ) ;
visualAttributes . Add ( ( int ) 1 ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . DOUBLEBUFFER ) ;
visualAttributes . Add ( ( int ) 0 ) ;
}
else
{
Debug . Print ( "Preparing visual for DisplayMode: {0}" , mode . ToString ( ) ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . RGBA ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . RED_SIZE ) ;
visualAttributes . Add ( ( int ) mode . Color . Red ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . GREEN_SIZE ) ;
visualAttributes . Add ( ( int ) mode . Color . Green ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . BLUE_SIZE ) ;
visualAttributes . Add ( ( int ) mode . Color . Blue ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . ALPHA_SIZE ) ;
visualAttributes . Add ( ( int ) mode . Color . Alpha ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . DEPTH_SIZE ) ;
visualAttributes . Add ( ( int ) mode . DepthBits ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . DOUBLEBUFFER ) ;
visualAttributes . Add ( ( int ) 0 ) ;
}
2008-01-15 10:59:36 +00:00
2008-01-15 11:02:23 +00:00
windowInfo . CopyInfoFrom ( info ) ;
2008-01-15 12:32:38 +00:00
visual = Glx . ChooseVisual ( windowInfo . Display , windowInfo . Screen , visualAttributes . ToArray ( ) ) ;
2007-08-20 12:25:48 +00:00
if ( visual = = IntPtr . Zero )
2008-01-11 20:23:41 +00:00
return false ;
2007-08-20 12:25:48 +00:00
else
{
2007-11-04 15:37:41 +00:00
windowInfo . VisualInfo = ( XVisualInfo ) Marshal . PtrToStructure ( visual ,
typeof ( XVisualInfo ) ) ;
Debug . Print ( "Chose visual {0}" , windowInfo . VisualInfo . ToString ( ) ) ;
2007-08-20 12:25:48 +00:00
}
2008-01-11 20:23:41 +00:00
return true ;
}
#endregion
void IGLContextCreationHack . SetWindowHandle ( IntPtr handle )
{
this . windowInfo . Handle = handle ;
2007-08-20 12:25:48 +00:00
}
#endregion
2007-09-09 15:10:21 +00:00
#region - - - IGLContext Members - - -
#region public IntPtr Context
2007-08-20 12:25:48 +00:00
2007-09-09 15:10:21 +00:00
public IntPtr Context
2007-08-20 12:25:48 +00:00
{
2007-09-09 15:10:21 +00:00
get { return context ; }
private set { context = value ; }
}
2007-08-20 12:25:48 +00:00
2007-09-09 15:10:21 +00:00
#endregion
2007-08-20 12:25:48 +00:00
2007-09-09 15:10:21 +00:00
#region public DisplayMode Mode
2007-08-20 12:25:48 +00:00
2007-09-09 15:10:21 +00:00
public DisplayMode Mode
{
get { return mode ; }
private set
2007-08-20 12:25:48 +00:00
{
2007-09-09 15:10:21 +00:00
if ( context = = IntPtr . Zero )
mode = value ;
else
Debug . Print ( "Cannot change DisplayMode of an existing context." ) ;
2007-08-20 12:25:48 +00:00
}
2007-09-09 15:10:21 +00:00
}
#endregion
#region public IWindowInfo Info
public IWindowInfo Info { get { return windowInfo ; } }
#endregion
public void CreateContext ( )
{
this . CreateContext ( true , null ) ;
}
public void CreateContext ( bool direct )
{
this . CreateContext ( direct , null ) ;
}
#region public void CreateContext ( bool direct , IGLContext shareContext )
public void CreateContext ( bool direct , IGLContext shareContext )
{
try
2007-08-20 12:25:48 +00:00
{
2007-09-09 15:10:21 +00:00
Debug . WriteLine ( "Creating opengl context." ) ;
Debug . Indent ( ) ;
IntPtr shareHandle = shareContext ! = null ? ( shareContext as X11GLContext ) . Context : IntPtr . Zero ;
Debug . Write ( direct ? "Context is direct, " : "Context is indirect, " ) ;
Debug . WriteLine ( shareHandle = = IntPtr . Zero ? "not shared." :
String . Format ( "shared with ({0})." , shareHandle ) ) ;
// Try to call Glx.CreateContext with the specified parameters.
context = Glx . CreateContext ( windowInfo . Display , visual , shareHandle , direct ) ;
// Context creation succeeded, return.
if ( context ! = IntPtr . Zero )
{
Debug . Print ( "New opengl context created. (id: {0})" , context ) ;
2007-11-04 15:37:41 +00:00
this . MakeCurrent ( ) ;
GL . LoadAll ( ) ;
Glu . LoadAll ( ) ;
2007-09-09 15:10:21 +00:00
return ;
}
// Context creation failed. Retry with a non-shared context with the
// direct/indirect rendering mode flipped.
Debug . Print ( "Cotnext creation failed, retrying with a non-shared, {0} context." ,
! direct ? "direct" : "indirect" ) ;
context = Glx . CreateContext ( windowInfo . Display , visual , IntPtr . Zero , ! direct ) ;
if ( context ! = IntPtr . Zero )
{
Debug . Print ( "New opengl context created. (id: {0})" , context ) ;
2007-11-04 15:37:41 +00:00
this . MakeCurrent ( ) ;
GL . LoadAll ( ) ;
Glu . LoadAll ( ) ;
2007-09-09 15:10:21 +00:00
return ;
}
2007-08-20 12:25:48 +00:00
throw new ApplicationException ( "Glx.CreateContext call failed (returned 0)." ) ;
}
2007-09-09 15:10:21 +00:00
finally
{
Debug . Unindent ( ) ;
}
2007-08-20 12:25:48 +00:00
}
#endregion
2007-07-23 00:15:18 +00:00
#region public void SwapBuffers ( )
public void SwapBuffers ( )
{
2007-08-05 13:42:31 +00:00
Glx . SwapBuffers ( windowInfo . Display , windowInfo . Handle ) ;
2007-07-23 00:15:18 +00:00
}
#endregion
#region public void MakeCurrent ( )
2007-08-20 12:25:48 +00:00
bool result ;
2007-07-23 00:15:18 +00:00
public void MakeCurrent ( )
{
2007-08-20 12:25:48 +00:00
Debug . Write ( String . Format ( "Making context {0} current on thread {1} (Display: {2}, Screen: {3}, Window: {4})... " ,
context , System . Threading . Thread . CurrentThread . ManagedThreadId , windowInfo . Display , windowInfo . Screen , windowInfo . Handle ) ) ;
if ( windowInfo . Display ! = IntPtr . Zero & & windowInfo . Handle ! = IntPtr . Zero & & context ! = IntPtr . Zero )
2007-07-23 00:15:18 +00:00
{
2007-08-20 12:25:48 +00:00
result = Glx . MakeCurrent ( windowInfo . Display , windowInfo . Handle , context ) ;
if ( ! result )
{
Debug . WriteLine ( "failed." ) ;
// probably need to recreate context here.
//throw new ApplicationException(String.Format("Failed to make context {0} current on thread {1}.",
// context, System.Threading.Thread.CurrentThread.ManagedThreadId));
}
else
{
Debug . WriteLine ( "done!" ) ;
}
2007-07-23 00:15:18 +00:00
}
}
#endregion
2007-12-09 18:15:51 +00:00
public bool IsCurrent
2007-07-23 00:15:18 +00:00
{
2007-12-09 18:15:51 +00:00
//return GetCurrentContext() == context;
get { throw new NotImplementedException ( ) ; }
}
public IntPtr GetCurrentContext ( )
{
//return Glx.GetCurrentContext();
2007-07-23 00:15:18 +00:00
throw new NotImplementedException ( ) ;
}
2007-12-09 18:15:51 +00:00
public event DestroyEvent < IGLContext > Destroy ;
2007-07-23 00:15:18 +00:00
#region public IntPtr GetAddress ( string function )
public IntPtr GetAddress ( string function )
{
return Glx . GetProcAddress ( function ) ;
}
#endregion
2007-12-09 18:15:51 +00:00
public void RegisterForDisposal ( IDisposable resource )
{
throw new NotImplementedException ( "Use the general GLContext class instead." ) ;
}
public void DisposeResources ( )
{
throw new NotImplementedException ( "Use the general GLContext class instead." ) ;
}
2007-07-23 00:15:18 +00:00
public IEnumerable < DisplayMode > GetDisplayModes ( )
{
throw new Exception ( "The method or operation is not implemented." ) ;
}
2007-09-29 15:24:55 +00:00
public bool VSync
{
get
{
return false ;
}
set
{
}
}
2007-07-23 00:15:18 +00:00
#endregion
#region - - - IDisposable Members - - -
public void Dispose ( )
{
this . Dispose ( true ) ;
GC . SuppressFinalize ( this ) ;
}
private void Dispose ( bool manuallyCalled )
{
if ( ! disposed )
{
// Clean unmanaged resources:
2007-08-20 12:25:48 +00:00
Glx . MakeCurrent ( windowInfo . Display , IntPtr . Zero , IntPtr . Zero ) ;
Glx . DestroyContext ( windowInfo . Display , context ) ;
2007-07-23 00:15:18 +00:00
API . Free ( visual ) ;
if ( manuallyCalled )
{
// Safe to clean managed resources, too
}
}
disposed = true ;
}
~ X11GLContext ( )
{
this . Dispose ( false ) ;
}
#endregion
}
}