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
;