comctl32/tests: Flush events before testing edit control IME messages.
[wine.git] / dlls / opengl32 / wgl.c
blobd5b0a78b916a0e2d5ea84fd97d5d3e5ecaae3790
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"
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <math.h>
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winreg.h"
32 #include "ntuser.h"
34 #include "opengl_ext.h"
36 #include "unixlib.h"
38 #include "wine/glu.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
42 WINE_DECLARE_DEBUG_CHANNEL(fps);
44 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
46 /***********************************************************************
47 * wglGetCurrentReadDCARB
49 * Provided by the WGL_ARB_make_current_read extension.
51 HDC WINAPI wglGetCurrentReadDCARB(void)
53 struct wgl_handle *ptr = get_current_context_ptr();
55 if (!ptr) return 0;
56 return ptr->u.context->read_dc;
59 /***********************************************************************
60 * wglGetCurrentDC (OPENGL32.@)
62 HDC WINAPI wglGetCurrentDC(void)
64 struct wgl_handle *ptr = get_current_context_ptr();
66 if (!ptr) return 0;
67 return ptr->u.context->draw_dc;
70 /***********************************************************************
71 * wglGetCurrentContext (OPENGL32.@)
73 HGLRC WINAPI wglGetCurrentContext(void)
75 return NtCurrentTeb()->glCurrentRC;
78 /***********************************************************************
79 * wglChoosePixelFormat (OPENGL32.@)
81 INT WINAPI wglChoosePixelFormat(HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd)
83 PIXELFORMATDESCRIPTOR format, best;
84 int i, count, best_format;
85 int bestDBuffer = -1, bestStereo = -1;
87 TRACE_(wgl)( "%p %p: size %u version %u flags %u type %u color %u %u,%u,%u,%u "
88 "accum %u depth %u stencil %u aux %u\n",
89 hdc, ppfd, ppfd->nSize, ppfd->nVersion, ppfd->dwFlags, ppfd->iPixelType,
90 ppfd->cColorBits, ppfd->cRedBits, ppfd->cGreenBits, ppfd->cBlueBits, ppfd->cAlphaBits,
91 ppfd->cAccumBits, ppfd->cDepthBits, ppfd->cStencilBits, ppfd->cAuxBuffers );
93 count = wglDescribePixelFormat( hdc, 0, 0, NULL );
94 if (!count) return 0;
96 best_format = 0;
97 best.dwFlags = 0;
98 best.cAlphaBits = -1;
99 best.cColorBits = -1;
100 best.cDepthBits = -1;
101 best.cStencilBits = -1;
102 best.cAuxBuffers = -1;
104 for (i = 1; i <= count; i++)
106 if (!wglDescribePixelFormat( hdc, i, sizeof(format), &format )) continue;
108 if ((ppfd->iPixelType == PFD_TYPE_COLORINDEX) != (format.iPixelType == PFD_TYPE_COLORINDEX))
110 TRACE( "pixel type mismatch for iPixelFormat=%d\n", i );
111 continue;
114 /* only use bitmap capable for formats for bitmap rendering */
115 if( (ppfd->dwFlags & PFD_DRAW_TO_BITMAP) != (format.dwFlags & PFD_DRAW_TO_BITMAP))
117 TRACE( "PFD_DRAW_TO_BITMAP mismatch for iPixelFormat=%d\n", i );
118 continue;
121 /* The behavior of PDF_STEREO/PFD_STEREO_DONTCARE and PFD_DOUBLEBUFFER / PFD_DOUBLEBUFFER_DONTCARE
122 * is not very clear on MSDN. They specify that ChoosePixelFormat tries to match pixel formats
123 * with the flag (PFD_STEREO / PFD_DOUBLEBUFFERING) set. Otherwise it says that it tries to match
124 * formats without the given flag set.
125 * A test on Windows using a Radeon 9500pro on WinXP (the driver doesn't support Stereo)
126 * has indicated that a format without stereo is returned when stereo is unavailable.
127 * So in case PFD_STEREO is set, formats that support it should have priority above formats
128 * without. In case PFD_STEREO_DONTCARE is set, stereo is ignored.
130 * To summarize the following is most likely the correct behavior:
131 * stereo not set -> prefer non-stereo formats, but also accept stereo formats
132 * stereo set -> prefer stereo formats, but also accept non-stereo formats
133 * stereo don't care -> it doesn't matter whether we get stereo or not
135 * In Wine we will treat non-stereo the same way as don't care because it makes
136 * format selection even more complicated and second drivers with Stereo advertise
137 * each format twice anyway.
140 /* Doublebuffer, see the comments above */
141 if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE))
143 if (((ppfd->dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) &&
144 ((format.dwFlags & PFD_DOUBLEBUFFER) == (ppfd->dwFlags & PFD_DOUBLEBUFFER)))
145 goto found;
147 if (bestDBuffer != -1 && (format.dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) continue;
149 else if (!best_format)
150 goto found;
152 /* Stereo, see the comments above. */
153 if (!(ppfd->dwFlags & PFD_STEREO_DONTCARE))
155 if (((ppfd->dwFlags & PFD_STEREO) != bestStereo) &&
156 ((format.dwFlags & PFD_STEREO) == (ppfd->dwFlags & PFD_STEREO)))
157 goto found;
159 if (bestStereo != -1 && (format.dwFlags & PFD_STEREO) != bestStereo) continue;
161 else if (!best_format)
162 goto found;
164 /* Below we will do a number of checks to select the 'best' pixelformat.
165 * We assume the precedence cColorBits > cAlphaBits > cDepthBits > cStencilBits -> cAuxBuffers.
166 * The code works by trying to match the most important options as close as possible.
167 * When a reasonable format is found, we will try to match more options.
168 * It appears (see the opengl32 test) that Windows opengl drivers ignore options
169 * like cColorBits, cAlphaBits and friends if they are set to 0, so they are considered
170 * as DONTCARE. At least Serious Sam TSE relies on this behavior. */
172 if (ppfd->cColorBits)
174 if (((ppfd->cColorBits > best.cColorBits) && (format.cColorBits > best.cColorBits)) ||
175 ((format.cColorBits >= ppfd->cColorBits) && (format.cColorBits < best.cColorBits)))
176 goto found;
178 if (best.cColorBits != format.cColorBits) /* Do further checks if the format is compatible */
180 TRACE( "color mismatch for iPixelFormat=%d\n", i );
181 continue;
184 if (ppfd->cAlphaBits)
186 if (((ppfd->cAlphaBits > best.cAlphaBits) && (format.cAlphaBits > best.cAlphaBits)) ||
187 ((format.cAlphaBits >= ppfd->cAlphaBits) && (format.cAlphaBits < best.cAlphaBits)))
188 goto found;
190 if (best.cAlphaBits != format.cAlphaBits)
192 TRACE( "alpha mismatch for iPixelFormat=%d\n", i );
193 continue;
196 if (ppfd->cStencilBits)
198 if (((ppfd->cStencilBits > best.cStencilBits) && (format.cStencilBits > best.cStencilBits)) ||
199 ((format.cStencilBits >= ppfd->cStencilBits) && (format.cStencilBits < best.cStencilBits)))
200 goto found;
202 if (best.cStencilBits != format.cStencilBits)
204 TRACE( "stencil mismatch for iPixelFormat=%d\n", i );
205 continue;
208 if (ppfd->cDepthBits && !(ppfd->dwFlags & PFD_DEPTH_DONTCARE))
210 if (((ppfd->cDepthBits > best.cDepthBits) && (format.cDepthBits > best.cDepthBits)) ||
211 ((format.cDepthBits >= ppfd->cDepthBits) && (format.cDepthBits < best.cDepthBits)))
212 goto found;
214 if (best.cDepthBits != format.cDepthBits)
216 TRACE( "depth mismatch for iPixelFormat=%d\n", i );
217 continue;
220 if (ppfd->cAuxBuffers)
222 if (((ppfd->cAuxBuffers > best.cAuxBuffers) && (format.cAuxBuffers > best.cAuxBuffers)) ||
223 ((format.cAuxBuffers >= ppfd->cAuxBuffers) && (format.cAuxBuffers < best.cAuxBuffers)))
224 goto found;
226 if (best.cAuxBuffers != format.cAuxBuffers)
228 TRACE( "aux mismatch for iPixelFormat=%d\n", i );
229 continue;
232 if (ppfd->dwFlags & PFD_DEPTH_DONTCARE && format.cDepthBits < best.cDepthBits)
233 goto found;
235 continue;
237 found:
238 best_format = i;
239 best = format;
240 bestDBuffer = format.dwFlags & PFD_DOUBLEBUFFER;
241 bestStereo = format.dwFlags & PFD_STEREO;
244 TRACE( "returning %u\n", best_format );
245 return best_format;
248 /***********************************************************************
249 * wglGetPixelFormat (OPENGL32.@)
251 INT WINAPI wglGetPixelFormat(HDC hdc)
253 struct wglGetPixelFormat_params args = { .hdc = hdc, };
254 NTSTATUS status;
256 TRACE( "hdc %p\n", hdc );
258 if ((status = UNIX_CALL( wglGetPixelFormat, &args )))
260 WARN( "wglGetPixelFormat returned %#x\n", status );
261 SetLastError( ERROR_INVALID_PIXEL_FORMAT );
264 return args.ret;
267 /***********************************************************************
268 * wglSwapBuffers (OPENGL32.@)
270 BOOL WINAPI DECLSPEC_HOTPATCH wglSwapBuffers( HDC hdc )
272 struct wglSwapBuffers_params args = { .hdc = hdc, };
273 NTSTATUS status;
275 if ((status = UNIX_CALL( wglSwapBuffers, &args ))) WARN( "wglSwapBuffers returned %#x\n", status );
276 else if (TRACE_ON(fps))
278 static long prev_time, start_time;
279 static unsigned long frames, frames_total;
281 DWORD time = GetTickCount();
282 frames++;
283 frames_total++;
284 /* every 1.5 seconds */
285 if (time - prev_time > 1500)
287 TRACE_(fps)("@ approx %.2ffps, total %.2ffps\n",
288 1000.0*frames/(time - prev_time), 1000.0*frames_total/(time - start_time));
289 prev_time = time;
290 frames = 0;
291 if (start_time == 0) start_time = time;
295 return args.ret;
298 /***********************************************************************
299 * wglCreateLayerContext (OPENGL32.@)
301 HGLRC WINAPI wglCreateLayerContext( HDC hdc, int iLayerPlane )
303 TRACE("(%p,%d)\n", hdc, iLayerPlane);
305 if (iLayerPlane == 0) return wglCreateContext( hdc );
307 FIXME("no handler for layer %d\n", iLayerPlane);
308 return NULL;
311 /***********************************************************************
312 * wglDescribeLayerPlane (OPENGL32.@)
314 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
315 int iPixelFormat,
316 int iLayerPlane,
317 UINT nBytes,
318 LPLAYERPLANEDESCRIPTOR plpd) {
319 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
321 return FALSE;
324 /***********************************************************************
325 * wglGetLayerPaletteEntries (OPENGL32.@)
327 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
328 int iLayerPlane,
329 int iStart,
330 int cEntries,
331 const COLORREF *pcr) {
332 FIXME("(): stub!\n");
334 return 0;
337 /* check if the extension is present in the list */
338 static BOOL has_extension( const char *list, const char *ext, size_t len )
340 while (list)
342 while (*list == ' ') list++;
343 if (!strncmp( list, ext, len ) && (!list[len] || list[len] == ' ')) return TRUE;
344 list = strchr( list, ' ' );
346 return FALSE;
349 static GLubyte *filter_extensions_list( const char *extensions, const char *disabled )
351 const char *end;
352 char *p, *str;
354 p = str = HeapAlloc( GetProcessHeap(), 0, strlen( extensions ) + 2 );
355 if (!str) return NULL;
357 TRACE( "GL_EXTENSIONS:\n" );
359 for (;;)
361 while (*extensions == ' ') extensions++;
362 if (!*extensions) break;
364 if (!(end = strchr( extensions, ' ' ))) end = extensions + strlen( extensions );
365 memcpy( p, extensions, end - extensions );
366 p[end - extensions] = 0;
368 if (!has_extension( disabled, p, strlen( p ) ))
370 TRACE( "++ %s\n", p );
371 p += end - extensions;
372 *p++ = ' ';
374 else
376 TRACE( "-- %s (disabled by config)\n", p );
378 extensions = end;
380 *p = 0;
381 return (GLubyte *)str;
384 static GLuint *filter_extensions_index( const char *disabled )
386 const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
387 GLuint *disabled_index;
388 GLint extensions_count;
389 unsigned int i = 0, j;
390 const char *ext;
392 if (!funcs->ext.p_glGetStringi)
394 void **func_ptr = (void **)&funcs->ext.p_glGetStringi;
395 *func_ptr = funcs->wgl.p_wglGetProcAddress( "glGetStringi" );
396 if (!funcs->ext.p_glGetStringi) return NULL;
399 funcs->gl.p_glGetIntegerv( GL_NUM_EXTENSIONS, &extensions_count );
400 disabled_index = HeapAlloc( GetProcessHeap(), 0, extensions_count * sizeof(*disabled_index) );
401 if (!disabled_index) return NULL;
403 TRACE( "GL_EXTENSIONS:\n" );
405 for (j = 0; j < extensions_count; ++j)
407 ext = (const char *)funcs->ext.p_glGetStringi( GL_EXTENSIONS, j );
408 if (!has_extension( disabled, ext, strlen( ext ) ))
410 TRACE( "++ %s\n", ext );
412 else
414 TRACE( "-- %s (disabled by config)\n", ext );
415 disabled_index[i++] = j;
419 disabled_index[i] = ~0u;
420 return disabled_index;
423 /* build the extension string by filtering out the disabled extensions */
424 static BOOL filter_extensions( const char *extensions, GLubyte **exts_list, GLuint **disabled_exts )
426 static const char *disabled;
428 if (!disabled)
430 HKEY hkey;
431 DWORD size;
432 char *str = NULL;
434 /* @@ Wine registry key: HKCU\Software\Wine\OpenGL */
435 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\OpenGL", &hkey ))
437 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, NULL, &size ))
439 str = HeapAlloc( GetProcessHeap(), 0, size );
440 if (RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (BYTE *)str, &size )) *str = 0;
442 RegCloseKey( hkey );
444 if (str)
446 if (InterlockedCompareExchangePointer( (void **)&disabled, str, NULL ))
447 HeapFree( GetProcessHeap(), 0, str );
449 else disabled = "";
452 if (!disabled[0]) return FALSE;
453 if (extensions && !*exts_list) *exts_list = filter_extensions_list( extensions, disabled );
454 if (!*disabled_exts) *disabled_exts = filter_extensions_index( disabled );
455 return (exts_list && *exts_list) || *disabled_exts;
458 void WINAPI glGetIntegerv(GLenum pname, GLint *data)
460 struct glGetIntegerv_params args = { .pname = pname, .data = data, };
461 NTSTATUS status;
463 TRACE( "pname %d, data %p\n", pname, data );
465 if (pname == GL_NUM_EXTENSIONS)
467 struct wgl_handle *ptr = get_current_context_ptr();
468 GLuint **disabled = &ptr->u.context->disabled_exts;
470 if (*disabled || filter_extensions( NULL, NULL, disabled ))
472 const GLuint *disabled_exts = *disabled;
473 GLint count, disabled_count = 0;
475 args.data = &count;
476 if ((status = UNIX_CALL( glGetIntegerv, &args ))) WARN( "glGetIntegerv returned %#x\n", status );
478 while (*disabled_exts++ != ~0u)
479 disabled_count++;
480 *data = count - disabled_count;
481 return;
485 if ((status = UNIX_CALL( glGetIntegerv, &args ))) WARN( "glGetIntegerv returned %#x\n", status );
488 const GLubyte * WINAPI glGetStringi(GLenum name, GLuint index)
490 const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
492 TRACE("(%d, %d)\n", name, index);
493 if (!funcs->ext.p_glGetStringi)
495 void **func_ptr = (void **)&funcs->ext.p_glGetStringi;
497 *func_ptr = funcs->wgl.p_wglGetProcAddress("glGetStringi");
500 if (name == GL_EXTENSIONS)
502 struct wgl_handle *ptr = get_current_context_ptr();
504 if (ptr->u.context->disabled_exts ||
505 filter_extensions(NULL, NULL, &ptr->u.context->disabled_exts))
507 const GLuint *disabled_exts = ptr->u.context->disabled_exts;
508 unsigned int disabled_count = 0;
510 while (index + disabled_count >= *disabled_exts++)
511 disabled_count++;
512 return funcs->ext.p_glGetStringi(name, index + disabled_count);
515 return funcs->ext.p_glGetStringi(name, index);
518 static int compar(const void *elt_a, const void *elt_b) {
519 return strcmp(((const OpenGL_extension *) elt_a)->name,
520 ((const OpenGL_extension *) elt_b)->name);
523 /* Check if a GL extension is supported */
524 static BOOL check_extension_support( const char *extension, const char *available_extensions )
526 const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
527 size_t len;
529 TRACE("Checking for extension '%s'\n", extension);
531 /* We use the GetProcAddress function from the display driver to retrieve function pointers
532 * for OpenGL and WGL extensions. In case of winex11.drv the OpenGL extension lookup is done
533 * using glXGetProcAddress. This function is quite unreliable in the sense that its specs don't
534 * require the function to return NULL when an extension isn't found. For this reason we check
535 * if the OpenGL extension required for the function we are looking up is supported. */
537 while ((len = strcspn( extension, " " )))
539 /* Check if the extension is part of the GL extension string to see if it is supported. */
540 if (has_extension( available_extensions, extension, len )) return TRUE;
542 /* In general an OpenGL function starts as an ARB/EXT extension and at some stage
543 * it becomes part of the core OpenGL library and can be reached without the ARB/EXT
544 * suffix as well. In the extension table, these functions contain GL_VERSION_major_minor.
545 * Check if we are searching for a core GL function */
546 if (!strncmp( extension, "GL_VERSION_", 11 ))
548 const GLubyte *gl_version = funcs->gl.p_glGetString(GL_VERSION);
549 const char *version = extension + 11; /* Move past 'GL_VERSION_' */
551 if (!gl_version)
553 ERR( "No OpenGL version found!\n" );
554 return FALSE;
557 /* Compare the major/minor version numbers of the native OpenGL library and what is required by the function.
558 * The gl_version string is guaranteed to have at least a major/minor and sometimes it has a release number as well. */
559 if ((gl_version[0] > version[0]) || ((gl_version[0] == version[0]) && (gl_version[2] >= version[2]))) return TRUE;
561 WARN( "The function requires OpenGL version '%c.%c' while your drivers only provide '%c.%c'\n",
562 version[0], version[2], gl_version[0], gl_version[2] );
565 if (extension[len] == ' ') len++;
566 extension += len;
569 return FALSE;
572 static char *build_extension_list(void)
574 GLint len = 0, capacity, i, extensions_count;
575 char *extension, *tmp, *available_extensions;
577 glGetIntegerv( GL_NUM_EXTENSIONS, &extensions_count );
578 capacity = 128 * extensions_count;
580 if (!(available_extensions = HeapAlloc( GetProcessHeap(), 0, capacity ))) return NULL;
581 for (i = 0; i < extensions_count; ++i)
583 extension = (char *)glGetStringi( GL_EXTENSIONS, i );
584 capacity = max( capacity, len + strlen( extension ) + 2 );
585 if (!(tmp = HeapReAlloc( GetProcessHeap(), 0, available_extensions, capacity ))) break;
586 available_extensions = tmp;
587 len += sprintf( available_extensions + len, "%s ", extension );
589 if (len) available_extensions[len - 1] = 0;
591 return available_extensions;
594 static char *heap_strdup( const char *str )
596 int len = strlen( str ) + 1;
597 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
598 memcpy( ret, str, len );
599 return ret;
602 /* Check if a GL extension is supported */
603 static BOOL is_extension_supported( const char *extension )
605 enum wgl_handle_type type = get_current_context_type();
606 char *available_extensions = NULL;
607 BOOL ret = FALSE;
609 if (type == HANDLE_CONTEXT) available_extensions = heap_strdup( (const char *)glGetString( GL_EXTENSIONS ) );
610 if (!available_extensions) available_extensions = build_extension_list();
612 if (!available_extensions) ERR( "No OpenGL extensions found, check if your OpenGL setup is correct!\n" );
613 else ret = check_extension_support( extension, available_extensions );
615 HeapFree( GetProcessHeap(), 0, available_extensions );
616 return ret;
619 /***********************************************************************
620 * wglGetProcAddress (OPENGL32.@)
622 PROC WINAPI wglGetProcAddress( LPCSTR name )
624 struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
625 void **func_ptr;
626 OpenGL_extension ext;
627 const OpenGL_extension *ext_ret;
629 if (!name) return NULL;
631 /* Without an active context opengl32 doesn't know to what
632 * driver it has to dispatch wglGetProcAddress.
634 if (!get_current_context_ptr())
636 WARN("No active WGL context found\n");
637 return NULL;
640 ext.name = name;
641 ext_ret = bsearch(&ext, extension_registry, extension_registry_size, sizeof(ext), compar);
642 if (!ext_ret)
644 WARN("Function %s unknown\n", name);
645 return NULL;
648 func_ptr = (void **)&funcs->ext + (ext_ret - extension_registry);
649 if (!*func_ptr)
651 void *driver_func = funcs->wgl.p_wglGetProcAddress( name );
653 if (!is_extension_supported(ext_ret->extension))
655 unsigned int i;
656 static const struct { const char *name, *alt; } alternatives[] =
658 { "glCopyTexSubImage3DEXT", "glCopyTexSubImage3D" }, /* needed by RuneScape */
659 { "glVertexAttribDivisor", "glVertexAttribDivisorARB"}, /* needed by Caffeine */
662 for (i = 0; i < ARRAY_SIZE(alternatives); i++)
664 if (strcmp( name, alternatives[i].name )) continue;
665 WARN("Extension %s required for %s not supported, trying %s\n",
666 ext_ret->extension, name, alternatives[i].alt );
667 return wglGetProcAddress( alternatives[i].alt );
669 WARN("Extension %s required for %s not supported\n", ext_ret->extension, name);
670 return NULL;
673 if (driver_func == NULL)
675 WARN("Function %s not supported by driver\n", name);
676 return NULL;
678 *func_ptr = driver_func;
681 TRACE("returning %s -> %p\n", name, ext_ret->func);
682 return ext_ret->func;
685 /***********************************************************************
686 * wglRealizeLayerPalette (OPENGL32.@)
688 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
689 int iLayerPlane,
690 BOOL bRealize) {
691 FIXME("()\n");
693 return FALSE;
696 /***********************************************************************
697 * wglSetLayerPaletteEntries (OPENGL32.@)
699 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
700 int iLayerPlane,
701 int iStart,
702 int cEntries,
703 const COLORREF *pcr) {
704 FIXME("(): stub!\n");
706 return 0;
709 /***********************************************************************
710 * wglGetDefaultProcAddress (OPENGL32.@)
712 PROC WINAPI wglGetDefaultProcAddress( LPCSTR name )
714 FIXME( "%s: stub\n", debugstr_a(name));
715 return NULL;
718 /***********************************************************************
719 * wglSwapLayerBuffers (OPENGL32.@)
721 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
722 UINT fuPlanes) {
723 TRACE("(%p, %08x)\n", hdc, fuPlanes);
725 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
726 if (!wglSwapBuffers( hdc )) return FALSE;
727 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
730 if (fuPlanes) {
731 WARN("Following layers unhandled: %08x\n", fuPlanes);
734 return TRUE;
737 /***********************************************************************
738 * wglUseFontBitmaps_common
740 static BOOL wglUseFontBitmaps_common( HDC hdc, DWORD first, DWORD count, DWORD listBase, BOOL unicode )
742 GLYPHMETRICS gm;
743 unsigned int glyph, size = 0;
744 void *bitmap = NULL, *gl_bitmap = NULL;
745 int org_alignment;
746 BOOL ret = TRUE;
748 glGetIntegerv( GL_UNPACK_ALIGNMENT, &org_alignment );
749 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
751 for (glyph = first; glyph < first + count; glyph++) {
752 unsigned int needed_size, height, width, width_int;
754 if (unicode)
755 needed_size = GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
756 else
757 needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
759 TRACE("Glyph: %3d / List: %d size %d\n", glyph, listBase, needed_size);
760 if (needed_size == GDI_ERROR) {
761 ret = FALSE;
762 break;
765 if (needed_size > size) {
766 size = needed_size;
767 HeapFree(GetProcessHeap(), 0, bitmap);
768 HeapFree(GetProcessHeap(), 0, gl_bitmap);
769 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
770 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
772 if (needed_size != 0) {
773 if (unicode)
774 ret = (GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm,
775 size, bitmap, &identity) != GDI_ERROR);
776 else
777 ret = (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm,
778 size, bitmap, &identity) != GDI_ERROR);
779 if (!ret) break;
782 if (TRACE_ON(wgl)) {
783 unsigned int bitmask;
784 unsigned char *bitmap_ = bitmap;
786 TRACE(" - bbox: %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
787 TRACE(" - origin: (%d, %d)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
788 TRACE(" - increment: %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
789 if (needed_size != 0) {
790 TRACE(" - bitmap:\n");
791 for (height = 0; height < gm.gmBlackBoxY; height++) {
792 TRACE(" ");
793 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
794 if (bitmask == 0) {
795 bitmap_ += 1;
796 bitmask = 0x80;
798 if (*bitmap_ & bitmask)
799 TRACE("*");
800 else
801 TRACE(" ");
803 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
804 TRACE("\n");
809 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
810 * glyph for it to be drawn properly.
812 if (needed_size != 0) {
813 width_int = (gm.gmBlackBoxX + 31) / 32;
814 for (height = 0; height < gm.gmBlackBoxY; height++) {
815 for (width = 0; width < width_int; width++) {
816 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
817 ((int *) bitmap)[height * width_int + width];
822 glNewList( listBase++, GL_COMPILE );
823 if (needed_size != 0) {
824 glBitmap( gm.gmBlackBoxX, gm.gmBlackBoxY, 0 - gm.gmptGlyphOrigin.x,
825 (int)gm.gmBlackBoxY - gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY, gl_bitmap );
826 } else {
827 /* This is the case of 'empty' glyphs like the space character */
828 glBitmap( 0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL );
830 glEndList();
833 glPixelStorei( GL_UNPACK_ALIGNMENT, org_alignment );
834 HeapFree(GetProcessHeap(), 0, bitmap);
835 HeapFree(GetProcessHeap(), 0, gl_bitmap);
836 return ret;
839 /***********************************************************************
840 * wglUseFontBitmapsA (OPENGL32.@)
842 BOOL WINAPI wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase)
844 return wglUseFontBitmaps_common( hdc, first, count, listBase, FALSE );
847 /***********************************************************************
848 * wglUseFontBitmapsW (OPENGL32.@)
850 BOOL WINAPI wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase)
852 return wglUseFontBitmaps_common( hdc, first, count, listBase, TRUE );
855 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
857 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
858 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
859 vertex[2] = 0.0;
862 typedef struct _bezier_vector {
863 GLdouble x;
864 GLdouble y;
865 } bezier_vector;
867 static double bezier_deviation_squared(const bezier_vector *p)
869 bezier_vector deviation;
870 bezier_vector vertex;
871 bezier_vector base;
872 double base_length;
873 double dot;
875 vertex.x = (p[0].x + p[1].x*2 + p[2].x)/4 - p[0].x;
876 vertex.y = (p[0].y + p[1].y*2 + p[2].y)/4 - p[0].y;
878 base.x = p[2].x - p[0].x;
879 base.y = p[2].y - p[0].y;
881 base_length = sqrt(base.x*base.x + base.y*base.y);
882 base.x /= base_length;
883 base.y /= base_length;
885 dot = base.x*vertex.x + base.y*vertex.y;
886 dot = min(max(dot, 0.0), base_length);
887 base.x *= dot;
888 base.y *= dot;
890 deviation.x = vertex.x-base.x;
891 deviation.y = vertex.y-base.y;
893 return deviation.x*deviation.x + deviation.y*deviation.y;
896 static int bezier_approximate(const bezier_vector *p, bezier_vector *points, FLOAT deviation)
898 bezier_vector first_curve[3];
899 bezier_vector second_curve[3];
900 bezier_vector vertex;
901 int total_vertices;
903 if(bezier_deviation_squared(p) <= deviation*deviation)
905 if(points)
906 *points = p[2];
907 return 1;
910 vertex.x = (p[0].x + p[1].x*2 + p[2].x)/4;
911 vertex.y = (p[0].y + p[1].y*2 + p[2].y)/4;
913 first_curve[0] = p[0];
914 first_curve[1].x = (p[0].x + p[1].x)/2;
915 first_curve[1].y = (p[0].y + p[1].y)/2;
916 first_curve[2] = vertex;
918 second_curve[0] = vertex;
919 second_curve[1].x = (p[2].x + p[1].x)/2;
920 second_curve[1].y = (p[2].y + p[1].y)/2;
921 second_curve[2] = p[2];
923 total_vertices = bezier_approximate(first_curve, points, deviation);
924 if(points)
925 points += total_vertices;
926 total_vertices += bezier_approximate(second_curve, points, deviation);
927 return total_vertices;
930 /***********************************************************************
931 * wglUseFontOutlines_common
933 static BOOL wglUseFontOutlines_common(HDC hdc,
934 DWORD first,
935 DWORD count,
936 DWORD listBase,
937 FLOAT deviation,
938 FLOAT extrusion,
939 int format,
940 LPGLYPHMETRICSFLOAT lpgmf,
941 BOOL unicode)
943 UINT glyph;
944 GLUtesselator *tess = NULL;
945 LOGFONTW lf;
946 HFONT old_font, unscaled_font;
947 UINT em_size = 1024;
948 RECT rc;
950 TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
951 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
953 if(deviation <= 0.0)
954 deviation = 1.0/em_size;
956 if(format == WGL_FONT_POLYGONS)
958 tess = gluNewTess();
959 if(!tess)
961 ERR("glu32 is required for this function but isn't available\n");
962 return FALSE;
964 gluTessCallback( tess, GLU_TESS_VERTEX, (void *)glVertex3dv );
965 gluTessCallback( tess, GLU_TESS_BEGIN, (void *)glBegin );
966 gluTessCallback( tess, GLU_TESS_END, glEnd );
969 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
970 rc.left = rc.right = rc.bottom = 0;
971 rc.top = em_size;
972 DPtoLP(hdc, (POINT*)&rc, 2);
973 lf.lfHeight = -abs(rc.top - rc.bottom);
974 lf.lfOrientation = lf.lfEscapement = 0;
975 unscaled_font = CreateFontIndirectW(&lf);
976 old_font = SelectObject(hdc, unscaled_font);
978 for (glyph = first; glyph < first + count; glyph++)
980 DWORD needed;
981 GLYPHMETRICS gm;
982 BYTE *buf;
983 TTPOLYGONHEADER *pph;
984 TTPOLYCURVE *ppc;
985 GLdouble *vertices = NULL;
986 int vertex_total = -1;
988 if(unicode)
989 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
990 else
991 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
993 if(needed == GDI_ERROR)
994 goto error;
996 buf = HeapAlloc(GetProcessHeap(), 0, needed);
998 if(unicode)
999 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
1000 else
1001 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
1003 TRACE("glyph %d\n", glyph);
1005 if(lpgmf)
1007 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
1008 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
1009 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
1010 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
1011 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
1012 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
1014 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
1015 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
1016 lpgmf++;
1019 glNewList( listBase++, GL_COMPILE );
1020 glFrontFace( GL_CCW );
1021 if(format == WGL_FONT_POLYGONS)
1023 glNormal3d( 0.0, 0.0, 1.0 );
1024 gluTessNormal(tess, 0, 0, 1);
1025 gluTessBeginPolygon(tess, NULL);
1028 while(!vertices)
1030 if(vertex_total != -1)
1031 vertices = HeapAlloc(GetProcessHeap(), 0, vertex_total * 3 * sizeof(GLdouble));
1032 vertex_total = 0;
1034 pph = (TTPOLYGONHEADER*)buf;
1035 while((BYTE*)pph < buf + needed)
1037 GLdouble previous[3];
1038 fixed_to_double(pph->pfxStart, em_size, previous);
1040 if(vertices)
1041 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
1043 if (format == WGL_FONT_POLYGONS) gluTessBeginContour( tess );
1044 else glBegin( GL_LINE_LOOP );
1046 if(vertices)
1048 fixed_to_double(pph->pfxStart, em_size, vertices);
1049 if (format == WGL_FONT_POLYGONS) gluTessVertex( tess, vertices, vertices );
1050 else glVertex3d( vertices[0], vertices[1], vertices[2] );
1051 vertices += 3;
1053 vertex_total++;
1055 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1056 while((char*)ppc < (char*)pph + pph->cb)
1058 int i, j;
1059 int num;
1061 switch(ppc->wType) {
1062 case TT_PRIM_LINE:
1063 for(i = 0; i < ppc->cpfx; i++)
1065 if(vertices)
1067 TRACE("\t\tline to %d, %d\n",
1068 ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1069 fixed_to_double(ppc->apfx[i], em_size, vertices);
1070 if (format == WGL_FONT_POLYGONS) gluTessVertex( tess, vertices, vertices );
1071 else glVertex3d( vertices[0], vertices[1], vertices[2] );
1072 vertices += 3;
1074 fixed_to_double(ppc->apfx[i], em_size, previous);
1075 vertex_total++;
1077 break;
1079 case TT_PRIM_QSPLINE:
1080 for(i = 0; i < ppc->cpfx-1; i++)
1082 bezier_vector curve[3];
1083 bezier_vector *points;
1084 GLdouble curve_vertex[3];
1086 if(vertices)
1087 TRACE("\t\tcurve %d,%d %d,%d\n",
1088 ppc->apfx[i].x.value, ppc->apfx[i].y.value,
1089 ppc->apfx[i + 1].x.value, ppc->apfx[i + 1].y.value);
1091 curve[0].x = previous[0];
1092 curve[0].y = previous[1];
1093 fixed_to_double(ppc->apfx[i], em_size, curve_vertex);
1094 curve[1].x = curve_vertex[0];
1095 curve[1].y = curve_vertex[1];
1096 fixed_to_double(ppc->apfx[i + 1], em_size, curve_vertex);
1097 curve[2].x = curve_vertex[0];
1098 curve[2].y = curve_vertex[1];
1099 if(i < ppc->cpfx-2)
1101 curve[2].x = (curve[1].x + curve[2].x)/2;
1102 curve[2].y = (curve[1].y + curve[2].y)/2;
1104 num = bezier_approximate(curve, NULL, deviation);
1105 points = HeapAlloc(GetProcessHeap(), 0, num*sizeof(bezier_vector));
1106 num = bezier_approximate(curve, points, deviation);
1107 vertex_total += num;
1108 if(vertices)
1110 for(j=0; j<num; j++)
1112 TRACE("\t\t\tvertex at %f,%f\n", points[j].x, points[j].y);
1113 vertices[0] = points[j].x;
1114 vertices[1] = points[j].y;
1115 vertices[2] = 0.0;
1116 if (format == WGL_FONT_POLYGONS) gluTessVertex( tess, vertices, vertices );
1117 else glVertex3d( vertices[0], vertices[1], vertices[2] );
1118 vertices += 3;
1121 HeapFree(GetProcessHeap(), 0, points);
1122 previous[0] = curve[2].x;
1123 previous[1] = curve[2].y;
1125 break;
1126 default:
1127 ERR("\t\tcurve type = %d\n", ppc->wType);
1128 if (format == WGL_FONT_POLYGONS) gluTessEndContour( tess );
1129 else glEnd();
1130 goto error_in_list;
1133 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1134 (ppc->cpfx - 1) * sizeof(POINTFX));
1136 if (format == WGL_FONT_POLYGONS) gluTessEndContour( tess );
1137 else glEnd();
1138 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1142 error_in_list:
1143 if (format == WGL_FONT_POLYGONS) gluTessEndPolygon( tess );
1144 glTranslated( (GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0 );
1145 glEndList();
1146 HeapFree(GetProcessHeap(), 0, buf);
1147 HeapFree(GetProcessHeap(), 0, vertices);
1150 error:
1151 DeleteObject(SelectObject(hdc, old_font));
1152 if(format == WGL_FONT_POLYGONS)
1153 gluDeleteTess(tess);
1154 return TRUE;
1158 /***********************************************************************
1159 * wglUseFontOutlinesA (OPENGL32.@)
1161 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1162 DWORD first,
1163 DWORD count,
1164 DWORD listBase,
1165 FLOAT deviation,
1166 FLOAT extrusion,
1167 int format,
1168 LPGLYPHMETRICSFLOAT lpgmf)
1170 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1173 /***********************************************************************
1174 * wglUseFontOutlinesW (OPENGL32.@)
1176 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
1177 DWORD first,
1178 DWORD count,
1179 DWORD listBase,
1180 FLOAT deviation,
1181 FLOAT extrusion,
1182 int format,
1183 LPGLYPHMETRICSFLOAT lpgmf)
1185 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1188 /***********************************************************************
1189 * glDebugEntry (OPENGL32.@)
1191 GLint WINAPI glDebugEntry( GLint unknown1, GLint unknown2 )
1193 return 0;
1196 /***********************************************************************
1197 * glGetString (OPENGL32.@)
1199 const GLubyte * WINAPI glGetString( GLenum name )
1201 struct glGetString_params args = { .name = name, };
1202 NTSTATUS status;
1204 TRACE( "name %d\n", name );
1206 if ((status = UNIX_CALL( glGetString, &args ))) WARN( "glGetString returned %#x\n", status );
1208 if (name == GL_EXTENSIONS && args.ret)
1210 struct wgl_handle *ptr = get_current_context_ptr();
1211 GLubyte **extensions = &ptr->u.context->extensions;
1212 GLuint **disabled = &ptr->u.context->disabled_exts;
1213 if (*extensions || filter_extensions( (const char *)args.ret, extensions, disabled )) return *extensions;
1216 return args.ret;
1219 static BOOL WINAPI call_opengl_debug_message_callback( struct wine_gl_debug_message_params *params, ULONG size )
1221 params->user_callback( params->source, params->type, params->id, params->severity,
1222 params->length, params->message, params->user_data );
1223 return TRUE;
1226 /***********************************************************************
1227 * OpenGL initialisation routine
1229 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1231 void **kernel_callback_table;
1233 switch(reason)
1235 case DLL_PROCESS_ATTACH:
1236 NtCurrentTeb()->glTable = &null_opengl_funcs;
1238 kernel_callback_table = NtCurrentTeb()->Peb->KernelCallbackTable;
1239 kernel_callback_table[NtUserCallOpenGLDebugMessageCallback] = call_opengl_debug_message_callback;
1240 break;
1241 case DLL_THREAD_ATTACH:
1242 NtCurrentTeb()->glTable = &null_opengl_funcs;
1243 break;
1245 return TRUE;