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