mshtml: Keep reference in node returned from get_node.
[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/library.h"
43 #include "wine/debug.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
46 WINE_DECLARE_DEBUG_CHANNEL(opengl);
47
48 static struct
49 {
50     PROC  (WINAPI *p_wglGetProcAddress)(LPCSTR  lpszProc);
51     BOOL  (WINAPI *p_SetPixelFormat)(HDC hdc, INT iPixelFormat, const PIXELFORMATDESCRIPTOR *ppfd);
52     BOOL  (WINAPI *p_wglMakeCurrent)(HDC hdc, HGLRC hglrc);
53     HGLRC (WINAPI *p_wglCreateContext)(HDC hdc);
54     INT   (WINAPI *p_ChoosePixelFormat)(HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd);
55     INT   (WINAPI *p_DescribePixelFormat)(HDC hdc, INT iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd);
56     INT   (WINAPI *p_GetPixelFormat)(HDC hdc);
57
58     /* internal WGL functions */
59     BOOL  (WINAPI *p_wglCopyContext)(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask);
60     BOOL  (WINAPI *p_wglDeleteContext)(HGLRC hglrc);
61     void  (WINAPI *p_wglFinish)(void);
62     void  (WINAPI *p_wglFlush)(void);
63     HGLRC (WINAPI *p_wglGetCurrentContext)(void);
64     HDC   (WINAPI *p_wglGetCurrentDC)(void);
65     void  (WINAPI *p_wglGetIntegerv)(GLenum pname, GLint* params);
66     BOOL  (WINAPI *p_wglShareLists)(HGLRC hglrc1, HGLRC hglrc2);
67 } wine_wgl;
68
69 #ifdef SONAME_LIBGLU
70 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
71 MAKE_FUNCPTR(gluNewTess)
72 MAKE_FUNCPTR(gluDeleteTess)
73 MAKE_FUNCPTR(gluTessBeginContour)
74 MAKE_FUNCPTR(gluTessBeginPolygon)
75 MAKE_FUNCPTR(gluTessCallback)
76 MAKE_FUNCPTR(gluTessEndContour)
77 MAKE_FUNCPTR(gluTessEndPolygon)
78 MAKE_FUNCPTR(gluTessVertex)
79 #undef MAKE_FUNCPTR
80 #endif /* SONAME_LIBGLU */
81
82 void (*wine_tsx11_lock_ptr)(void) = NULL;
83 void (*wine_tsx11_unlock_ptr)(void) = NULL;
84
85 static HMODULE opengl32_handle;
86 static void* libglu_handle = NULL;
87
88 static char* internal_gl_disabled_extensions = NULL;
89 static char* internal_gl_extensions = NULL;
90
91 const GLubyte * WINAPI wine_glGetString( GLenum name );
92
93 /***********************************************************************
94  *               wglSetPixelFormat(OPENGL32.@)
95  */
96 BOOL WINAPI wglSetPixelFormat( HDC hdc, INT iPixelFormat,
97                                const PIXELFORMATDESCRIPTOR *ppfd)
98 {
99   return wine_wgl.p_SetPixelFormat(hdc, iPixelFormat, ppfd);
100 }
101
102 /***********************************************************************
103  *              wglCopyContext (OPENGL32.@)
104  */
105 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask)
106 {
107     if (!hglrcSrc || !hglrcDst)
108     {
109         SetLastError(ERROR_INVALID_HANDLE);
110         return FALSE;
111     }
112     return wine_wgl.p_wglCopyContext(hglrcSrc, hglrcDst, mask);
113 }
114
115 /***********************************************************************
116  *              wglDeleteContext (OPENGL32.@)
117  */
118 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
119 {
120     if (!hglrc)
121     {
122         SetLastError(ERROR_INVALID_HANDLE);
123         return FALSE;
124     }
125     return wine_wgl.p_wglDeleteContext(hglrc);
126 }
127
128 /***********************************************************************
129  *              wglMakeCurrent (OPENGL32.@)
130  */
131 BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hglrc)
132 {
133   return wine_wgl.p_wglMakeCurrent(hdc, hglrc);
134 }
135
136 /***********************************************************************
137  *              wglShareLists (OPENGL32.@)
138  */
139 BOOL WINAPI wglShareLists(HGLRC hglrc1, HGLRC hglrc2)
140 {
141     if (!hglrc1 || !hglrc2)
142     {
143         SetLastError(ERROR_INVALID_HANDLE);
144         return FALSE;
145     }
146     return wine_wgl.p_wglShareLists(hglrc1, hglrc2);
147 }
148
149 /***********************************************************************
150  *              wglGetCurrentDC (OPENGL32.@)
151  */
152 HDC WINAPI wglGetCurrentDC(void)
153 {
154   return wine_wgl.p_wglGetCurrentDC();
155 }
156
157 /***********************************************************************
158  *              wglCreateContext (OPENGL32.@)
159  */
160 HGLRC WINAPI wglCreateContext(HDC hdc)
161 {
162   return wine_wgl.p_wglCreateContext(hdc);
163 }
164
165 /***********************************************************************
166  *              wglGetCurrentContext (OPENGL32.@)
167  */
168 HGLRC WINAPI wglGetCurrentContext(void)
169 {
170   return wine_wgl.p_wglGetCurrentContext();
171 }
172
173 /***********************************************************************
174  *              wglChoosePixelFormat (OPENGL32.@)
175  */
176 INT WINAPI wglChoosePixelFormat(HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd)
177 {
178   return wine_wgl.p_ChoosePixelFormat(hdc, ppfd);
179 }
180
181 /***********************************************************************
182  *              wglDescribePixelFormat (OPENGL32.@)
183  */
184 INT WINAPI wglDescribePixelFormat(HDC hdc, INT iPixelFormat, UINT nBytes,
185                                 LPPIXELFORMATDESCRIPTOR ppfd)
186 {
187   return wine_wgl.p_DescribePixelFormat(hdc, iPixelFormat, nBytes, ppfd);
188 }
189 /***********************************************************************
190  *              wglGetPixelFormat (OPENGL32.@)
191  */
192 INT WINAPI wglGetPixelFormat(HDC hdc)
193 {
194   return wine_wgl.p_GetPixelFormat(hdc);
195 }
196
197 /***********************************************************************
198  *              wglCreateLayerContext (OPENGL32.@)
199  */
200 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
201                                    int iLayerPlane) {
202   TRACE("(%p,%d)\n", hdc, iLayerPlane);
203
204   if (iLayerPlane == 0) {
205       return wglCreateContext(hdc);
206   }
207   FIXME(" no handler for layer %d\n", iLayerPlane);
208
209   return NULL;
210 }
211
212 /***********************************************************************
213  *              wglDescribeLayerPlane (OPENGL32.@)
214  */
215 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
216                                   int iPixelFormat,
217                                   int iLayerPlane,
218                                   UINT nBytes,
219                                   LPLAYERPLANEDESCRIPTOR plpd) {
220   FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
221
222   return FALSE;
223 }
224
225 /***********************************************************************
226  *              wglGetLayerPaletteEntries (OPENGL32.@)
227  */
228 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
229                                      int iLayerPlane,
230                                      int iStart,
231                                      int cEntries,
232                                      const COLORREF *pcr) {
233   FIXME("(): stub !\n");
234
235   return 0;
236 }
237
238 static int compar(const void *elt_a, const void *elt_b) {
239   return strcmp(((const OpenGL_extension *) elt_a)->name,
240                 ((const OpenGL_extension *) elt_b)->name);
241 }
242
243 /* Check if a GL extension is supported */
244 static BOOL is_extension_supported(const char* extension)
245 {
246     const char *gl_ext_string = (const char*)wine_glGetString(GL_EXTENSIONS);
247
248     TRACE("Checking for extension '%s'\n", extension);
249
250     if(!gl_ext_string) {
251         ERR("No OpenGL extensions found, check if your OpenGL setup is correct!\n");
252         return FALSE;
253     }
254
255     /* We use the GetProcAddress function from the display driver to retrieve function pointers
256      * for OpenGL and WGL extensions. In case of winex11.drv the OpenGL extension lookup is done
257      * using glXGetProcAddress. This function is quite unreliable in the sense that its specs don't
258      * require the function to return NULL when a extension isn't found. For this reason we check
259      * if the OpenGL extension required for the function we are looking up is supported. */
260
261     /* Check if the extension is part of the GL extension string to see if it is supported. */
262     if(strstr(gl_ext_string, extension) != NULL)
263         return TRUE;
264
265     /* In general an OpenGL function starts as an ARB/EXT extension and at some stage
266      * it becomes part of the core OpenGL library and can be reached without the ARB/EXT
267      * suffix as well. In the extension table, these functions contain GL_VERSION_major_minor.
268      * Check if we are searching for a core GL function */
269     if(strncmp(extension, "GL_VERSION_", 11) == 0)
270     {
271         const GLubyte *gl_version = glGetString(GL_VERSION);
272         const char *version = extension + 11; /* Move past 'GL_VERSION_' */
273
274         if(!gl_version) {
275             ERR("Error no OpenGL version found,\n");
276             return FALSE;
277         }
278
279         /* Compare the major/minor version numbers of the native OpenGL library and what is required by the function.
280          * The gl_version string is guaranteed to have at least a major/minor and sometimes it has a release number as well. */
281         if( (gl_version[0] >= version[0]) || ((gl_version[0] == version[0]) && (gl_version[2] >= version[2])) ) {
282             return TRUE;
283         }
284         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]);
285     }
286
287     return FALSE;
288 }
289
290 /***********************************************************************
291  *              wglGetProcAddress (OPENGL32.@)
292  */
293 PROC WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
294   void *local_func;
295   OpenGL_extension  ext;
296   const OpenGL_extension *ext_ret;
297
298   TRACE("(%s)\n", lpszProc);
299
300   if (lpszProc == NULL)
301     return NULL;
302
303   /* Without an active context opengl32 doesn't know to what
304    * driver it has to dispatch wglGetProcAddress.
305    */
306   if (wglGetCurrentContext() == NULL)
307   {
308     WARN("No active WGL context found\n");
309     return NULL;
310   }
311
312   /* First, look if it's not already defined in the 'standard' OpenGL functions */
313   if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
314     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
315     return local_func;
316   }
317
318   /* After that, search in the thunks to find the real name of the extension */
319   ext.name = lpszProc;
320   ext_ret = bsearch(&ext, extension_registry, extension_registry_size,
321                     sizeof(OpenGL_extension), compar);
322
323   /* If nothing was found, we are looking for a WGL extension or an unknown GL extension. */
324   if (ext_ret == NULL) {
325     /* If the function name starts with a w it is a WGL extension */
326     if(lpszProc[0] == 'w')
327       return wine_wgl.p_wglGetProcAddress(lpszProc);
328
329     /* We are dealing with an unknown GL extension. */
330     WARN("Extension '%s' not defined in opengl32.dll's function table!\n", lpszProc);
331     return NULL;
332   } else { /* We are looking for an OpenGL extension */
333
334     /* Check if the GL extension required by the function is available */
335     if(!is_extension_supported(ext_ret->extension)) {
336         WARN("Extension '%s' required by function '%s' not supported!\n", ext_ret->extension, lpszProc);
337     }
338
339     local_func = wine_wgl.p_wglGetProcAddress(ext_ret->name);
340
341     /* After that, look at the extensions defined in the Linux OpenGL library */
342     if (local_func == NULL) {
343       char buf[256];
344       void *ret = NULL;
345
346       /* Remove the 3 last letters (EXT, ARB, ...).
347
348          I know that some extensions have more than 3 letters (MESA, NV,
349          INTEL, ...), but this is only a stop-gap measure to fix buggy
350          OpenGL drivers (moreover, it is only useful for old 1.0 apps
351          that query the glBindTextureEXT extension).
352       */
353       memcpy(buf, ext_ret->name, strlen(ext_ret->name) - 3);
354       buf[strlen(ext_ret->name) - 3] = '\0';
355       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
356
357       ret = GetProcAddress(opengl32_handle, buf);
358       if (ret != NULL) {
359         TRACE(" found function in main OpenGL library (%p) !\n", ret);
360       } else {
361         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->name);
362       }
363
364       return ret;
365     } else {
366       TRACE(" returning function  (%p)\n", ext_ret->func);
367       extension_funcs[ext_ret - extension_registry] = local_func;
368
369       return ext_ret->func;
370     }
371   }
372 }
373
374 /***********************************************************************
375  *              wglRealizeLayerPalette (OPENGL32.@)
376  */
377 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
378                                    int iLayerPlane,
379                                    BOOL bRealize) {
380   FIXME("()\n");
381
382   return FALSE;
383 }
384
385 /***********************************************************************
386  *              wglSetLayerPaletteEntries (OPENGL32.@)
387  */
388 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
389                                      int iLayerPlane,
390                                      int iStart,
391                                      int cEntries,
392                                      const COLORREF *pcr) {
393   FIXME("(): stub !\n");
394
395   return 0;
396 }
397
398 /***********************************************************************
399  *              wglSwapLayerBuffers (OPENGL32.@)
400  */
401 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
402                                 UINT fuPlanes) {
403   TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
404
405   if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
406     if (!SwapBuffers(hdc)) return FALSE;
407     fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
408   }
409
410   if (fuPlanes) {
411     WARN("Following layers unhandled : %08x\n", fuPlanes);
412   }
413
414   return TRUE;
415 }
416
417 /***********************************************************************
418  *              wglUseFontBitmaps_common
419  */
420 static BOOL wglUseFontBitmaps_common( HDC hdc, DWORD first, DWORD count, DWORD listBase, BOOL unicode )
421 {
422      GLYPHMETRICS gm;
423      unsigned int glyph, size = 0;
424      void *bitmap = NULL, *gl_bitmap = NULL;
425      int org_alignment;
426      BOOL ret = TRUE;
427
428      ENTER_GL();
429      glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
430      glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
431      LEAVE_GL();
432
433      for (glyph = first; glyph < first + count; glyph++) {
434          static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
435          unsigned int needed_size, height, width, width_int;
436
437          if (unicode)
438              needed_size = GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
439          else
440              needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
441
442          TRACE("Glyph : %3d / List : %d size %d\n", glyph, listBase, needed_size);
443          if (needed_size == GDI_ERROR) {
444              ret = FALSE;
445              break;
446          }
447
448          if (needed_size > size) {
449              size = needed_size;
450              HeapFree(GetProcessHeap(), 0, bitmap);
451              HeapFree(GetProcessHeap(), 0, gl_bitmap);
452              bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
453              gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
454          }
455          if (unicode)
456              ret = (GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
457          else
458              ret = (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
459          if (!ret) break;
460
461          if (TRACE_ON(wgl)) {
462              unsigned int bitmask;
463              unsigned char *bitmap_ = bitmap;
464
465              TRACE("  - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
466              TRACE("  - origin : (%d , %d)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
467              TRACE("  - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
468              if (needed_size != 0) {
469                  TRACE("  - bitmap :\n");
470                  for (height = 0; height < gm.gmBlackBoxY; height++) {
471                      TRACE("      ");
472                      for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
473                          if (bitmask == 0) {
474                              bitmap_ += 1;
475                              bitmask = 0x80;
476                          }
477                          if (*bitmap_ & bitmask)
478                              TRACE("*");
479                          else
480                              TRACE(" ");
481                      }
482                      bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
483                      TRACE("\n");
484                  }
485              }
486          }
487
488          /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
489          * glyph for it to be drawn properly.
490          */
491          if (needed_size != 0) {
492              width_int = (gm.gmBlackBoxX + 31) / 32;
493              for (height = 0; height < gm.gmBlackBoxY; height++) {
494                  for (width = 0; width < width_int; width++) {
495                      ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
496                      ((int *) bitmap)[height * width_int + width];
497                  }
498              }
499          }
500
501          ENTER_GL();
502          glNewList(listBase++, GL_COMPILE);
503          if (needed_size != 0) {
504              glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
505                      0 - gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - gm.gmptGlyphOrigin.y,
506                      gm.gmCellIncX, gm.gmCellIncY,
507                      gl_bitmap);
508          } else {
509              /* This is the case of 'empty' glyphs like the space character */
510              glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
511          }
512          glEndList();
513          LEAVE_GL();
514      }
515
516      ENTER_GL();
517      glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
518      LEAVE_GL();
519      HeapFree(GetProcessHeap(), 0, bitmap);
520      HeapFree(GetProcessHeap(), 0, gl_bitmap);
521      return ret;
522 }
523
524 /***********************************************************************
525  *              wglUseFontBitmapsA (OPENGL32.@)
526  */
527 BOOL WINAPI wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase)
528 {
529     return wglUseFontBitmaps_common( hdc, first, count, listBase, FALSE );
530 }
531
532 /***********************************************************************
533  *              wglUseFontBitmapsW (OPENGL32.@)
534  */
535 BOOL WINAPI wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase)
536 {
537     return wglUseFontBitmaps_common( hdc, first, count, listBase, TRUE );
538 }
539
540 #ifdef SONAME_LIBGLU
541
542 static void *load_libglu(void)
543 {
544     static int already_loaded;
545     void *handle;
546
547     if (already_loaded) return libglu_handle;
548     already_loaded = 1;
549
550     TRACE("Trying to load GLU library: %s\n", SONAME_LIBGLU);
551     handle = wine_dlopen(SONAME_LIBGLU, RTLD_NOW, NULL, 0);
552     if (!handle)
553     {
554         WARN("Failed to load %s\n", SONAME_LIBGLU);
555         return NULL;
556     }
557
558 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(handle, #f, NULL, 0)) == NULL) goto sym_not_found;
559 LOAD_FUNCPTR(gluNewTess)
560 LOAD_FUNCPTR(gluDeleteTess)
561 LOAD_FUNCPTR(gluTessBeginContour)
562 LOAD_FUNCPTR(gluTessBeginPolygon)
563 LOAD_FUNCPTR(gluTessCallback)
564 LOAD_FUNCPTR(gluTessEndContour)
565 LOAD_FUNCPTR(gluTessEndPolygon)
566 LOAD_FUNCPTR(gluTessVertex)
567 #undef LOAD_FUNCPTR
568     libglu_handle = handle;
569     return handle;
570
571 sym_not_found:
572     WARN("Unable to load function ptrs from libGLU\n");
573     /* Close the library as we won't use it */
574     wine_dlclose(handle, NULL, 0);
575     return NULL;
576 }
577
578 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
579 {
580     vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;  
581     vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;  
582     vertex[2] = 0.0;
583 }
584
585 static void tess_callback_vertex(GLvoid *vertex)
586 {
587     GLdouble *dbl = vertex;
588     TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
589     glVertex3dv(vertex);
590 }
591
592 static void tess_callback_begin(GLenum which)
593 {
594     TRACE("%d\n", which);
595     glBegin(which);
596 }
597
598 static void tess_callback_end(void)
599 {
600     TRACE("\n");
601     glEnd();
602 }
603
604 /***********************************************************************
605  *              wglUseFontOutlines_common
606  */
607 static BOOL wglUseFontOutlines_common(HDC hdc,
608                                       DWORD first,
609                                       DWORD count,
610                                       DWORD listBase,
611                                       FLOAT deviation,
612                                       FLOAT extrusion,
613                                       int format,
614                                       LPGLYPHMETRICSFLOAT lpgmf,
615                                       BOOL unicode)
616 {
617     UINT glyph;
618     const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
619     GLUtesselator *tess;
620     LOGFONTW lf;
621     HFONT old_font, unscaled_font;
622     UINT em_size = 1024;
623     RECT rc;
624
625     TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
626           listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
627
628     if (!load_libglu())
629     {
630         ERR("libGLU is required for this function but isn't loaded\n");
631         return FALSE;
632     }
633
634     ENTER_GL();
635     tess = pgluNewTess();
636     if(tess)
637     {
638         pgluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
639         pgluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
640         pgluTessCallback(tess, GLU_TESS_END, tess_callback_end);
641     }
642     LEAVE_GL();
643
644     if(!tess) return FALSE;
645
646     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
647     rc.left = rc.right = rc.bottom = 0;
648     rc.top = em_size;
649     DPtoLP(hdc, (POINT*)&rc, 2);
650     lf.lfHeight = -abs(rc.top - rc.bottom);
651     lf.lfOrientation = lf.lfEscapement = 0;
652     unscaled_font = CreateFontIndirectW(&lf);
653     old_font = SelectObject(hdc, unscaled_font);
654
655     for (glyph = first; glyph < first + count; glyph++)
656     {
657         DWORD needed;
658         GLYPHMETRICS gm;
659         BYTE *buf;
660         TTPOLYGONHEADER *pph;
661         TTPOLYCURVE *ppc;
662         GLdouble *vertices;
663
664         if(unicode)
665             needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
666         else
667             needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
668
669         if(needed == GDI_ERROR)
670             goto error;
671
672         buf = HeapAlloc(GetProcessHeap(), 0, needed);
673         vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
674
675         if(unicode)
676             GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
677         else
678             GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
679
680         TRACE("glyph %d\n", glyph);
681
682         if(lpgmf)
683         {
684             lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
685             lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
686             lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
687             lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
688             lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
689             lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
690
691             TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
692                   lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY); 
693             lpgmf++;
694         }
695
696         ENTER_GL();
697         glNewList(listBase++, GL_COMPILE);
698         pgluTessBeginPolygon(tess, NULL);
699
700         pph = (TTPOLYGONHEADER*)buf;
701         while((BYTE*)pph < buf + needed)
702         {
703             TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
704
705             pgluTessBeginContour(tess);
706
707             fixed_to_double(pph->pfxStart, em_size, vertices);
708             pgluTessVertex(tess, vertices, vertices);
709             vertices += 3;
710
711             ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
712             while((char*)ppc < (char*)pph + pph->cb)
713             {
714                 int i;
715
716                 switch(ppc->wType) {
717                 case TT_PRIM_LINE:
718                     for(i = 0; i < ppc->cpfx; i++)
719                     {
720                         TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
721                         fixed_to_double(ppc->apfx[i], em_size, vertices); 
722                         pgluTessVertex(tess, vertices, vertices);
723                         vertices += 3;
724                     }
725                     break;
726
727                 case TT_PRIM_QSPLINE:
728                     for(i = 0; i < ppc->cpfx/2; i++)
729                     {
730                         /* FIXME just connecting the control points for now */
731                         TRACE("\t\tcurve  %d,%d %d,%d\n",
732                               ppc->apfx[i * 2].x.value,     ppc->apfx[i * 3].y.value,
733                               ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
734                         fixed_to_double(ppc->apfx[i * 2], em_size, vertices); 
735                         pgluTessVertex(tess, vertices, vertices);
736                         vertices += 3;
737                         fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices); 
738                         pgluTessVertex(tess, vertices, vertices);
739                         vertices += 3;
740                     }
741                     break;
742                 default:
743                     ERR("\t\tcurve type = %d\n", ppc->wType);
744                     pgluTessEndContour(tess);
745                     goto error_in_list;
746                 }
747
748                 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
749                                      (ppc->cpfx - 1) * sizeof(POINTFX));
750             }
751             pgluTessEndContour(tess);
752             pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
753         }
754
755 error_in_list:
756         pgluTessEndPolygon(tess);
757         glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
758         glEndList();
759         LEAVE_GL();
760         HeapFree(GetProcessHeap(), 0, buf);
761         HeapFree(GetProcessHeap(), 0, vertices);
762     }
763
764  error:
765     DeleteObject(SelectObject(hdc, old_font));
766     pgluDeleteTess(tess);
767     return TRUE;
768
769 }
770
771 #else /* SONAME_LIBGLU */
772
773 static BOOL wglUseFontOutlines_common(HDC hdc,
774                                       DWORD first,
775                                       DWORD count,
776                                       DWORD listBase,
777                                       FLOAT deviation,
778                                       FLOAT extrusion,
779                                       int format,
780                                       LPGLYPHMETRICSFLOAT lpgmf,
781                                       BOOL unicode)
782 {
783     FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
784     return FALSE;
785 }
786
787 #endif /* SONAME_LIBGLU */
788
789 /***********************************************************************
790  *              wglUseFontOutlinesA (OPENGL32.@)
791  */
792 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
793                                 DWORD first,
794                                 DWORD count,
795                                 DWORD listBase,
796                                 FLOAT deviation,
797                                 FLOAT extrusion,
798                                 int format,
799                                 LPGLYPHMETRICSFLOAT lpgmf)
800 {
801     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
802 }
803
804 /***********************************************************************
805  *              wglUseFontOutlinesW (OPENGL32.@)
806  */
807 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
808                                 DWORD first,
809                                 DWORD count,
810                                 DWORD listBase,
811                                 FLOAT deviation,
812                                 FLOAT extrusion,
813                                 int format,
814                                 LPGLYPHMETRICSFLOAT lpgmf)
815 {
816     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
817 }
818
819 /***********************************************************************
820  *              glFinish (OPENGL32.@)
821  */
822 void WINAPI wine_glFinish( void )
823 {
824     TRACE("()\n");
825     wine_wgl.p_wglFinish();
826 }
827
828 /***********************************************************************
829  *              glFlush (OPENGL32.@)
830  */
831 void WINAPI wine_glFlush( void )
832 {
833     TRACE("()\n");
834     wine_wgl.p_wglFlush();
835 }
836
837 /***********************************************************************
838  *              glGetString (OPENGL32.@)
839  */
840 const GLubyte * WINAPI wine_glGetString( GLenum name )
841 {
842   const GLubyte *ret;
843   const char* GL_Extensions = NULL;
844
845   /* this is for buggy nvidia driver, crashing if called from a different
846      thread with no context */
847   if(wglGetCurrentContext() == NULL)
848     return NULL;
849
850   if (GL_EXTENSIONS != name) {
851     ENTER_GL();
852     ret = glGetString(name);
853     LEAVE_GL();
854     return ret;
855   }
856
857   if (NULL == internal_gl_extensions) {
858     ENTER_GL();
859     GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
860
861     if (GL_Extensions)
862     {
863       size_t len = strlen(GL_Extensions);
864       internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
865
866       TRACE("GL_EXTENSIONS reported:\n");
867       while (*GL_Extensions != 0x00) {
868         const char* Start = GL_Extensions;
869         char        ThisExtn[256];
870
871         while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
872           GL_Extensions++;
873         }
874         memcpy(ThisExtn, Start, (GL_Extensions - Start));
875         ThisExtn[GL_Extensions - Start] = 0;
876         TRACE("- %s:", ThisExtn);
877         
878         /* test if supported API is disabled by config */
879         if (!internal_gl_disabled_extensions || !strstr(internal_gl_disabled_extensions, ThisExtn)) {
880           strcat(internal_gl_extensions, " ");
881           strcat(internal_gl_extensions, ThisExtn);
882           TRACE(" active\n");
883         } else {
884           TRACE(" deactived (by config)\n");
885         }
886
887         if (*GL_Extensions == ' ') GL_Extensions++;
888       }
889     }
890     LEAVE_GL();
891   }
892   return (const GLubyte *) internal_gl_extensions;
893 }
894
895 /***********************************************************************
896  *              glGetIntegerv (OPENGL32.@)
897  */
898 void WINAPI wine_glGetIntegerv( GLenum pname, GLint* params )
899 {
900     wine_wgl.p_wglGetIntegerv(pname, params);
901 }
902
903 /***********************************************************************
904  *              wglSwapBuffers (OPENGL32.@)
905  */
906 BOOL WINAPI DECLSPEC_HOTPATCH wglSwapBuffers( HDC hdc )
907 {
908     return SwapBuffers(hdc);
909 }
910
911 /* This is for brain-dead applications that use OpenGL functions before even
912    creating a rendering context.... */
913 static BOOL process_attach(void)
914 {
915   HMODULE mod_x11, mod_gdi32;
916   DWORD size;
917   HKEY hkey = 0;
918
919   GetDesktopWindow();  /* make sure winex11 is loaded (FIXME) */
920   mod_x11 = GetModuleHandleA( "winex11.drv" );
921   mod_gdi32 = GetModuleHandleA( "gdi32.dll" );
922
923   if (!mod_x11 || !mod_gdi32)
924   {
925       ERR("X11DRV or GDI32 not loaded. Cannot create default context.\n");
926       return FALSE;
927   }
928
929   wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod_x11, "wine_tsx11_lock" );
930   wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod_x11, "wine_tsx11_unlock" );
931
932   wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod_gdi32, "wglGetProcAddress");
933   wine_wgl.p_SetPixelFormat = (void *)GetProcAddress(mod_gdi32, "SetPixelFormat");
934   wine_wgl.p_wglMakeCurrent = (void *)GetProcAddress(mod_gdi32, "wglMakeCurrent");
935   wine_wgl.p_wglCreateContext = (void *)GetProcAddress(mod_gdi32, "wglCreateContext");
936   wine_wgl.p_ChoosePixelFormat = (void *)GetProcAddress(mod_gdi32, "ChoosePixelFormat");
937   wine_wgl.p_DescribePixelFormat = (void *)GetProcAddress(mod_gdi32, "DescribePixelFormat");
938   wine_wgl.p_GetPixelFormat = (void *)GetProcAddress(mod_gdi32, "GetPixelFormat");
939
940   /* internal WGL functions */
941   wine_wgl.p_wglCopyContext = (void *)wine_wgl.p_wglGetProcAddress("wglCopyContext");
942   wine_wgl.p_wglDeleteContext = (void *)wine_wgl.p_wglGetProcAddress("wglDeleteContext");
943   wine_wgl.p_wglFinish = (void *)wine_wgl.p_wglGetProcAddress("wglFinish");
944   wine_wgl.p_wglFlush = (void *)wine_wgl.p_wglGetProcAddress("wglFlush");
945   wine_wgl.p_wglGetCurrentContext = (void *)wine_wgl.p_wglGetProcAddress("wglGetCurrentContext");
946   wine_wgl.p_wglGetCurrentDC = (void *)wine_wgl.p_wglGetProcAddress("wglGetCurrentDC");
947   wine_wgl.p_wglGetIntegerv = (void *)wine_wgl.p_wglGetProcAddress("wglGetIntegerv");
948   wine_wgl.p_wglShareLists = (void *)wine_wgl.p_wglGetProcAddress("wglShareLists");
949
950   if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\OpenGL", &hkey)) {
951     if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, NULL, &size)) {
952       internal_gl_disabled_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
953       RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size);
954       TRACE("found DisabledExtensions=%s\n", debugstr_a(internal_gl_disabled_extensions));
955     }
956     RegCloseKey(hkey);
957   }
958
959   return TRUE;
960 }
961
962
963 /**********************************************************************/
964
965 static void process_detach(void)
966 {
967   if (libglu_handle) wine_dlclose(libglu_handle, NULL, 0);
968   HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
969   HeapFree(GetProcessHeap(), 0, internal_gl_disabled_extensions);
970 }
971
972 /***********************************************************************
973  *           OpenGL initialisation routine
974  */
975 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
976 {
977     switch(reason)
978     {
979     case DLL_PROCESS_ATTACH:
980         opengl32_handle = hinst;
981         DisableThreadLibraryCalls(hinst);
982         return process_attach();
983     case DLL_PROCESS_DETACH:
984         process_detach();
985         break;
986     }
987     return TRUE;
988 }