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