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")
44 //---------------------------------------------------------------------------
46 //---------------------------------------------------------------------------
47 int wxGLCanvas::m_glxVersion
= 0;
49 //---------------------------------------------------------------------------
51 //---------------------------------------------------------------------------
53 XVisualInfo
*g_vi
= (XVisualInfo
*) NULL
;
54 //-----------------------------------------------------------------------------
56 //-----------------------------------------------------------------------------
58 extern void wxapp_install_idle_handler();
61 //---------------------------------------------------------------------------
63 //---------------------------------------------------------------------------
65 IMPLEMENT_CLASS(wxGLContext
,wxObject
)
67 wxGLContext::wxGLContext( bool WXUNUSED(isRGB
), wxWindow
*win
, const wxPalette
& WXUNUSED(palette
) )
70 m_widget
= win
->m_wxwindow
;
72 wxGLCanvas
*gc
= (wxGLCanvas
*) win
;
74 if (wxGLCanvas::GetGLXVersion() >= 13)
77 GLXFBConfig
*fbc
= gc
->m_fbc
;
78 wxCHECK_RET( fbc
, _T("invalid GLXFBConfig for OpenGl") );
79 m_glContext
= glXCreateNewContext( GDK_DISPLAY(), fbc
[0], GLX_RGBA_TYPE
, None
, GL_TRUE
);
84 XVisualInfo
*vi
= (XVisualInfo
*) gc
->m_vi
;
85 wxCHECK_RET( vi
, _T("invalid visual for OpenGl") );
86 m_glContext
= glXCreateContext( GDK_DISPLAY(), vi
, None
, GL_TRUE
);
89 wxCHECK_RET( m_glContext
, _T("Couldn't create OpenGl context") );
92 wxGLContext::wxGLContext(
93 bool WXUNUSED(isRGB
), wxWindow
*win
,
94 const wxPalette
& WXUNUSED(palette
),
95 const wxGLContext
*other
/* for sharing display lists */
99 m_widget
= win
->m_wxwindow
;
101 wxGLCanvas
*gc
= (wxGLCanvas
*) win
;
103 if (wxGLCanvas::GetGLXVersion() >= 13)
106 GLXFBConfig
*fbc
= gc
->m_fbc
;
107 wxCHECK_RET( fbc
, _T("invalid GLXFBConfig for OpenGl") );
108 m_glContext
= glXCreateNewContext( GDK_DISPLAY(), fbc
[0], GLX_RGBA_TYPE
,
109 other
? other
->m_glContext
: None
,
115 XVisualInfo
*vi
= (XVisualInfo
*) gc
->m_vi
;
116 wxCHECK_RET( vi
, _T("invalid visual for OpenGl") );
117 m_glContext
= glXCreateContext( GDK_DISPLAY(), vi
,
118 other
? other
->m_glContext
: None
,
124 wxFAIL_MSG( _T("Couldn't create OpenGl context") );
128 wxGLContext::~wxGLContext()
130 if (!m_glContext
) return;
132 if (m_glContext
== glXGetCurrentContext())
134 if (wxGLCanvas::GetGLXVersion() >= 13)
136 glXMakeContextCurrent( GDK_DISPLAY(), None
, None
, NULL
);
139 glXMakeCurrent( GDK_DISPLAY(), None
, NULL
);
142 glXDestroyContext( GDK_DISPLAY(), m_glContext
);
145 void wxGLContext::SwapBuffers()
149 GdkWindow
*window
= GTK_PIZZA(m_widget
)->bin_window
;
150 glXSwapBuffers( GDK_DISPLAY(), GDK_WINDOW_XWINDOW( window
) );
154 void wxGLContext::SetCurrent()
158 GdkWindow
*window
= GTK_PIZZA(m_widget
)->bin_window
;
160 if (wxGLCanvas::GetGLXVersion() >= 13)
162 glXMakeContextCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window
), GDK_WINDOW_XWINDOW(window
), m_glContext
);
165 glXMakeCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window
), m_glContext
);
169 void wxGLContext::SetColour(const wxChar
*colour
)
171 wxColour col
= wxTheColourDatabase
->Find(colour
);
174 float r
= (float)(col
.Red()/256.0);
175 float g
= (float)(col
.Green()/256.0);
176 float b
= (float)(col
.Blue()/256.0);
181 void wxGLContext::SetupPixelFormat()
185 void wxGLContext::SetupPalette( const wxPalette
& WXUNUSED(palette
) )
189 wxPalette
wxGLContext::CreateDefaultPalette()
191 return wxNullPalette
;
194 //-----------------------------------------------------------------------------
195 // "realize" from m_wxwindow
196 //-----------------------------------------------------------------------------
200 gtk_glwindow_realized_callback( GtkWidget
*WXUNUSED(widget
), wxGLCanvas
*win
)
202 if ( !win
->m_glContext
)
204 wxGLContext
*share
= win
->m_sharedContext
;
205 if ( !share
&& win
->m_sharedContextOf
)
206 share
= win
->m_sharedContextOf
->GetContext();
208 win
->m_glContext
= new wxGLContext( TRUE
, win
, wxNullPalette
, share
);
215 //-----------------------------------------------------------------------------
216 // "map" from m_wxwindow
217 //-----------------------------------------------------------------------------
221 gtk_glwindow_map_callback( GtkWidget
* WXUNUSED(widget
), wxGLCanvas
*win
)
223 if (win
->m_glContext
/* && win->m_exposed*/)
225 wxPaintEvent
event( win
->GetId() );
226 event
.SetEventObject( win
);
227 win
->GetEventHandler()->ProcessEvent( event
);
229 win
->m_exposed
= FALSE
;
230 win
->GetUpdateRegion().Clear();
237 //-----------------------------------------------------------------------------
238 // "expose_event" of m_wxwindow
239 //-----------------------------------------------------------------------------
243 gtk_glwindow_expose_callback( GtkWidget
*WXUNUSED(widget
), GdkEventExpose
*gdk_event
, wxGLCanvas
*win
)
246 wxapp_install_idle_handler();
248 win
->m_exposed
= TRUE
;
250 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
252 gdk_event
->area
.width
,
253 gdk_event
->area
.height
);
257 //-----------------------------------------------------------------------------
258 // "draw" of m_wxwindow
259 //-----------------------------------------------------------------------------
264 gtk_glwindow_draw_callback( GtkWidget
*WXUNUSED(widget
), GdkRectangle
*rect
, wxGLCanvas
*win
)
267 wxapp_install_idle_handler();
269 win
->m_exposed
= TRUE
;
271 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
,
272 rect
->width
, rect
->height
);
277 //-----------------------------------------------------------------------------
278 // "size_allocate" of m_wxwindow
279 //-----------------------------------------------------------------------------
283 gtk_glcanvas_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxGLCanvas
*win
)
286 wxapp_install_idle_handler();
291 wxSizeEvent
event( wxSize(win
->m_width
,win
->m_height
), win
->GetId() );
292 event
.SetEventObject( win
);
293 win
->GetEventHandler()->ProcessEvent( event
);
297 //---------------------------------------------------------------------------
299 //---------------------------------------------------------------------------
301 IMPLEMENT_CLASS(wxGLCanvas
, wxWindow
)
303 BEGIN_EVENT_TABLE(wxGLCanvas
, wxWindow
)
304 EVT_SIZE(wxGLCanvas::OnSize
)
307 wxGLCanvas::wxGLCanvas( wxWindow
*parent
, wxWindowID id
,
308 const wxPoint
& pos
, const wxSize
& size
,
309 long style
, const wxString
& name
,
311 const wxPalette
& palette
)
313 Create( parent
, NULL
, NULL
, id
, pos
, size
, style
, name
, attribList
, palette
);
316 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
317 const wxGLContext
*shared
,
319 const wxPoint
& pos
, const wxSize
& size
,
320 long style
, const wxString
& name
,
322 const wxPalette
& palette
)
324 Create( parent
, shared
, NULL
, id
, pos
, size
, style
, name
, attribList
, palette
);
327 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
328 const wxGLCanvas
*shared
,
330 const wxPoint
& pos
, const wxSize
& size
,
331 long style
, const wxString
& name
,
333 const wxPalette
& palette
)
335 Create( parent
, NULL
, shared
, id
, pos
, size
, style
, name
, attribList
, palette
);
338 bool wxGLCanvas::Create( wxWindow
*parent
,
339 const wxGLContext
*shared
,
340 const wxGLCanvas
*shared_context_of
,
342 const wxPoint
& pos
, const wxSize
& size
,
343 long style
, const wxString
& name
,
345 const wxPalette
& palette
)
347 m_sharedContext
= (wxGLContext
*)shared
; // const_cast
348 m_sharedContextOf
= (wxGLCanvas
*)shared_context_of
; // const_cast
349 m_glContext
= (wxGLContext
*) NULL
;
353 m_nativeSizeEvent
= TRUE
;
357 // to be sure the glx version is known
358 wxGLCanvas::QueryGLXVersion();
360 if (wxGLCanvas::GetGLXVersion() >= 13)
362 // GLX >= 1.3 uses a GLXFBConfig
363 GLXFBConfig
* fbc
= NULL
;
364 if (wxTheApp
->m_glFBCInfo
!= NULL
)
366 fbc
= (GLXFBConfig
*) wxTheApp
->m_glFBCInfo
;
367 m_canFreeFBC
= FALSE
; // owned by wxTheApp - don't free upon destruction
371 fbc
= (GLXFBConfig
*) wxGLCanvas::ChooseGLFBC(attribList
);
374 m_fbc
= fbc
; // save for later use
375 wxCHECK_MSG( m_fbc
, FALSE
, _T("required FBConfig couldn't be found") );
378 XVisualInfo
*vi
= NULL
;
379 if (wxTheApp
->m_glVisualInfo
!= NULL
)
381 vi
= (XVisualInfo
*)wxTheApp
->m_glVisualInfo
;
382 m_canFreeVi
= FALSE
; // owned by wxTheApp - don't free upon destruction
386 if (wxGLCanvas::GetGLXVersion() >= 13)
388 vi
= glXGetVisualFromFBConfig(GDK_DISPLAY(), m_fbc
[0]);
391 vi
= (XVisualInfo
*) ChooseGLVisual(attribList
);
394 m_vi
= vi
; // save for later use
396 wxCHECK_MSG( m_vi
, FALSE
, _T("required visual couldn't be found") );
397 GdkVisual
*visual
= gdkx_visual_get( vi
->visualid
);
398 GdkColormap
*colormap
= gdk_colormap_new( visual
, TRUE
);
400 gtk_widget_push_colormap( colormap
);
401 gtk_widget_push_visual( visual
);
403 wxWindow::Create( parent
, id
, pos
, size
, style
, name
);
405 m_glWidget
= m_wxwindow
;
408 gtk_widget_set_double_buffered( m_glWidget
, FALSE
);
411 gtk_pizza_set_clear( GTK_PIZZA(m_wxwindow
), FALSE
);
413 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
414 GTK_SIGNAL_FUNC(gtk_glwindow_realized_callback
), (gpointer
) this );
416 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "map",
417 GTK_SIGNAL_FUNC(gtk_glwindow_map_callback
), (gpointer
) this );
419 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
420 GTK_SIGNAL_FUNC(gtk_glwindow_expose_callback
), (gpointer
)this );
423 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
424 GTK_SIGNAL_FUNC(gtk_glwindow_draw_callback
), (gpointer
)this );
427 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_allocate",
428 GTK_SIGNAL_FUNC(gtk_glcanvas_size_callback
), (gpointer
)this );
430 gtk_widget_pop_visual();
431 gtk_widget_pop_colormap();
433 // if our parent window is already visible, we had been realized before we
434 // connected to the "realize" signal and hence our m_glContext hasn't been
435 // initialized yet and we have to do it now
436 if (GTK_WIDGET_REALIZED(m_wxwindow
))
437 gtk_glwindow_realized_callback( m_wxwindow
, this );
439 if (GTK_WIDGET_MAPPED(m_wxwindow
))
440 gtk_glwindow_map_callback( m_wxwindow
, this );
445 wxGLCanvas::~wxGLCanvas()
447 GLXFBConfig
* fbc
= (GLXFBConfig
*) m_fbc
;
448 if (fbc
&& m_canFreeFBC
) XFree( fbc
);
450 XVisualInfo
*vi
= (XVisualInfo
*) m_vi
;
451 if (vi
&& m_canFreeVi
) XFree( vi
);
456 void* wxGLCanvas::ChooseGLVisual(int *attribList
)
459 GetGLAttribListFromWX( attribList
, data
);
460 attribList
= (int*) data
;
462 Display
*dpy
= GDK_DISPLAY();
464 return glXChooseVisual( dpy
, DefaultScreen(dpy
), attribList
);
467 void* wxGLCanvas::ChooseGLFBC(int *attribList
)
470 GetGLAttribListFromWX( attribList
, data
);
471 attribList
= (int*) data
;
474 return glXChooseFBConfig( GDK_DISPLAY(), DefaultScreen(GDK_DISPLAY()),
475 attribList
, &returned
);
479 void wxGLCanvas::GetGLAttribListFromWX(int *wx_attribList
, int *gl_attribList
)
483 if (wxGLCanvas::GetGLXVersion() >= 13)
484 // leave GLX >= 1.3 choose the default attributes
485 gl_attribList
[0] = 0;
489 // default settings if attriblist = 0
490 gl_attribList
[i
++] = GLX_RGBA
;
491 gl_attribList
[i
++] = GLX_DOUBLEBUFFER
;
492 gl_attribList
[i
++] = GLX_DEPTH_SIZE
; gl_attribList
[i
++] = 1;
493 gl_attribList
[i
++] = GLX_RED_SIZE
; gl_attribList
[i
++] = 1;
494 gl_attribList
[i
++] = GLX_GREEN_SIZE
; gl_attribList
[i
++] = 1;
495 gl_attribList
[i
++] = GLX_BLUE_SIZE
; gl_attribList
[i
++] = 1;
496 gl_attribList
[i
++] = GLX_ALPHA_SIZE
; gl_attribList
[i
++] = 0;
497 gl_attribList
[i
++] = None
;
503 while( (wx_attribList
[arg
]!=0) && (p
<510) )
505 switch( wx_attribList
[arg
++] )
508 if (wxGLCanvas::GetGLXVersion() <= 12)
509 // for GLX >= 1.3, GLX_RGBA is useless (setting this flags will crash on most opengl implm)
510 gl_attribList
[p
++] = GLX_RGBA
;
512 case WX_GL_BUFFER_SIZE
:
513 gl_attribList
[p
++]=GLX_BUFFER_SIZE
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
515 gl_attribList
[p
++]=GLX_LEVEL
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
516 case WX_GL_DOUBLEBUFFER
:
517 if (wxGLCanvas::GetGLXVersion() <= 12)
518 gl_attribList
[p
++] = GLX_DOUBLEBUFFER
;
520 // for GLX >= 1.3, GLX_DOUBLEBUFFER format is different (1 <=> True)
521 // it seems this flag is useless for some hardware opengl implementation.
522 // but for Mesa 6.2.1, this flag is used so don't ignore it.
523 gl_attribList
[p
++] = GLX_DOUBLEBUFFER
; gl_attribList
[p
++]=1;
525 case WX_GL_STEREO
: gl_attribList
[p
++] = GLX_STEREO
; break;
526 case WX_GL_AUX_BUFFERS
:
527 gl_attribList
[p
++]=GLX_AUX_BUFFERS
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
529 gl_attribList
[p
++]=GLX_RED_SIZE
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
530 case WX_GL_MIN_GREEN
:
531 gl_attribList
[p
++]=GLX_GREEN_SIZE
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
533 gl_attribList
[p
++]=GLX_BLUE_SIZE
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
534 case WX_GL_MIN_ALPHA
:
535 gl_attribList
[p
++]=GLX_ALPHA_SIZE
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
536 case WX_GL_DEPTH_SIZE
:
537 gl_attribList
[p
++]=GLX_DEPTH_SIZE
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
538 case WX_GL_STENCIL_SIZE
:
539 gl_attribList
[p
++]=GLX_STENCIL_SIZE
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
540 case WX_GL_MIN_ACCUM_RED
:
541 gl_attribList
[p
++]=GLX_ACCUM_RED_SIZE
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
542 case WX_GL_MIN_ACCUM_GREEN
:
543 gl_attribList
[p
++]=GLX_ACCUM_GREEN_SIZE
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
544 case WX_GL_MIN_ACCUM_BLUE
:
545 gl_attribList
[p
++]=GLX_ACCUM_BLUE_SIZE
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
546 case WX_GL_MIN_ACCUM_ALPHA
:
547 gl_attribList
[p
++]=GLX_ACCUM_ALPHA_SIZE
; gl_attribList
[p
++]=wx_attribList
[arg
++]; break;
552 gl_attribList
[p
] = 0;
556 void wxGLCanvas::QueryGLXVersion()
558 if (m_glxVersion
== 0)
560 // check the GLX version
561 int glxMajorVer
, glxMinorVer
;
562 bool ok
= glXQueryVersion(GDK_DISPLAY(), &glxMajorVer
, &glxMinorVer
);
563 wxASSERT_MSG( ok
, _T("GLX version not found") );
565 m_glxVersion
= 10; // 1.0 by default
567 m_glxVersion
= glxMajorVer
*10 + glxMinorVer
;
571 int wxGLCanvas::GetGLXVersion()
573 wxASSERT_MSG( m_glxVersion
>0, _T("GLX version has not been initialized with wxGLCanvas::QueryGLXVersion()") );
578 void wxGLCanvas::SwapBuffers()
581 m_glContext
->SwapBuffers();
584 void wxGLCanvas::OnSize(wxSizeEvent
& WXUNUSED(event
))
588 void wxGLCanvas::SetCurrent()
591 m_glContext
->SetCurrent();
594 void wxGLCanvas::SetColour( const wxChar
*colour
)
597 m_glContext
->SetColour( colour
);
600 void wxGLCanvas::OnInternalIdle()
602 if (m_glContext
&& m_exposed
)
604 wxPaintEvent
event( GetId() );
605 event
.SetEventObject( this );
606 GetEventHandler()->ProcessEvent( event
);
609 GetUpdateRegion().Clear();
612 wxWindow::OnInternalIdle();
617 //---------------------------------------------------------------------------
619 //---------------------------------------------------------------------------
621 IMPLEMENT_CLASS(wxGLApp
, wxApp
)
628 XFree(m_glVisualInfo
);
631 bool wxGLApp::InitGLVisual(int *attribList
)
633 wxGLCanvas::QueryGLXVersion();
635 if (wxGLCanvas::GetGLXVersion() >= 13)
640 m_glFBCInfo
= wxGLCanvas::ChooseGLFBC(attribList
);
645 XFree(m_glVisualInfo
);
646 m_glVisualInfo
= glXGetVisualFromFBConfig(GDK_DISPLAY(), ((GLXFBConfig
*)m_glFBCInfo
)[0]);
648 return (m_glFBCInfo
!= NULL
) && (m_glVisualInfo
!= NULL
);
654 XFree(m_glVisualInfo
);
655 m_glVisualInfo
= wxGLCanvas::ChooseGLVisual(attribList
);
656 return m_glVisualInfo
!= NULL
;