]> git.saurik.com Git - wxWidgets.git/blob - src/motif/glcanvas.cpp
added support for animated GIFs to wxHTML
[wxWidgets.git] / src / motif / glcanvas.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: glcanvas.cpp
3 // Purpose: wxGLCanvas, for using OpenGL with wxWindows 2.0 for Motif.
4 // Uses the GLX extension.
5 // Author: Julian Smart and Wolfram Gloger
6 // Modified by:
7 // Created: 1995, 1999
8 // RCS-ID: $Id$
9 // Copyright: (c) Julian Smart, Wolfram Gloger
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 #ifdef __GNUG__
14 #pragma implementation "glcanvas.h"
15 #endif
16
17 #include "wx/setup.h"
18
19 #if wxUSE_GLCANVAS
20
21 #include "wx/glcanvas.h"
22 #include "wx/utils.h"
23 #include "wx/app.h"
24
25 #include <Xm/Xm.h>
26 #include "wx/motif/private.h"
27
28 #ifdef OLD_MESA
29 // workaround for bug in Mesa's glx.c
30 static int bitcount( unsigned long n )
31 {
32 int bits;
33 for (bits=0; n>0;) {
34 if(n & 1) bits++;
35 n = n >> 1;
36 }
37 return bits;
38 }
39 #endif
40
41 /*
42 * GLContext implementation
43 */
44
45 IMPLEMENT_CLASS(wxGLContext,wxObject)
46
47 wxGLContext::wxGLContext( bool WXUNUSED(isRGB), wxWindow *win,
48 const wxPalette& WXUNUSED(palette) )
49 {
50 m_window = win;
51 // m_widget = win->m_wxwindow;
52
53 wxGLCanvas *gc = (wxGLCanvas*) win;
54 XVisualInfo *vi = (XVisualInfo *) gc->m_vi;
55
56 wxCHECK_RET( vi, "invalid visual for OpenGl" );
57
58 m_glContext = glXCreateContext( (Display *)m_window->GetXDisplay(), vi,
59 None, GL_TRUE);
60
61 wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" );
62 }
63
64 wxGLContext::wxGLContext(
65 bool WXUNUSED(isRGB), wxWindow *win,
66 const wxPalette& WXUNUSED(palette),
67 const wxGLContext *other /* for sharing display lists */
68 )
69 {
70 m_window = win;
71 // m_widget = win->m_wxwindow;
72
73 wxGLCanvas *gc = (wxGLCanvas*) win;
74 XVisualInfo *vi = (XVisualInfo *) gc->m_vi;
75
76 wxCHECK_RET( vi, "invalid visual for OpenGl" );
77
78 if( other != 0 )
79 m_glContext = glXCreateContext( (Display *)m_window->GetXDisplay(), vi,
80 other->m_glContext, GL_TRUE );
81 else
82 m_glContext = glXCreateContext( (Display *)m_window->GetXDisplay(), vi,
83 None, GL_TRUE );
84
85 wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" );
86 }
87
88 wxGLContext::~wxGLContext()
89 {
90 if (!m_glContext) return;
91
92 if (m_glContext == glXGetCurrentContext())
93 {
94 glXMakeCurrent( (Display*) m_window->GetXDisplay(), None, NULL);
95 }
96
97 glXDestroyContext( (Display*) m_window->GetXDisplay(), m_glContext );
98 }
99
100 void wxGLContext::SwapBuffers()
101 {
102 if (m_glContext)
103 {
104 Display* display = (Display*) m_window->GetXDisplay();
105 glXSwapBuffers(display, (Window) m_window->GetXWindow());
106 }
107 }
108
109 void wxGLContext::SetCurrent()
110 {
111 if (m_glContext)
112 {
113 Display* display = (Display*) m_window->GetXDisplay();
114 glXMakeCurrent(display, (Window) m_window->GetXWindow(),
115 m_glContext );;
116 }
117 }
118
119 void wxGLContext::SetColour(const char *colour)
120 {
121 wxColour *the_colour = wxTheColourDatabase->FindColour(colour);
122 if(the_colour) {
123 GLboolean b;
124 glGetBooleanv(GL_RGBA_MODE, &b);
125 if(b) {
126 glColor3ub(the_colour->Red(),
127 the_colour->Green(),
128 the_colour->Blue());
129 } else {
130 GLint pix = (GLint)the_colour->m_pixel;
131 if(pix == -1) {
132 XColor exact_def;
133 exact_def.red = (unsigned short)the_colour->Red() << 8;
134 exact_def.green = (unsigned short)the_colour->Green() << 8;
135 exact_def.blue = (unsigned short)the_colour->Blue() << 8;
136 exact_def.flags = DoRed | DoGreen | DoBlue;
137 if(!XAllocColor((Display*) m_window->GetXDisplay(),
138 (Colormap) wxTheApp->GetMainColormap(m_window->GetXDisplay()),
139 &exact_def)) {
140 wxDebugMsg("wxGLCanvas: cannot allocate color\n");
141 return;
142 }
143 pix = the_colour->m_pixel = exact_def.pixel;
144 }
145 glIndexi(pix);
146 }
147 }
148 }
149
150 void wxGLContext::SetupPixelFormat()
151 {
152 }
153
154 void wxGLContext::SetupPalette( const wxPalette& WXUNUSED(palette) )
155 {
156 }
157
158 wxPalette wxGLContext::CreateDefaultPalette()
159 {
160 return wxNullPalette;
161 }
162
163
164
165
166 /*
167 * GLCanvas implementation
168 */
169
170 IMPLEMENT_CLASS(wxGLCanvas, wxScrolledWindow)
171
172 BEGIN_EVENT_TABLE(wxGLCanvas, wxScrolledWindow)
173 // EVT_SIZE(wxGLCanvas::OnSize)
174 END_EVENT_TABLE()
175
176
177 wxGLCanvas::wxGLCanvas( wxWindow *parent, wxWindowID id,
178 const wxPoint& pos, const wxSize& size,
179 long style, const wxString& name,
180 int *attribList,
181 const wxPalette& palette )
182 : wxScrolledWindow(parent, id, pos, size, style, name)
183 {
184 Create( parent, NULL, NULL, id, pos, size, style, name, attribList, palette );
185 }
186
187 wxGLCanvas::wxGLCanvas( wxWindow *parent,
188 const wxGLContext *shared,
189 wxWindowID id,
190 const wxPoint& pos, const wxSize& size,
191 long style, const wxString& name,
192 int *attribList,
193 const wxPalette& palette )
194 : wxScrolledWindow(parent, id, pos, size, style, name)
195 {
196 Create( parent, shared, NULL, id, pos, size, style, name, attribList, palette );
197 }
198
199 wxGLCanvas::wxGLCanvas( wxWindow *parent,
200 const wxGLCanvas *shared,
201 wxWindowID id,
202 const wxPoint& pos, const wxSize& size,
203 long style, const wxString& name,
204 int *attribList,
205 const wxPalette& palette )
206 : wxScrolledWindow(parent, id, pos, size, style, name)
207 {
208 Create( parent, NULL, shared, id, pos, size, style, name, attribList, palette );
209 }
210
211
212 /*
213 bool wxGLCanvas::Create(wxWindow *parent,
214 const wxGLContext *shared, const wxGLCanvas *shared_context_of,
215 wxWindowID id = -1, const wxPoint& pos,
216 const wxSize& size, long style,
217 const wxString& name, int *attribList, const wxPalette& palette):
218 wxScrolledWindow(parent, id, pos, size, style, name)
219 */
220
221 bool wxGLCanvas::Create( wxWindow *parent,
222 const wxGLContext *shared,
223 const wxGLCanvas *shared_context_of,
224 wxWindowID id,
225 const wxPoint& pos, const wxSize& size,
226 long style, const wxString& name,
227 int *attribList,
228 const wxPalette& palette)
229 {
230 XVisualInfo *vi, vi_templ;
231 XWindowAttributes xwa;
232 int val, n;
233
234 m_sharedContext = (wxGLContext*)shared; // const_cast
235 m_sharedContextOf = (wxGLCanvas*)shared_context_of; // const_cast
236 m_glContext = (wxGLContext*) NULL;
237
238 Display* display = (Display*) GetXDisplay();
239
240 // Check for the presence of the GLX extension
241 if(!glXQueryExtension(display, NULL, NULL)) {
242 wxDebugMsg("wxGLCanvas: GLX extension is missing\n");
243 return false;
244 }
245
246 if(attribList) {
247 int data[512], arg=0, p=0;
248
249 while( (attribList[arg]!=0) && (p<512) )
250 {
251 switch( attribList[arg++] )
252 {
253 case WX_GL_RGBA: data[p++] = GLX_RGBA; break;
254 case WX_GL_BUFFER_SIZE:
255 data[p++]=GLX_BUFFER_SIZE; data[p++]=attribList[arg++]; break;
256 case WX_GL_LEVEL:
257 data[p++]=GLX_LEVEL; data[p++]=attribList[arg++]; break;
258 case WX_GL_DOUBLEBUFFER: data[p++] = GLX_DOUBLEBUFFER; break;
259 case WX_GL_STEREO: data[p++] = GLX_STEREO; break;
260 case WX_GL_AUX_BUFFERS:
261 data[p++]=GLX_AUX_BUFFERS; data[p++]=attribList[arg++]; break;
262 case WX_GL_MIN_RED:
263 data[p++]=GLX_RED_SIZE; data[p++]=attribList[arg++]; break;
264 case WX_GL_MIN_GREEN:
265 data[p++]=GLX_GREEN_SIZE; data[p++]=attribList[arg++]; break;
266 case WX_GL_MIN_BLUE:
267 data[p++]=GLX_BLUE_SIZE; data[p++]=attribList[arg++]; break;
268 case WX_GL_MIN_ALPHA:
269 data[p++]=GLX_ALPHA_SIZE; data[p++]=attribList[arg++]; break;
270 case WX_GL_DEPTH_SIZE:
271 data[p++]=GLX_DEPTH_SIZE; data[p++]=attribList[arg++]; break;
272 case WX_GL_STENCIL_SIZE:
273 data[p++]=GLX_STENCIL_SIZE; data[p++]=attribList[arg++]; break;
274 case WX_GL_MIN_ACCUM_RED:
275 data[p++]=GLX_ACCUM_RED_SIZE; data[p++]=attribList[arg++]; break;
276 case WX_GL_MIN_ACCUM_GREEN:
277 data[p++]=GLX_ACCUM_GREEN_SIZE; data[p++]=attribList[arg++]; break;
278 case WX_GL_MIN_ACCUM_BLUE:
279 data[p++]=GLX_ACCUM_BLUE_SIZE; data[p++]=attribList[arg++]; break;
280 case WX_GL_MIN_ACCUM_ALPHA:
281 data[p++]=GLX_ACCUM_ALPHA_SIZE; data[p++]=attribList[arg++]; break;
282 default:
283 break;
284 }
285 }
286 data[p] = 0;
287
288 attribList = (int*) data;
289 // Get an appropriate visual
290 vi = glXChooseVisual(display, DefaultScreen(display), attribList);
291 if(!vi) return false;
292
293 // Here we should make sure that vi is the same visual as the
294 // one used by the xwindow drawable in wxCanvas. However,
295 // there is currently no mechanism for this in wx_canvs.cc.
296 } else {
297 // By default, we use the visual of xwindow
298 // NI: is this really senseful ? opengl in e.g. color index mode ?
299 XGetWindowAttributes(display, (Window) GetXWindow(), &xwa);
300 vi_templ.visualid = XVisualIDFromVisual(xwa.visual);
301 vi = XGetVisualInfo(display, VisualIDMask, &vi_templ, &n);
302 if(!vi) return false;
303 glXGetConfig(display, vi, GLX_USE_GL, &val);
304 if(!val) return false;
305 // Basically, this is it. It should be possible to use vi
306 // in glXCreateContext() below. But this fails with Mesa.
307 // I notified the Mesa author about it; there may be a fix.
308 #ifdef OLD_MESA
309 // Construct an attribute list matching the visual
310 int a_list[32];
311 n = 0;
312 if(vi->c_class==TrueColor || vi->c_class==DirectColor) { // RGBA visual
313 a_list[n++] = GLX_RGBA;
314 a_list[n++] = GLX_RED_SIZE;
315 a_list[n++] = bitcount(vi->red_mask);
316 a_list[n++] = GLX_GREEN_SIZE;
317 a_list[n++] = bitcount(vi->green_mask);
318 a_list[n++] = GLX_BLUE_SIZE;
319 a_list[n++] = bitcount(vi->blue_mask);
320 glXGetConfig(display, vi, GLX_ALPHA_SIZE, &val);
321 a_list[n++] = GLX_ALPHA_SIZE;
322 a_list[n++] = val;
323 } else { // Color index visual
324 glXGetConfig(display, vi, GLX_BUFFER_SIZE, &val);
325 a_list[n++] = GLX_BUFFER_SIZE;
326 a_list[n++] = val;
327 }
328 a_list[n] = None;
329 // XFree(vi);
330 vi = glXChooseVisual(display, DefaultScreen(display), a_list);
331 if(!vi) return false;
332 #endif /* OLD_MESA */
333 }
334
335 m_vi = vi; // safe for later use
336
337 wxCHECK_MSG( m_vi, FALSE, "required visual couldn't be found" );
338
339 // Create the GLX context and make it current
340
341 wxGLContext *share= m_sharedContext;
342 if (share==NULL && m_sharedContextOf)
343 share = m_sharedContextOf->GetContext();
344
345 m_glContext = new wxGLContext( TRUE, this, wxNullPalette, share );
346
347 #ifndef OLD_MESA
348 // XFree(vi);
349 #endif
350 SetCurrent();
351
352 return true;
353 }
354
355 wxGLCanvas::~wxGLCanvas(void)
356 {
357 XVisualInfo *vi = (XVisualInfo *) m_vi;
358
359 if (vi) XFree( vi );
360 if (m_glContext) delete m_glContext;
361
362 // Display* display = (Display*) GetXDisplay();
363 // if(glx_cx) glXDestroyContext(display, glx_cx);
364 }
365
366 void wxGLCanvas::SwapBuffers()
367 {
368 if( m_glContext ) m_glContext->SwapBuffers();
369
370 // Display* display = (Display*) GetXDisplay();
371 // if(glx_cx) glXSwapBuffers(display, (Window) GetXWindow());
372 }
373
374 void wxGLCanvas::SetCurrent()
375 {
376 if( m_glContext ) m_glContext->SetCurrent();
377
378 // Display* display = (Display*) GetXDisplay();
379 // if(glx_cx) glXMakeCurrent(display, (Window) GetXWindow(), glx_cx);
380 }
381
382 void wxGLCanvas::SetColour(const char *col)
383 {
384 if( m_glContext ) m_glContext->SetColour(col);
385 }
386
387 #endif
388 // wxUSE_GLCANVAS
389