1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        gtk/glcanvas.cpp 
   3 // Purpose:     wxGLCanvas, for using OpenGL/Mesa with wxWidgets and GTK 
   4 // Author:      Robert Roebling 
   8 // Copyright:   (c) Robert Roebling 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  13 #pragma implementation "glcanvas.h" 
  16 // For compilers that support precompilation, includes "wx.h". 
  17 #include "wx/wxprec.h" 
  23 #include "wx/glcanvas.h" 
  26 #include "wx/colour.h" 
  27 #include "wx/module.h" 
  37 #include "wx/gtk/win_gtk.h" 
  39 // DLL options compatibility check: 
  41 WX_CHECK_BUILD_OPTIONS("wxGL") 
  43 //--------------------------------------------------------------------------- 
  45 //--------------------------------------------------------------------------- 
  47 XVisualInfo 
*g_vi 
= (XVisualInfo
*) NULL
; 
  49 //----------------------------------------------------------------------------- 
  51 //----------------------------------------------------------------------------- 
  53 extern void wxapp_install_idle_handler(); 
  56 //--------------------------------------------------------------------------- 
  58 //--------------------------------------------------------------------------- 
  60 IMPLEMENT_CLASS(wxGLContext
,wxObject
) 
  62 wxGLContext::wxGLContext( bool WXUNUSED(isRGB
), wxWindow 
*win
, const wxPalette
& WXUNUSED(palette
) ) 
  65     m_widget 
= win
->m_wxwindow
; 
  67     wxGLCanvas 
*gc 
= (wxGLCanvas
*) win
; 
  68     XVisualInfo 
*vi 
= (XVisualInfo 
*) gc
->m_vi
; 
  70     wxCHECK_RET( vi
, _T("invalid visual for OpenGl") ); 
  72     m_glContext 
= glXCreateContext( GDK_DISPLAY(), vi
, None
, GL_TRUE 
); 
  74     wxCHECK_RET( m_glContext
, _T("Couldn't create OpenGl context") ); 
  77 wxGLContext::wxGLContext( 
  78                bool WXUNUSED(isRGB
), wxWindow 
*win
, 
  79                const wxPalette
& WXUNUSED(palette
), 
  80                const wxGLContext 
*other        
/* for sharing display lists */ 
  84     m_widget 
= win
->m_wxwindow
; 
  86     wxGLCanvas 
*gc 
= (wxGLCanvas
*) win
; 
  87     XVisualInfo 
*vi 
= (XVisualInfo 
*) gc
->m_vi
; 
  89     wxCHECK_RET( vi
, _T("invalid visual for OpenGl") ); 
  91     m_glContext 
= glXCreateContext( GDK_DISPLAY(), vi
, 
  92                                     other 
? other
->m_glContext 
: None
, 
  97         wxFAIL_MSG( _T("Couldn't create OpenGl context") ); 
 101 wxGLContext::~wxGLContext() 
 103     if (!m_glContext
) return; 
 105     if (m_glContext 
== glXGetCurrentContext()) 
 107         glXMakeCurrent( GDK_DISPLAY(), None
, NULL
); 
 110     glXDestroyContext( GDK_DISPLAY(), m_glContext 
); 
 113 void wxGLContext::SwapBuffers() 
 117         GdkWindow 
*window 
= GTK_PIZZA(m_widget
)->bin_window
; 
 118         glXSwapBuffers( GDK_DISPLAY(), GDK_WINDOW_XWINDOW( window 
) ); 
 122 void wxGLContext::SetCurrent() 
 126         GdkWindow 
*window 
= GTK_PIZZA(m_widget
)->bin_window
; 
 127         glXMakeCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window
), m_glContext 
); 
 131 void wxGLContext::SetColour(const wxChar 
*colour
) 
 133     wxColour col 
= wxTheColourDatabase
->Find(colour
); 
 136         float r 
= (float)(col
.Red()/256.0); 
 137         float g 
= (float)(col
.Green()/256.0); 
 138         float b 
= (float)(col
.Blue()/256.0); 
 143 void wxGLContext::SetupPixelFormat() 
 147 void wxGLContext::SetupPalette( const wxPalette
& WXUNUSED(palette
) ) 
 151 wxPalette 
wxGLContext::CreateDefaultPalette() 
 153     return wxNullPalette
