1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/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 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
17 #include "wx/glcanvas.h"
24 #include "wx/colour.h"
25 #include "wx/module.h"
34 #include "wx/gtk1/win_gtk.h"
36 // DLL options compatibility check:
38 WX_CHECK_BUILD_OPTIONS("wxGL")
41 //---------------------------------------------------------------------------
43 //---------------------------------------------------------------------------
44 int wxGLCanvas::m_glxVersion
= 0;
46 //---------------------------------------------------------------------------
48 //---------------------------------------------------------------------------
50 XVisualInfo
*g_vi
= (XVisualInfo
*) NULL
;
51 //-----------------------------------------------------------------------------
53 //-----------------------------------------------------------------------------
55 extern void wxapp_install_idle_handler();
58 //---------------------------------------------------------------------------
60 //---------------------------------------------------------------------------
62 IMPLEMENT_CLASS(wxGLContext
,wxObject
)
64 wxGLContext::wxGLContext( bool WXUNUSED(isRGB
), wxWindow
*win
, const wxPalette
& WXUNUSED(palette
) )
67 m_widget
= win
->m_wxwindow
;
69 wxGLCanvas
*gc
= (wxGLCanvas
*) win
;
71 if (wxGLCanvas::GetGLXVersion() >= 13)
74 GLXFBConfig
*fbc
= gc
->m_fbc
;
75 wxCHECK_RET( fbc
, _T("invalid GLXFBConfig for OpenGl") );
76 m_glContext
= glXCreateNewContext( GDK_DISPLAY(), fbc
[0], GLX_RGBA_TYPE
, None
, GL_TRUE
);
81 XVisualInfo
*vi
= (XVisualInfo
*) gc
->m_vi
;
82 wxCHECK_RET( vi
, _T("invalid visual for OpenGl") );
83 m_glContext
= glXCreateContext( GDK_DISPLAY(), vi
, None
, GL_TRUE
);
86 wxCHECK_RET( m_glContext
, _T("Couldn't create OpenGl context") );
89 wxGLContext::wxGLContext(
90 bool WXUNUSED(isRGB
), wxWindow
*win
,
91 const wxPalette
& WXUNUSED(palette
),
92 const wxGLContext
*other
/* for sharing display lists */
96 m_widget
= win
->m_wxwindow
;
98 wxGLCanvas
*gc
= (wxGLCanvas
*) win
;
100 if (wxGLCanvas::GetGLXVersion() >= 13)
103 GLXFBConfig
*fbc
= gc
->m_fbc
;
104 wxCHECK_RET( fbc
, _T("invalid GLXFBConfig for OpenGl") );
105 m_glContext
= glXCreateNewContext( GDK_DISPLAY(), fbc
[0], GLX_RGBA_TYPE
,
106 other
? other
->m_glContext
: None
,
112 XVisualInfo
*vi
= (XVisualInfo
*) gc
->m_vi
;
113 wxCHECK_RET( vi
, _T("invalid visual for OpenGl") );
114 m_glContext
= glXCreateContext( GDK_DISPLAY(), vi
,
115 other
? other
->m_glContext
: None
,
121 wxFAIL_MSG( _T("Couldn't create OpenGl context") );
125 wxGLContext::~wxGLContext()
127 if (!m_glContext
) return;
129 if (m_glContext
== glXGetCurrentContext())
131 if (wxGLCanvas::GetGLXVersion() >= 13)
133 glXMakeContextCurrent( GDK_DISPLAY(), None
, None
, NULL
);
136 glXMakeCurrent( GDK_DISPLAY(), None
, NULL
);
139 glXDestroyContext( GDK_DISPLAY(), m_glContext
);
142 void wxGLContext::SwapBuffers()
146 GdkWindow
*window
= GTK_PIZZA(m_widget
)->bin_window
;
147 glXSwapBuffers( GDK_DISPLAY(), GDK_WINDOW_XWINDOW( window
) );
151 void wxGLContext::SetCurrent()
155 GdkWindow
*window
= GTK_PIZZA(m_widget
)->bin_window
;
157 if (wxGLCanvas::GetGLXVersion() >= 13)
159 glXMakeContextCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window
),
160 GDK_WINDOW_XWINDOW(window
), m_glContext
);
163 glXMakeCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window
), m_glContext
);
167 void wxGLContext::SetColour(const wxChar
*colour
)
169 wxColour col
= wxTheColourDatabase
->Find(colour
);
172 float r
= (float)(col
.Red()/256.0);
173 float g
= (float)(col
.Green()/256.0);
174 float b
= (float)(col
.Blue()/256.0);
179 void wxGLContext::SetupPixelFormat()
183 void wxGLContext::SetupPalette( const wxPalette
& WXUNUSED(palette
) )
187 wxPalette
wxGLContext::CreateDefaultPalette()
189 return wxNullPalette
;
192 //-----------------------------------------------------------------------------
193 // "realize" from m_wxwindow
194 //-----------------------------------------------------------------------------
198 gtk_glwindow_realized_callback( GtkWidget
*WXUNUSED(widget
), wxGLCanvas
*win
)
200 if ( !win
->m_glContext
)
202 wxGLContext
*share
= win
->m_sharedContext
;
203 if ( !share
&& win
->m_sharedContextOf
)
204 share
= win
->m_sharedContextOf
->GetContext();
206 win
->m_glContext
= new wxGLContext( TRUE
, win
, wxNullPalette
, share
);
213 //-----------------------------------------------------------------------------
214 // "map" from m_wxwindow
215 //-----------------------------------------------------------------------------
219 gtk_glwindow_map_callback( GtkWidget
* WXUNUSED(widget
), wxGLCanvas
*win
)
221 if (win
->m_glContext
/* && win->m_exposed*/)
223 wxPaintEvent
event( win
->GetId() );
224 event
.SetEventObject( win
);
225 win
->GetEventHandler()->ProcessEvent( event
);
227 win
->m_exposed
= false;
228 win
->GetUpdateRegion().Clear();
235 //-----------------------------------------------------------------------------
236 // "expose_event" of m_wxwindow
237 //-----------------------------------------------------------------------------
241 gtk_glwindow_expose_callback( GtkWidget
*WXUNUSED(widget
), GdkEventExpose
*gdk_event
, wxGLCanvas
*win
)
244 wxapp_install_idle_handler();
246 win
->m_exposed
= true;
248 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
250 gdk_event
->area
.width
,
251 gdk_event
->area
.height
);
255 //-----------------------------------------------------------------------------
256 // "draw" of m_wxwindow
257 //-----------------------------------------------------------------------------
261 gtk_glwindow_draw_callback( GtkWidget
*WXUNUSED(widget
), GdkRectangle
*rect
, wxGLCanvas
*win
)
264 wxapp_install_idle_handler();
266 win
->m_exposed
= true;
268 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
,
269 rect
->width
, rect
->height
);
273 //-----------------------------------------------------------------------------
274 // "size_allocate" of m_wxwindow
275 //-----------------------------------------------------------------------------
279 gtk_glcanvas_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxGLCanvas
*win
)
282 wxapp_install_idle_handler();
287 wxSizeEvent
event( wxSize(win
->m_width
,win
->m_height
), win
->GetId() );
288 event
.SetEventObject( win
);
289 win
->GetEventHandler()->ProcessEvent( event
);
293 //---------------------------------------------------------------------------
295 //---------------------------------------------------------------------------
297 IMPLEMENT_CLASS(wxGLCanvas
, wxWindow
)
299 BEGIN_EVENT_TABLE(wxGLCanvas
, wxWindow
)
300 EVT_SIZE(wxGLCanvas::OnSize
)
303 wxGLCanvas::wxGLCanvas( wxWindow
*parent
, wxWindowID id
,
304 const wxPoint
& pos
, const wxSize
& size
,
305 long style
, const wxString
& name
,
307 const wxPalette
& palette
)
309 Create( parent
, NULL
, NULL
, id
, pos
, size
, style
, name
, attribList
, palette
);
312 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
313 const wxGLContext
*shared
,
315 const wxPoint
& pos
, const wxSize
& size
,
316 long style
, const wxString
& name
,
318 const wxPalette
& palette
)
320 Create( parent
, shared
, NULL
, id
, pos
, size
, style
, name
, attribList
, palette
);
323 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
324 const wxGLCanvas
*shared
,
326 const wxPoint
& pos
, const wxSize
& size
,
327 long style
, const wxString
& name
,
329 const wxPalette
& palette
)
331 Create( parent
, NULL
, shared
, id
, pos
, size
, style
, name
, attribList
, palette
);
334 bool wxGLCanvas::Create( wxWindow
*parent
,
335 const wxGLContext
*shared
,
336 const wxGLCanvas
*shared_context_of
,
338 const wxPoint
& pos
, const wxSize
& size
,
339 long style
, const wxString
& name
,
341 const wxPalette
& palette
)
343 m_sharedContext
= (wxGLContext
*)shared
; // const_cast
344 m_sharedContextOf
= (wxGLCanvas
*)shared_context_of
; // const_cast
345 m_glContext
= (wxGLContext
*) NULL
;
349 m_nativeSizeEvent
= true;
353 // to be sure the glx version is known
354 wxGLCanvas::QueryGLXVersion();
356 if (wxGLCanvas::GetGLXVersion() >= 13)
358 // GLX >= 1.3 uses a GLXFBConfig
359 GLXFBConfig
* fbc
= NULL
;
360 if (wxTheApp
->m_glFBCInfo
!= NULL
)
362 fbc
= (GLXFBConfig
*) wxTheApp
->m_glFBCInfo
;
363 m_canFreeFBC
= false; // owned by wxTheApp - don't free upon destruction
367 fbc
= (GLXFBConfig
*) wxGLCanvas::ChooseGLFBC(attribList
);
370 m_fbc
= fbc
; // save for later use
371 wxCHECK_MSG( m_fbc
, false, _T("required FBConfig couldn't be found") );
374 XVisualInfo
*vi
= NULL
;
375 if (wxTheApp
->m_glVisualInfo
!= NULL
)
377 vi
= (XVisualInfo
*)wxTheApp
->m_glVisualInfo
;
378 m_canFreeVi
= false; // owned by wxTheApp - don't free upon destruction
382 if (wxGLCanvas::GetGLXVersion() >= 13)
384 vi
= glXGetVisualFromFBConfig(GDK_DISPLAY(), m_fbc
[0]);
387 vi
= (XVisualInfo
*) ChooseGLVisual(attribList
);
392 m_vi
= vi
; // save for later use
394 wxCHECK_MSG( m_vi
, false, _T("required visual couldn't be found") );
396 GdkColormap
*colormap
;
398 // MR: This needs a fix for lower gtk+ versions too. Might need to rethink logic (FIXME)
400 if (!gtk_check_version(2,2,0))
402 wxWindow::Create( parent
, id
, pos
, size
, style
, name
);
404 m_glWidget
= m_wxwindow
;
406 GdkScreen
*screen
= gtk_widget_get_screen( m_glWidget
);
407 colormap
= gdk_screen_get_default_colormap(screen
);
408 visual
= gdk_colormap_get_visual(colormap
);
410 if (GDK_VISUAL_XVISUAL(visual
)->visualid
!= vi
->visualid
)
412 visual
= gdk_x11_screen_lookup_visual( screen
, vi
->visualid
);
413 colormap
= gdk_colormap_new(visual
, FALSE
);
416 gtk_widget_set_colormap( m_glWidget
, colormap
);
421 visual
= gdkx_visual_get( vi
->visualid
);
422 colormap
= gdk_colormap_new( visual
, TRUE
);
424 gtk_widget_push_colormap( colormap
);
425 gtk_widget_push_visual( visual
);
427 wxWindow::Create( parent
, id
, pos
, size
, style
, name
);
428 m_glWidget
= m_wxwindow
;
431 gtk_pizza_set_clear( GTK_PIZZA(m_wxwindow
), FALSE
);
433 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
434 GTK_SIGNAL_FUNC(gtk_glwindow_realized_callback
), (gpointer
) this );
436 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "map",
437 GTK_SIGNAL_FUNC(gtk_glwindow_map_callback
), (gpointer
) this );
439 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
440 GTK_SIGNAL_FUNC(gtk_glwindow_expose_callback
), (gpointer
)this );
442 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
443 GTK_SIGNAL_FUNC(gtk_glwindow_draw_callback
), (gpointer
)this );
445 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_allocate",
446 GTK_SIGNAL_FUNC(gtk_glcanvas_size_callback
), (gpointer
)this );
448 gtk_widget_pop_visual();
449 gtk_widget_pop_colormap();
451 // if our parent window is already visible, we had been realized before we
452 // connected to the "realize" signal and hence our m_glContext hasn't been
453 // initialized yet and we have to do it now
454 if (GTK_WIDGET_REALIZED(m_wxwindow
))
455 gtk_glwindow_realized_callback( m_wxwindow
, this );
457 if (GTK_WIDGET_MAPPED(m_wxwindow
))
458 gtk_glwindow_map_callback( m_wxwindow
, this );
463 wxGLCanvas::~wxGLCanvas()
465 GLXFBConfig
* fbc
= (GLXFBConfig
*) m_fbc
;
466 if (fbc
&& m_canFreeFBC
)
469 XVisualInfo
*vi
= (XVisualInfo
*) m_vi
;
470 if (vi
&& m_canFreeVi
)
476 void* wxGLCanvas::ChooseGLVisual(int *attribList
)
479 GetGLAttribListFromWX( attribList
, data
);
480 attribList
= (int*) data
;
482 Display
*dpy
= GDK_DISPLAY();
484 return glXChooseVisual( dpy
, DefaultScreen(dpy
), attribList
);
487 void* wxGLCanvas::ChooseGLFBC(int *attribList
)
490 GetGLAttribListFromWX( attribList
, data
);
491 attribList
= (int*) data
;
494 return glXChooseFBConfig( GDK_DISPLAY(), DefaultScreen(GDK_DISPLAY()),
495 attribList
, &returned
);
499 void wxGLCanvas::GetGLAttribListFromWX(int *wx_attribList
, int *gl_attribList
)
503 if (wxGLCanvas::GetGLXVersion() >= 13)
504 // leave GLX >= 1.3 choose the default attributes
505 gl_attribList
[0] = 0;
509 // default settings if attriblist = 0
510 gl_attribList
[i
++] = GLX_RGBA
;
511 gl_attribList
[i
++] = GLX_DOUBLEBUFFER
;
512 gl_attribList
[i
++] = GLX_DEPTH_SIZE
; gl_attribList
[i
++] = 1;
513 gl_attribList
[i
++] = GLX_RED_SIZE
; gl_attribList
[i
++] = 1;
514 gl_attribList
[i
++] = GLX_GREEN_SIZE
; gl_attribList
[i
++] = 1;
515 gl_attribList
[i
++] = GLX_BLUE_SIZE
; gl_attribList
[i
++] = 1;
516 gl_attribList
[i
++] = GLX_ALPHA_SIZE
; gl_attribList
[i
++] = 0;
517 gl_attribList
[i
++] = None
;
523 while( (wx_attribList
[arg
]!=0) && (p
<510) )
525 switch( wx_attribList
[arg
++] )
528 if (wxGLCanvas::GetGLXVersion() <= 12)
529 // for GLX >= 1.3, GLX_RGBA is useless (setting this flags will crash on most opengl implm)
530 gl_attribList
[p
++] = GLX_RGBA
;
532 case WX_GL_BUFFER_SIZE
:
533 gl_attribList
[p
++] = GLX_BUFFER_SIZE
;
534 gl_attribList
[p
++] = wx_attribList
[arg
++];
537 gl_attribList
[p
++] = GLX_LEVEL
;
538 gl_attribList
[p
++] = wx_attribList
[arg
++];
540 case WX_GL_DOUBLEBUFFER
:
541 if (wxGLCanvas::GetGLXVersion() <= 12)
542 gl_attribList
[p
++] = GLX_DOUBLEBUFFER
;
544 // for GLX >= 1.3, GLX_DOUBLEBUFFER format is different (1 <=> True)
545 // it seems this flag is useless for some hardware opengl implementation.
546 // but for Mesa 6.2.1, this flag is used so don't ignore it.
547 gl_attribList
[p
++] = GLX_DOUBLEBUFFER
;
548 gl_attribList
[p
++] = 1;
551 gl_attribList
[p
++] = GLX_STEREO
;
553 case WX_GL_AUX_BUFFERS
:
554 gl_attribList
[p
++] = GLX_AUX_BUFFERS
;
555 gl_attribList
[p
++] = wx_attribList
[arg
++];
558 gl_attribList
[p
++] = GLX_RED_SIZE
;
559 gl_attribList
[p
++] = wx_attribList
[arg
++];
561 case WX_GL_MIN_GREEN
:
562 gl_attribList
[p
++] = GLX_GREEN_SIZE
;
563 gl_attribList
[p
++] = wx_attribList
[arg
++];
566 gl_attribList
[p
++] = GLX_BLUE_SIZE
;
567 gl_attribList
[p
++] = wx_attribList
[arg
++];
569 case WX_GL_MIN_ALPHA
:
570 gl_attribList
[p
++] = GLX_ALPHA_SIZE
;
571 gl_attribList
[p
++] = wx_attribList
[arg
++];
573 case WX_GL_DEPTH_SIZE
:
574 gl_attribList
[p
++] = GLX_DEPTH_SIZE
;
575 gl_attribList
[p
++] = wx_attribList
[arg
++];
577 case WX_GL_STENCIL_SIZE
:
578 gl_attribList
[p
++] = GLX_STENCIL_SIZE
;
579 gl_attribList
[p
++] = wx_attribList
[arg
++];
581 case WX_GL_MIN_ACCUM_RED
:
582 gl_attribList
[p
++] = GLX_ACCUM_RED_SIZE
;
583 gl_attribList
[p
++] = wx_attribList
[arg
++];
585 case WX_GL_MIN_ACCUM_GREEN
:
586 gl_attribList
[p
++] = GLX_ACCUM_GREEN_SIZE
;
587 gl_attribList
[p
++] = wx_attribList
[arg
++];
589 case WX_GL_MIN_ACCUM_BLUE
:
590 gl_attribList
[p
++] = GLX_ACCUM_BLUE_SIZE
;
591 gl_attribList
[p
++] = wx_attribList
[arg
++];
593 case WX_GL_MIN_ACCUM_ALPHA
:
594 gl_attribList
[p
++] = GLX_ACCUM_ALPHA_SIZE
;
595 gl_attribList
[p
++] = wx_attribList
[arg
++];
602 gl_attribList
[p
] = 0;
606 void wxGLCanvas::QueryGLXVersion()
608 if (m_glxVersion
== 0)
610 // check the GLX version
611 int glxMajorVer
, glxMinorVer
;
612 bool ok
= glXQueryVersion(GDK_DISPLAY(), &glxMajorVer
, &glxMinorVer
);
613 wxASSERT_MSG( ok
, _T("GLX version not found") );
615 m_glxVersion
= 10; // 1.0 by default
617 m_glxVersion
= glxMajorVer
*10 + glxMinorVer
;
621 int wxGLCanvas::GetGLXVersion()
623 wxASSERT_MSG( m_glxVersion
>0, _T("GLX version has not been initialized with wxGLCanvas::QueryGLXVersion()") );
628 void wxGLCanvas::SwapBuffers()
631 m_glContext
->SwapBuffers();
634 void wxGLCanvas::OnSize(wxSizeEvent
& WXUNUSED(event
))
638 void wxGLCanvas::SetCurrent()
641 m_glContext
->SetCurrent();
644 void wxGLCanvas::SetColour( const wxChar
*colour
)
647 m_glContext
->SetColour( colour
);
650 void wxGLCanvas::OnInternalIdle()
652 if (m_glContext
&& m_exposed
)
654 wxPaintEvent
event( GetId() );
655 event
.SetEventObject( this );
656 GetEventHandler()->ProcessEvent( event
);
659 GetUpdateRegion().Clear();
662 wxWindow::OnInternalIdle();
667 //---------------------------------------------------------------------------
669 //---------------------------------------------------------------------------
671 IMPLEMENT_CLASS(wxGLApp
, wxApp
)
678 XFree(m_glVisualInfo
);
681 bool wxGLApp::InitGLVisual(int *attribList
)
683 wxGLCanvas::QueryGLXVersion();
685 if (wxGLCanvas::GetGLXVersion() >= 13)
690 m_glFBCInfo
= wxGLCanvas::ChooseGLFBC(attribList
);
695 XFree(m_glVisualInfo
);
696 m_glVisualInfo
= glXGetVisualFromFBConfig(GDK_DISPLAY(), ((GLXFBConfig
*)m_glFBCInfo
)[0]);
698 return (m_glFBCInfo
!= NULL
) && (m_glVisualInfo
!= NULL
);
704 XFree(m_glVisualInfo
);
705 m_glVisualInfo
= wxGLCanvas::ChooseGLVisual(attribList
);
706 return m_glVisualInfo
!= NULL
;