user: Fix CopyImage function declaration.
[wine] / dlls / opengl32 / wgl.c
1 /* Window-specific OpenGL functions implementation.
2  *
3  * Copyright (c) 1999 Lionel Ulmer
4  * Copyright (c) 2005 Raphael Junqueira
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "wingdi.h"
34 #include "winternl.h"
35 #include "winnt.h"
36
37 #include "opengl_ext.h"
38 #ifdef HAVE_GL_GLU_H
39 #undef far
40 #undef near
41 #include <GL/glu.h>
42 #endif
43 #include "wine/library.h"
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
47 WINE_DECLARE_DEBUG_CHANNEL(opengl);
48
49 typedef struct wine_wgl_s {
50     HGLRC WINAPI (*p_wglCreateContext)(HDC hdc);
51     BOOL WINAPI  (*p_wglDeleteContext)(HGLRC hglrc);
52     HGLRC WINAPI (*p_wglGetCurrentContext)(void);
53     HDC WINAPI   (*p_wglGetCurrentDC)(void);
54     PROC WINAPI  (*p_wglGetProcAddress)(LPCSTR  lpszProc);
55     BOOL WINAPI  (*p_wglMakeCurrent)(HDC hdc, HGLRC hglrc);
56     BOOL WINAPI  (*p_wglShareLists)(HGLRC hglrc1, HGLRC hglrc2);
57     BOOL WINAPI  (*p_wglUseFontBitmapsA)(HDC hdc, DWORD first, DWORD count, DWORD listBase);
58     BOOL WINAPI  (*p_wglUseFontBitmapsW)(HDC hdc, DWORD first, DWORD count, DWORD listBase);
59
60     void WINAPI  (*p_wglGetIntegerv)(GLenum pname, GLint* params);
61 } wine_wgl_t;
62
63 /** global wgl object */
64 static wine_wgl_t wine_wgl;
65
66 /* x11drv GDI escapes */
67 #define X11DRV_ESCAPE 6789
68 enum x11drv_escape_codes
69 {
70     X11DRV_GET_DISPLAY,         /* get X11 display for a DC */
71     X11DRV_GET_DRAWABLE,        /* get current drawable for a DC */
72     X11DRV_GET_FONT,            /* get current X font for a DC */
73     X11DRV_SET_DRAWABLE,        /* set current drawable for a DC */
74     X11DRV_START_EXPOSURES,     /* start graphics exposures */
75     X11DRV_END_EXPOSURES,       /* end graphics exposures */
76     X11DRV_GET_DCE,             /* get the DCE pointer */
77     X11DRV_SET_DCE,             /* set the DCE pointer */
78     X11DRV_GET_GLX_DRAWABLE,    /* get current glx drawable for a DC */
79     X11DRV_SYNC_PIXMAP          /* sync the dibsection to its pixmap */
80 };
81
82 void (*wine_tsx11_lock_ptr)(void) = NULL;
83 void (*wine_tsx11_unlock_ptr)(void) = NULL;
84
85 static GLXContext default_cx = NULL;
86 static Display *default_display;  /* display to use for default context */
87
88 static HMODULE opengl32_handle;
89
90 static void* (*p_glXGetProcAddressARB)(const GLubyte *);
91
92 static char  internal_gl_disabled_extensions[512];
93 static char* internal_gl_extensions = NULL;
94
95 typedef struct wine_glcontext {
96   HDC hdc;
97   Display *display;
98   XVisualInfo *vis;
99   GLXFBConfig fb_conf;
100   GLXContext ctx;
101   BOOL do_escape;
102   struct wine_glcontext *next;
103   struct wine_glcontext *prev;
104 } Wine_GLContext;
105
106 void enter_gl(void)
107 {
108     Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
109     
110     if (curctx && curctx->do_escape)
111     {
112         enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
113         ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
114     }
115
116     wine_tsx11_lock_ptr();
117     return;
118 }
119
120 /* retrieve the X display to use on a given DC */
121 inline static Display *get_display( HDC hdc )
122 {
123     Display *display;
124     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
125
126     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
127                     sizeof(display), (LPSTR)&display )) display = NULL;
128     return display;
129 }
130
131 /***********************************************************************
132  *              wglCreateContext (OPENGL32.@)
133  */
134 HGLRC WINAPI wglCreateContext(HDC hdc)
135 {
136     TRACE("(%p)\n", hdc);
137     return wine_wgl.p_wglCreateContext(hdc);
138 }
139
140 /***********************************************************************
141  *              wglCreateLayerContext (OPENGL32.@)
142  */
143 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
144                                    int iLayerPlane) {
145   TRACE("(%p,%d)\n", hdc, iLayerPlane);
146
147   if (iLayerPlane == 0) {
148       return wglCreateContext(hdc);
149   }
150   FIXME(" no handler for layer %d\n", iLayerPlane);
151
152   return NULL;
153 }
154
155 /***********************************************************************
156  *              wglCopyContext (OPENGL32.@)
157  */
158 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
159                            HGLRC hglrcDst,
160                            UINT mask) {
161   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
162
163   return FALSE;
164 }
165
166 /***********************************************************************
167  *              wglDeleteContext (OPENGL32.@)
168  */
169 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
170 {
171     TRACE("(%p)\n", hglrc);
172     return wine_wgl.p_wglDeleteContext(hglrc);
173 }
174
175 /***********************************************************************
176  *              wglDescribeLayerPlane (OPENGL32.@)
177  */
178 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
179                                   int iPixelFormat,
180                                   int iLayerPlane,
181                                   UINT nBytes,
182                                   LPLAYERPLANEDESCRIPTOR plpd) {
183   FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
184
185   return FALSE;
186 }
187
188 /***********************************************************************
189  *              wglGetCurrentContext (OPENGL32.@)
190  */
191 HGLRC WINAPI wglGetCurrentContext(void) {
192     TRACE("\n");
193     return wine_wgl.p_wglGetCurrentContext();
194 }
195
196 /***********************************************************************
197  *              wglGetCurrentDC (OPENGL32.@)
198  */
199 HDC WINAPI wglGetCurrentDC(void) {
200     TRACE("\n");
201     return wine_wgl.p_wglGetCurrentDC();
202 }
203
204 /***********************************************************************
205  *              wglGetLayerPaletteEntries (OPENGL32.@)
206  */
207 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
208                                      int iLayerPlane,
209                                      int iStart,
210                                      int cEntries,
211                                      const COLORREF *pcr) {
212   FIXME("(): stub !\n");
213
214   return 0;
215 }
216
217 /***********************************************************************
218  *              wglGetProcAddress (OPENGL32.@)
219  */
220 static int compar(const void *elt_a, const void *elt_b) {
221   return strcmp(((const OpenGL_extension *) elt_a)->name,
222                 ((const OpenGL_extension *) elt_b)->name);
223 }
224
225 PROC WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
226   void *local_func;
227   OpenGL_extension  ext;
228   const OpenGL_extension *ext_ret;
229
230   TRACE("(%s)\n", lpszProc);
231
232   /* First, look if it's not already defined in the 'standard' OpenGL functions */
233   if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
234     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
235     return local_func;
236   }
237
238   if (p_glXGetProcAddressARB == NULL) {
239     ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
240     return NULL;
241   }
242   
243   /* After that, search in the thunks to find the real name of the extension */
244   ext.name = lpszProc;
245   ext_ret = (const OpenGL_extension *) bsearch(&ext, extension_registry,
246                                          extension_registry_size, sizeof(OpenGL_extension), compar);
247
248   /* If nothing was found, we are looking for a WGL extension */
249   if (ext_ret == NULL) {
250     return wine_wgl.p_wglGetProcAddress(lpszProc);
251   } else { /* We are looking for an OpenGL extension */
252     const char *glx_name = ext_ret->glx_name ? ext_ret->glx_name : ext_ret->name;
253     ENTER_GL();
254     local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
255     LEAVE_GL();
256     
257     /* After that, look at the extensions defined in the Linux OpenGL library */
258     if (local_func == NULL) {
259       char buf[256];
260       void *ret = NULL;
261
262       /* Remove the 3 last letters (EXT, ARB, ...).
263
264          I know that some extensions have more than 3 letters (MESA, NV,
265          INTEL, ...), but this is only a stop-gap measure to fix buggy
266          OpenGL drivers (moreover, it is only useful for old 1.0 apps
267          that query the glBindTextureEXT extension).
268       */
269       memcpy(buf, glx_name, strlen(glx_name) - 3);
270       buf[strlen(glx_name) - 3] = '\0';
271       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
272
273       ret = GetProcAddress(opengl32_handle, buf);
274       if (ret != NULL) {
275         TRACE(" found function in main OpenGL library (%p) !\n", ret);
276       } else {
277         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
278       }
279
280       return ret;
281     } else {
282       TRACE(" returning function  (%p)\n", ext_ret->func);
283       extension_funcs[ext_ret - extension_registry] = local_func;
284
285       return ext_ret->func;
286     }
287   }
288 }
289
290 /***********************************************************************
291  *              wglMakeCurrent (OPENGL32.@)
292  */
293 BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hglrc) {
294     TRACE("hdc: (%p), hglrc: (%p)\n", hdc, hglrc);
295     return wine_wgl.p_wglMakeCurrent(hdc, hglrc);
296 }
297
298 /***********************************************************************
299  *              wglRealizeLayerPalette (OPENGL32.@)
300  */
301 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
302                                    int iLayerPlane,
303                                    BOOL bRealize) {
304   FIXME("()\n");
305
306   return FALSE;
307 }
308
309 /***********************************************************************
310  *              wglSetLayerPaletteEntries (OPENGL32.@)
311  */
312 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
313                                      int iLayerPlane,
314                                      int iStart,
315                                      int cEntries,
316                                      const COLORREF *pcr) {
317   FIXME("(): stub !\n");
318
319   return 0;
320 }
321
322 /***********************************************************************
323  *              wglShareLists (OPENGL32.@)
324  */
325 BOOL WINAPI wglShareLists(HGLRC hglrc1, HGLRC hglrc2) {
326     TRACE("(%p, %p)\n", hglrc1, hglrc2);
327     return wine_wgl.p_wglShareLists(hglrc1, hglrc2);
328 }
329
330 /***********************************************************************
331  *              wglSwapLayerBuffers (OPENGL32.@)
332  */
333 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
334                                 UINT fuPlanes) {
335   TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
336
337   if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
338     if (!SwapBuffers(hdc)) return FALSE;
339     fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
340   }
341
342   if (fuPlanes) {
343     WARN("Following layers unhandled : %08x\n", fuPlanes);
344   }
345
346   return TRUE;
347 }
348
349 /***********************************************************************
350  *              wglUseFontBitmapsA (OPENGL32.@)
351  */
352 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
353                                DWORD first,
354                                DWORD count,
355                                DWORD listBase)
356 {
357     TRACE("(%p, %ld, %ld, %ld)\n", hdc, first, count, listBase);
358     return wine_wgl.p_wglUseFontBitmapsA(hdc, first, count, listBase);
359 }
360
361 /***********************************************************************
362  *              wglUseFontBitmapsW (OPENGL32.@)
363  */
364 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
365                                DWORD first,
366                                DWORD count,
367                                DWORD listBase)
368 {
369     TRACE("(%p, %ld, %ld, %ld)\n", hdc, first, count, listBase);
370     return wine_wgl.p_wglUseFontBitmapsW(hdc, first, count, listBase);
371 }
372
373 #ifdef HAVE_GL_GLU_H
374
375 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
376 {
377     vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;  
378     vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;  
379     vertex[2] = 0.0;
380 }
381
382 static void tess_callback_vertex(GLvoid *vertex)
383 {
384     GLdouble *dbl = vertex;
385     TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
386     glVertex3dv(vertex);
387 }
388
389 static void tess_callback_begin(GLenum which)
390 {
391     TRACE("%d\n", which);
392     glBegin(which);
393 }
394
395 static void tess_callback_end(void)
396 {
397     TRACE("\n");
398     glEnd();
399 }
400
401 /***********************************************************************
402  *              wglUseFontOutlines_common
403  */
404 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
405                                       DWORD first,
406                                       DWORD count,
407                                       DWORD listBase,
408                                       FLOAT deviation,
409                                       FLOAT extrusion,
410                                       int format,
411                                       LPGLYPHMETRICSFLOAT lpgmf,
412                                       BOOL unicode)
413 {
414     UINT glyph;
415     const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
416     GLUtesselator *tess;
417     LOGFONTW lf;
418     HFONT old_font, unscaled_font;
419     UINT em_size = 1024;
420     RECT rc;
421
422     TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
423           listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
424
425
426     ENTER_GL();
427     tess = gluNewTess();
428     if(tess)
429     {
430         gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
431         gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
432         gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
433     }
434     LEAVE_GL();
435
436     if(!tess) return FALSE;
437
438     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
439     rc.left = rc.right = rc.bottom = 0;
440     rc.top = em_size;
441     DPtoLP(hdc, (POINT*)&rc, 2);
442     lf.lfHeight = -abs(rc.top - rc.bottom);
443     lf.lfOrientation = lf.lfEscapement = 0;
444     unscaled_font = CreateFontIndirectW(&lf);
445     old_font = SelectObject(hdc, unscaled_font);
446
447     for (glyph = first; glyph < first + count; glyph++)
448     {
449         DWORD needed;
450         GLYPHMETRICS gm;
451         BYTE *buf;
452         TTPOLYGONHEADER *pph;
453         TTPOLYCURVE *ppc;
454         GLdouble *vertices;
455
456         if(unicode)
457             needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
458         else
459             needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
460
461         if(needed == GDI_ERROR)
462             goto error;
463
464         buf = HeapAlloc(GetProcessHeap(), 0, needed);
465         vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
466
467         if(unicode)
468             GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
469         else
470             GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
471
472         TRACE("glyph %d\n", glyph);
473
474         if(lpgmf)
475         {
476             lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
477             lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
478             lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
479             lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
480             lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
481             lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
482
483             TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
484                   lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY); 
485             lpgmf++;
486         }
487
488         ENTER_GL();
489         glNewList(listBase++, GL_COMPILE);
490         gluTessBeginPolygon(tess, NULL);
491
492         pph = (TTPOLYGONHEADER*)buf;
493         while((BYTE*)pph < buf + needed)
494         {
495             TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
496
497             gluTessBeginContour(tess);
498
499             fixed_to_double(pph->pfxStart, em_size, vertices);
500             gluTessVertex(tess, vertices, vertices);
501             vertices += 3;
502
503             ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
504             while((char*)ppc < (char*)pph + pph->cb)
505             {
506                 int i;
507
508                 switch(ppc->wType) {
509                 case TT_PRIM_LINE:
510                     for(i = 0; i < ppc->cpfx; i++)
511                     {
512                         TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
513                         fixed_to_double(ppc->apfx[i], em_size, vertices); 
514                         gluTessVertex(tess, vertices, vertices);
515                         vertices += 3;
516                     }
517                     break;
518
519                 case TT_PRIM_QSPLINE:
520                     for(i = 0; i < ppc->cpfx/2; i++)
521                     {
522                         /* FIXME just connecting the control points for now */
523                         TRACE("\t\tcurve  %d,%d %d,%d\n",
524                               ppc->apfx[i * 2].x.value,     ppc->apfx[i * 3].y.value,
525                               ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
526                         fixed_to_double(ppc->apfx[i * 2], em_size, vertices); 
527                         gluTessVertex(tess, vertices, vertices);
528                         vertices += 3;
529                         fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices); 
530                         gluTessVertex(tess, vertices, vertices);
531                         vertices += 3;
532                     }
533                     break;
534                 default:
535                     ERR("\t\tcurve type = %d\n", ppc->wType);
536                     gluTessEndContour(tess);
537                     goto error_in_list;
538                 }
539
540                 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
541                                      (ppc->cpfx - 1) * sizeof(POINTFX));
542             }
543             gluTessEndContour(tess);
544             pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
545         }
546
547 error_in_list:
548         gluTessEndPolygon(tess);
549         glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
550         glEndList();
551         LEAVE_GL();
552         HeapFree(GetProcessHeap(), 0, buf);
553         HeapFree(GetProcessHeap(), 0, vertices);
554     }
555
556  error:
557     DeleteObject(SelectObject(hdc, old_font));
558     gluDeleteTess(tess);
559     return TRUE;
560
561 }
562
563 #else /* HAVE_GL_GLU_H */
564
565 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
566                                       DWORD first,
567                                       DWORD count,
568                                       DWORD listBase,
569                                       FLOAT deviation,
570                                       FLOAT extrusion,
571                                       int format,
572                                       LPGLYPHMETRICSFLOAT lpgmf,
573                                       BOOL unicode)
574 {
575     FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
576     return FALSE;
577 }
578
579 #endif /* HAVE_GL_GLU_H */
580
581 /***********************************************************************
582  *              wglUseFontOutlinesA (OPENGL32.@)
583  */
584 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
585                                 DWORD first,
586                                 DWORD count,
587                                 DWORD listBase,
588                                 FLOAT deviation,
589                                 FLOAT extrusion,
590                                 int format,
591                                 LPGLYPHMETRICSFLOAT lpgmf)
592 {
593     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
594 }
595
596 /***********************************************************************
597  *              wglUseFontOutlinesW (OPENGL32.@)
598  */
599 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
600                                 DWORD first,
601                                 DWORD count,
602                                 DWORD listBase,
603                                 FLOAT deviation,
604                                 FLOAT extrusion,
605                                 int format,
606                                 LPGLYPHMETRICSFLOAT lpgmf)
607 {
608     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
609 }
610
611 const GLubyte * internal_glGetString(GLenum name) {
612   const char* GL_Extensions = NULL;
613   
614   if (GL_EXTENSIONS != name) {
615     return glGetString(name);
616   }
617
618   if (NULL == internal_gl_extensions) {
619     GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
620
621     TRACE("GL_EXTENSIONS reported:\n");  
622     if (NULL == GL_Extensions) {
623       ERR("GL_EXTENSIONS returns NULL\n");      
624       return NULL;
625     } else {
626       size_t len = strlen(GL_Extensions);
627       internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
628
629       while (*GL_Extensions != 0x00) {
630         const char* Start = GL_Extensions;
631         char        ThisExtn[256];
632          
633         memset(ThisExtn, 0x00, sizeof(ThisExtn));
634         while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
635           GL_Extensions++;
636         }
637         memcpy(ThisExtn, Start, (GL_Extensions - Start));
638         TRACE("- %s:", ThisExtn);
639         
640         /* test if supported API is disabled by config */
641         if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
642           strcat(internal_gl_extensions, " ");
643           strcat(internal_gl_extensions, ThisExtn);
644           TRACE(" active\n");
645         } else {
646           TRACE(" deactived (by config)\n");
647         }
648
649         if (*GL_Extensions == ' ') GL_Extensions++;
650       }
651     }
652   }
653   return (const GLubyte *) internal_gl_extensions;
654 }
655
656 void internal_glGetIntegerv(GLenum pname, GLint* params) {
657   TRACE("pname: 0x%x, params %p\n", pname, params);
658   glGetIntegerv(pname, params);
659   /* A few parameters like GL_DEPTH_BITS differ between WGL and GLX, the wglGetIntegerv helper function handles those */
660   wine_wgl.p_wglGetIntegerv(pname, params);
661 }
662
663
664 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
665    include all dependencies
666 */
667 #ifndef SONAME_LIBGL
668 #define SONAME_LIBGL "libGL.so"
669 #endif
670
671 /* This is for brain-dead applications that use OpenGL functions before even
672    creating a rendering context.... */
673 static BOOL process_attach(void)
674 {
675   XWindowAttributes win_attr;
676   Visual *rootVisual;
677   int num;
678   XVisualInfo template;
679   HDC hdc;
680   XVisualInfo *vis = NULL;
681   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
682   HMODULE mod = GetModuleHandleA( "winex11.drv" );
683   void *opengl_handle;
684   DWORD size = sizeof(internal_gl_disabled_extensions);
685   HKEY hkey = 0;
686
687   if (!root || !mod)
688   {
689       ERR("X11DRV not loaded. Cannot create default context.\n");
690       return FALSE;
691   }
692
693   wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
694   wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
695
696   /* Load WGL function pointers from winex11.drv */
697   wine_wgl.p_wglCreateContext = (void *)GetProcAddress(mod, "wglCreateContext");
698   wine_wgl.p_wglDeleteContext = (void *)GetProcAddress(mod, "wglDeleteContext");
699   wine_wgl.p_wglGetCurrentContext = (void *)GetProcAddress(mod, "wglGetCurrentContext");
700   wine_wgl.p_wglGetCurrentDC = (void *)GetProcAddress(mod, "wglGetCurrentDC");
701   wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod, "wglGetProcAddress");
702   wine_wgl.p_wglMakeCurrent = (void *)GetProcAddress(mod, "wglMakeCurrent");
703   wine_wgl.p_wglShareLists = (void *)GetProcAddress(mod, "wglShareLists");
704   wine_wgl.p_wglUseFontBitmapsA = (void*)GetProcAddress(mod, "wglUseFontBitmapsA");
705   wine_wgl.p_wglUseFontBitmapsW = (void*)GetProcAddress(mod, "wglUseFontBitmapsW");
706
707   /* Interal WGL function */
708   wine_wgl.p_wglGetIntegerv = (void *)GetProcAddress(mod, "wglGetIntegerv");
709
710   hdc = GetDC(0);
711   default_display = get_display( hdc );
712   ReleaseDC( 0, hdc );
713   if (!default_display)
714   {
715       ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
716       return FALSE;
717   }
718
719   ENTER_GL();
720
721   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
722      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
723      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
724      with mismatched visuals.  Note that the Root Window visual may not be double
725      buffered, so apps actually attempting to render this way may flicker */
726   if (XGetWindowAttributes( default_display, root, &win_attr ))
727   {
728     rootVisual = win_attr.visual;
729   }
730   else
731   {
732     /* Get the default visual, since we can't seem to get the attributes from the
733        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
734     rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
735   }
736
737   template.visualid = XVisualIDFromVisual(rootVisual);
738   vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
739   if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
740   if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
741   XFree(vis);
742   LEAVE_GL();
743
744   opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
745   if (opengl_handle != NULL) {
746    p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
747    wine_dlclose(opengl_handle, NULL, 0);
748    if (p_glXGetProcAddressARB == NULL)
749            TRACE("could not find glXGetProcAddressARB in libGL.\n");
750   }
751
752   internal_gl_disabled_extensions[0] = 0;
753   if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
754     if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
755       TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
756     }
757     RegCloseKey(hkey);
758   }
759
760   if (default_cx == NULL) {
761     ERR("Could not create default context.\n");
762   }
763   return TRUE;
764 }
765
766
767 /**********************************************************************/
768
769 static void process_detach(void)
770 {
771   glXDestroyContext(default_display, default_cx);
772
773   HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
774 }
775
776 /***********************************************************************
777  *           OpenGL initialisation routine
778  */
779 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
780 {
781     switch(reason)
782     {
783     case DLL_PROCESS_ATTACH:
784         opengl32_handle = hinst;
785         DisableThreadLibraryCalls(hinst);
786         return process_attach();
787     case DLL_PROCESS_DETACH:
788         process_detach();
789         break;
790     }
791     return TRUE;
792 }