; 
 156 //----------------------------------------------------------------------------- 
 157 // "realize" from m_wxwindow 
 158 //----------------------------------------------------------------------------- 
 161 gtk_glwindow_realized_callback( GtkWidget 
* WXUNUSED(widget
), wxGLCanvas 
*win 
) 
 163     if ( !win
->m_glContext 
) 
 165         wxGLContext 
*share 
= win
->m_sharedContext
; 
 166         if ( !share 
&& win
->m_sharedContextOf 
) 
 167             share 
= win
->m_sharedContextOf
->GetContext(); 
 169         win
->m_glContext 
= new wxGLContext( TRUE
, win
, wxNullPalette
, share 
); 
 175 //----------------------------------------------------------------------------- 
 176 // "map" from m_wxwindow 
 177 //----------------------------------------------------------------------------- 
 180 gtk_glwindow_map_callback( GtkWidget 
* WXUNUSED(widget
), wxGLCanvas 
*win 
) 
 182     if (win
->m_glContext
/* && win->m_exposed*/) 
 184         wxPaintEvent 
event( win
->GetId() ); 
 185         event
.SetEventObject( win 
); 
 186         win
->GetEventHandler()->ProcessEvent( event 
); 
 188         win
->m_exposed 
= FALSE
; 
 189         win
->GetUpdateRegion().Clear(); 
 195 //----------------------------------------------------------------------------- 
 196 // "expose_event" of m_wxwindow 
 197 //----------------------------------------------------------------------------- 
 200 gtk_glwindow_expose_callback( GtkWidget 
*WXUNUSED(widget
), GdkEventExpose 
*gdk_event
, wxGLCanvas 
*win 
) 
 203         wxapp_install_idle_handler(); 
 205     win
->m_exposed 
= TRUE
; 
 207     win
->GetUpdateRegion().Union( gdk_event
->area
.x
, 
 209                                   gdk_event
->area
.width
, 
 210                                   gdk_event
->area
.height 
); 
 213 //----------------------------------------------------------------------------- 
 214 // "draw" of m_wxwindow 
 215 //----------------------------------------------------------------------------- 
 219 gtk_glwindow_draw_callback( GtkWidget 
*WXUNUSED(widget
), GdkRectangle 
*rect
, wxGLCanvas 
*win 
) 
 222         wxapp_install_idle_handler(); 
 224     win
->m_exposed 
= TRUE
; 
 226     win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, 
 227                                   rect
->width
, rect
->height 
); 
 231 //----------------------------------------------------------------------------- 
 232 // "size_allocate" of m_wxwindow 
 233 //----------------------------------------------------------------------------- 
 236 gtk_glcanvas_size_callback( GtkWidget 
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxGLCanvas 
*win 
) 
 239         wxapp_install_idle_handler(); 
 244     wxSizeEvent 
event( wxSize(win
->m_width
,win
->m_height
), win
->GetId() ); 
 245     event
.SetEventObject( win 
); 
 246     win
->GetEventHandler()->ProcessEvent( event 
); 
 249 //--------------------------------------------------------------------------- 
 251 //--------------------------------------------------------------------------- 
 253 IMPLEMENT_CLASS(wxGLCanvas
, wxWindow
) 
 255 BEGIN_EVENT_TABLE(wxGLCanvas
, wxWindow
) 
 256     EVT_SIZE(wxGLCanvas::OnSize
) 
 259 wxGLCanvas::wxGLCanvas( wxWindow 
*parent
, wxWindowID id
, 
 260                         const wxPoint
& pos
, const wxSize
& size
, 
 261                         long style
, const wxString
& name
, 
 263                         const wxPalette
& palette 
) 
 265     Create( parent
, NULL
, NULL
, id
, pos
, size
, style
, name
, attribList
, palette 
); 
 268 wxGLCanvas::wxGLCanvas( wxWindow 
*parent
, 
 269                         const wxGLContext 
*shared
, 
 271                         const wxPoint
& pos
, const wxSize
& size
, 
 272                         long style
, const wxString
& name
, 
 274                         const wxPalette
& palette 
) 
 276     Create( parent
, shared
, NULL
, id
, pos
, size
, style
, name
, attribList
, palette 
); 
 279 wxGLCanvas::wxGLCanvas( wxWindow 
*parent
, 
 280                         const wxGLCanvas 
*shared
, 
 282                         const wxPoint
& pos
, const wxSize
& size
, 
 283                         long style
, const wxString
& name
, 
 285                         const wxPalette
& palette 
) 
 287     Create( parent
, NULL
, shared
, id
, pos
, size
, style
, name
, attribList
, palette 
); 
 290 bool wxGLCanvas::Create( wxWindow 
*parent
, 
 291                          const wxGLContext 
*shared
, 
 292                          const wxGLCanvas 
*shared_context_of
, 
 294                          const wxPoint
& pos
, const wxSize
& size
, 
 295                          long style
, const wxString
& name
, 
 297                          const wxPalette
& palette
) 
 299     m_sharedContext 
