added build options sanity checks into all main libraries
[wxWidgets.git] / src / gtk / glcanvas.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/glcanvas.cpp
3 // Purpose: wxGLCanvas, for using OpenGL/Mesa with wxWindows and GTK
4 // Author: Robert Roebling
5 // Modified by:
6 // Created: 17/08/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Robert Roebling
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "glcanvas.h"
14 #endif
15
16 #include "wx/setup.h"
17
18 #if wxUSE_GLCANVAS
19
20 #include "wx/glcanvas.h"
21
22 #include "wx/frame.h"
23 #include "wx/colour.h"
24 #include "wx/module.h"
25 #include "wx/app.h"
26
27 extern "C"
28 {
29 #include "gtk/gtk.h"
30 #include "gdk/gdk.h"
31 #include "gdk/gdkx.h"
32 }
33
34 #include "wx/gtk/win_gtk.h"
35
36 // DLL options compatibility check:
37 #include "wx/build.h"
38 WX_CHECK_BUILD_OPTIONS("wxGL")
39
40 //---------------------------------------------------------------------------
41 // global data
42 //---------------------------------------------------------------------------
43
44 XVisualInfo *g_vi = (XVisualInfo*) NULL;
45
46 //-----------------------------------------------------------------------------
47 // idle system
48 //-----------------------------------------------------------------------------
49
50 extern void wxapp_install_idle_handler();
51 extern bool g_isIdle;
52
53 //---------------------------------------------------------------------------
54 // wxGLContext
55 //---------------------------------------------------------------------------
56
57 IMPLEMENT_CLASS(wxGLContext,wxObject)
58
59 wxGLContext::wxGLContext( bool WXUNUSED(isRGB), wxWindow *win, const wxPalette& WXUNUSED(palette) )
60 {
61 m_window = win;
62 m_widget = win->m_wxwindow;
63
64 wxGLCanvas *gc = (wxGLCanvas*) win;
65 XVisualInfo *vi = (XVisualInfo *) gc->m_vi;
66
67 wxCHECK_RET( vi, _T("invalid visual for OpenGl") );
68
69 m_glContext = glXCreateContext( GDK_DISPLAY(), vi, None, GL_TRUE );
70
71 wxCHECK_RET( m_glContext, _T("Couldn't create OpenGl context") );
72 }
73
74 wxGLContext::wxGLContext(
75 bool WXUNUSED(isRGB), wxWindow *win,
76 const wxPalette& WXUNUSED(palette),
77 const wxGLContext *other /* for sharing display lists */
78 )
79 {
80 m_window = win;
81 m_widget = win->m_wxwindow;
82
83 wxGLCanvas *gc = (wxGLCanvas*) win;
84 XVisualInfo *vi = (XVisualInfo *) gc->m_vi;
85
86 wxCHECK_RET( vi, _T("invalid visual for OpenGl") );
87
88 m_glContext = glXCreateContext( GDK_DISPLAY(), vi,
89 other ? other->m_glContext : None,
90 GL_TRUE );
91
92 if ( !m_glContext )
93 {
94 wxFAIL_MSG( _T("Couldn't create OpenGl context") );
95 }
96 }
97
98 wxGLContext::~wxGLContext()
99 {
100 if (!m_glContext) return;
101
102 if (m_glContext == glXGetCurrentContext())
103 {
104 glXMakeCurrent( GDK_DISPLAY(), None, NULL);
105 }
106
107 glXDestroyContext( GDK_DISPLAY(), m_glContext );
108 }
109
110 void wxGLContext::SwapBuffers()
111 {
112 if (m_glContext)
113 {
114 GdkWindow *window = GTK_PIZZA(m_widget)->bin_window;
115 glXSwapBuffers( GDK_DISPLAY(), GDK_WINDOW_XWINDOW( window ) );
116 }
117 }
118
119 void wxGLContext::SetCurrent()
120 {
121 if (m_glContext)
122 {
123 GdkWindow *window = GTK_PIZZA(m_widget)->bin_window;
124 glXMakeCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window), m_glContext );
125 }
126 }
127
128 void wxGLContext::SetColour(const wxChar *colour)
129 {
130 float r = 0.0;
131 float g = 0.0;
132 float b = 0.0;
133 wxColour *col = wxTheColourDatabase->FindColour(colour);
134 if (col)
135 {
136 r = (float)(col->Red()/256.0);
137 g = (float)(col->Green()/256.0);
138 b = (float)(col->Blue()/256.0);
139 glColor3f( r, g, b);
140 }
141 }
142
143 void wxGLContext::SetupPixelFormat()
144 {
145 }
146
147 void wxGLContext::SetupPalette( const wxPalette& WXUNUSED(palette) )
148 {
149 }
150
151 wxPalette wxGLContext::CreateDefaultPalette()
152 {
153 return wxNullPalette;
154 }
155
156 //-----------------------------------------------------------------------------
157 // "realize" from m_wxwindow
158 //-----------------------------------------------------------------------------
159
160 static gint
161 gtk_glwindow_realized_callback( GtkWidget * WXUNUSED(widget), wxGLCanvas *win )
162 {
163 wxGLContext *share= win->m_sharedContext;
164 if (share==NULL && win->m_sharedContextOf) share=win->m_sharedContextOf->GetContext();
165
166 win->m_glContext = new wxGLContext( TRUE, win, wxNullPalette, share );
167
168 return FALSE;
169 }
170
171 //-----------------------------------------------------------------------------
172 // "map" from m_wxwindow
173 //-----------------------------------------------------------------------------
174
175 static gint
176 gtk_glwindow_map_callback( GtkWidget * WXUNUSED(widget), wxGLCanvas *win )
177 {
178 if (win->m_glContext/* && win->m_exposed*/)
179 {
180 wxPaintEvent event( win->GetId() );
181 event.SetEventObject( win );
182 win->GetEventHandler()->ProcessEvent( event );
183
184 win->m_exposed = FALSE;
185 win->GetUpdateRegion().Clear();
186 }
187
188 return FALSE;
189 }
190
191 //-----------------------------------------------------------------------------
192 // "expose_event" of m_wxwindow
193 //-----------------------------------------------------------------------------
194
195 static void
196 gtk_glwindow_expose_callback( GtkWidget *WXUNUSED(widget), GdkEventExpose *gdk_event, wxGLCanvas *win )
197 {
198 if (g_isIdle)
199 wxapp_install_idle_handler();
200
201 win->m_exposed = TRUE;
202
203 win->GetUpdateRegion().Union( gdk_event->area.x,
204 gdk_event->area.y,
205 gdk_event->area.width,
206 gdk_event->area.height );
207 }
208
209 //-----------------------------------------------------------------------------
210 // "draw" of m_wxwindow
211 //-----------------------------------------------------------------------------
212
213 #ifndef __WXGTK20__
214 static void
215 gtk_glwindow_draw_callback( GtkWidget *WXUNUSED(widget), GdkRectangle *rect, wxGLCanvas *win )
216 {
217 if (g_isIdle)
218 wxapp_install_idle_handler();
219
220 win->m_exposed = TRUE;
221
222 win->GetUpdateRegion().Union( rect->x, rect->y,
223 rect->width, rect->height );
224 }
225 #endif
226
227 //-----------------------------------------------------------------------------
228 // "size_allocate" of m_wxwindow
229 //-----------------------------------------------------------------------------
230
231 static void
232 gtk_glcanvas_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxGLCanvas *win )
233 {
234 if (g_isIdle)
235 wxapp_install_idle_handler();
236
237 if (!win->m_hasVMT)
238 return;
239
240 wxSizeEvent event( wxSize(win->m_width,win->m_height), win->GetId() );
241 event.SetEventObject( win );
242 win->GetEventHandler()->ProcessEvent( event );
243 }
244
245 //---------------------------------------------------------------------------
246 // wxGlCanvas
247 //---------------------------------------------------------------------------
248
249 IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
250
251 BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
252 EVT_SIZE(wxGLCanvas::OnSize)
253 END_EVENT_TABLE()
254
255 wxGLCanvas::wxGLCanvas( wxWindow *parent, wxWindowID id,
256 const wxPoint& pos, const wxSize& size,
257 long style, const wxString& name,
258 int *attribList,
259 const wxPalette& palette )
260 {
261 Create( parent, NULL, NULL, id, pos, size, style, name, attribList, palette );
262 }
263
264 wxGLCanvas::wxGLCanvas( wxWindow *parent,
265 const wxGLContext *shared,
266 wxWindowID id,
267 const wxPoint& pos, const wxSize& size,
268 long style, const wxString& name,
269 int *attribList,
270 const wxPalette& palette )
271 {
272 Create( parent, shared, NULL, id, pos, size, style, name, attribList, palette );
273 }
274
275 wxGLCanvas::wxGLCanvas( wxWindow *parent,
276 const wxGLCanvas *shared,
277 wxWindowID id,
278 const wxPoint& pos, const wxSize& size,
279 long style, const wxString& name,
280 int *attribList,
281 const wxPalette& palette )
282 {
283 Create( parent, NULL, shared, id, pos, size, style, name, attribList, palette );
284 }
285
286 bool wxGLCanvas::Create( wxWindow *parent,
287 const wxGLContext *shared,
288 const wxGLCanvas *shared_context_of,
289 wxWindowID id,
290 const wxPoint& pos, const wxSize& size,
291 long style, const wxString& name,
292 int *attribList,
293 const wxPalette& palette)
294 {
295 m_sharedContext = (wxGLContext*)shared; // const_cast
296 m_sharedContextOf = (wxGLCanvas*)shared_context_of; // const_cast
297 m_glContext = (wxGLContext*) NULL;
298
299 m_exposed = FALSE;
300 m_noExpose = TRUE;
301 m_nativeSizeEvent = TRUE;
302
303 XVisualInfo *vi = NULL;
304 if (wxTheApp->m_glVisualInfo != NULL)
305 {
306 vi = (XVisualInfo *) wxTheApp->m_glVisualInfo;
307 m_canFreeVi = FALSE; // owned by wxTheApp - don't free upon destruction
308 }
309 else
310 {
311 vi = (XVisualInfo *) ChooseGLVisual(attribList);
312 m_canFreeVi = TRUE;
313 }
314 m_vi = vi; // save for later use
315
316 wxCHECK_MSG( m_vi, FALSE, _T("required visual couldn't be found") );
317
318 GdkVisual *visual = gdkx_visual_get( vi->visualid );
319 GdkColormap *colormap = gdk_colormap_new( gdkx_visual_get(vi->visualid), TRUE );
320
321 gtk_widget_push_colormap( colormap );
322 gtk_widget_push_visual( visual );
323
324 wxWindow::Create( parent, id, pos, size, style, name );
325
326 m_glWidget = m_wxwindow;
327
328 #ifdef __WXGTK20__
329 gtk_widget_set_double_buffered( m_glWidget, FALSE );
330 #endif
331
332 gtk_pizza_set_clear( GTK_PIZZA(m_wxwindow), FALSE );
333
334 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
335 GTK_SIGNAL_FUNC(gtk_glwindow_realized_callback), (gpointer) this );
336
337 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "map",
338 GTK_SIGNAL_FUNC(gtk_glwindow_map_callback), (gpointer) this );
339
340 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
341 GTK_SIGNAL_FUNC(gtk_glwindow_expose_callback), (gpointer)this );
342
343 #ifndef __WXGTK20__
344 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
345 GTK_SIGNAL_FUNC(gtk_glwindow_draw_callback), (gpointer)this );
346 #endif
347
348 gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate",
349 GTK_SIGNAL_FUNC(gtk_glcanvas_size_callback), (gpointer)this );
350
351 gtk_widget_pop_visual();
352 gtk_widget_pop_colormap();
353
354 if (GTK_WIDGET_REALIZED(m_wxwindow))
355 gtk_glwindow_realized_callback( m_wxwindow, this );
356
357 if (GTK_WIDGET_MAPPED(m_wxwindow))
358 gtk_glwindow_map_callback( m_wxwindow, this );
359
360 return TRUE;
361 }
362
363 wxGLCanvas::~wxGLCanvas()
364 {
365 XVisualInfo *vi = (XVisualInfo *) m_vi;
366
367 if (vi && m_canFreeVi) XFree( vi );
368 if (m_glContext) delete m_glContext;
369 }
370
371 void* wxGLCanvas::ChooseGLVisual(int *attribList)
372 {
373 int data[512];
374 if (!attribList)
375 {
376 // default settings if attriblist = 0
377 data[0] = GLX_RGBA;
378 data[1] = GLX_DOUBLEBUFFER;
379 data[2] = GLX_DEPTH_SIZE; data[3] = 1;
380 data[4] = GLX_RED_SIZE; data[5] = 1;
381 data[6] = GLX_GREEN_SIZE; data[7] = 1;
382 data[8] = GLX_BLUE_SIZE; data[9] = 1;
383 data[10] = GLX_ALPHA_SIZE; data[11] = 0;
384 data[12] = None;
385
386 attribList = (int*) data;
387 }
388 else
389 {
390 int arg=0, p=0;
391
392 while( (attribList[arg]!=0) && (p<510) )
393 {
394 switch( attribList[arg++] )
395 {
396 case WX_GL_RGBA: data[p++] = GLX_RGBA; break;
397 case WX_GL_BUFFER_SIZE:
398 data[p++]=GLX_BUFFER_SIZE; data[p++]=attribList[arg++]; break;
399 case WX_GL_LEVEL:
400 data[p++]=GLX_LEVEL; data[p++]=attribList[arg++]; break;
401 case WX_GL_DOUBLEBUFFER: data[p++] = GLX_DOUBLEBUFFER; break;
402 case WX_GL_STEREO: data[p++] = GLX_STEREO; break;
403 case WX_GL_AUX_BUFFERS:
404 data[p++]=GLX_AUX_BUFFERS; data[p++]=attribList[arg++]; break;
405 case WX_GL_MIN_RED:
406 data[p++]=GLX_RED_SIZE; data[p++]=attribList[arg++]; break;
407 case WX_GL_MIN_GREEN:
408 data[p++]=GLX_GREEN_SIZE; data[p++]=attribList[arg++]; break;
409 case WX_GL_MIN_BLUE:
410 data[p++]=GLX_BLUE_SIZE; data[p++]=attribList[arg++]; break;
411 case WX_GL_MIN_ALPHA:
412 data[p++]=GLX_ALPHA_SIZE; data[p++]=attribList[arg++]; break;
413 case WX_GL_DEPTH_SIZE:
414 data[p++]=GLX_DEPTH_SIZE; data[p++]=attribList[arg++]; break;
415 case WX_GL_STENCIL_SIZE:
416 data[p++]=GLX_STENCIL_SIZE; data[p++]=attribList[arg++]; break;
417 case WX_GL_MIN_ACCUM_RED:
418 data[p++]=GLX_ACCUM_RED_SIZE; data[p++]=attribList[arg++]; break;
419 case WX_GL_MIN_ACCUM_GREEN:
420 data[p++]=GLX_ACCUM_GREEN_SIZE; data[p++]=attribList[arg++]; break;
421 case WX_GL_MIN_ACCUM_BLUE:
422 data[p++]=GLX_ACCUM_BLUE_SIZE; data[p++]=attribList[arg++]; break;
423 case WX_GL_MIN_ACCUM_ALPHA:
424 data[p++]=GLX_ACCUM_ALPHA_SIZE; data[p++]=attribList[arg++]; break;
425 default:
426 break;
427 }
428 }
429 data[p] = 0;
430
431 attribList = (int*) data;
432 }
433
434
435 Display *dpy = GDK_DISPLAY();
436
437 return glXChooseVisual( dpy, DefaultScreen(dpy), attribList );
438 }
439
440 void wxGLCanvas::SwapBuffers()
441 {
442 if (m_glContext)
443 m_glContext->SwapBuffers();
444 }
445
446 void wxGLCanvas::OnSize(wxSizeEvent& WXUNUSED(event))
447 {
448 }
449
450 void wxGLCanvas::SetCurrent()
451 {
452 if (m_glContext)
453 m_glContext->SetCurrent();
454 }
455
456 void wxGLCanvas::SetColour( const wxChar *colour )
457 {
458 if (m_glContext)
459 m_glContext->SetColour( colour );
460 }
461
462 void wxGLCanvas::OnInternalIdle()
463 {
464 if (m_glContext && m_exposed)
465 {
466 wxPaintEvent event( GetId() );
467 event.SetEventObject( this );
468 GetEventHandler()->ProcessEvent( event );
469
470 m_exposed = FALSE;
471 GetUpdateRegion().Clear();
472 }
473
474 wxWindow::OnInternalIdle();
475 }
476
477
478
479 //---------------------------------------------------------------------------
480 // wxGLApp
481 //---------------------------------------------------------------------------
482
483 IMPLEMENT_CLASS(wxGLApp, wxApp)
484
485 wxGLApp::~wxGLApp()
486 {
487 if (m_glVisualInfo)
488 XFree(m_glVisualInfo);
489 }
490
491 bool wxGLApp::InitGLVisual(int *attribList)
492 {
493 if (m_glVisualInfo)
494 XFree(m_glVisualInfo);
495
496 m_glVisualInfo = wxGLCanvas::ChooseGLVisual(attribList);
497
498 return m_glVisualInfo != NULL;
499 }
500
501 #endif
502 // wxUSE_GLCANVAS
503