d3d10: Add support for parsing sample masks to parse_fx10_object().
[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 "winreg.h"
32 #include "wingdi.h"
33 #include "winternl.h"
34 #include "winnt.h"
35
36 #include "opengl_ext.h"
37 #ifdef HAVE_GL_GLU_H
38 #undef far
39 #undef near
40 #include <GL/glu.h>
41 #endif
42 #include "wine/gdi_driver.h"
43 #include "wine/wgl_driver.h"
44 #include "wine/library.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
48 WINE_DECLARE_DEBUG_CHANNEL(opengl);
49
50 #ifdef SONAME_LIBGLU
51 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
52 MAKE_FUNCPTR(gluNewTess)
53 MAKE_FUNCPTR(gluDeleteTess)
54 MAKE_FUNCPTR(gluTessBeginContour)
55 MAKE_FUNCPTR(gluTessBeginPolygon)
56 MAKE_FUNCPTR(gluTessCallback)
57 MAKE_FUNCPTR(gluTessEndContour)
58 MAKE_FUNCPTR(gluTessEndPolygon)
59 MAKE_FUNCPTR(gluTessVertex)
60 #undef MAKE_FUNCPTR
61 #endif /* SONAME_LIBGLU */
62
63 static HMODULE opengl32_handle;
64 static void* libglu_handle = NULL;
65
66 extern struct opengl_funcs null_opengl_funcs;
67
68 const GLubyte * WINAPI wine_glGetString( GLenum name );
69
70 /* internal GDI functions */
71 extern INT WINAPI GdiDescribePixelFormat( HDC hdc, INT fmt, UINT size, PIXELFORMATDESCRIPTOR *pfd );
72 extern BOOL WINAPI GdiSetPixelFormat( HDC hdc, INT fmt, const PIXELFORMATDESCRIPTOR *pfd );
73 extern BOOL WINAPI GdiSwapBuffers( HDC hdc );
74
75 /* handle management */
76
77 #define MAX_WGL_HANDLES 1024
78
79 struct wgl_handle
80 {
81     UINT                    handle;
82     DWORD                   tid;
83     struct wgl_context *    context;
84     const struct wgl_funcs *funcs;
85 };
86
87 static struct wgl_handle wgl_handles[MAX_WGL_HANDLES];
88 static struct wgl_handle *next_free;
89 static unsigned int handle_count;
90
91 static CRITICAL_SECTION wgl_section;
92 static CRITICAL_SECTION_DEBUG critsect_debug =
93 {
94     0, 0, &wgl_section,
95     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
96       0, 0, { (DWORD_PTR)(__FILE__ ": wgl_section") }
97 };
98 static CRITICAL_SECTION wgl_section = { &critsect_debug, -1, 0, 0, 0, 0 };
99
100 static inline const struct wgl_funcs *get_dc_funcs( HDC hdc )
101 {
102     return __wine_get_wgl_driver( hdc, WINE_GDI_DRIVER_VERSION );
103 }
104
105 static inline HGLRC next_handle( struct wgl_handle *ptr )
106 {
107     WORD generation = HIWORD( ptr->handle ) + 1;
108     if (!generation) generation++;
109     ptr->handle = MAKELONG( ptr - wgl_handles, generation );
110     return ULongToHandle( ptr->handle );
111 }
112
113 /* the current handle is assumed valid and doesn't need locking */
114 static inline struct wgl_handle *get_current_handle_ptr(void)
115 {
116     if (!NtCurrentTeb()->glCurrentRC) return NULL;
117     return &wgl_handles[LOWORD(NtCurrentTeb()->glCurrentRC)];
118 }
119
120 static struct wgl_handle *get_handle_ptr( HGLRC handle )
121 {
122     unsigned int index = LOWORD( handle );
123
124     EnterCriticalSection( &wgl_section );
125     if (index < handle_count && ULongToHandle(wgl_handles[index].handle) == handle)
126         return &wgl_handles[index];
127
128     LeaveCriticalSection( &wgl_section );
129     SetLastError( ERROR_INVALID_HANDLE );
130     return NULL;
131 }
132
133 static void release_handle_ptr( struct wgl_handle *ptr )
134 {
135     if (ptr) LeaveCriticalSection( &wgl_section );
136 }
137
138 static HGLRC alloc_handle( struct wgl_context *context, const struct wgl_funcs *funcs )
139 {
140     HGLRC handle = 0;
141     struct wgl_handle *ptr = NULL;
142
143     EnterCriticalSection( &wgl_section );
144     if ((ptr = next_free))
145         next_free = (struct wgl_handle *)next_free->context;
146     else if (handle_count < MAX_WGL_HANDLES)
147         ptr = &wgl_handles[handle_count++];
148
149     if (ptr)
150     {
151         ptr->context = context;
152         ptr->funcs = funcs;
153         handle = next_handle( ptr );
154     }
155     else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
156     LeaveCriticalSection( &wgl_section );
157     return handle;
158 }
159
160 static void free_handle_ptr( struct wgl_handle *ptr )
161 {
162     ptr->handle |= 0xffff;
163     ptr->context = (struct wgl_context *)next_free;
164     ptr->funcs = NULL;
165     next_free = ptr;
166     LeaveCriticalSection( &wgl_section );
167 }
168
169 /***********************************************************************
170  *               wglSetPixelFormat(OPENGL32.@)
171  */
172 BOOL WINAPI wglSetPixelFormat( HDC hdc, INT iPixelFormat,
173                                const PIXELFORMATDESCRIPTOR *ppfd)
174 {
175     return GdiSetPixelFormat(hdc, iPixelFormat, ppfd);
176 }
177
178 /***********************************************************************
179  *              wglCopyContext (OPENGL32.@)
180  */
181 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask)
182 {
183     struct wgl_handle *src, *dst;
184     BOOL ret = FALSE;
185
186     if (!(src = get_handle_ptr( hglrcSrc ))) return FALSE;
187     if ((dst = get_handle_ptr( hglrcDst )))
188     {
189         if (src->funcs != dst->funcs) SetLastError( ERROR_INVALID_HANDLE );
190         else ret = src->funcs->p_wglCopyContext( src->context, dst->context, mask );
191     }
192     release_handle_ptr( dst );
193     release_handle_ptr( src );
194     return ret;
195 }
196
197 /***********************************************************************
198  *              wglDeleteContext (OPENGL32.@)
199  */
200 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
201 {
202     struct wgl_handle *ptr = get_handle_ptr( hglrc );
203
204     if (!ptr) return FALSE;
205
206     if (ptr->tid && ptr->tid != GetCurrentThreadId())
207     {
208         SetLastError( ERROR_BUSY );
209         release_handle_ptr( ptr );
210         return FALSE;
211     }
212     if (hglrc == NtCurrentTeb()->glCurrentRC) wglMakeCurrent( 0, 0 );
213     ptr->funcs->p_wglDeleteContext( ptr->context );
214     free_handle_ptr( ptr );
215     return TRUE;
216 }
217
218 /***********************************************************************
219  *              wglMakeCurrent (OPENGL32.@)
220  */
221 BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hglrc)
222 {
223     BOOL ret = TRUE;
224     struct wgl_handle *ptr, *prev = get_current_handle_ptr();
225
226     if (hglrc)
227     {
228         if (!(ptr = get_handle_ptr( hglrc ))) return FALSE;
229         if (!ptr->tid || ptr->tid == GetCurrentThreadId())
230         {
231             ret = ptr->funcs->p_wglMakeCurrent( hdc, ptr->context );
232             if (ret)
233             {
234                 if (prev) prev->tid = 0;
235                 ptr->tid = GetCurrentThreadId();
236                 NtCurrentTeb()->glCurrentRC = hglrc;
237             }
238         }
239         else
240         {
241             SetLastError( ERROR_BUSY );
242             ret = FALSE;
243         }
244         release_handle_ptr( ptr );
245     }
246     else if (prev)
247     {
248         if (!prev->funcs->p_wglMakeCurrent( 0, NULL )) return FALSE;
249         prev->tid = 0;
250         NtCurrentTeb()->glCurrentRC = 0;
251         NtCurrentTeb()->glTable = &null_opengl_funcs;
252     }
253     else if (!hdc)
254     {
255         SetLastError( ERROR_INVALID_HANDLE );
256         ret = FALSE;
257     }
258     return ret;
259 }
260
261 /***********************************************************************
262  *              wglCreateContextAttribsARB  (wrapper for the extension function returned by the driver)
263  */
264 static HGLRC WINAPI wglCreateContextAttribsARB( HDC hdc, HGLRC share, const int *attribs )
265 {
266     HGLRC ret = 0;
267     struct wgl_context *context;
268     struct wgl_handle *share_ptr = NULL;
269     const struct wgl_funcs *funcs = get_dc_funcs( hdc );
270
271     if (!funcs) return 0;
272     if (share && !(share_ptr = get_handle_ptr( share ))) return 0;
273     if ((context = funcs->p_wglCreateContextAttribsARB( hdc, share_ptr ? share_ptr->context : NULL,
274                                                         attribs )))
275     {
276         ret = alloc_handle( context, funcs );
277         if (!ret) funcs->p_wglDeleteContext( context );
278     }
279     release_handle_ptr( share_ptr );
280     return ret;
281
282 }
283
284 /***********************************************************************
285  *              wglMakeContextCurrentARB  (wrapper for the extension function returned by the driver)
286  */
287 static BOOL WINAPI wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, HGLRC hglrc )
288 {
289     BOOL ret = TRUE;
290     struct wgl_handle *ptr, *prev = get_current_handle_ptr();
291
292     if (hglrc)
293     {
294         if (!(ptr = get_handle_ptr( hglrc ))) return FALSE;
295         if (!ptr->tid || ptr->tid == GetCurrentThreadId())
296         {
297             ret = ptr->funcs->p_wglMakeContextCurrentARB( draw_hdc, read_hdc, ptr->context );
298             if (ret)
299             {
300                 if (prev) prev->tid = 0;
301                 ptr->tid = GetCurrentThreadId();
302                 NtCurrentTeb()->glCurrentRC = hglrc;
303             }
304         }
305         else
306         {
307             SetLastError( ERROR_BUSY );
308             ret = FALSE;
309         }
310         release_handle_ptr( ptr );
311     }
312     else if (prev)
313     {
314         if (!prev->funcs->p_wglMakeCurrent( 0, NULL )) return FALSE;
315         prev->tid = 0;
316         NtCurrentTeb()->glCurrentRC = 0;
317         NtCurrentTeb()->glTable = &null_opengl_funcs;
318     }
319     return ret;
320 }
321
322 /***********************************************************************
323  *              wglShareLists (OPENGL32.@)
324  */
325 BOOL WINAPI wglShareLists(HGLRC hglrcSrc, HGLRC hglrcDst)
326 {
327     BOOL ret = FALSE;
328     struct wgl_handle *src, *dst;
329
330     if (!(src = get_handle_ptr( hglrcSrc ))) return FALSE;
331     if ((dst = get_handle_ptr( hglrcDst )))
332     {
333         if (src->funcs != dst->funcs) SetLastError( ERROR_INVALID_HANDLE );
334         else ret = src->funcs->p_wglShareLists( src->context, dst->context );
335     }
336     release_handle_ptr( dst );
337     release_handle_ptr( src );
338     return ret;
339 }
340
341 /***********************************************************************
342  *              wglGetCurrentDC (OPENGL32.@)
343  */
344 HDC WINAPI wglGetCurrentDC(void)
345 {
346     struct wgl_handle *context = get_current_handle_ptr();
347     if (!context) return 0;
348     return context->funcs->p_wglGetCurrentDC( context->context );
349 }
350
351 /***********************************************************************
352  *              wglCreateContext (OPENGL32.@)
353  */
354 HGLRC WINAPI wglCreateContext(HDC hdc)
355 {
356     HGLRC ret = 0;
357     struct wgl_context *context;
358     const struct wgl_funcs *funcs = get_dc_funcs( hdc );
359
360     if (!funcs) return 0;
361     if (!(context = funcs->p_wglCreateContext( hdc ))) return 0;
362     ret = alloc_handle( context, funcs );
363     if (!ret) funcs->p_wglDeleteContext( context );
364     return ret;
365 }
366
367 /***********************************************************************
368  *              wglGetCurrentContext (OPENGL32.@)
369  */
370 HGLRC WINAPI wglGetCurrentContext(void)
371 {
372     return NtCurrentTeb()->glCurrentRC;
373 }
374
375 /***********************************************************************
376  *              wglChoosePixelFormat (OPENGL32.@)
377  */
378 INT WINAPI wglChoosePixelFormat(HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd)
379 {
380     PIXELFORMATDESCRIPTOR format, best;
381     int i, count, best_format;
382     int bestDBuffer = -1, bestStereo = -1;
383
384     TRACE_(wgl)( "%p %p: size %u version %u flags %u type %u color %u %u,%u,%u,%u "
385                  "accum %u depth %u stencil %u aux %u\n",
386                  hdc, ppfd, ppfd->nSize, ppfd->nVersion, ppfd->dwFlags, ppfd->iPixelType,
387                  ppfd->cColorBits, ppfd->cRedBits, ppfd->cGreenBits, ppfd->cBlueBits, ppfd->cAlphaBits,
388                  ppfd->cAccumBits, ppfd->cDepthBits, ppfd->cStencilBits, ppfd->cAuxBuffers );
389
390     count = GdiDescribePixelFormat( hdc, 0, 0, NULL );
391     if (!count) return 0;
392
393     best_format = 0;
394     best.dwFlags = 0;
395     best.cAlphaBits = -1;
396     best.cColorBits = -1;
397     best.cDepthBits = -1;
398     best.cStencilBits = -1;
399     best.cAuxBuffers = -1;
400
401     for (i = 1; i <= count; i++)
402     {
403         if (!GdiDescribePixelFormat( hdc, i, sizeof(format), &format )) continue;
404
405         if (ppfd->iPixelType != format.iPixelType)
406         {
407             TRACE( "pixel type mismatch for iPixelFormat=%d\n", i );
408             continue;
409         }
410
411         /* only use bitmap capable for formats for bitmap rendering */
412         if( (ppfd->dwFlags & PFD_DRAW_TO_BITMAP) != (format.dwFlags & PFD_DRAW_TO_BITMAP))
413         {
414             TRACE( "PFD_DRAW_TO_BITMAP mismatch for iPixelFormat=%d\n", i );
415             continue;
416         }
417
418         /* The behavior of PDF_STEREO/PFD_STEREO_DONTCARE and PFD_DOUBLEBUFFER / PFD_DOUBLEBUFFER_DONTCARE
419          * is not very clear on MSDN. They specify that ChoosePixelFormat tries to match pixel formats
420          * with the flag (PFD_STEREO / PFD_DOUBLEBUFFERING) set. Otherwise it says that it tries to match
421          * formats without the given flag set.
422          * A test on Windows using a Radeon 9500pro on WinXP (the driver doesn't support Stereo)
423          * has indicated that a format without stereo is returned when stereo is unavailable.
424          * So in case PFD_STEREO is set, formats that support it should have priority above formats
425          * without. In case PFD_STEREO_DONTCARE is set, stereo is ignored.
426          *
427          * To summarize the following is most likely the correct behavior:
428          * stereo not set -> prefer non-stereo formats, but also accept stereo formats
429          * stereo set -> prefer stereo formats, but also accept non-stereo formats
430          * stereo don't care -> it doesn't matter whether we get stereo or not
431          *
432          * In Wine we will treat non-stereo the same way as don't care because it makes
433          * format selection even more complicated and second drivers with Stereo advertise
434          * each format twice anyway.
435          */
436
437         /* Doublebuffer, see the comments above */
438         if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE))
439         {
440             if (((ppfd->dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) &&
441                 ((format.dwFlags & PFD_DOUBLEBUFFER) == (ppfd->dwFlags & PFD_DOUBLEBUFFER)))
442                 goto found;
443
444             if (bestDBuffer != -1 && (format.dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) continue;
445         }
446
447         /* Stereo, see the comments above. */
448         if (!(ppfd->dwFlags & PFD_STEREO_DONTCARE))
449         {
450             if (((ppfd->dwFlags & PFD_STEREO) != bestStereo) &&
451                 ((format.dwFlags & PFD_STEREO) == (ppfd->dwFlags & PFD_STEREO)))
452                 goto found;
453
454             if (bestStereo != -1 && (format.dwFlags & PFD_STEREO) != bestStereo) continue;
455         }
456
457         /* Below we will do a number of checks to select the 'best' pixelformat.
458          * We assume the precedence cColorBits > cAlphaBits > cDepthBits > cStencilBits -> cAuxBuffers.
459          * The code works by trying to match the most important options as close as possible.
460          * When a reasonable format is found, we will try to match more options.
461          * It appears (see the opengl32 test) that Windows opengl drivers ignore options
462          * like cColorBits, cAlphaBits and friends if they are set to 0, so they are considered
463          * as DONTCARE. At least Serious Sam TSE relies on this behavior. */
464
465         if (ppfd->cColorBits)
466         {
467             if (((ppfd->cColorBits > best.cColorBits) && (format.cColorBits > best.cColorBits)) ||
468                 ((format.cColorBits >= ppfd->cColorBits) && (format.cColorBits < best.cColorBits)))
469                 goto found;
470
471             if (best.cColorBits != format.cColorBits)  /* Do further checks if the format is compatible */
472             {
473                 TRACE( "color mismatch for iPixelFormat=%d\n", i );
474                 continue;
475             }
476         }
477         if (ppfd->cAlphaBits)
478         {
479             if (((ppfd->cAlphaBits > best.cAlphaBits) && (format.cAlphaBits > best.cAlphaBits)) ||
480                 ((format.cAlphaBits >= ppfd->cAlphaBits) && (format.cAlphaBits < best.cAlphaBits)))
481                 goto found;
482
483             if (best.cAlphaBits != format.cAlphaBits)
484             {
485                 TRACE( "alpha mismatch for iPixelFormat=%d\n", i );
486                 continue;
487             }
488         }
489         if (ppfd->cDepthBits)
490         {
491             if (((ppfd->cDepthBits > best.cDepthBits) && (format.cDepthBits > best.cDepthBits)) ||
492                 ((format.cDepthBits >= ppfd->cDepthBits) && (format.cDepthBits < best.cDepthBits)))
493                 goto found;
494
495             if (best.cDepthBits != format.cDepthBits)
496             {
497                 TRACE( "depth mismatch for iPixelFormat=%d\n", i );
498                 continue;
499             }
500         }
501         if (ppfd->cStencilBits)
502         {
503             if (((ppfd->cStencilBits > best.cStencilBits) && (format.cStencilBits > best.cStencilBits)) ||
504                 ((format.cStencilBits >= ppfd->cStencilBits) && (format.cStencilBits < best.cStencilBits)))
505                 goto found;
506
507             if (best.cStencilBits != format.cStencilBits)
508             {
509                 TRACE( "stencil mismatch for iPixelFormat=%d\n", i );
510                 continue;
511             }
512         }
513         if (ppfd->cAuxBuffers)
514         {
515             if (((ppfd->cAuxBuffers > best.cAuxBuffers) && (format.cAuxBuffers > best.cAuxBuffers)) ||
516                 ((format.cAuxBuffers >= ppfd->cAuxBuffers) && (format.cAuxBuffers < best.cAuxBuffers)))
517                 goto found;
518
519             if (best.cAuxBuffers != format.cAuxBuffers)
520             {
521                 TRACE( "aux mismatch for iPixelFormat=%d\n", i );
522                 continue;
523             }
524         }
525         continue;
526
527     found:
528         best_format = i;
529         best = format;
530         bestDBuffer = format.dwFlags & PFD_DOUBLEBUFFER;
531         bestStereo = format.dwFlags & PFD_STEREO;
532     }
533
534     TRACE( "returning %u\n", best_format );
535     return best_format;
536 }
537
538 /***********************************************************************
539  *              wglDescribePixelFormat (OPENGL32.@)
540  */
541 INT WINAPI wglDescribePixelFormat(HDC hdc, INT iPixelFormat, UINT nBytes,
542                                 LPPIXELFORMATDESCRIPTOR ppfd)
543 {
544   return GdiDescribePixelFormat(hdc, iPixelFormat, nBytes, ppfd);
545 }
546
547 /***********************************************************************
548  *              wglGetPixelFormat (OPENGL32.@)
549  */
550 INT WINAPI wglGetPixelFormat(HDC hdc)
551 {
552     const struct wgl_funcs *funcs = get_dc_funcs( hdc );
553     if (!funcs) return 0;
554     return funcs->p_GetPixelFormat( hdc );
555 }
556
557 /***********************************************************************
558  *              wglCreateLayerContext (OPENGL32.@)
559  */
560 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
561                                    int iLayerPlane) {
562   TRACE("(%p,%d)\n", hdc, iLayerPlane);
563
564   if (iLayerPlane == 0) {
565       return wglCreateContext(hdc);
566   }
567   FIXME("no handler for layer %d\n", iLayerPlane);
568
569   return NULL;
570 }
571
572 /***********************************************************************
573  *              wglDescribeLayerPlane (OPENGL32.@)
574  */
575 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
576                                   int iPixelFormat,
577                                   int iLayerPlane,
578                                   UINT nBytes,
579                                   LPLAYERPLANEDESCRIPTOR plpd) {
580   FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
581
582   return FALSE;
583 }
584
585 /***********************************************************************
586  *              wglGetLayerPaletteEntries (OPENGL32.@)
587  */
588 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
589                                      int iLayerPlane,
590                                      int iStart,
591                                      int cEntries,
592                                      const COLORREF *pcr) {
593   FIXME("(): stub!\n");
594
595   return 0;
596 }
597
598 /* check if the extension is present in the list */
599 static BOOL has_extension( const char *list, const char *ext )
600 {
601     size_t len = strlen( ext );
602
603     while (list)
604     {
605         while (*list == ' ') list++;
606         if (!strncmp( list, ext, len ) && (!list[len] || list[len] == ' ')) return TRUE;
607         list = strchr( list, ' ' );
608     }
609     return FALSE;
610 }
611
612 static int compar(const void *elt_a, const void *elt_b) {
613   return strcmp(((const OpenGL_extension *) elt_a)->name,
614                 ((const OpenGL_extension *) elt_b)->name);
615 }
616
617 /* Check if a GL extension is supported */
618 static BOOL is_extension_supported(const char* extension)
619 {
620     const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
621     const char *gl_ext_string = (const char*)wine_glGetString(GL_EXTENSIONS);
622
623     TRACE("Checking for extension '%s'\n", extension);
624
625     if(!gl_ext_string) {
626         ERR("No OpenGL extensions found, check if your OpenGL setup is correct!\n");
627         return FALSE;
628     }
629
630     /* We use the GetProcAddress function from the display driver to retrieve function pointers
631      * for OpenGL and WGL extensions. In case of winex11.drv the OpenGL extension lookup is done
632      * using glXGetProcAddress. This function is quite unreliable in the sense that its specs don't
633      * require the function to return NULL when an extension isn't found. For this reason we check
634      * if the OpenGL extension required for the function we are looking up is supported. */
635
636     /* Check if the extension is part of the GL extension string to see if it is supported. */
637     if (has_extension(gl_ext_string, extension))
638         return TRUE;
639
640     /* In general an OpenGL function starts as an ARB/EXT extension and at some stage
641      * it becomes part of the core OpenGL library and can be reached without the ARB/EXT
642      * suffix as well. In the extension table, these functions contain GL_VERSION_major_minor.
643      * Check if we are searching for a core GL function */
644     if(strncmp(extension, "GL_VERSION_", 11) == 0)
645     {
646         const GLubyte *gl_version = funcs->gl.p_glGetString(GL_VERSION);
647         const char *version = extension + 11; /* Move past 'GL_VERSION_' */
648
649         if(!gl_version) {
650             ERR("No OpenGL version found!\n");
651             return FALSE;
652         }
653
654         /* Compare the major/minor version numbers of the native OpenGL library and what is required by the function.
655          * The gl_version string is guaranteed to have at least a major/minor and sometimes it has a release number as well. */
656         if( (gl_version[0] >= version[0]) || ((gl_version[0] == version[0]) && (gl_version[2] >= version[2])) ) {
657             return TRUE;
658         }
659         WARN("The function requires OpenGL version '%c.%c' while your drivers only provide '%c.%c'\n", version[0], version[2], gl_version[0], gl_version[2]);
660     }
661
662     return FALSE;
663 }
664
665 static const OpenGL_extension wgl_extensions[] =
666 {
667     { "wglCreateContextAttribsARB", "WGL_ARB_create_context", wglCreateContextAttribsARB },
668     { "wglMakeContextCurrentARB", "WGL_ARB_make_current_read", wglMakeContextCurrentARB },
669 };
670
671 /***********************************************************************
672  *              wglGetProcAddress (OPENGL32.@)
673  */
674 PROC WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
675   void *local_func;
676   OpenGL_extension  ext;
677   const OpenGL_extension *ext_ret;
678   struct wgl_handle *context = get_current_handle_ptr();
679
680   TRACE("(%s)\n", lpszProc);
681
682   if (lpszProc == NULL)
683     return NULL;
684
685   /* Without an active context opengl32 doesn't know to what
686    * driver it has to dispatch wglGetProcAddress.
687    */
688   if (!context)
689   {
690     WARN("No active WGL context found\n");
691     return NULL;
692   }
693
694   /* Search in the thunks to find the real name of the extension */
695   ext.name = lpszProc;
696   ext_ret = bsearch(&ext, extension_registry, extension_registry_size,
697                     sizeof(OpenGL_extension), compar);
698
699   /* If nothing was found, we are looking for a WGL extension or an unknown GL extension. */
700   if (ext_ret == NULL) {
701     /* If the function name starts with a 'w', it is a WGL extension */
702     if(lpszProc[0] == 'w')
703     {
704         local_func = context->funcs->p_wglGetProcAddress( lpszProc );
705         if (local_func == (void *)1)  /* special function that needs a wrapper */
706         {
707             ext_ret = bsearch( &ext, wgl_extensions, sizeof(wgl_extensions)/sizeof(wgl_extensions[0]),
708                                sizeof(OpenGL_extension), compar );
709             if (ext_ret) return ext_ret->func;
710
711             FIXME( "wrapper missing for %s\n", lpszProc );
712             return NULL;
713         }
714         return local_func;
715     }
716
717     /* We are dealing with an unknown GL extension */
718     WARN("Extension '%s' not defined in opengl32.dll's function table!\n", lpszProc);
719     return NULL;
720   } else { /* We are looking for an OpenGL extension */
721
722     /* Check if the GL extension required by the function is available */
723     if(!is_extension_supported(ext_ret->extension)) {
724         WARN("Extension '%s' required by function '%s' not supported!\n", ext_ret->extension, lpszProc);
725     }
726
727     local_func = context->funcs->p_wglGetProcAddress( ext_ret->name );
728
729     /* After that, look at the extensions defined in the Linux OpenGL library */
730     if (local_func == NULL) {
731       char buf[256];
732       void *ret = NULL;
733
734       /* Remove the last 3 letters (EXT, ARB, ...).
735
736          I know that some extensions have more than 3 letters (MESA, NV,
737          INTEL, ...), but this is only a stop-gap measure to fix buggy
738          OpenGL drivers (moreover, it is only useful for old 1.0 apps
739          that query the glBindTextureEXT extension).
740       */
741       memcpy(buf, ext_ret->name, strlen(ext_ret->name) - 3);
742       buf[strlen(ext_ret->name) - 3] = '\0';
743       TRACE("Extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
744
745       ret = GetProcAddress(opengl32_handle, buf);
746       if (ret != NULL) {
747         TRACE("Found function in main OpenGL library (%p)!\n", ret);
748       } else {
749         WARN("Did not find function %s (%s) in your OpenGL library!\n", lpszProc, ext_ret->name);
750       }
751
752       return ret;
753     } else {
754       struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
755       *((void **)&funcs->ext + (ext_ret - extension_registry)) = local_func;
756       TRACE("returning function (%p)\n", ext_ret->func);
757       return ext_ret->func;
758     }
759   }
760 }
761
762 /***********************************************************************
763  *              wglRealizeLayerPalette (OPENGL32.@)
764  */
765 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
766                                    int iLayerPlane,
767                                    BOOL bRealize) {
768   FIXME("()\n");
769
770   return FALSE;
771 }
772
773 /***********************************************************************
774  *              wglSetLayerPaletteEntries (OPENGL32.@)
775  */
776 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
777                                      int iLayerPlane,
778                                      int iStart,
779                                      int cEntries,
780                                      const COLORREF *pcr) {
781   FIXME("(): stub!\n");
782
783   return 0;
784 }
785
786 /***********************************************************************
787  *              wglSwapLayerBuffers (OPENGL32.@)
788  */
789 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
790                                 UINT fuPlanes) {
791   TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
792
793   if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
794     if (!GdiSwapBuffers(hdc)) return FALSE;
795     fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
796   }
797
798   if (fuPlanes) {
799     WARN("Following layers unhandled: %08x\n", fuPlanes);
800   }
801
802   return TRUE;
803 }
804
805 /***********************************************************************
806  *              wglUseFontBitmaps_common
807  */
808 static BOOL wglUseFontBitmaps_common( HDC hdc, DWORD first, DWORD count, DWORD listBase, BOOL unicode )
809 {
810     const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
811      GLYPHMETRICS gm;
812      unsigned int glyph, size = 0;
813      void *bitmap = NULL, *gl_bitmap = NULL;
814      int org_alignment;
815      BOOL ret = TRUE;
816
817      funcs->gl.p_glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
818      funcs->gl.p_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
819
820      for (glyph = first; glyph < first + count; glyph++) {
821          static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
822          unsigned int needed_size, height, width, width_int;
823
824          if (unicode)
825              needed_size = GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
826          else
827              needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
828
829          TRACE("Glyph: %3d / List: %d size %d\n", glyph, listBase, needed_size);
830          if (needed_size == GDI_ERROR) {
831              ret = FALSE;
832              break;
833          }
834
835          if (needed_size > size) {
836              size = needed_size;
837              HeapFree(GetProcessHeap(), 0, bitmap);
838              HeapFree(GetProcessHeap(), 0, gl_bitmap);
839              bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
840              gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
841          }
842          if (unicode)
843              ret = (GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
844          else
845              ret = (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
846          if (!ret) break;
847
848          if (TRACE_ON(wgl)) {
849              unsigned int bitmask;
850              unsigned char *bitmap_ = bitmap;
851
852              TRACE("  - bbox: %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
853              TRACE("  - origin: (%d, %d)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
854              TRACE("  - increment: %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
855              if (needed_size != 0) {
856                  TRACE("  - bitmap:\n");
857                  for (height = 0; height < gm.gmBlackBoxY; height++) {
858                      TRACE("      ");
859                      for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
860                          if (bitmask == 0) {
861                              bitmap_ += 1;
862                              bitmask = 0x80;
863                          }
864                          if (*bitmap_ & bitmask)
865                              TRACE("*");
866                          else
867                              TRACE(" ");
868                      }
869                      bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
870                      TRACE("\n");
871                  }
872              }
873          }
874
875          /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
876          * glyph for it to be drawn properly.
877          */
878          if (needed_size != 0) {
879              width_int = (gm.gmBlackBoxX + 31) / 32;
880              for (height = 0; height < gm.gmBlackBoxY; height++) {
881                  for (width = 0; width < width_int; width++) {
882                      ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
883                      ((int *) bitmap)[height * width_int + width];
884                  }
885              }
886          }
887
888          funcs->gl.p_glNewList(listBase++, GL_COMPILE);
889          if (needed_size != 0) {
890              funcs->gl.p_glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
891                      0 - gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - gm.gmptGlyphOrigin.y,
892                      gm.gmCellIncX, gm.gmCellIncY,
893                      gl_bitmap);
894          } else {
895              /* This is the case of 'empty' glyphs like the space character */
896              funcs->gl.p_glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
897          }
898          funcs->gl.p_glEndList();
899      }
900
901      funcs->gl.p_glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
902      HeapFree(GetProcessHeap(), 0, bitmap);
903      HeapFree(GetProcessHeap(), 0, gl_bitmap);
904      return ret;
905 }
906
907 /***********************************************************************
908  *              wglUseFontBitmapsA (OPENGL32.@)
909  */
910 BOOL WINAPI wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase)
911 {
912     return wglUseFontBitmaps_common( hdc, first, count, listBase, FALSE );
913 }
914
915 /***********************************************************************
916  *              wglUseFontBitmapsW (OPENGL32.@)
917  */
918 BOOL WINAPI wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase)
919 {
920     return wglUseFontBitmaps_common( hdc, first, count, listBase, TRUE );
921 }
922
923 #ifdef SONAME_LIBGLU
924
925 static void *load_libglu(void)
926 {
927     static int already_loaded;
928     void *handle;
929
930     if (already_loaded) return libglu_handle;
931     already_loaded = 1;
932
933     TRACE("Trying to load GLU library: %s\n", SONAME_LIBGLU);
934     handle = wine_dlopen(SONAME_LIBGLU, RTLD_NOW, NULL, 0);
935     if (!handle)
936     {
937         WARN("Failed to load %s\n", SONAME_LIBGLU);
938         return NULL;
939     }
940
941 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(handle, #f, NULL, 0)) == NULL) goto sym_not_found;
942 LOAD_FUNCPTR(gluNewTess)
943 LOAD_FUNCPTR(gluDeleteTess)
944 LOAD_FUNCPTR(gluTessBeginContour)
945 LOAD_FUNCPTR(gluTessBeginPolygon)
946 LOAD_FUNCPTR(gluTessCallback)
947 LOAD_FUNCPTR(gluTessEndContour)
948 LOAD_FUNCPTR(gluTessEndPolygon)
949 LOAD_FUNCPTR(gluTessVertex)
950 #undef LOAD_FUNCPTR
951     libglu_handle = handle;
952     return handle;
953
954 sym_not_found:
955     WARN("Unable to load function ptrs from libGLU\n");
956     /* Close the library as we won't use it */
957     wine_dlclose(handle, NULL, 0);
958     return NULL;
959 }
960
961 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
962 {
963     vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;  
964     vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;  
965     vertex[2] = 0.0;
966 }
967
968 static void tess_callback_vertex(GLvoid *vertex)
969 {
970     const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
971     GLdouble *dbl = vertex;
972     TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
973     funcs->gl.p_glVertex3dv(vertex);
974 }
975
976 static void tess_callback_begin(GLenum which)
977 {
978     const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
979     TRACE("%d\n", which);
980     funcs->gl.p_glBegin(which);
981 }
982
983 static void tess_callback_end(void)
984 {
985     const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
986     TRACE("\n");
987     funcs->gl.p_glEnd();
988 }
989
990 /***********************************************************************
991  *              wglUseFontOutlines_common
992  */
993 static BOOL wglUseFontOutlines_common(HDC hdc,
994                                       DWORD first,
995                                       DWORD count,
996                                       DWORD listBase,
997                                       FLOAT deviation,
998                                       FLOAT extrusion,
999                                       int format,
1000                                       LPGLYPHMETRICSFLOAT lpgmf,
1001                                       BOOL unicode)
1002 {
1003     const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
1004     UINT glyph;
1005     const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
1006     GLUtesselator *tess;
1007     LOGFONTW lf;
1008     HFONT old_font, unscaled_font;
1009     UINT em_size = 1024;
1010     RECT rc;
1011
1012     TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
1013           listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
1014
1015     if (!load_libglu())
1016     {
1017         ERR("libGLU is required for this function but isn't loaded\n");
1018         return FALSE;
1019     }
1020
1021     tess = pgluNewTess();
1022     if(!tess) return FALSE;
1023     pgluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
1024     pgluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
1025     pgluTessCallback(tess, GLU_TESS_END, tess_callback_end);
1026
1027     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1028     rc.left = rc.right = rc.bottom = 0;
1029     rc.top = em_size;
1030     DPtoLP(hdc, (POINT*)&rc, 2);
1031     lf.lfHeight = -abs(rc.top - rc.bottom);
1032     lf.lfOrientation = lf.lfEscapement = 0;
1033     unscaled_font = CreateFontIndirectW(&lf);
1034     old_font = SelectObject(hdc, unscaled_font);
1035
1036     for (glyph = first; glyph < first + count; glyph++)
1037     {
1038         DWORD needed;
1039         GLYPHMETRICS gm;
1040         BYTE *buf;
1041         TTPOLYGONHEADER *pph;
1042         TTPOLYCURVE *ppc;
1043         GLdouble *vertices;
1044
1045         if(unicode)
1046             needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
1047         else
1048             needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
1049
1050         if(needed == GDI_ERROR)
1051             goto error;
1052
1053         buf = HeapAlloc(GetProcessHeap(), 0, needed);
1054         vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
1055
1056         if(unicode)
1057             GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
1058         else
1059             GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
1060
1061         TRACE("glyph %d\n", glyph);
1062
1063         if(lpgmf)
1064         {
1065             lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
1066             lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
1067             lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
1068             lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
1069             lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
1070             lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
1071
1072             TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
1073                   lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY); 
1074             lpgmf++;
1075         }
1076
1077         funcs->gl.p_glNewList(listBase++, GL_COMPILE);
1078         pgluTessBeginPolygon(tess, NULL);
1079
1080         pph = (TTPOLYGONHEADER*)buf;
1081         while((BYTE*)pph < buf + needed)
1082         {
1083             TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
1084
1085             pgluTessBeginContour(tess);
1086
1087             fixed_to_double(pph->pfxStart, em_size, vertices);
1088             pgluTessVertex(tess, vertices, vertices);
1089             vertices += 3;
1090
1091             ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1092             while((char*)ppc < (char*)pph + pph->cb)
1093             {
1094                 int i;
1095
1096                 switch(ppc->wType) {
1097                 case TT_PRIM_LINE:
1098                     for(i = 0; i < ppc->cpfx; i++)
1099                     {
1100                         TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1101                         fixed_to_double(ppc->apfx[i], em_size, vertices); 
1102                         pgluTessVertex(tess, vertices, vertices);
1103                         vertices += 3;
1104                     }
1105                     break;
1106
1107                 case TT_PRIM_QSPLINE:
1108                     for(i = 0; i < ppc->cpfx/2; i++)
1109                     {
1110                         /* FIXME: just connecting the control points for now */
1111                         TRACE("\t\tcurve  %d,%d %d,%d\n",
1112                               ppc->apfx[i * 2].x.value,     ppc->apfx[i * 3].y.value,
1113                               ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
1114                         fixed_to_double(ppc->apfx[i * 2], em_size, vertices); 
1115                         pgluTessVertex(tess, vertices, vertices);
1116                         vertices += 3;
1117                         fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices); 
1118                         pgluTessVertex(tess, vertices, vertices);
1119                         vertices += 3;
1120                     }
1121                     break;
1122                 default:
1123                     ERR("\t\tcurve type = %d\n", ppc->wType);
1124                     pgluTessEndContour(tess);
1125                     goto error_in_list;
1126                 }
1127
1128                 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1129                                      (ppc->cpfx - 1) * sizeof(POINTFX));
1130             }
1131             pgluTessEndContour(tess);
1132             pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1133         }
1134
1135 error_in_list:
1136         pgluTessEndPolygon(tess);
1137         funcs->gl.p_glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
1138         funcs->gl.p_glEndList();
1139         HeapFree(GetProcessHeap(), 0, buf);
1140         HeapFree(GetProcessHeap(), 0, vertices);
1141     }
1142
1143  error:
1144     DeleteObject(SelectObject(hdc, old_font));
1145     pgluDeleteTess(tess);
1146     return TRUE;
1147
1148 }
1149
1150 #else /* SONAME_LIBGLU */
1151
1152 static BOOL wglUseFontOutlines_common(HDC hdc,
1153                                       DWORD first,
1154                                       DWORD count,
1155                                       DWORD listBase,
1156                                       FLOAT deviation,
1157                                       FLOAT extrusion,
1158                                       int format,
1159                                       LPGLYPHMETRICSFLOAT lpgmf,
1160                                       BOOL unicode)
1161 {
1162     FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1163     return FALSE;
1164 }
1165
1166 #endif /* SONAME_LIBGLU */
1167
1168 /***********************************************************************
1169  *              wglUseFontOutlinesA (OPENGL32.@)
1170  */
1171 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1172                                 DWORD first,
1173                                 DWORD count,
1174                                 DWORD listBase,
1175                                 FLOAT deviation,
1176                                 FLOAT extrusion,
1177                                 int format,
1178                                 LPGLYPHMETRICSFLOAT lpgmf)
1179 {
1180     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1181 }
1182
1183 /***********************************************************************
1184  *              wglUseFontOutlinesW (OPENGL32.@)
1185  */
1186 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
1187                                 DWORD first,
1188                                 DWORD count,
1189                                 DWORD listBase,
1190                                 FLOAT deviation,
1191                                 FLOAT extrusion,
1192                                 int format,
1193                                 LPGLYPHMETRICSFLOAT lpgmf)
1194 {
1195     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1196 }
1197
1198 /***********************************************************************
1199  *              glDebugEntry (OPENGL32.@)
1200  */
1201 GLint WINAPI wine_glDebugEntry( GLint unknown1, GLint unknown2 )
1202 {
1203     return 0;
1204 }
1205
1206 /* build the extension string by filtering out the disabled extensions */
1207 static char *build_gl_extensions( const char *extensions )
1208 {
1209     char *p, *str, *disabled = NULL;
1210     const char *end;
1211     HKEY hkey;
1212
1213     TRACE( "GL_EXTENSIONS:\n" );
1214
1215     if (!extensions) extensions = "";
1216
1217     /* @@ Wine registry key: HKCU\Software\Wine\OpenGL */
1218     if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\OpenGL", &hkey ))
1219     {
1220         DWORD size, ret = RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, NULL, &size );
1221         if (!ret && (disabled = HeapAlloc( GetProcessHeap(), 0, size )))
1222             ret = RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (BYTE *)disabled, &size );
1223         RegCloseKey( hkey );
1224         if (ret) *disabled = 0;
1225     }
1226
1227     if ((str = HeapAlloc( GetProcessHeap(), 0, strlen(extensions) + 2 )))
1228     {
1229         p = str;
1230         for (;;)
1231         {
1232             while (*extensions == ' ') extensions++;
1233             if (!*extensions) break;
1234             if (!(end = strchr( extensions, ' ' ))) end = extensions + strlen( extensions );
1235             memcpy( p, extensions, end - extensions );
1236             p[end - extensions] = 0;
1237             if (!has_extension( disabled, p ))
1238             {
1239                 TRACE("++ %s\n", p );
1240                 p += end - extensions;
1241                 *p++ = ' ';
1242             }
1243             else TRACE("-- %s (disabled by config)\n", p );
1244             extensions = end;
1245         }
1246         *p = 0;
1247     }
1248     HeapFree( GetProcessHeap(), 0, disabled );
1249     return str;
1250 }
1251
1252 /***********************************************************************
1253  *              glGetString (OPENGL32.@)
1254  */
1255 const GLubyte * WINAPI wine_glGetString( GLenum name )
1256 {
1257   const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
1258   static const GLubyte *gl_extensions;
1259
1260   /* this is for buggy nvidia driver, crashing if called from a different
1261      thread with no context */
1262   if(wglGetCurrentContext() == NULL)
1263     return NULL;
1264
1265   if (name != GL_EXTENSIONS) return funcs->gl.p_glGetString(name);
1266
1267   if (!gl_extensions)
1268   {
1269       const char *orig_ext = (const char *)funcs->gl.p_glGetString(GL_EXTENSIONS);
1270       char *new_ext = build_gl_extensions( orig_ext );
1271       if (InterlockedCompareExchangePointer( (void **)&gl_extensions, new_ext, NULL ))
1272           HeapFree( GetProcessHeap(), 0, new_ext );
1273   }
1274   return gl_extensions;
1275 }
1276
1277 /***********************************************************************
1278  *              wglSwapBuffers (OPENGL32.@)
1279  */
1280 BOOL WINAPI DECLSPEC_HOTPATCH wglSwapBuffers( HDC hdc )
1281 {
1282     return GdiSwapBuffers(hdc);
1283 }
1284
1285 /**********************************************************************/
1286
1287 static void process_detach(void)
1288 {
1289   if (libglu_handle) wine_dlclose(libglu_handle, NULL, 0);
1290 }
1291
1292 /***********************************************************************
1293  *           OpenGL initialisation routine
1294  */
1295 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1296 {
1297     switch(reason)
1298     {
1299     case DLL_PROCESS_ATTACH:
1300         opengl32_handle = hinst;
1301         DisableThreadLibraryCalls(hinst);
1302         NtCurrentTeb()->glTable = &null_opengl_funcs;
1303         break;
1304     case DLL_THREAD_ATTACH:
1305         NtCurrentTeb()->glTable = &null_opengl_funcs;
1306         break;
1307     case DLL_PROCESS_DETACH:
1308         process_detach();
1309         break;
1310     }
1311     return TRUE;
1312 }