= (wxGLContext
*)shared
;  // const_cast 
 300     m_sharedContextOf 
= (wxGLCanvas
*)shared_context_of
;  // const_cast 
 301     m_glContext 
= (wxGLContext
*) NULL
; 
 305     m_nativeSizeEvent 
= TRUE
; 
 307     XVisualInfo 
*vi 
= NULL
; 
 308     if (wxTheApp
->m_glVisualInfo 
!= NULL
) 
 310         vi 
= (XVisualInfo 
*) wxTheApp
->m_glVisualInfo
; 
 311         m_canFreeVi 
= FALSE
; // owned by wxTheApp - don't free upon destruction 
 315         vi 
= (XVisualInfo 
*) ChooseGLVisual(attribList
); 
 318     m_vi 
= vi
;  // save for later use 
 320     wxCHECK_MSG( m_vi
, FALSE
, _T("required visual couldn't be found") ); 
 322     GdkVisual 
*visual 
= gdkx_visual_get( vi
->visualid 
); 
 323     GdkColormap 
*colormap 
= gdk_colormap_new( visual
, TRUE 
); 
 325     gtk_widget_push_colormap( colormap 
); 
 326     gtk_widget_push_visual( visual 
); 
 328     wxWindow::Create( parent
, id
, pos
, size
, style
, name 
); 
 330     m_glWidget 
= m_wxwindow
; 
 333     gtk_widget_set_double_buffered( m_glWidget
, FALSE 
); 
 336     gtk_pizza_set_clear( GTK_PIZZA(m_wxwindow
), FALSE 
); 
 338     gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize", 
 339                             GTK_SIGNAL_FUNC(gtk_glwindow_realized_callback
), (gpointer
) this ); 
 341     gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "map", 
 342                             GTK_SIGNAL_FUNC(gtk_glwindow_map_callback
), (gpointer
) this ); 
 344     gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event", 
 345         GTK_SIGNAL_FUNC(gtk_glwindow_expose_callback
), (gpointer
)this ); 
 348     gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw", 
 349         GTK_SIGNAL_FUNC(gtk_glwindow_draw_callback
), (gpointer
)this ); 
 352     gtk_signal_connect( GTK_OBJECT(m_widget
), "size_allocate", 
 353         GTK_SIGNAL_FUNC(gtk_glcanvas_size_callback
), (gpointer
)this ); 
 355     gtk_widget_pop_visual(); 
 356     gtk_widget_pop_colormap(); 
 358     // if our parent window is already visible, we had been realized before we 
 359     // connected to the "realize" signal and hence our m_glContext hasn't been 
 360     // initialized yet and we have to do it now 
 361     if (GTK_WIDGET_REALIZED(m_wxwindow
)) 
 362         gtk_glwindow_realized_callback( m_wxwindow
, this ); 
 364     if (GTK_WIDGET_MAPPED(m_wxwindow
)) 
 365         gtk_glwindow_map_callback( m_wxwindow
, this ); 
 370 wxGLCanvas::~wxGLCanvas() 
 372     XVisualInfo 
*vi 
= (XVisualInfo 
*) m_vi
; 
 374     if (vi 
&& m_canFreeVi
) XFree( vi 
); 
 378 void* wxGLCanvas::ChooseGLVisual(int *attribList
) 
 383         // default settings if attriblist = 0 
 385         data
[1] = GLX_DOUBLEBUFFER
; 
 386         data
[2] = GLX_DEPTH_SIZE
;   data
[3] = 1; 
 387         data
[4] = GLX_RED_SIZE
;     data
[5] = 1; 
 388         data
[6] = GLX_GREEN_SIZE
;   data
[7] = 1; 
 389         data
[8] = GLX_BLUE_SIZE
;    data
[9] = 1; 
 390         data
