opengl32: Disable wglGetProcAddress for core GL 1.0/1.1 functions.
[wine/multimedia.git] / dlls / opengl32 / wgl.c
blobeca42e24c3866d622d07b7699313aa750beec7c2
1 /* Window-specific OpenGL functions implementation.
3 * Copyright (c) 1999 Lionel Ulmer
4 * Copyright (c) 2005 Raphael Junqueira
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
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"
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"
45 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
46 WINE_DECLARE_DEBUG_CHANNEL(opengl);
48 static struct
50 PROC (WINAPI *p_wglGetProcAddress)(LPCSTR lpszProc);
51 BOOL (WINAPI *p_wglMakeCurrent)(HDC hdc, HGLRC hglrc);
52 HGLRC (WINAPI *p_wglCreateContext)(HDC hdc);
53 INT (WINAPI *p_GetPixelFormat)(HDC hdc);
55 /* internal WGL functions */
56 BOOL (WINAPI *p_wglCopyContext)(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask);
57 BOOL (WINAPI *p_wglDeleteContext)(HGLRC hglrc);
58 void (WINAPI *p_wglFinish)(void);
59 void (WINAPI *p_wglFlush)(void);
60 HGLRC (WINAPI *p_wglGetCurrentContext)(void);
61 HDC (WINAPI *p_wglGetCurrentDC)(void);
62 void (WINAPI *p_wglGetIntegerv)(GLenum pname, GLint* params);
63 BOOL (WINAPI *p_wglShareLists)(HGLRC hglrc1, HGLRC hglrc2);
64 } wine_wgl;
66 #ifdef SONAME_LIBGLU
67 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
68 MAKE_FUNCPTR(gluNewTess)
69 MAKE_FUNCPTR(gluDeleteTess)
70 MAKE_FUNCPTR(gluTessBeginContour)
71 MAKE_FUNCPTR(gluTessBeginPolygon)
72 MAKE_FUNCPTR(gluTessCallback)
73 MAKE_FUNCPTR(gluTessEndContour)
74 MAKE_FUNCPTR(gluTessEndPolygon)
75 MAKE_FUNCPTR(gluTessVertex)
76 #undef MAKE_FUNCPTR
77 #endif /* SONAME_LIBGLU */
79 void (*wine_tsx11_lock_ptr)(void) = NULL;
80 void (*wine_tsx11_unlock_ptr)(void) = NULL;
82 static HMODULE opengl32_handle;
83 static void* libglu_handle = NULL;
85 static char* internal_gl_disabled_extensions = NULL;
86 static char* internal_gl_extensions = NULL;
88 const GLubyte * WINAPI wine_glGetString( GLenum name );
90 /* internal GDI functions */
91 extern INT WINAPI GdiDescribePixelFormat( HDC hdc, INT fmt, UINT size, PIXELFORMATDESCRIPTOR *pfd );
92 extern BOOL WINAPI GdiSetPixelFormat( HDC hdc, INT fmt, const PIXELFORMATDESCRIPTOR *pfd );
93 extern BOOL WINAPI GdiSwapBuffers( HDC hdc );
95 /***********************************************************************
96 * wglSetPixelFormat(OPENGL32.@)
98 BOOL WINAPI wglSetPixelFormat( HDC hdc, INT iPixelFormat,
99 const PIXELFORMATDESCRIPTOR *ppfd)
101 return GdiSetPixelFormat(hdc, iPixelFormat, ppfd);
104 /***********************************************************************
105 * wglCopyContext (OPENGL32.@)
107 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask)
109 if (!hglrcSrc || !hglrcDst)
111 SetLastError(ERROR_INVALID_HANDLE);
112 return FALSE;
114 return wine_wgl.p_wglCopyContext(hglrcSrc, hglrcDst, mask);
117 /***********************************************************************
118 * wglDeleteContext (OPENGL32.@)
120 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
122 if (!hglrc)
124 SetLastError(ERROR_INVALID_HANDLE);
125 return FALSE;
127 return wine_wgl.p_wglDeleteContext(hglrc);
130 /***********************************************************************
131 * wglMakeCurrent (OPENGL32.@)
133 BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hglrc)
135 return wine_wgl.p_wglMakeCurrent(hdc, hglrc);
138 /***********************************************************************
139 * wglShareLists (OPENGL32.@)
141 BOOL WINAPI wglShareLists(HGLRC hglrc1, HGLRC hglrc2)
143 if (!hglrc1 || !hglrc2)
145 SetLastError(ERROR_INVALID_HANDLE);
146 return FALSE;
148 return wine_wgl.p_wglShareLists(hglrc1, hglrc2);
151 /***********************************************************************
152 * wglGetCurrentDC (OPENGL32.@)
154 HDC WINAPI wglGetCurrentDC(void)
156 return wine_wgl.p_wglGetCurrentDC();
159 /***********************************************************************
160 * wglCreateContext (OPENGL32.@)
162 HGLRC WINAPI wglCreateContext(HDC hdc)
164 return wine_wgl.p_wglCreateContext(hdc);
167 /***********************************************************************
168 * wglGetCurrentContext (OPENGL32.@)
170 HGLRC WINAPI wglGetCurrentContext(void)
172 return wine_wgl.p_wglGetCurrentContext();
175 /***********************************************************************
176 * wglChoosePixelFormat (OPENGL32.@)
178 INT WINAPI wglChoosePixelFormat(HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd)
180 PIXELFORMATDESCRIPTOR format, best;
181 int i, count, best_format;
182 int bestDBuffer = -1, bestStereo = -1;
184 TRACE_(wgl)( "%p %p: size %u version %u flags %u type %u color %u %u,%u,%u,%u "
185 "accum %u depth %u stencil %u aux %u\n",
186 hdc, ppfd, ppfd->nSize, ppfd->nVersion, ppfd->dwFlags, ppfd->iPixelType,
187 ppfd->cColorBits, ppfd->cRedBits, ppfd->cGreenBits, ppfd->cBlueBits, ppfd->cAlphaBits,
188 ppfd->cAccumBits, ppfd->cDepthBits, ppfd->cStencilBits, ppfd->cAuxBuffers );
190 count = GdiDescribePixelFormat( hdc, 0, 0, NULL );
191 if (!count) return 0;
193 best_format = 0;
194 best.dwFlags = 0;
195 best.cAlphaBits = -1;
196 best.cColorBits = -1;
197 best.cDepthBits = -1;
198 best.cStencilBits = -1;
199 best.cAuxBuffers = -1;
201 for (i = 1; i <= count; i++)
203 if (!GdiDescribePixelFormat( hdc, i, sizeof(format), &format )) continue;
205 if (ppfd->iPixelType != format.iPixelType)
207 TRACE( "pixel type mismatch for iPixelFormat=%d\n", i );
208 continue;
211 /* only use bitmap capable for formats for bitmap rendering */
212 if( (ppfd->dwFlags & PFD_DRAW_TO_BITMAP) != (format.dwFlags & PFD_DRAW_TO_BITMAP))
214 TRACE( "PFD_DRAW_TO_BITMAP mismatch for iPixelFormat=%d\n", i );
215 continue;
218 /* The behavior of PDF_STEREO/PFD_STEREO_DONTCARE and PFD_DOUBLEBUFFER / PFD_DOUBLEBUFFER_DONTCARE
219 * is not very clear on MSDN. They specify that ChoosePixelFormat tries to match pixel formats
220 * with the flag (PFD_STEREO / PFD_DOUBLEBUFFERING) set. Otherwise it says that it tries to match
221 * formats without the given flag set.
222 * A test on Windows using a Radeon 9500pro on WinXP (the driver doesn't support Stereo)
223 * has indicated that a format without stereo is returned when stereo is unavailable.
224 * So in case PFD_STEREO is set, formats that support it should have priority above formats
225 * without. In case PFD_STEREO_DONTCARE is set, stereo is ignored.
227 * To summarize the following is most likely the correct behavior:
228 * stereo not set -> prefer no-stereo formats, else also accept stereo formats
229 * stereo set -> prefer stereo formats, else also accept no-stereo formats
230 * stereo don't care -> it doesn't matter whether we get stereo or not
232 * In Wine we will treat no-stereo the same way as don't care because it makes
233 * format selection even more complicated and second drivers with Stereo advertise
234 * each format twice anyway.
237 /* Doublebuffer, see the comments above */
238 if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE))
240 if (((ppfd->dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) &&
241 ((format.dwFlags & PFD_DOUBLEBUFFER) == (ppfd->dwFlags & PFD_DOUBLEBUFFER)))
242 goto found;
244 if (bestDBuffer != -1 && (format.dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) continue;
247 /* Stereo, see the comments above. */
248 if (!(ppfd->dwFlags & PFD_STEREO_DONTCARE))
250 if (((ppfd->dwFlags & PFD_STEREO) != bestStereo) &&
251 ((format.dwFlags & PFD_STEREO) == (ppfd->dwFlags & PFD_STEREO)))
252 goto found;
254 if (bestStereo != -1 && (format.dwFlags & PFD_STEREO) != bestStereo) continue;
257 /* Below we will do a number of checks to select the 'best' pixelformat.
258 * We assume the precedence cColorBits > cAlphaBits > cDepthBits > cStencilBits -> cAuxBuffers.
259 * The code works by trying to match the most important options as close as possible.
260 * When a reasonable format is found, we will try to match more options.
261 * It appears (see the opengl32 test) that Windows opengl drivers ignore options
262 * like cColorBits, cAlphaBits and friends if they are set to 0, so they are considered
263 * as DONTCARE. At least Serious Sam TSE relies on this behavior. */
265 if (ppfd->cColorBits)
267 if (((ppfd->cColorBits > best.cColorBits) && (format.cColorBits > best.cColorBits)) ||
268 ((format.cColorBits >= ppfd->cColorBits) && (format.cColorBits < best.cColorBits)))
269 goto found;
271 if (best.cColorBits != format.cColorBits) /* Do further checks if the format is compatible */
273 TRACE( "color mismatch for iPixelFormat=%d\n", i );
274 continue;
277 if (ppfd->cAlphaBits)
279 if (((ppfd->cAlphaBits > best.cAlphaBits) && (format.cAlphaBits > best.cAlphaBits)) ||
280 ((format.cAlphaBits >= ppfd->cAlphaBits) && (format.cAlphaBits < best.cAlphaBits)))
281 goto found;
283 if (best.cAlphaBits != format.cAlphaBits)
285 TRACE( "alpha mismatch for iPixelFormat=%d\n", i );
286 continue;
289 if (ppfd->cDepthBits)
291 if (((ppfd->cDepthBits > best.cDepthBits) && (format.cDepthBits > best.cDepthBits)) ||
292 ((format.cDepthBits >= ppfd->cDepthBits) && (format.cDepthBits < best.cDepthBits)))
293 goto found;
295 if (best.cDepthBits != format.cDepthBits)
297 TRACE( "depth mismatch for iPixelFormat=%d\n", i );
298 continue;
301 if (ppfd->cStencilBits)
303 if (((ppfd->cStencilBits > best.cStencilBits) && (format.cStencilBits > best.cStencilBits)) ||
304 ((format.cStencilBits >= ppfd->cStencilBits) && (format.cStencilBits < best.cStencilBits)))
305 goto found;
307 if (best.cStencilBits != format.cStencilBits)
309 TRACE( "stencil mismatch for iPixelFormat=%d\n", i );
310 continue;
313 if (ppfd->cAuxBuffers)
315 if (((ppfd->cAuxBuffers > best.cAuxBuffers) && (format.cAuxBuffers > best.cAuxBuffers)) ||
316 ((format.cAuxBuffers >= ppfd->cAuxBuffers) && (format.cAuxBuffers < best.cAuxBuffers)))
317 goto found;
319 if (best.cAuxBuffers != format.cAuxBuffers)
321 TRACE( "aux mismatch for iPixelFormat=%d\n", i );
322 continue;
325 continue;
327 found:
328 best_format = i;
329 best = format;
330 bestDBuffer = format.dwFlags & PFD_DOUBLEBUFFER;
331 bestStereo = format.dwFlags & PFD_STEREO;
334 TRACE( "returning %u\n", best_format );
335 return best_format;
338 /***********************************************************************
339 * wglDescribePixelFormat (OPENGL32.@)
341 INT WINAPI wglDescribePixelFormat(HDC hdc, INT iPixelFormat, UINT nBytes,
342 LPPIXELFORMATDESCRIPTOR ppfd)
344 return GdiDescribePixelFormat(hdc, iPixelFormat, nBytes, ppfd);
347 /***********************************************************************
348 * wglGetPixelFormat (OPENGL32.@)
350 INT WINAPI wglGetPixelFormat(HDC hdc)
352 return wine_wgl.p_GetPixelFormat(hdc);
355 /***********************************************************************
356 * wglCreateLayerContext (OPENGL32.@)
358 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
359 int iLayerPlane) {
360 TRACE("(%p,%d)\n", hdc, iLayerPlane);
362 if (iLayerPlane == 0) {
363 return wglCreateContext(hdc);
365 FIXME(" no handler for layer %d\n", iLayerPlane);
367 return NULL;
370 /***********************************************************************
371 * wglDescribeLayerPlane (OPENGL32.@)
373 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
374 int iPixelFormat,
375 int iLayerPlane,
376 UINT nBytes,
377 LPLAYERPLANEDESCRIPTOR plpd) {
378 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
380 return FALSE;
383 /***********************************************************************
384 * wglGetLayerPaletteEntries (OPENGL32.@)
386 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
387 int iLayerPlane,
388 int iStart,
389 int cEntries,
390 const COLORREF *pcr) {
391 FIXME("(): stub !\n");
393 return 0;
396 static int compar(const void *elt_a, const void *elt_b) {
397 return strcmp(((const OpenGL_extension *) elt_a)->name,
398 ((const OpenGL_extension *) elt_b)->name);
401 /* Check if a GL extension is supported */
402 static BOOL is_extension_supported(const char* extension)
404 const char *gl_ext_string = (const char*)wine_glGetString(GL_EXTENSIONS);
406 TRACE("Checking for extension '%s'\n", extension);
408 if(!gl_ext_string) {
409 ERR("No OpenGL extensions found, check if your OpenGL setup is correct!\n");
410 return FALSE;
413 /* We use the GetProcAddress function from the display driver to retrieve function pointers
414 * for OpenGL and WGL extensions. In case of winex11.drv the OpenGL extension lookup is done
415 * using glXGetProcAddress. This function is quite unreliable in the sense that its specs don't
416 * require the function to return NULL when a extension isn't found. For this reason we check
417 * if the OpenGL extension required for the function we are looking up is supported. */
419 /* Check if the extension is part of the GL extension string to see if it is supported. */
420 if(strstr(gl_ext_string, extension) != NULL)
421 return TRUE;
423 /* In general an OpenGL function starts as an ARB/EXT extension and at some stage
424 * it becomes part of the core OpenGL library and can be reached without the ARB/EXT
425 * suffix as well. In the extension table, these functions contain GL_VERSION_major_minor.
426 * Check if we are searching for a core GL function */
427 if(strncmp(extension, "GL_VERSION_", 11) == 0)
429 const GLubyte *gl_version = glGetString(GL_VERSION);
430 const char *version = extension + 11; /* Move past 'GL_VERSION_' */
432 if(!gl_version) {
433 ERR("Error no OpenGL version found,\n");
434 return FALSE;
437 /* Compare the major/minor version numbers of the native OpenGL library and what is required by the function.
438 * The gl_version string is guaranteed to have at least a major/minor and sometimes it has a release number as well. */
439 if( (gl_version[0] >= version[0]) || ((gl_version[0] == version[0]) && (gl_version[2] >= version[2])) ) {
440 return TRUE;
442 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]);
445 return FALSE;
448 /***********************************************************************
449 * wglGetProcAddress (OPENGL32.@)
451 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
452 void *local_func;
453 OpenGL_extension ext;
454 const OpenGL_extension *ext_ret;
456 TRACE("(%s)\n", lpszProc);
458 if (lpszProc == NULL)
459 return NULL;
461 /* Without an active context opengl32 doesn't know to what
462 * driver it has to dispatch wglGetProcAddress.
464 if (wglGetCurrentContext() == NULL)
466 WARN("No active WGL context found\n");
467 return NULL;
470 /* Search in the thunks to find the real name of the extension */
471 ext.name = lpszProc;
472 ext_ret = bsearch(&ext, extension_registry, extension_registry_size,
473 sizeof(OpenGL_extension), compar);
475 /* If nothing was found, we are looking for a WGL extension or an unknown GL extension. */
476 if (ext_ret == NULL) {
477 /* If the function name starts with a w it is a WGL extension */
478 if(lpszProc[0] == 'w')
479 return wine_wgl.p_wglGetProcAddress(lpszProc);
481 /* We are dealing with an unknown GL extension. */
482 WARN("Extension '%s' not defined in opengl32.dll's function table!\n", lpszProc);
483 return NULL;
484 } else { /* We are looking for an OpenGL extension */
486 /* Check if the GL extension required by the function is available */
487 if(!is_extension_supported(ext_ret->extension)) {
488 WARN("Extension '%s' required by function '%s' not supported!\n", ext_ret->extension, lpszProc);
491 local_func = wine_wgl.p_wglGetProcAddress(ext_ret->name);
493 /* After that, look at the extensions defined in the Linux OpenGL library */
494 if (local_func == NULL) {
495 char buf[256];
496 void *ret = NULL;
498 /* Remove the 3 last letters (EXT, ARB, ...).
500 I know that some extensions have more than 3 letters (MESA, NV,
501 INTEL, ...), but this is only a stop-gap measure to fix buggy
502 OpenGL drivers (moreover, it is only useful for old 1.0 apps
503 that query the glBindTextureEXT extension).
505 memcpy(buf, ext_ret->name, strlen(ext_ret->name) - 3);
506 buf[strlen(ext_ret->name) - 3] = '\0';
507 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
509 ret = GetProcAddress(opengl32_handle, buf);
510 if (ret != NULL) {
511 TRACE(" found function in main OpenGL library (%p) !\n", ret);
512 } else {
513 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->name);
516 return ret;
517 } else {
518 TRACE(" returning function (%p)\n", ext_ret->func);
519 extension_funcs[ext_ret - extension_registry] = local_func;
521 return ext_ret->func;
526 /***********************************************************************
527 * wglRealizeLayerPalette (OPENGL32.@)
529 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
530 int iLayerPlane,
531 BOOL bRealize) {
532 FIXME("()\n");
534 return FALSE;
537 /***********************************************************************
538 * wglSetLayerPaletteEntries (OPENGL32.@)
540 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
541 int iLayerPlane,
542 int iStart,
543 int cEntries,
544 const COLORREF *pcr) {
545 FIXME("(): stub !\n");
547 return 0;
550 /***********************************************************************
551 * wglSwapLayerBuffers (OPENGL32.@)
553 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
554 UINT fuPlanes) {
555 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
557 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
558 if (!GdiSwapBuffers(hdc)) return FALSE;
559 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
562 if (fuPlanes) {
563 WARN("Following layers unhandled : %08x\n", fuPlanes);
566 return TRUE;
569 /***********************************************************************
570 * wglUseFontBitmaps_common
572 static BOOL wglUseFontBitmaps_common( HDC hdc, DWORD first, DWORD count, DWORD listBase, BOOL unicode )
574 GLYPHMETRICS gm;
575 unsigned int glyph, size = 0;
576 void *bitmap = NULL, *gl_bitmap = NULL;
577 int org_alignment;
578 BOOL ret = TRUE;
580 ENTER_GL();
581 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
582 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
583 LEAVE_GL();
585 for (glyph = first; glyph < first + count; glyph++) {
586 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
587 unsigned int needed_size, height, width, width_int;
589 if (unicode)
590 needed_size = GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
591 else
592 needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
594 TRACE("Glyph : %3d / List : %d size %d\n", glyph, listBase, needed_size);
595 if (needed_size == GDI_ERROR) {
596 ret = FALSE;
597 break;
600 if (needed_size > size) {
601 size = needed_size;
602 HeapFree(GetProcessHeap(), 0, bitmap);
603 HeapFree(GetProcessHeap(), 0, gl_bitmap);
604 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
605 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
607 if (unicode)
608 ret = (GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
609 else
610 ret = (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
611 if (!ret) break;
613 if (TRACE_ON(wgl)) {
614 unsigned int bitmask;
615 unsigned char *bitmap_ = bitmap;
617 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
618 TRACE(" - origin : (%d , %d)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
619 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
620 if (needed_size != 0) {
621 TRACE(" - bitmap :\n");
622 for (height = 0; height < gm.gmBlackBoxY; height++) {
623 TRACE(" ");
624 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
625 if (bitmask == 0) {
626 bitmap_ += 1;
627 bitmask = 0x80;
629 if (*bitmap_ & bitmask)
630 TRACE("*");
631 else
632 TRACE(" ");
634 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
635 TRACE("\n");
640 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
641 * glyph for it to be drawn properly.
643 if (needed_size != 0) {
644 width_int = (gm.gmBlackBoxX + 31) / 32;
645 for (height = 0; height < gm.gmBlackBoxY; height++) {
646 for (width = 0; width < width_int; width++) {
647 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
648 ((int *) bitmap)[height * width_int + width];
653 ENTER_GL();
654 glNewList(listBase++, GL_COMPILE);
655 if (needed_size != 0) {
656 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
657 0 - gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - gm.gmptGlyphOrigin.y,
658 gm.gmCellIncX, gm.gmCellIncY,
659 gl_bitmap);
660 } else {
661 /* This is the case of 'empty' glyphs like the space character */
662 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
664 glEndList();
665 LEAVE_GL();
668 ENTER_GL();
669 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
670 LEAVE_GL();
671 HeapFree(GetProcessHeap(), 0, bitmap);
672 HeapFree(GetProcessHeap(), 0, gl_bitmap);
673 return ret;
676 /***********************************************************************
677 * wglUseFontBitmapsA (OPENGL32.@)
679 BOOL WINAPI wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase)
681 return wglUseFontBitmaps_common( hdc, first, count, listBase, FALSE );
684 /***********************************************************************
685 * wglUseFontBitmapsW (OPENGL32.@)
687 BOOL WINAPI wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase)
689 return wglUseFontBitmaps_common( hdc, first, count, listBase, TRUE );
692 #ifdef SONAME_LIBGLU
694 static void *load_libglu(void)
696 static int already_loaded;
697 void *handle;
699 if (already_loaded) return libglu_handle;
700 already_loaded = 1;
702 TRACE("Trying to load GLU library: %s\n", SONAME_LIBGLU);
703 handle = wine_dlopen(SONAME_LIBGLU, RTLD_NOW, NULL, 0);
704 if (!handle)
706 WARN("Failed to load %s\n", SONAME_LIBGLU);
707 return NULL;
710 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(handle, #f, NULL, 0)) == NULL) goto sym_not_found;
711 LOAD_FUNCPTR(gluNewTess)
712 LOAD_FUNCPTR(gluDeleteTess)
713 LOAD_FUNCPTR(gluTessBeginContour)
714 LOAD_FUNCPTR(gluTessBeginPolygon)
715 LOAD_FUNCPTR(gluTessCallback)
716 LOAD_FUNCPTR(gluTessEndContour)
717 LOAD_FUNCPTR(gluTessEndPolygon)
718 LOAD_FUNCPTR(gluTessVertex)
719 #undef LOAD_FUNCPTR
720 libglu_handle = handle;
721 return handle;
723 sym_not_found:
724 WARN("Unable to load function ptrs from libGLU\n");
725 /* Close the library as we won't use it */
726 wine_dlclose(handle, NULL, 0);
727 return NULL;
730 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
732 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
733 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
734 vertex[2] = 0.0;
737 static void tess_callback_vertex(GLvoid *vertex)
739 GLdouble *dbl = vertex;
740 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
741 glVertex3dv(vertex);
744 static void tess_callback_begin(GLenum which)
746 TRACE("%d\n", which);
747 glBegin(which);
750 static void tess_callback_end(void)
752 TRACE("\n");
753 glEnd();
756 /***********************************************************************
757 * wglUseFontOutlines_common
759 static BOOL wglUseFontOutlines_common(HDC hdc,
760 DWORD first,
761 DWORD count,
762 DWORD listBase,
763 FLOAT deviation,
764 FLOAT extrusion,
765 int format,
766 LPGLYPHMETRICSFLOAT lpgmf,
767 BOOL unicode)
769 UINT glyph;
770 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
771 GLUtesselator *tess;
772 LOGFONTW lf;
773 HFONT old_font, unscaled_font;
774 UINT em_size = 1024;
775 RECT rc;
777 TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
778 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
780 if (!load_libglu())
782 ERR("libGLU is required for this function but isn't loaded\n");
783 return FALSE;
786 ENTER_GL();
787 tess = pgluNewTess();
788 if(tess)
790 pgluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
791 pgluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
792 pgluTessCallback(tess, GLU_TESS_END, tess_callback_end);
794 LEAVE_GL();
796 if(!tess) return FALSE;
798 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
799 rc.left = rc.right = rc.bottom = 0;
800 rc.top = em_size;
801 DPtoLP(hdc, (POINT*)&rc, 2);
802 lf.lfHeight = -abs(rc.top - rc.bottom);
803 lf.lfOrientation = lf.lfEscapement = 0;
804 unscaled_font = CreateFontIndirectW(&lf);
805 old_font = SelectObject(hdc, unscaled_font);
807 for (glyph = first; glyph < first + count; glyph++)
809 DWORD needed;
810 GLYPHMETRICS gm;
811 BYTE *buf;
812 TTPOLYGONHEADER *pph;
813 TTPOLYCURVE *ppc;
814 GLdouble *vertices;
816 if(unicode)
817 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
818 else
819 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
821 if(needed == GDI_ERROR)
822 goto error;
824 buf = HeapAlloc(GetProcessHeap(), 0, needed);
825 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
827 if(unicode)
828 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
829 else
830 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
832 TRACE("glyph %d\n", glyph);
834 if(lpgmf)
836 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
837 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
838 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
839 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
840 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
841 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
843 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
844 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
845 lpgmf++;
848 ENTER_GL();
849 glNewList(listBase++, GL_COMPILE);
850 pgluTessBeginPolygon(tess, NULL);
852 pph = (TTPOLYGONHEADER*)buf;
853 while((BYTE*)pph < buf + needed)
855 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
857 pgluTessBeginContour(tess);
859 fixed_to_double(pph->pfxStart, em_size, vertices);
860 pgluTessVertex(tess, vertices, vertices);
861 vertices += 3;
863 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
864 while((char*)ppc < (char*)pph + pph->cb)
866 int i;
868 switch(ppc->wType) {
869 case TT_PRIM_LINE:
870 for(i = 0; i < ppc->cpfx; i++)
872 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
873 fixed_to_double(ppc->apfx[i], em_size, vertices);
874 pgluTessVertex(tess, vertices, vertices);
875 vertices += 3;
877 break;
879 case TT_PRIM_QSPLINE:
880 for(i = 0; i < ppc->cpfx/2; i++)
882 /* FIXME just connecting the control points for now */
883 TRACE("\t\tcurve %d,%d %d,%d\n",
884 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
885 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
886 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
887 pgluTessVertex(tess, vertices, vertices);
888 vertices += 3;
889 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
890 pgluTessVertex(tess, vertices, vertices);
891 vertices += 3;
893 break;
894 default:
895 ERR("\t\tcurve type = %d\n", ppc->wType);
896 pgluTessEndContour(tess);
897 goto error_in_list;
900 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
901 (ppc->cpfx - 1) * sizeof(POINTFX));
903 pgluTessEndContour(tess);
904 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
907 error_in_list:
908 pgluTessEndPolygon(tess);
909 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
910 glEndList();
911 LEAVE_GL();
912 HeapFree(GetProcessHeap(), 0, buf);
913 HeapFree(GetProcessHeap(), 0, vertices);
916 error:
917 DeleteObject(SelectObject(hdc, old_font));
918 pgluDeleteTess(tess);
919 return TRUE;
923 #else /* SONAME_LIBGLU */
925 static BOOL wglUseFontOutlines_common(HDC hdc,
926 DWORD first,
927 DWORD count,
928 DWORD listBase,
929 FLOAT deviation,
930 FLOAT extrusion,
931 int format,
932 LPGLYPHMETRICSFLOAT lpgmf,
933 BOOL unicode)
935 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
936 return FALSE;
939 #endif /* SONAME_LIBGLU */
941 /***********************************************************************
942 * wglUseFontOutlinesA (OPENGL32.@)
944 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
945 DWORD first,
946 DWORD count,
947 DWORD listBase,
948 FLOAT deviation,
949 FLOAT extrusion,
950 int format,
951 LPGLYPHMETRICSFLOAT lpgmf)
953 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
956 /***********************************************************************
957 * wglUseFontOutlinesW (OPENGL32.@)
959 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
960 DWORD first,
961 DWORD count,
962 DWORD listBase,
963 FLOAT deviation,
964 FLOAT extrusion,
965 int format,
966 LPGLYPHMETRICSFLOAT lpgmf)
968 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
971 /***********************************************************************
972 * glFinish (OPENGL32.@)
974 void WINAPI wine_glFinish( void )
976 TRACE("()\n");
977 wine_wgl.p_wglFinish();
980 /***********************************************************************
981 * glFlush (OPENGL32.@)
983 void WINAPI wine_glFlush( void )
985 TRACE("()\n");
986 wine_wgl.p_wglFlush();
989 /***********************************************************************
990 * glGetString (OPENGL32.@)
992 const GLubyte * WINAPI wine_glGetString( GLenum name )
994 const GLubyte *ret;
995 const char* GL_Extensions = NULL;
997 /* this is for buggy nvidia driver, crashing if called from a different
998 thread with no context */
999 if(wglGetCurrentContext() == NULL)
1000 return NULL;
1002 if (GL_EXTENSIONS != name) {
1003 ENTER_GL();
1004 ret = glGetString(name);
1005 LEAVE_GL();
1006 return ret;
1009 if (NULL == internal_gl_extensions) {
1010 ENTER_GL();
1011 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1013 if (GL_Extensions)
1015 size_t len = strlen(GL_Extensions);
1016 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1018 TRACE("GL_EXTENSIONS reported:\n");
1019 while (*GL_Extensions != 0x00) {
1020 const char* Start = GL_Extensions;
1021 char ThisExtn[256];
1023 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1024 GL_Extensions++;
1026 memcpy(ThisExtn, Start, (GL_Extensions - Start));
1027 ThisExtn[GL_Extensions - Start] = 0;
1028 TRACE("- %s:", ThisExtn);
1030 /* test if supported API is disabled by config */
1031 if (!internal_gl_disabled_extensions || !strstr(internal_gl_disabled_extensions, ThisExtn)) {
1032 strcat(internal_gl_extensions, " ");
1033 strcat(internal_gl_extensions, ThisExtn);
1034 TRACE(" active\n");
1035 } else {
1036 TRACE(" deactived (by config)\n");
1039 if (*GL_Extensions == ' ') GL_Extensions++;
1042 LEAVE_GL();
1044 return (const GLubyte *) internal_gl_extensions;
1047 /***********************************************************************
1048 * glGetIntegerv (OPENGL32.@)
1050 void WINAPI wine_glGetIntegerv( GLenum pname, GLint* params )
1052 wine_wgl.p_wglGetIntegerv(pname, params);
1055 /***********************************************************************
1056 * wglSwapBuffers (OPENGL32.@)
1058 BOOL WINAPI DECLSPEC_HOTPATCH wglSwapBuffers( HDC hdc )
1060 return GdiSwapBuffers(hdc);
1063 /* This is for brain-dead applications that use OpenGL functions before even
1064 creating a rendering context.... */
1065 static BOOL process_attach(void)
1067 HMODULE mod_x11, mod_gdi32;
1068 DWORD size;
1069 HKEY hkey = 0;
1071 GetDesktopWindow(); /* make sure winex11 is loaded (FIXME) */
1072 mod_x11 = GetModuleHandleA( "winex11.drv" );
1073 mod_gdi32 = GetModuleHandleA( "gdi32.dll" );
1075 if (!mod_x11 || !mod_gdi32)
1077 ERR("X11DRV or GDI32 not loaded. Cannot create default context.\n");
1078 return FALSE;
1081 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod_x11, "wine_tsx11_lock" );
1082 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod_x11, "wine_tsx11_unlock" );
1084 wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod_gdi32, "wglGetProcAddress");
1085 wine_wgl.p_wglMakeCurrent = (void *)GetProcAddress(mod_gdi32, "wglMakeCurrent");
1086 wine_wgl.p_wglCreateContext = (void *)GetProcAddress(mod_gdi32, "wglCreateContext");
1087 wine_wgl.p_GetPixelFormat = (void *)GetProcAddress(mod_gdi32, "GetPixelFormat");
1089 /* internal WGL functions */
1090 wine_wgl.p_wglCopyContext = (void *)wine_wgl.p_wglGetProcAddress("wglCopyContext");
1091 wine_wgl.p_wglDeleteContext = (void *)wine_wgl.p_wglGetProcAddress("wglDeleteContext");
1092 wine_wgl.p_wglFinish = (void *)wine_wgl.p_wglGetProcAddress("wglFinish");
1093 wine_wgl.p_wglFlush = (void *)wine_wgl.p_wglGetProcAddress("wglFlush");
1094 wine_wgl.p_wglGetCurrentContext = (void *)wine_wgl.p_wglGetProcAddress("wglGetCurrentContext");
1095 wine_wgl.p_wglGetCurrentDC = (void *)wine_wgl.p_wglGetProcAddress("wglGetCurrentDC");
1096 wine_wgl.p_wglGetIntegerv = (void *)wine_wgl.p_wglGetProcAddress("wglGetIntegerv");
1097 wine_wgl.p_wglShareLists = (void *)wine_wgl.p_wglGetProcAddress("wglShareLists");
1099 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\OpenGL", &hkey)) {
1100 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, NULL, &size)) {
1101 internal_gl_disabled_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1102 RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size);
1103 TRACE("found DisabledExtensions=%s\n", debugstr_a(internal_gl_disabled_extensions));
1105 RegCloseKey(hkey);
1108 return TRUE;
1112 /**********************************************************************/
1114 static void process_detach(void)
1116 if (libglu_handle) wine_dlclose(libglu_handle, NULL, 0);
1117 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1118 HeapFree(GetProcessHeap(), 0, internal_gl_disabled_extensions);
1121 /***********************************************************************
1122 * OpenGL initialisation routine
1124 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1126 switch(reason)
1128 case DLL_PROCESS_ATTACH:
1129 opengl32_handle = hinst;
1130 DisableThreadLibraryCalls(hinst);
1131 return process_attach();
1132 case DLL_PROCESS_DETACH:
1133 process_detach();
1134 break;
1136 return TRUE;