gdi32: Forward SwapBuffers to opengl32 which in turn calls GdiSwapBuffers.
[wine.git] / dlls / opengl32 / wgl.c
blob79aefcd906d41fa02a792cd8d5c84bbcd9773362
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 /* First, look if it's not already defined in the 'standard' OpenGL functions */
471 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
472 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
473 return local_func;
476 /* After that, search in the thunks to find the real name of the extension */
477 ext.name = lpszProc;
478 ext_ret = bsearch(&ext, extension_registry, extension_registry_size,
479 sizeof(OpenGL_extension), compar);
481 /* If nothing was found, we are looking for a WGL extension or an unknown GL extension. */
482 if (ext_ret == NULL) {
483 /* If the function name starts with a w it is a WGL extension */
484 if(lpszProc[0] == 'w')
485 return wine_wgl.p_wglGetProcAddress(lpszProc);
487 /* We are dealing with an unknown GL extension. */
488 WARN("Extension '%s' not defined in opengl32.dll's function table!\n", lpszProc);
489 return NULL;
490 } else { /* We are looking for an OpenGL extension */
492 /* Check if the GL extension required by the function is available */
493 if(!is_extension_supported(ext_ret->extension)) {
494 WARN("Extension '%s' required by function '%s' not supported!\n", ext_ret->extension, lpszProc);
497 local_func = wine_wgl.p_wglGetProcAddress(ext_ret->name);
499 /* After that, look at the extensions defined in the Linux OpenGL library */
500 if (local_func == NULL) {
501 char buf[256];
502 void *ret = NULL;
504 /* Remove the 3 last letters (EXT, ARB, ...).
506 I know that some extensions have more than 3 letters (MESA, NV,
507 INTEL, ...), but this is only a stop-gap measure to fix buggy
508 OpenGL drivers (moreover, it is only useful for old 1.0 apps
509 that query the glBindTextureEXT extension).
511 memcpy(buf, ext_ret->name, strlen(ext_ret->name) - 3);
512 buf[strlen(ext_ret->name) - 3] = '\0';
513 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
515 ret = GetProcAddress(opengl32_handle, buf);
516 if (ret != NULL) {
517 TRACE(" found function in main OpenGL library (%p) !\n", ret);
518 } else {
519 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->name);
522 return ret;
523 } else {
524 TRACE(" returning function (%p)\n", ext_ret->func);
525 extension_funcs[ext_ret - extension_registry] = local_func;
527 return ext_ret->func;
532 /***********************************************************************
533 * wglRealizeLayerPalette (OPENGL32.@)
535 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
536 int iLayerPlane,
537 BOOL bRealize) {
538 FIXME("()\n");
540 return FALSE;
543 /***********************************************************************
544 * wglSetLayerPaletteEntries (OPENGL32.@)
546 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
547 int iLayerPlane,
548 int iStart,
549 int cEntries,
550 const COLORREF *pcr) {
551 FIXME("(): stub !\n");
553 return 0;
556 /***********************************************************************
557 * wglSwapLayerBuffers (OPENGL32.@)
559 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
560 UINT fuPlanes) {
561 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
563 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
564 if (!GdiSwapBuffers(hdc)) return FALSE;
565 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
568 if (fuPlanes) {
569 WARN("Following layers unhandled : %08x\n", fuPlanes);
572 return TRUE;
575 /***********************************************************************
576 * wglUseFontBitmaps_common
578 static BOOL wglUseFontBitmaps_common( HDC hdc, DWORD first, DWORD count, DWORD listBase, BOOL unicode )
580 GLYPHMETRICS gm;
581 unsigned int glyph, size = 0;
582 void *bitmap = NULL, *gl_bitmap = NULL;
583 int org_alignment;
584 BOOL ret = TRUE;
586 ENTER_GL();
587 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
588 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
589 LEAVE_GL();
591 for (glyph = first; glyph < first + count; glyph++) {
592 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
593 unsigned int needed_size, height, width, width_int;
595 if (unicode)
596 needed_size = GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
597 else
598 needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
600 TRACE("Glyph : %3d / List : %d size %d\n", glyph, listBase, needed_size);
601 if (needed_size == GDI_ERROR) {
602 ret = FALSE;
603 break;
606 if (needed_size > size) {
607 size = needed_size;
608 HeapFree(GetProcessHeap(), 0, bitmap);
609 HeapFree(GetProcessHeap(), 0, gl_bitmap);
610 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
611 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
613 if (unicode)
614 ret = (GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
615 else
616 ret = (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
617 if (!ret) break;
619 if (TRACE_ON(wgl)) {
620 unsigned int bitmask;
621 unsigned char *bitmap_ = bitmap;
623 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
624 TRACE(" - origin : (%d , %d)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
625 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
626 if (needed_size != 0) {
627 TRACE(" - bitmap :\n");
628 for (height = 0; height < gm.gmBlackBoxY; height++) {
629 TRACE(" ");
630 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
631 if (bitmask == 0) {
632 bitmap_ += 1;
633 bitmask = 0x80;
635 if (*bitmap_ & bitmask)
636 TRACE("*");
637 else
638 TRACE(" ");
640 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
641 TRACE("\n");
646 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
647 * glyph for it to be drawn properly.
649 if (needed_size != 0) {
650 width_int = (gm.gmBlackBoxX + 31) / 32;
651 for (height = 0; height < gm.gmBlackBoxY; height++) {
652 for (width = 0; width < width_int; width++) {
653 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
654 ((int *) bitmap)[height * width_int + width];
659 ENTER_GL();
660 glNewList(listBase++, GL_COMPILE);
661 if (needed_size != 0) {
662 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
663 0 - gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - gm.gmptGlyphOrigin.y,
664 gm.gmCellIncX, gm.gmCellIncY,
665 gl_bitmap);
666 } else {
667 /* This is the case of 'empty' glyphs like the space character */
668 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
670 glEndList();
671 LEAVE_GL();
674 ENTER_GL();
675 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
676 LEAVE_GL();
677 HeapFree(GetProcessHeap(), 0, bitmap);
678 HeapFree(GetProcessHeap(), 0, gl_bitmap);
679 return ret;
682 /***********************************************************************
683 * wglUseFontBitmapsA (OPENGL32.@)
685 BOOL WINAPI wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase)
687 return wglUseFontBitmaps_common( hdc, first, count, listBase, FALSE );
690 /***********************************************************************
691 * wglUseFontBitmapsW (OPENGL32.@)
693 BOOL WINAPI wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase)
695 return wglUseFontBitmaps_common( hdc, first, count, listBase, TRUE );
698 #ifdef SONAME_LIBGLU
700 static void *load_libglu(void)
702 static int already_loaded;
703 void *handle;
705 if (already_loaded) return libglu_handle;
706 already_loaded = 1;
708 TRACE("Trying to load GLU library: %s\n", SONAME_LIBGLU);
709 handle = wine_dlopen(SONAME_LIBGLU, RTLD_NOW, NULL, 0);
710 if (!handle)
712 WARN("Failed to load %s\n", SONAME_LIBGLU);
713 return NULL;
716 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(handle, #f, NULL, 0)) == NULL) goto sym_not_found;
717 LOAD_FUNCPTR(gluNewTess)
718 LOAD_FUNCPTR(gluDeleteTess)
719 LOAD_FUNCPTR(gluTessBeginContour)
720 LOAD_FUNCPTR(gluTessBeginPolygon)
721 LOAD_FUNCPTR(gluTessCallback)
722 LOAD_FUNCPTR(gluTessEndContour)
723 LOAD_FUNCPTR(gluTessEndPolygon)
724 LOAD_FUNCPTR(gluTessVertex)
725 #undef LOAD_FUNCPTR
726 libglu_handle = handle;
727 return handle;
729 sym_not_found:
730 WARN("Unable to load function ptrs from libGLU\n");
731 /* Close the library as we won't use it */
732 wine_dlclose(handle, NULL, 0);
733 return NULL;
736 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
738 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
739 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
740 vertex[2] = 0.0;
743 static void tess_callback_vertex(GLvoid *vertex)
745 GLdouble *dbl = vertex;
746 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
747 glVertex3dv(vertex);
750 static void tess_callback_begin(GLenum which)
752 TRACE("%d\n", which);
753 glBegin(which);
756 static void tess_callback_end(void)
758 TRACE("\n");
759 glEnd();
762 /***********************************************************************
763 * wglUseFontOutlines_common
765 static BOOL wglUseFontOutlines_common(HDC hdc,
766 DWORD first,
767 DWORD count,
768 DWORD listBase,
769 FLOAT deviation,
770 FLOAT extrusion,
771 int format,
772 LPGLYPHMETRICSFLOAT lpgmf,
773 BOOL unicode)
775 UINT glyph;
776 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
777 GLUtesselator *tess;
778 LOGFONTW lf;
779 HFONT old_font, unscaled_font;
780 UINT em_size = 1024;
781 RECT rc;
783 TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
784 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
786 if (!load_libglu())
788 ERR("libGLU is required for this function but isn't loaded\n");
789 return FALSE;
792 ENTER_GL();
793 tess = pgluNewTess();
794 if(tess)
796 pgluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
797 pgluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
798 pgluTessCallback(tess, GLU_TESS_END, tess_callback_end);
800 LEAVE_GL();
802 if(!tess) return FALSE;
804 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
805 rc.left = rc.right = rc.bottom = 0;
806 rc.top = em_size;
807 DPtoLP(hdc, (POINT*)&rc, 2);
808 lf.lfHeight = -abs(rc.top - rc.bottom);
809 lf.lfOrientation = lf.lfEscapement = 0;
810 unscaled_font = CreateFontIndirectW(&lf);
811 old_font = SelectObject(hdc, unscaled_font);
813 for (glyph = first; glyph < first + count; glyph++)
815 DWORD needed;
816 GLYPHMETRICS gm;
817 BYTE *buf;
818 TTPOLYGONHEADER *pph;
819 TTPOLYCURVE *ppc;
820 GLdouble *vertices;
822 if(unicode)
823 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
824 else
825 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
827 if(needed == GDI_ERROR)
828 goto error;
830 buf = HeapAlloc(GetProcessHeap(), 0, needed);
831 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
833 if(unicode)
834 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
835 else
836 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
838 TRACE("glyph %d\n", glyph);
840 if(lpgmf)
842 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
843 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
844 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
845 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
846 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
847 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
849 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
850 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
851 lpgmf++;
854 ENTER_GL();
855 glNewList(listBase++, GL_COMPILE);
856 pgluTessBeginPolygon(tess, NULL);
858 pph = (TTPOLYGONHEADER*)buf;
859 while((BYTE*)pph < buf + needed)
861 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
863 pgluTessBeginContour(tess);
865 fixed_to_double(pph->pfxStart, em_size, vertices);
866 pgluTessVertex(tess, vertices, vertices);
867 vertices += 3;
869 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
870 while((char*)ppc < (char*)pph + pph->cb)
872 int i;
874 switch(ppc->wType) {
875 case TT_PRIM_LINE:
876 for(i = 0; i < ppc->cpfx; i++)
878 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
879 fixed_to_double(ppc->apfx[i], em_size, vertices);
880 pgluTessVertex(tess, vertices, vertices);
881 vertices += 3;
883 break;
885 case TT_PRIM_QSPLINE:
886 for(i = 0; i < ppc->cpfx/2; i++)
888 /* FIXME just connecting the control points for now */
889 TRACE("\t\tcurve %d,%d %d,%d\n",
890 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
891 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
892 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
893 pgluTessVertex(tess, vertices, vertices);
894 vertices += 3;
895 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
896 pgluTessVertex(tess, vertices, vertices);
897 vertices += 3;
899 break;
900 default:
901 ERR("\t\tcurve type = %d\n", ppc->wType);
902 pgluTessEndContour(tess);
903 goto error_in_list;
906 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
907 (ppc->cpfx - 1) * sizeof(POINTFX));
909 pgluTessEndContour(tess);
910 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
913 error_in_list:
914 pgluTessEndPolygon(tess);
915 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
916 glEndList();
917 LEAVE_GL();
918 HeapFree(GetProcessHeap(), 0, buf);
919 HeapFree(GetProcessHeap(), 0, vertices);
922 error:
923 DeleteObject(SelectObject(hdc, old_font));
924 pgluDeleteTess(tess);
925 return TRUE;
929 #else /* SONAME_LIBGLU */
931 static BOOL wglUseFontOutlines_common(HDC hdc,
932 DWORD first,
933 DWORD count,
934 DWORD listBase,
935 FLOAT deviation,
936 FLOAT extrusion,
937 int format,
938 LPGLYPHMETRICSFLOAT lpgmf,
939 BOOL unicode)
941 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
942 return FALSE;
945 #endif /* SONAME_LIBGLU */
947 /***********************************************************************
948 * wglUseFontOutlinesA (OPENGL32.@)
950 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
951 DWORD first,
952 DWORD count,
953 DWORD listBase,
954 FLOAT deviation,
955 FLOAT extrusion,
956 int format,
957 LPGLYPHMETRICSFLOAT lpgmf)
959 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
962 /***********************************************************************
963 * wglUseFontOutlinesW (OPENGL32.@)
965 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
966 DWORD first,
967 DWORD count,
968 DWORD listBase,
969 FLOAT deviation,
970 FLOAT extrusion,
971 int format,
972 LPGLYPHMETRICSFLOAT lpgmf)
974 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
977 /***********************************************************************
978 * glFinish (OPENGL32.@)
980 void WINAPI wine_glFinish( void )
982 TRACE("()\n");
983 wine_wgl.p_wglFinish();
986 /***********************************************************************
987 * glFlush (OPENGL32.@)
989 void WINAPI wine_glFlush( void )
991 TRACE("()\n");
992 wine_wgl.p_wglFlush();
995 /***********************************************************************
996 * glGetString (OPENGL32.@)
998 const GLubyte * WINAPI wine_glGetString( GLenum name )
1000 const GLubyte *ret;
1001 const char* GL_Extensions = NULL;
1003 /* this is for buggy nvidia driver, crashing if called from a different
1004 thread with no context */
1005 if(wglGetCurrentContext() == NULL)
1006 return NULL;
1008 if (GL_EXTENSIONS != name) {
1009 ENTER_GL();
1010 ret = glGetString(name);
1011 LEAVE_GL();
1012 return ret;
1015 if (NULL == internal_gl_extensions) {
1016 ENTER_GL();
1017 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1019 if (GL_Extensions)
1021 size_t len = strlen(GL_Extensions);
1022 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1024 TRACE("GL_EXTENSIONS reported:\n");
1025 while (*GL_Extensions != 0x00) {
1026 const char* Start = GL_Extensions;
1027 char ThisExtn[256];
1029 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1030 GL_Extensions++;
1032 memcpy(ThisExtn, Start, (GL_Extensions - Start));
1033 ThisExtn[GL_Extensions - Start] = 0;
1034 TRACE("- %s:", ThisExtn);
1036 /* test if supported API is disabled by config */
1037 if (!internal_gl_disabled_extensions || !strstr(internal_gl_disabled_extensions, ThisExtn)) {
1038 strcat(internal_gl_extensions, " ");
1039 strcat(internal_gl_extensions, ThisExtn);
1040 TRACE(" active\n");
1041 } else {
1042 TRACE(" deactived (by config)\n");
1045 if (*GL_Extensions == ' ') GL_Extensions++;
1048 LEAVE_GL();
1050 return (const GLubyte *) internal_gl_extensions;
1053 /***********************************************************************
1054 * glGetIntegerv (OPENGL32.@)
1056 void WINAPI wine_glGetIntegerv( GLenum pname, GLint* params )
1058 wine_wgl.p_wglGetIntegerv(pname, params);
1061 /***********************************************************************
1062 * wglSwapBuffers (OPENGL32.@)
1064 BOOL WINAPI DECLSPEC_HOTPATCH wglSwapBuffers( HDC hdc )
1066 return GdiSwapBuffers(hdc);
1069 /* This is for brain-dead applications that use OpenGL functions before even
1070 creating a rendering context.... */
1071 static BOOL process_attach(void)
1073 HMODULE mod_x11, mod_gdi32;
1074 DWORD size;
1075 HKEY hkey = 0;
1077 GetDesktopWindow(); /* make sure winex11 is loaded (FIXME) */
1078 mod_x11 = GetModuleHandleA( "winex11.drv" );
1079 mod_gdi32 = GetModuleHandleA( "gdi32.dll" );
1081 if (!mod_x11 || !mod_gdi32)
1083 ERR("X11DRV or GDI32 not loaded. Cannot create default context.\n");
1084 return FALSE;
1087 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod_x11, "wine_tsx11_lock" );
1088 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod_x11, "wine_tsx11_unlock" );
1090 wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod_gdi32, "wglGetProcAddress");
1091 wine_wgl.p_wglMakeCurrent = (void *)GetProcAddress(mod_gdi32, "wglMakeCurrent");
1092 wine_wgl.p_wglCreateContext = (void *)GetProcAddress(mod_gdi32, "wglCreateContext");
1093 wine_wgl.p_GetPixelFormat = (void *)GetProcAddress(mod_gdi32, "GetPixelFormat");
1095 /* internal WGL functions */
1096 wine_wgl.p_wglCopyContext = (void *)wine_wgl.p_wglGetProcAddress("wglCopyContext");
1097 wine_wgl.p_wglDeleteContext = (void *)wine_wgl.p_wglGetProcAddress("wglDeleteContext");
1098 wine_wgl.p_wglFinish = (void *)wine_wgl.p_wglGetProcAddress("wglFinish");
1099 wine_wgl.p_wglFlush = (void *)wine_wgl.p_wglGetProcAddress("wglFlush");
1100 wine_wgl.p_wglGetCurrentContext = (void *)wine_wgl.p_wglGetProcAddress("wglGetCurrentContext");
1101 wine_wgl.p_wglGetCurrentDC = (void *)wine_wgl.p_wglGetProcAddress("wglGetCurrentDC");
1102 wine_wgl.p_wglGetIntegerv = (void *)wine_wgl.p_wglGetProcAddress("wglGetIntegerv");
1103 wine_wgl.p_wglShareLists = (void *)wine_wgl.p_wglGetProcAddress("wglShareLists");
1105 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\OpenGL", &hkey)) {
1106 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, NULL, &size)) {
1107 internal_gl_disabled_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1108 RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size);
1109 TRACE("found DisabledExtensions=%s\n", debugstr_a(internal_gl_disabled_extensions));
1111 RegCloseKey(hkey);
1114 return TRUE;
1118 /**********************************************************************/
1120 static void process_detach(void)
1122 if (libglu_handle) wine_dlclose(libglu_handle, NULL, 0);
1123 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1124 HeapFree(GetProcessHeap(), 0, internal_gl_disabled_extensions);
1127 /***********************************************************************
1128 * OpenGL initialisation routine
1130 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1132 switch(reason)
1134 case DLL_PROCESS_ATTACH:
1135 opengl32_handle = hinst;
1136 DisableThreadLibraryCalls(hinst);
1137 return process_attach();
1138 case DLL_PROCESS_DETACH:
1139 process_detach();
1140 break;
1142 return TRUE;