server: Make timer id allocation algorithm conform to the Windows one.
[wine/wine-kai.git] / dlls / opengl32 / wgl.c
blobd1574885935adf1b5835b96e5bd0c61366a21e58
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 typedef struct wine_wgl_s {
49 PROC WINAPI (*p_wglGetProcAddress)(LPCSTR lpszProc);
51 void WINAPI (*p_wglGetIntegerv)(GLenum pname, GLint* params);
52 void WINAPI (*p_wglFinish)(void);
53 void WINAPI (*p_wglFlush)(void);
54 } wine_wgl_t;
56 /** global wgl object */
57 static wine_wgl_t wine_wgl;
59 /* x11drv GDI escapes */
60 #define X11DRV_ESCAPE 6789
61 enum x11drv_escape_codes
63 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
64 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
65 X11DRV_GET_FONT, /* get current X font for a DC */
66 X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
67 X11DRV_START_EXPOSURES, /* start graphics exposures */
68 X11DRV_END_EXPOSURES, /* end graphics exposures */
69 X11DRV_GET_DCE, /* get the DCE pointer */
70 X11DRV_SET_DCE, /* set the DCE pointer */
71 X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */
72 X11DRV_SYNC_PIXMAP /* sync the dibsection to its pixmap */
75 void (*wine_tsx11_lock_ptr)(void) = NULL;
76 void (*wine_tsx11_unlock_ptr)(void) = NULL;
78 static HMODULE opengl32_handle;
80 static char internal_gl_disabled_extensions[512];
81 static char* internal_gl_extensions = NULL;
83 typedef struct wine_glcontext {
84 HDC hdc;
85 XVisualInfo *vis;
86 GLXFBConfig fb_conf;
87 GLXContext ctx;
88 BOOL do_escape;
89 /* ... more stuff here */
90 } Wine_GLContext;
92 void enter_gl(void)
94 Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
96 if (curctx && curctx->do_escape)
98 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
99 ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
102 wine_tsx11_lock_ptr();
103 return;
106 const GLubyte * WINAPI wine_glGetString( GLenum name );
108 /***********************************************************************
109 * wglCreateLayerContext (OPENGL32.@)
111 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
112 int iLayerPlane) {
113 TRACE("(%p,%d)\n", hdc, iLayerPlane);
115 if (iLayerPlane == 0) {
116 return wglCreateContext(hdc);
118 FIXME(" no handler for layer %d\n", iLayerPlane);
120 return NULL;
123 /***********************************************************************
124 * wglDescribeLayerPlane (OPENGL32.@)
126 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
127 int iPixelFormat,
128 int iLayerPlane,
129 UINT nBytes,
130 LPLAYERPLANEDESCRIPTOR plpd) {
131 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
133 return FALSE;
136 /***********************************************************************
137 * wglGetLayerPaletteEntries (OPENGL32.@)
139 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
140 int iLayerPlane,
141 int iStart,
142 int cEntries,
143 const COLORREF *pcr) {
144 FIXME("(): stub !\n");
146 return 0;
149 static int compar(const void *elt_a, const void *elt_b) {
150 return strcmp(((const OpenGL_extension *) elt_a)->name,
151 ((const OpenGL_extension *) elt_b)->name);
154 /* Check if a GL extension is supported */
155 static BOOL is_extension_supported(const char* extension)
157 const char *gl_ext_string = (const char*)wine_glGetString(GL_EXTENSIONS);
159 TRACE("Checking for extension '%s'\n", extension);
161 if(!gl_ext_string) {
162 ERR("No OpenGL extensions found, check if your OpenGL setup is correct!\n");
163 return FALSE;
166 /* We use the GetProcAddress function from the display driver to retrieve function pointers
167 * for OpenGL and WGL extensions. In case of winex11.drv the OpenGL extension lookup is done
168 * using glXGetProcAddress. This function is quite unreliable in the sense that its specs don't
169 * require the function to return NULL when a extension isn't found. For this reason we check
170 * if the OpenGL extension required for the function we are looking up is supported. */
172 /* Check if the extension is part of the GL extension string to see if it is supported. */
173 if(strstr(gl_ext_string, extension) != NULL)
174 return TRUE;
176 /* In general an OpenGL function starts as an ARB/EXT extension and at some stage
177 * it becomes part of the core OpenGL library and can be reached without the ARB/EXT
178 * suffix as well. In the extension table, these functions contain GL_VERSION_major_minor.
179 * Check if we are searching for a core GL function */
180 if(strncmp(extension, "GL_VERSION_", 11) == 0)
182 const GLubyte *gl_version = glGetString(GL_VERSION);
183 const char *version = extension + 11; /* Move past 'GL_VERSION_' */
185 if(!gl_version) {
186 ERR("Error no OpenGL version found,\n");
187 return FALSE;
190 /* Compare the major/minor version numbers of the native OpenGL library and what is required by the function.
191 * The gl_version string is guaranteed to have at least a major/minor and sometimes it has a release number as well. */
192 if( (gl_version[0] >= version[0]) || ((gl_version[0] == version[0]) && (gl_version[2] >= version[2])) ) {
193 return TRUE;
195 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]);
198 return FALSE;
201 /***********************************************************************
202 * wglGetProcAddress (OPENGL32.@)
204 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
205 void *local_func;
206 OpenGL_extension ext;
207 const OpenGL_extension *ext_ret;
209 TRACE("(%s)\n", lpszProc);
211 if(lpszProc == NULL)
212 return NULL;
214 /* First, look if it's not already defined in the 'standard' OpenGL functions */
215 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
216 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
217 return local_func;
220 /* After that, search in the thunks to find the real name of the extension */
221 ext.name = lpszProc;
222 ext_ret = (const OpenGL_extension *) bsearch(&ext, extension_registry,
223 extension_registry_size, sizeof(OpenGL_extension), compar);
225 /* If nothing was found, we are looking for a WGL extension or an unknown GL extension. */
226 if (ext_ret == NULL) {
227 /* If the function name starts with a w it is a WGL extension */
228 if(lpszProc[0] == 'w')
229 return wine_wgl.p_wglGetProcAddress(lpszProc);
231 /* We are dealing with an unknown GL extension. */
232 WARN("Extension '%s' not defined in opengl32.dll's function table!\n", lpszProc);
233 return NULL;
234 } else { /* We are looking for an OpenGL extension */
236 /* Check if the GL extension required by the function is available */
237 if(!is_extension_supported(ext_ret->extension)) {
238 WARN("Extension '%s' required by function '%s' not supported!\n", ext_ret->extension, lpszProc);
241 local_func = wine_wgl.p_wglGetProcAddress(ext_ret->name);
243 /* After that, look at the extensions defined in the Linux OpenGL library */
244 if (local_func == NULL) {
245 char buf[256];
246 void *ret = NULL;
248 /* Remove the 3 last letters (EXT, ARB, ...).
250 I know that some extensions have more than 3 letters (MESA, NV,
251 INTEL, ...), but this is only a stop-gap measure to fix buggy
252 OpenGL drivers (moreover, it is only useful for old 1.0 apps
253 that query the glBindTextureEXT extension).
255 memcpy(buf, ext_ret->name, strlen(ext_ret->name) - 3);
256 buf[strlen(ext_ret->name) - 3] = '\0';
257 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
259 ret = GetProcAddress(opengl32_handle, buf);
260 if (ret != NULL) {
261 TRACE(" found function in main OpenGL library (%p) !\n", ret);
262 } else {
263 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->name);
266 return ret;
267 } else {
268 TRACE(" returning function (%p)\n", ext_ret->func);
269 extension_funcs[ext_ret - extension_registry] = local_func;
271 return ext_ret->func;
276 /***********************************************************************
277 * wglRealizeLayerPalette (OPENGL32.@)
279 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
280 int iLayerPlane,
281 BOOL bRealize) {
282 FIXME("()\n");
284 return FALSE;
287 /***********************************************************************
288 * wglSetLayerPaletteEntries (OPENGL32.@)
290 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
291 int iLayerPlane,
292 int iStart,
293 int cEntries,
294 const COLORREF *pcr) {
295 FIXME("(): stub !\n");
297 return 0;
300 /***********************************************************************
301 * wglSwapLayerBuffers (OPENGL32.@)
303 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
304 UINT fuPlanes) {
305 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
307 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
308 if (!SwapBuffers(hdc)) return FALSE;
309 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
312 if (fuPlanes) {
313 WARN("Following layers unhandled : %08x\n", fuPlanes);
316 return TRUE;
319 #ifdef HAVE_GL_GLU_H
321 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
323 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
324 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
325 vertex[2] = 0.0;
328 static void tess_callback_vertex(GLvoid *vertex)
330 GLdouble *dbl = vertex;
331 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
332 glVertex3dv(vertex);
335 static void tess_callback_begin(GLenum which)
337 TRACE("%d\n", which);
338 glBegin(which);
341 static void tess_callback_end(void)
343 TRACE("\n");
344 glEnd();
347 /***********************************************************************
348 * wglUseFontOutlines_common
350 static BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
351 DWORD first,
352 DWORD count,
353 DWORD listBase,
354 FLOAT deviation,
355 FLOAT extrusion,
356 int format,
357 LPGLYPHMETRICSFLOAT lpgmf,
358 BOOL unicode)
360 UINT glyph;
361 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
362 GLUtesselator *tess;
363 LOGFONTW lf;
364 HFONT old_font, unscaled_font;
365 UINT em_size = 1024;
366 RECT rc;
368 TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
369 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
372 ENTER_GL();
373 tess = gluNewTess();
374 if(tess)
376 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
377 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
378 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
380 LEAVE_GL();
382 if(!tess) return FALSE;
384 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
385 rc.left = rc.right = rc.bottom = 0;
386 rc.top = em_size;
387 DPtoLP(hdc, (POINT*)&rc, 2);
388 lf.lfHeight = -abs(rc.top - rc.bottom);
389 lf.lfOrientation = lf.lfEscapement = 0;
390 unscaled_font = CreateFontIndirectW(&lf);
391 old_font = SelectObject(hdc, unscaled_font);
393 for (glyph = first; glyph < first + count; glyph++)
395 DWORD needed;
396 GLYPHMETRICS gm;
397 BYTE *buf;
398 TTPOLYGONHEADER *pph;
399 TTPOLYCURVE *ppc;
400 GLdouble *vertices;
402 if(unicode)
403 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
404 else
405 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
407 if(needed == GDI_ERROR)
408 goto error;
410 buf = HeapAlloc(GetProcessHeap(), 0, needed);
411 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
413 if(unicode)
414 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
415 else
416 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
418 TRACE("glyph %d\n", glyph);
420 if(lpgmf)
422 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
423 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
424 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
425 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
426 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
427 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
429 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
430 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
431 lpgmf++;
434 ENTER_GL();
435 glNewList(listBase++, GL_COMPILE);
436 gluTessBeginPolygon(tess, NULL);
438 pph = (TTPOLYGONHEADER*)buf;
439 while((BYTE*)pph < buf + needed)
441 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
443 gluTessBeginContour(tess);
445 fixed_to_double(pph->pfxStart, em_size, vertices);
446 gluTessVertex(tess, vertices, vertices);
447 vertices += 3;
449 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
450 while((char*)ppc < (char*)pph + pph->cb)
452 int i;
454 switch(ppc->wType) {
455 case TT_PRIM_LINE:
456 for(i = 0; i < ppc->cpfx; i++)
458 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
459 fixed_to_double(ppc->apfx[i], em_size, vertices);
460 gluTessVertex(tess, vertices, vertices);
461 vertices += 3;
463 break;
465 case TT_PRIM_QSPLINE:
466 for(i = 0; i < ppc->cpfx/2; i++)
468 /* FIXME just connecting the control points for now */
469 TRACE("\t\tcurve %d,%d %d,%d\n",
470 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
471 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
472 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
473 gluTessVertex(tess, vertices, vertices);
474 vertices += 3;
475 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
476 gluTessVertex(tess, vertices, vertices);
477 vertices += 3;
479 break;
480 default:
481 ERR("\t\tcurve type = %d\n", ppc->wType);
482 gluTessEndContour(tess);
483 goto error_in_list;
486 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
487 (ppc->cpfx - 1) * sizeof(POINTFX));
489 gluTessEndContour(tess);
490 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
493 error_in_list:
494 gluTessEndPolygon(tess);
495 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
496 glEndList();
497 LEAVE_GL();
498 HeapFree(GetProcessHeap(), 0, buf);
499 HeapFree(GetProcessHeap(), 0, vertices);
502 error:
503 DeleteObject(SelectObject(hdc, old_font));
504 gluDeleteTess(tess);
505 return TRUE;
509 #else /* HAVE_GL_GLU_H */
511 static BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
512 DWORD first,
513 DWORD count,
514 DWORD listBase,
515 FLOAT deviation,
516 FLOAT extrusion,
517 int format,
518 LPGLYPHMETRICSFLOAT lpgmf,
519 BOOL unicode)
521 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
522 return FALSE;
525 #endif /* HAVE_GL_GLU_H */
527 /***********************************************************************
528 * wglUseFontOutlinesA (OPENGL32.@)
530 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
531 DWORD first,
532 DWORD count,
533 DWORD listBase,
534 FLOAT deviation,
535 FLOAT extrusion,
536 int format,
537 LPGLYPHMETRICSFLOAT lpgmf)
539 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
542 /***********************************************************************
543 * wglUseFontOutlinesW (OPENGL32.@)
545 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
546 DWORD first,
547 DWORD count,
548 DWORD listBase,
549 FLOAT deviation,
550 FLOAT extrusion,
551 int format,
552 LPGLYPHMETRICSFLOAT lpgmf)
554 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
557 /***********************************************************************
558 * glFinish (OPENGL32.@)
560 void WINAPI wine_glFinish( void )
562 TRACE("()\n");
563 wine_wgl.p_wglFinish();
566 /***********************************************************************
567 * glFlush (OPENGL32.@)
569 void WINAPI wine_glFlush( void )
571 TRACE("()\n");
572 wine_wgl.p_wglFlush();
575 /***********************************************************************
576 * glGetString (OPENGL32.@)
578 const GLubyte * WINAPI wine_glGetString( GLenum name )
580 const GLubyte *ret;
581 const char* GL_Extensions = NULL;
583 if (GL_EXTENSIONS != name) {
584 ENTER_GL();
585 ret = glGetString(name);
586 LEAVE_GL();
587 return ret;
590 if (NULL == internal_gl_extensions) {
591 ENTER_GL();
592 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
594 if (GL_Extensions)
596 size_t len = strlen(GL_Extensions);
597 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
599 TRACE("GL_EXTENSIONS reported:\n");
600 while (*GL_Extensions != 0x00) {
601 const char* Start = GL_Extensions;
602 char ThisExtn[256];
604 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
605 GL_Extensions++;
607 memcpy(ThisExtn, Start, (GL_Extensions - Start));
608 ThisExtn[GL_Extensions - Start] = 0;
609 TRACE("- %s:", ThisExtn);
611 /* test if supported API is disabled by config */
612 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
613 strcat(internal_gl_extensions, " ");
614 strcat(internal_gl_extensions, ThisExtn);
615 TRACE(" active\n");
616 } else {
617 TRACE(" deactived (by config)\n");
620 if (*GL_Extensions == ' ') GL_Extensions++;
623 LEAVE_GL();
625 return (const GLubyte *) internal_gl_extensions;
628 /***********************************************************************
629 * glGetIntegerv (OPENGL32.@)
631 void WINAPI wine_glGetIntegerv( GLenum pname, GLint* params )
633 wine_wgl.p_wglGetIntegerv(pname, params);
637 /* This is for brain-dead applications that use OpenGL functions before even
638 creating a rendering context.... */
639 static BOOL process_attach(void)
641 HMODULE mod_x11, mod_gdi32;
642 DWORD size = sizeof(internal_gl_disabled_extensions);
643 HKEY hkey = 0;
645 GetDesktopWindow(); /* make sure winex11 is loaded (FIXME) */
646 mod_x11 = GetModuleHandleA( "winex11.drv" );
647 mod_gdi32 = GetModuleHandleA( "gdi32.dll" );
649 if (!mod_x11 || !mod_gdi32)
651 ERR("X11DRV or GDI32 not loaded. Cannot create default context.\n");
652 return FALSE;
655 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod_x11, "wine_tsx11_lock" );
656 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod_x11, "wine_tsx11_unlock" );
658 wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod_gdi32, "wglGetProcAddress");
660 /* Interal WGL function */
661 wine_wgl.p_wglGetIntegerv = (void *)wine_wgl.p_wglGetProcAddress("wglGetIntegerv");
662 wine_wgl.p_wglFinish = (void *)wine_wgl.p_wglGetProcAddress("wglFinish");
663 wine_wgl.p_wglFlush = (void *)wine_wgl.p_wglGetProcAddress("wglFlush");
665 internal_gl_disabled_extensions[0] = 0;
666 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\OpenGL", &hkey)) {
667 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
668 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
670 RegCloseKey(hkey);
673 return TRUE;
677 /**********************************************************************/
679 static void process_detach(void)
681 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
684 /***********************************************************************
685 * OpenGL initialisation routine
687 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
689 switch(reason)
691 case DLL_PROCESS_ATTACH:
692 opengl32_handle = hinst;
693 DisableThreadLibraryCalls(hinst);
694 return process_attach();
695 case DLL_PROCESS_DETACH:
696 process_detach();
697 break;
699 return TRUE;