opengl32: Fix typos in comments.
[wine/multimedia.git] / dlls / opengl32 / wgl.c
blob64add99b59e67560e3a5ab6f547cda0730c2803a
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 HGLRC (WINAPI *p_wglCreateContext)(HDC hdc);
52 INT (WINAPI *p_GetPixelFormat)(HDC hdc);
54 /* internal WGL functions */
55 BOOL (WINAPI *p_wglCopyContext)(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask);
56 BOOL (WINAPI *p_wglDeleteContext)(HGLRC hglrc);
57 void (WINAPI *p_wglFinish)(void);
58 void (WINAPI *p_wglFlush)(void);
59 HGLRC (WINAPI *p_wglGetCurrentContext)(void);
60 HDC (WINAPI *p_wglGetCurrentDC)(void);
61 void (WINAPI *p_wglGetIntegerv)(GLenum pname, GLint* params);
62 BOOL (WINAPI *p_wglMakeCurrent)(HDC hdc, HGLRC hglrc);
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 static HMODULE opengl32_handle;
80 static void* libglu_handle = NULL;
82 const GLubyte * WINAPI wine_glGetString( GLenum name );
84 /* internal GDI functions */
85 extern INT WINAPI GdiDescribePixelFormat( HDC hdc, INT fmt, UINT size, PIXELFORMATDESCRIPTOR *pfd );
86 extern BOOL WINAPI GdiSetPixelFormat( HDC hdc, INT fmt, const PIXELFORMATDESCRIPTOR *pfd );
87 extern BOOL WINAPI GdiSwapBuffers( HDC hdc );
89 /***********************************************************************
90 * wglSetPixelFormat(OPENGL32.@)
92 BOOL WINAPI wglSetPixelFormat( HDC hdc, INT iPixelFormat,
93 const PIXELFORMATDESCRIPTOR *ppfd)
95 return GdiSetPixelFormat(hdc, iPixelFormat, ppfd);
98 /***********************************************************************
99 * wglCopyContext (OPENGL32.@)
101 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask)
103 if (!hglrcSrc || !hglrcDst)
105 SetLastError(ERROR_INVALID_HANDLE);
106 return FALSE;
108 return wine_wgl.p_wglCopyContext(hglrcSrc, hglrcDst, mask);
111 /***********************************************************************
112 * wglDeleteContext (OPENGL32.@)
114 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
116 if (!hglrc)
118 SetLastError(ERROR_INVALID_HANDLE);
119 return FALSE;
121 return wine_wgl.p_wglDeleteContext(hglrc);
124 /***********************************************************************
125 * wglMakeCurrent (OPENGL32.@)
127 BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hglrc)
129 if (!hglrc && !hdc && !NtCurrentTeb()->glContext)
131 SetLastError( ERROR_INVALID_HANDLE );
132 return FALSE;
134 return wine_wgl.p_wglMakeCurrent(hdc, hglrc);
137 /***********************************************************************
138 * wglShareLists (OPENGL32.@)
140 BOOL WINAPI wglShareLists(HGLRC hglrc1, HGLRC hglrc2)
142 if (!hglrc1 || !hglrc2)
144 SetLastError(ERROR_INVALID_HANDLE);
145 return FALSE;
147 return wine_wgl.p_wglShareLists(hglrc1, hglrc2);
150 /***********************************************************************
151 * wglGetCurrentDC (OPENGL32.@)
153 HDC WINAPI wglGetCurrentDC(void)
155 return wine_wgl.p_wglGetCurrentDC();
158 /***********************************************************************
159 * wglCreateContext (OPENGL32.@)
161 HGLRC WINAPI wglCreateContext(HDC hdc)
163 return wine_wgl.p_wglCreateContext(hdc);
166 /***********************************************************************
167 * wglGetCurrentContext (OPENGL32.@)
169 HGLRC WINAPI wglGetCurrentContext(void)
171 return wine_wgl.p_wglGetCurrentContext();
174 /***********************************************************************
175 * wglChoosePixelFormat (OPENGL32.@)
177 INT WINAPI wglChoosePixelFormat(HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd)
179 PIXELFORMATDESCRIPTOR format, best;
180 int i, count, best_format;
181 int bestDBuffer = -1, bestStereo = -1;
183 TRACE_(wgl)( "%p %p: size %u version %u flags %u type %u color %u %u,%u,%u,%u "
184 "accum %u depth %u stencil %u aux %u\n",
185 hdc, ppfd, ppfd->nSize, ppfd->nVersion, ppfd->dwFlags, ppfd->iPixelType,
186 ppfd->cColorBits, ppfd->cRedBits, ppfd->cGreenBits, ppfd->cBlueBits, ppfd->cAlphaBits,
187 ppfd->cAccumBits, ppfd->cDepthBits, ppfd->cStencilBits, ppfd->cAuxBuffers );
189 count = GdiDescribePixelFormat( hdc, 0, 0, NULL );
190 if (!count) return 0;
192 best_format = 0;
193 best.dwFlags = 0;
194 best.cAlphaBits = -1;
195 best.cColorBits = -1;
196 best.cDepthBits = -1;
197 best.cStencilBits = -1;
198 best.cAuxBuffers = -1;
200 for (i = 1; i <= count; i++)
202 if (!GdiDescribePixelFormat( hdc, i, sizeof(format), &format )) continue;
204 if (ppfd->iPixelType != format.iPixelType)
206 TRACE( "pixel type mismatch for iPixelFormat=%d\n", i );
207 continue;
210 /* only use bitmap capable for formats for bitmap rendering */
211 if( (ppfd->dwFlags & PFD_DRAW_TO_BITMAP) != (format.dwFlags & PFD_DRAW_TO_BITMAP))
213 TRACE( "PFD_DRAW_TO_BITMAP mismatch for iPixelFormat=%d\n", i );
214 continue;
217 /* The behavior of PDF_STEREO/PFD_STEREO_DONTCARE and PFD_DOUBLEBUFFER / PFD_DOUBLEBUFFER_DONTCARE
218 * is not very clear on MSDN. They specify that ChoosePixelFormat tries to match pixel formats
219 * with the flag (PFD_STEREO / PFD_DOUBLEBUFFERING) set. Otherwise it says that it tries to match
220 * formats without the given flag set.
221 * A test on Windows using a Radeon 9500pro on WinXP (the driver doesn't support Stereo)
222 * has indicated that a format without stereo is returned when stereo is unavailable.
223 * So in case PFD_STEREO is set, formats that support it should have priority above formats
224 * without. In case PFD_STEREO_DONTCARE is set, stereo is ignored.
226 * To summarize the following is most likely the correct behavior:
227 * stereo not set -> prefer non-stereo formats, but also accept stereo formats
228 * stereo set -> prefer stereo formats, but also accept non-stereo formats
229 * stereo don't care -> it doesn't matter whether we get stereo or not
231 * In Wine we will treat non-stereo the same way as don't care because it makes
232 * format selection even more complicated and second drivers with Stereo advertise
233 * each format twice anyway.
236 /* Doublebuffer, see the comments above */
237 if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE))
239 if (((ppfd->dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) &&
240 ((format.dwFlags & PFD_DOUBLEBUFFER) == (ppfd->dwFlags & PFD_DOUBLEBUFFER)))
241 goto found;
243 if (bestDBuffer != -1 && (format.dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) continue;
246 /* Stereo, see the comments above. */
247 if (!(ppfd->dwFlags & PFD_STEREO_DONTCARE))
249 if (((ppfd->dwFlags & PFD_STEREO) != bestStereo) &&
250 ((format.dwFlags & PFD_STEREO) == (ppfd->dwFlags & PFD_STEREO)))
251 goto found;
253 if (bestStereo != -1 && (format.dwFlags & PFD_STEREO) != bestStereo) continue;
256 /* Below we will do a number of checks to select the 'best' pixelformat.
257 * We assume the precedence cColorBits > cAlphaBits > cDepthBits > cStencilBits -> cAuxBuffers.
258 * The code works by trying to match the most important options as close as possible.
259 * When a reasonable format is found, we will try to match more options.
260 * It appears (see the opengl32 test) that Windows opengl drivers ignore options
261 * like cColorBits, cAlphaBits and friends if they are set to 0, so they are considered
262 * as DONTCARE. At least Serious Sam TSE relies on this behavior. */
264 if (ppfd->cColorBits)
266 if (((ppfd->cColorBits > best.cColorBits) && (format.cColorBits > best.cColorBits)) ||
267 ((format.cColorBits >= ppfd->cColorBits) && (format.cColorBits < best.cColorBits)))
268 goto found;
270 if (best.cColorBits != format.cColorBits) /* Do further checks if the format is compatible */
272 TRACE( "color mismatch for iPixelFormat=%d\n", i );
273 continue;
276 if (ppfd->cAlphaBits)
278 if (((ppfd->cAlphaBits > best.cAlphaBits) && (format.cAlphaBits > best.cAlphaBits)) ||
279 ((format.cAlphaBits >= ppfd->cAlphaBits) && (format.cAlphaBits < best.cAlphaBits)))
280 goto found;
282 if (best.cAlphaBits != format.cAlphaBits)
284 TRACE( "alpha mismatch for iPixelFormat=%d\n", i );
285 continue;
288 if (ppfd->cDepthBits)
290 if (((ppfd->cDepthBits > best.cDepthBits) && (format.cDepthBits > best.cDepthBits)) ||
291 ((format.cDepthBits >= ppfd->cDepthBits) && (format.cDepthBits < best.cDepthBits)))
292 goto found;
294 if (best.cDepthBits != format.cDepthBits)
296 TRACE( "depth mismatch for iPixelFormat=%d\n", i );
297 continue;
300 if (ppfd->cStencilBits)
302 if (((ppfd->cStencilBits > best.cStencilBits) && (format.cStencilBits > best.cStencilBits)) ||
303 ((format.cStencilBits >= ppfd->cStencilBits) && (format.cStencilBits < best.cStencilBits)))
304 goto found;
306 if (best.cStencilBits != format.cStencilBits)
308 TRACE( "stencil mismatch for iPixelFormat=%d\n", i );
309 continue;
312 if (ppfd->cAuxBuffers)
314 if (((ppfd->cAuxBuffers > best.cAuxBuffers) && (format.cAuxBuffers > best.cAuxBuffers)) ||
315 ((format.cAuxBuffers >= ppfd->cAuxBuffers) && (format.cAuxBuffers < best.cAuxBuffers)))
316 goto found;
318 if (best.cAuxBuffers != format.cAuxBuffers)
320 TRACE( "aux mismatch for iPixelFormat=%d\n", i );
321 continue;
324 continue;
326 found:
327 best_format = i;
328 best = format;
329 bestDBuffer = format.dwFlags & PFD_DOUBLEBUFFER;
330 bestStereo = format.dwFlags & PFD_STEREO;
333 TRACE( "returning %u\n", best_format );
334 return best_format;
337 /***********************************************************************
338 * wglDescribePixelFormat (OPENGL32.@)
340 INT WINAPI wglDescribePixelFormat(HDC hdc, INT iPixelFormat, UINT nBytes,
341 LPPIXELFORMATDESCRIPTOR ppfd)
343 return GdiDescribePixelFormat(hdc, iPixelFormat, nBytes, ppfd);
346 /***********************************************************************
347 * wglGetPixelFormat (OPENGL32.@)
349 INT WINAPI wglGetPixelFormat(HDC hdc)
351 return wine_wgl.p_GetPixelFormat(hdc);
354 /***********************************************************************
355 * wglCreateLayerContext (OPENGL32.@)
357 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
358 int iLayerPlane) {
359 TRACE("(%p,%d)\n", hdc, iLayerPlane);
361 if (iLayerPlane == 0) {
362 return wglCreateContext(hdc);
364 FIXME(" no handler for layer %d\n", iLayerPlane);
366 return NULL;
369 /***********************************************************************
370 * wglDescribeLayerPlane (OPENGL32.@)
372 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
373 int iPixelFormat,
374 int iLayerPlane,
375 UINT nBytes,
376 LPLAYERPLANEDESCRIPTOR plpd) {
377 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
379 return FALSE;
382 /***********************************************************************
383 * wglGetLayerPaletteEntries (OPENGL32.@)
385 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
386 int iLayerPlane,
387 int iStart,
388 int cEntries,
389 const COLORREF *pcr) {
390 FIXME("(): stub !\n");
392 return 0;
395 /* check if the extension is present in the list */
396 static BOOL has_extension( const char *list, const char *ext )
398 size_t len = strlen( ext );
400 while (list)
402 while (*list == ' ') list++;
403 if (!strncmp( list, ext, len ) && (!list[len] || list[len] == ' ')) return TRUE;
404 list = strchr( list, ' ' );
406 return FALSE;
409 static int compar(const void *elt_a, const void *elt_b) {
410 return strcmp(((const OpenGL_extension *) elt_a)->name,
411 ((const OpenGL_extension *) elt_b)->name);
414 /* Check if a GL extension is supported */
415 static BOOL is_extension_supported(const char* extension)
417 const char *gl_ext_string = (const char*)wine_glGetString(GL_EXTENSIONS);
419 TRACE("Checking for extension '%s'\n", extension);
421 if(!gl_ext_string) {
422 ERR("No OpenGL extensions found, check if your OpenGL setup is correct!\n");
423 return FALSE;
426 /* We use the GetProcAddress function from the display driver to retrieve function pointers
427 * for OpenGL and WGL extensions. In case of winex11.drv the OpenGL extension lookup is done
428 * using glXGetProcAddress. This function is quite unreliable in the sense that its specs don't
429 * require the function to return NULL when an extension isn't found. For this reason we check
430 * if the OpenGL extension required for the function we are looking up is supported. */
432 /* Check if the extension is part of the GL extension string to see if it is supported. */
433 if (has_extension(gl_ext_string, extension))
434 return TRUE;
436 /* In general an OpenGL function starts as an ARB/EXT extension and at some stage
437 * it becomes part of the core OpenGL library and can be reached without the ARB/EXT
438 * suffix as well. In the extension table, these functions contain GL_VERSION_major_minor.
439 * Check if we are searching for a core GL function */
440 if(strncmp(extension, "GL_VERSION_", 11) == 0)
442 const GLubyte *gl_version = glGetString(GL_VERSION);
443 const char *version = extension + 11; /* Move past 'GL_VERSION_' */
445 if(!gl_version) {
446 ERR("Error no OpenGL version found,\n");
447 return FALSE;
450 /* Compare the major/minor version numbers of the native OpenGL library and what is required by the function.
451 * The gl_version string is guaranteed to have at least a major/minor and sometimes it has a release number as well. */
452 if( (gl_version[0] >= version[0]) || ((gl_version[0] == version[0]) && (gl_version[2] >= version[2])) ) {
453 return TRUE;
455 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]);
458 return FALSE;
461 /***********************************************************************
462 * wglGetProcAddress (OPENGL32.@)
464 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
465 void *local_func;
466 OpenGL_extension ext;
467 const OpenGL_extension *ext_ret;
469 TRACE("(%s)\n", lpszProc);
471 if (lpszProc == NULL)
472 return NULL;
474 /* Without an active context opengl32 doesn't know to what
475 * driver it has to dispatch wglGetProcAddress.
477 if (wglGetCurrentContext() == NULL)
479 WARN("No active WGL context found\n");
480 return NULL;
483 /* Search in the thunks to find the real name of the extension */
484 ext.name = lpszProc;
485 ext_ret = bsearch(&ext, extension_registry, extension_registry_size,
486 sizeof(OpenGL_extension), compar);
488 /* If nothing was found, we are looking for a WGL extension or an unknown GL extension. */
489 if (ext_ret == NULL) {
490 /* If the function name starts with a 'w', it is a WGL extension */
491 if(lpszProc[0] == 'w')
492 return wine_wgl.p_wglGetProcAddress(lpszProc);
494 /* We are dealing with an unknown GL extension */
495 WARN("Extension '%s' not defined in opengl32.dll's function table!\n", lpszProc);
496 return NULL;
497 } else { /* We are looking for an OpenGL extension */
499 /* Check if the GL extension required by the function is available */
500 if(!is_extension_supported(ext_ret->extension)) {
501 WARN("Extension '%s' required by function '%s' not supported!\n", ext_ret->extension, lpszProc);
504 local_func = wine_wgl.p_wglGetProcAddress(ext_ret->name);
506 /* After that, look at the extensions defined in the Linux OpenGL library */
507 if (local_func == NULL) {
508 char buf[256];
509 void *ret = NULL;
511 /* Remove the last 3 letters (EXT, ARB, ...).
513 I know that some extensions have more than 3 letters (MESA, NV,
514 INTEL, ...), but this is only a stop-gap measure to fix buggy
515 OpenGL drivers (moreover, it is only useful for old 1.0 apps
516 that query the glBindTextureEXT extension).
518 memcpy(buf, ext_ret->name, strlen(ext_ret->name) - 3);
519 buf[strlen(ext_ret->name) - 3] = '\0';
520 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
522 ret = GetProcAddress(opengl32_handle, buf);
523 if (ret != NULL) {
524 TRACE(" found function in main OpenGL library (%p) !\n", ret);
525 } else {
526 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->name);
529 return ret;
530 } else {
531 TRACE(" returning function (%p)\n", ext_ret->func);
532 extension_funcs[ext_ret - extension_registry] = local_func;
534 return ext_ret->func;
539 /***********************************************************************
540 * wglRealizeLayerPalette (OPENGL32.@)
542 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
543 int iLayerPlane,
544 BOOL bRealize) {
545 FIXME("()\n");
547 return FALSE;
550 /***********************************************************************
551 * wglSetLayerPaletteEntries (OPENGL32.@)
553 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
554 int iLayerPlane,
555 int iStart,
556 int cEntries,
557 const COLORREF *pcr) {
558 FIXME("(): stub !\n");
560 return 0;
563 /***********************************************************************
564 * wglSwapLayerBuffers (OPENGL32.@)
566 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
567 UINT fuPlanes) {
568 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
570 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
571 if (!GdiSwapBuffers(hdc)) return FALSE;
572 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
575 if (fuPlanes) {
576 WARN("Following layers unhandled : %08x\n", fuPlanes);
579 return TRUE;
582 /***********************************************************************
583 * wglUseFontBitmaps_common
585 static BOOL wglUseFontBitmaps_common( HDC hdc, DWORD first, DWORD count, DWORD listBase, BOOL unicode )
587 GLYPHMETRICS gm;
588 unsigned int glyph, size = 0;
589 void *bitmap = NULL, *gl_bitmap = NULL;
590 int org_alignment;
591 BOOL ret = TRUE;
593 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
594 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
596 for (glyph = first; glyph < first + count; glyph++) {
597 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
598 unsigned int needed_size, height, width, width_int;
600 if (unicode)
601 needed_size = GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
602 else
603 needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
605 TRACE("Glyph : %3d / List : %d size %d\n", glyph, listBase, needed_size);
606 if (needed_size == GDI_ERROR) {
607 ret = FALSE;
608 break;
611 if (needed_size > size) {
612 size = needed_size;
613 HeapFree(GetProcessHeap(), 0, bitmap);
614 HeapFree(GetProcessHeap(), 0, gl_bitmap);
615 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
616 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
618 if (unicode)
619 ret = (GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
620 else
621 ret = (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
622 if (!ret) break;
624 if (TRACE_ON(wgl)) {
625 unsigned int bitmask;
626 unsigned char *bitmap_ = bitmap;
628 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
629 TRACE(" - origin : (%d , %d)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
630 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
631 if (needed_size != 0) {
632 TRACE(" - bitmap :\n");
633 for (height = 0; height < gm.gmBlackBoxY; height++) {
634 TRACE(" ");
635 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
636 if (bitmask == 0) {
637 bitmap_ += 1;
638 bitmask = 0x80;
640 if (*bitmap_ & bitmask)
641 TRACE("*");
642 else
643 TRACE(" ");
645 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
646 TRACE("\n");
651 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
652 * glyph for it to be drawn properly.
654 if (needed_size != 0) {
655 width_int = (gm.gmBlackBoxX + 31) / 32;
656 for (height = 0; height < gm.gmBlackBoxY; height++) {
657 for (width = 0; width < width_int; width++) {
658 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
659 ((int *) bitmap)[height * width_int + width];
664 glNewList(listBase++, GL_COMPILE);
665 if (needed_size != 0) {
666 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
667 0 - gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - gm.gmptGlyphOrigin.y,
668 gm.gmCellIncX, gm.gmCellIncY,
669 gl_bitmap);
670 } else {
671 /* This is the case of 'empty' glyphs like the space character */
672 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
674 glEndList();
677 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
678 HeapFree(GetProcessHeap(), 0, bitmap);
679 HeapFree(GetProcessHeap(), 0, gl_bitmap);
680 return ret;
683 /***********************************************************************
684 * wglUseFontBitmapsA (OPENGL32.@)
686 BOOL WINAPI wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase)
688 return wglUseFontBitmaps_common( hdc, first, count, listBase, FALSE );
691 /***********************************************************************
692 * wglUseFontBitmapsW (OPENGL32.@)
694 BOOL WINAPI wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase)
696 return wglUseFontBitmaps_common( hdc, first, count, listBase, TRUE );
699 #ifdef SONAME_LIBGLU
701 static void *load_libglu(void)
703 static int already_loaded;
704 void *handle;
706 if (already_loaded) return libglu_handle;
707 already_loaded = 1;
709 TRACE("Trying to load GLU library: %s\n", SONAME_LIBGLU);
710 handle = wine_dlopen(SONAME_LIBGLU, RTLD_NOW, NULL, 0);
711 if (!handle)
713 WARN("Failed to load %s\n", SONAME_LIBGLU);
714 return NULL;
717 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(handle, #f, NULL, 0)) == NULL) goto sym_not_found;
718 LOAD_FUNCPTR(gluNewTess)
719 LOAD_FUNCPTR(gluDeleteTess)
720 LOAD_FUNCPTR(gluTessBeginContour)
721 LOAD_FUNCPTR(gluTessBeginPolygon)
722 LOAD_FUNCPTR(gluTessCallback)
723 LOAD_FUNCPTR(gluTessEndContour)
724 LOAD_FUNCPTR(gluTessEndPolygon)
725 LOAD_FUNCPTR(gluTessVertex)
726 #undef LOAD_FUNCPTR
727 libglu_handle = handle;
728 return handle;
730 sym_not_found:
731 WARN("Unable to load function ptrs from libGLU\n");
732 /* Close the library as we won't use it */
733 wine_dlclose(handle, NULL, 0);
734 return NULL;
737 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
739 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
740 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
741 vertex[2] = 0.0;
744 static void tess_callback_vertex(GLvoid *vertex)
746 GLdouble *dbl = vertex;
747 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
748 glVertex3dv(vertex);
751 static void tess_callback_begin(GLenum which)
753 TRACE("%d\n", which);
754 glBegin(which);
757 static void tess_callback_end(void)
759 TRACE("\n");
760 glEnd();
763 /***********************************************************************
764 * wglUseFontOutlines_common
766 static BOOL wglUseFontOutlines_common(HDC hdc,
767 DWORD first,
768 DWORD count,
769 DWORD listBase,
770 FLOAT deviation,
771 FLOAT extrusion,
772 int format,
773 LPGLYPHMETRICSFLOAT lpgmf,
774 BOOL unicode)
776 UINT glyph;
777 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
778 GLUtesselator *tess;
779 LOGFONTW lf;
780 HFONT old_font, unscaled_font;
781 UINT em_size = 1024;
782 RECT rc;
784 TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
785 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
787 if (!load_libglu())
789 ERR("libGLU is required for this function but isn't loaded\n");
790 return FALSE;
793 tess = pgluNewTess();
794 if(!tess) return FALSE;
795 pgluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
796 pgluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
797 pgluTessCallback(tess, GLU_TESS_END, tess_callback_end);
799 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
800 rc.left = rc.right = rc.bottom = 0;
801 rc.top = em_size;
802 DPtoLP(hdc, (POINT*)&rc, 2);
803 lf.lfHeight = -abs(rc.top - rc.bottom);
804 lf.lfOrientation = lf.lfEscapement = 0;
805 unscaled_font = CreateFontIndirectW(&lf);
806 old_font = SelectObject(hdc, unscaled_font);
808 for (glyph = first; glyph < first + count; glyph++)
810 DWORD needed;
811 GLYPHMETRICS gm;
812 BYTE *buf;
813 TTPOLYGONHEADER *pph;
814 TTPOLYCURVE *ppc;
815 GLdouble *vertices;
817 if(unicode)
818 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
819 else
820 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
822 if(needed == GDI_ERROR)
823 goto error;
825 buf = HeapAlloc(GetProcessHeap(), 0, needed);
826 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
828 if(unicode)
829 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
830 else
831 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
833 TRACE("glyph %d\n", glyph);
835 if(lpgmf)
837 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
838 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
839 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
840 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
841 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
842 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
844 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
845 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
846 lpgmf++;
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 HeapFree(GetProcessHeap(), 0, buf);
912 HeapFree(GetProcessHeap(), 0, vertices);
915 error:
916 DeleteObject(SelectObject(hdc, old_font));
917 pgluDeleteTess(tess);
918 return TRUE;
922 #else /* SONAME_LIBGLU */
924 static BOOL wglUseFontOutlines_common(HDC hdc,
925 DWORD first,
926 DWORD count,
927 DWORD listBase,
928 FLOAT deviation,
929 FLOAT extrusion,
930 int format,
931 LPGLYPHMETRICSFLOAT lpgmf,
932 BOOL unicode)
934 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
935 return FALSE;
938 #endif /* SONAME_LIBGLU */
940 /***********************************************************************
941 * wglUseFontOutlinesA (OPENGL32.@)
943 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
944 DWORD first,
945 DWORD count,
946 DWORD listBase,
947 FLOAT deviation,
948 FLOAT extrusion,
949 int format,
950 LPGLYPHMETRICSFLOAT lpgmf)
952 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
955 /***********************************************************************
956 * wglUseFontOutlinesW (OPENGL32.@)
958 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
959 DWORD first,
960 DWORD count,
961 DWORD listBase,
962 FLOAT deviation,
963 FLOAT extrusion,
964 int format,
965 LPGLYPHMETRICSFLOAT lpgmf)
967 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
970 /***********************************************************************
971 * glDebugEntry (OPENGL32.@)
973 GLint WINAPI wine_glDebugEntry( GLint unknown1, GLint unknown2 )
975 return 0;
978 /***********************************************************************
979 * glFinish (OPENGL32.@)
981 void WINAPI wine_glFinish( void )
983 TRACE("()\n");
984 wine_wgl.p_wglFinish();
987 /***********************************************************************
988 * glFlush (OPENGL32.@)
990 void WINAPI wine_glFlush( void )
992 TRACE("()\n");
993 wine_wgl.p_wglFlush();
996 /* build the extension string by filtering out the disabled extensions */
997 static char *build_gl_extensions( const char *extensions )
999 char *p, *str, *disabled = NULL;
1000 const char *end;
1001 HKEY hkey;
1003 TRACE( "GL_EXTENSIONS:\n" );
1005 if (!extensions) extensions = "";
1007 /* @@ Wine registry key: HKCU\Software\Wine\OpenGL */
1008 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\OpenGL", &hkey ))
1010 DWORD size, ret = RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, NULL, &size );
1011 if (!ret && (disabled = HeapAlloc( GetProcessHeap(), 0, size )))
1012 ret = RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (BYTE *)disabled, &size );
1013 RegCloseKey( hkey );
1014 if (ret) *disabled = 0;
1017 if ((str = HeapAlloc( GetProcessHeap(), 0, strlen(extensions) + 2 )))
1019 p = str;
1020 for (;;)
1022 while (*extensions == ' ') extensions++;
1023 if (!*extensions) break;
1024 if (!(end = strchr( extensions, ' ' ))) end = extensions + strlen( extensions );
1025 memcpy( p, extensions, end - extensions );
1026 p[end - extensions] = 0;
1027 if (!has_extension( disabled, p ))
1029 TRACE("++ %s\n", p );
1030 p += end - extensions;
1031 *p++ = ' ';
1033 else TRACE("-- %s (disabled by config)\n", p );
1034 extensions = end;
1036 *p = 0;
1038 HeapFree( GetProcessHeap(), 0, disabled );
1039 return str;
1042 /***********************************************************************
1043 * glGetString (OPENGL32.@)
1045 const GLubyte * WINAPI wine_glGetString( GLenum name )
1047 static const GLubyte *gl_extensions;
1049 /* this is for buggy nvidia driver, crashing if called from a different
1050 thread with no context */
1051 if(wglGetCurrentContext() == NULL)
1052 return NULL;
1054 if (name != GL_EXTENSIONS) return glGetString(name);
1056 if (!gl_extensions)
1058 const char *orig_ext = (const char *)glGetString(GL_EXTENSIONS);
1059 char *new_ext = build_gl_extensions( orig_ext );
1060 if (InterlockedCompareExchangePointer( (void **)&gl_extensions, new_ext, NULL ))
1061 HeapFree( GetProcessHeap(), 0, new_ext );
1063 return gl_extensions;
1066 /***********************************************************************
1067 * glGetIntegerv (OPENGL32.@)
1069 void WINAPI wine_glGetIntegerv( GLenum pname, GLint* params )
1071 wine_wgl.p_wglGetIntegerv(pname, params);
1074 /***********************************************************************
1075 * wglSwapBuffers (OPENGL32.@)
1077 BOOL WINAPI DECLSPEC_HOTPATCH wglSwapBuffers( HDC hdc )
1079 return GdiSwapBuffers(hdc);
1082 /* This is for brain-dead applications that use OpenGL functions before even
1083 creating a rendering context.... */
1084 static BOOL process_attach(void)
1086 HMODULE mod_gdi32;
1088 GetDesktopWindow(); /* make sure winex11 is loaded (FIXME) */
1089 mod_gdi32 = GetModuleHandleA( "gdi32.dll" );
1091 if (!mod_gdi32)
1093 ERR("GDI32 not loaded. Cannot create default context.\n");
1094 return FALSE;
1097 wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod_gdi32, "wglGetProcAddress");
1098 wine_wgl.p_wglCreateContext = (void *)GetProcAddress(mod_gdi32, "wglCreateContext");
1099 wine_wgl.p_GetPixelFormat = (void *)GetProcAddress(mod_gdi32, "GetPixelFormat");
1101 /* internal WGL functions */
1102 wine_wgl.p_wglCopyContext = (void *)wine_wgl.p_wglGetProcAddress("wglCopyContext");
1103 wine_wgl.p_wglDeleteContext = (void *)wine_wgl.p_wglGetProcAddress("wglDeleteContext");
1104 wine_wgl.p_wglFinish = (void *)wine_wgl.p_wglGetProcAddress("wglFinish");
1105 wine_wgl.p_wglFlush = (void *)wine_wgl.p_wglGetProcAddress("wglFlush");
1106 wine_wgl.p_wglGetCurrentContext = (void *)wine_wgl.p_wglGetProcAddress("wglGetCurrentContext");
1107 wine_wgl.p_wglGetCurrentDC = (void *)wine_wgl.p_wglGetProcAddress("wglGetCurrentDC");
1108 wine_wgl.p_wglGetIntegerv = (void *)wine_wgl.p_wglGetProcAddress("wglGetIntegerv");
1109 wine_wgl.p_wglMakeCurrent = (void *)wine_wgl.p_wglGetProcAddress("wglMakeCurrent");
1110 wine_wgl.p_wglShareLists = (void *)wine_wgl.p_wglGetProcAddress("wglShareLists");
1111 return TRUE;
1115 /**********************************************************************/
1117 static void process_detach(void)
1119 if (libglu_handle) wine_dlclose(libglu_handle, NULL, 0);
1122 /***********************************************************************
1123 * OpenGL initialisation routine
1125 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1127 switch(reason)
1129 case DLL_PROCESS_ATTACH:
1130 opengl32_handle = hinst;
1131 DisableThreadLibraryCalls(hinst);
1132 return process_attach();
1133 case DLL_PROCESS_DETACH:
1134 process_detach();
1135 break;
1137 return TRUE;