[10] = GLX_ALPHA_SIZE
;  data
[11] = 0; 
 393         attribList 
= (int*) data
; 
 399       while( (attribList
[arg
]!=0) && (p
<510) ) 
 401         switch( attribList
[arg
++] ) 
 403           case WX_GL_RGBA
: data
[p
++] = GLX_RGBA
; break; 
 404           case WX_GL_BUFFER_SIZE
: 
 405             data
[p
++]=GLX_BUFFER_SIZE
; data
[p
++]=attribList
[arg
++]; break; 
 407             data
[p
++]=GLX_LEVEL
; data
[p
++]=attribList
[arg
++]; break; 
 408           case WX_GL_DOUBLEBUFFER
: data
[p
++] = GLX_DOUBLEBUFFER
; break; 
 409           case WX_GL_STEREO
: data
[p
++] = GLX_STEREO
; break; 
 410           case WX_GL_AUX_BUFFERS
: 
 411             data
[p
++]=GLX_AUX_BUFFERS
; data
[p
++]=attribList
[arg
++]; break; 
 413             data
[p
++]=GLX_RED_SIZE
; data
[p
++]=attribList
[arg
++]; break; 
 414           case WX_GL_MIN_GREEN
: 
 415             data
[p
++]=GLX_GREEN_SIZE
; data
[p
++]=attribList
[arg
++]; break; 
 417             data
[p
++]=GLX_BLUE_SIZE
; data
[p
++]=attribList
[arg
++]; break; 
 418           case WX_GL_MIN_ALPHA
: 
 419             data
[p
++]=GLX_ALPHA_SIZE
; data
[p
++]=attribList
[arg
++]; break; 
 420           case WX_GL_DEPTH_SIZE
: 
 421             data
[p
++]=GLX_DEPTH_SIZE
; data
[p
++]=attribList
[arg
++]; break; 
 422           case WX_GL_STENCIL_SIZE
: 
 423             data
[p
++]=GLX_STENCIL_SIZE
; data
[p
++]=attribList
[arg
++]; break; 
 424           case WX_GL_MIN_ACCUM_RED
: 
 425             data
[p
++]=GLX_ACCUM_RED_SIZE
; data
[p
++]=attribList
[arg
++]; break; 
 426           case WX_GL_MIN_ACCUM_GREEN
: 
 427             data
[p
++]=GLX_ACCUM_GREEN_SIZE
; data
[p
++]=attribList
[arg
++]; break; 
 428           case WX_GL_MIN_ACCUM_BLUE
: 
 429             data
[p
++]=GLX_ACCUM_BLUE_SIZE
; data
[p
++]=attribList
[arg
++]; break; 
 430           case WX_GL_MIN_ACCUM_ALPHA
: 
 431             data
[p
++]=GLX_ACCUM_ALPHA_SIZE
; data
[p
++]=attribList
[arg
++]; break; 
 438       attribList 
= (int*) data
; 
 442     Display 
*dpy 
= GDK_DISPLAY(); 
 444     return glXChooseVisual( dpy
, DefaultScreen(dpy
), attribList 
); 
 447 void wxGLCanvas::SwapBuffers() 
 450         m_glContext
->SwapBuffers(); 
 453 void wxGLCanvas::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
 457 void wxGLCanvas::SetCurrent() 
 460         m_glContext
->SetCurrent(); 
 463 void wxGLCanvas::SetColour( const wxChar 
*colour 
) 
 466         m_glContext
->SetColour( colour 
); 
 469 void wxGLCanvas::OnInternalIdle() 
 471     if (m_glContext 
&& m_exposed
) 
 473         wxPaintEvent 
event( GetId() ); 
 474         event
.SetEventObject( this ); 
 475         GetEventHandler()->ProcessEvent( event 
); 
 478         GetUpdateRegion().Clear(); 
 481     wxWindow::OnInternalIdle(); 
 486 //--------------------------------------------------------------------------- 
 488 //--------------------------------------------------------------------------- 
 490 IMPLEMENT_CLASS(wxGLApp
, wxApp
) 
 495         XFree(m_glVisualInfo
); 
 498 bool wxGLApp::InitGLVisual(int *attribList
) 
 501         XFree(m_glVisualInfo
); 
 503     m_glVisualInfo 
= wxGLCanvas::ChooseGLVisual(attribList
); 
 505     return m_glVisualInfo 
!= NULL
;