Fixed some issues found by winapi_check.
[wine/multimedia.git] / dlls / opengl32 / wgl.c
blob6a2f9c784f4239573472a614594dc94c5bb35aaf
1 /* Window-specific OpenGL functions implementation.
3 * Copyright (c) 1999 Lionel Ulmer
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "config.h"
22 #include <stdlib.h>
23 #include <string.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winerror.h"
30 #include "wgl.h"
31 #include "opengl_ext.h"
32 #include "wine/debug.h"
33 #include "wine/port.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
37 /* x11drv GDI escapes */
38 #define X11DRV_ESCAPE 6789
39 enum x11drv_escape_codes
41 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
42 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
43 X11DRV_GET_FONT, /* get current X font for a DC */
46 void (*wine_tsx11_lock_ptr)(void) = NULL;
47 void (*wine_tsx11_unlock_ptr)(void) = NULL;
49 static GLXContext default_cx = NULL;
50 static Display *default_display; /* display to use for default context */
52 static void *(*p_glXGetProcAddressARB)(const GLubyte *);
54 typedef struct wine_glcontext {
55 HDC hdc;
56 Display *display;
57 GLXContext ctx;
58 XVisualInfo *vis;
59 struct wine_glcontext *next;
60 struct wine_glcontext *prev;
61 } Wine_GLContext;
62 static Wine_GLContext *context_list;
64 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
66 Wine_GLContext *ret;
67 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
68 return ret;
71 static inline void free_context(Wine_GLContext *context)
73 if (context->next != NULL) context->next->prev = context->prev;
74 if (context->prev != NULL) context->prev->next = context->next;
75 else context_list = context->next;
77 HeapFree(GetProcessHeap(), 0, context);
80 static inline Wine_GLContext *alloc_context(void)
82 Wine_GLContext *ret;
84 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
86 ret->next = context_list;
87 if (context_list) context_list->prev = ret;
88 context_list = ret;
90 return ret;
93 inline static BOOL is_valid_context( Wine_GLContext *ctx )
95 Wine_GLContext *ptr;
96 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
97 return (ptr != NULL);
100 /* retrieve the X display to use on a given DC */
101 inline static Display *get_display( HDC hdc )
103 Display *display;
104 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
106 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
107 sizeof(display), (LPSTR)&display )) display = NULL;
108 return display;
112 /* retrieve the X drawable to use on a given DC */
113 inline static Drawable get_drawable( HDC hdc )
115 Drawable drawable;
116 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
118 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
119 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
120 return drawable;
124 /* retrieve the X drawable to use on a given DC */
125 inline static Font get_font( HDC hdc )
127 Font font;
128 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
130 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
131 sizeof(font), (LPSTR)&font )) font = 0;
132 return font;
136 /***********************************************************************
137 * wglCreateContext (OPENGL32.@)
139 HGLRC WINAPI wglCreateContext(HDC hdc)
141 XVisualInfo *vis;
142 Wine_GLContext *ret;
143 int num;
144 XVisualInfo template;
145 Display *display = get_display( hdc );
147 TRACE("(%p)\n", hdc);
149 /* First, get the visual in use by the X11DRV */
150 if (!display) return 0;
151 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
152 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
154 if (vis == NULL) {
155 ERR("NULL visual !!!\n");
156 /* Need to set errors here */
157 return NULL;
160 /* The context will be allocated in the wglMakeCurrent call */
161 ENTER_GL();
162 ret = alloc_context();
163 LEAVE_GL();
164 ret->hdc = hdc;
165 ret->display = display;
166 ret->vis = vis;
168 TRACE(" creating context %p (GL context creation delayed)\n", ret);
169 return (HGLRC) ret;
172 /***********************************************************************
173 * wglCreateLayerContext (OPENGL32.@)
175 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
176 int iLayerPlane) {
177 TRACE("(%p,%d)\n", hdc, iLayerPlane);
179 if (iLayerPlane == 0) {
180 return wglCreateContext(hdc);
182 FIXME(" no handler for layer %d\n", iLayerPlane);
184 return NULL;
187 /***********************************************************************
188 * wglCopyContext (OPENGL32.@)
190 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
191 HGLRC hglrcDst,
192 UINT mask) {
193 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
195 return FALSE;
198 /***********************************************************************
199 * wglDeleteContext (OPENGL32.@)
201 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
203 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
204 BOOL ret = TRUE;
206 TRACE("(%p)\n", hglrc);
208 ENTER_GL();
209 /* A game (Half Life not to name it) deletes twice the same context,
210 * so make sure it is valid first */
211 if (is_valid_context( ctx ))
213 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
214 free_context(ctx);
216 else
218 WARN("Error deleting context !\n");
219 SetLastError(ERROR_INVALID_HANDLE);
220 ret = FALSE;
222 LEAVE_GL();
224 return ret;
227 /***********************************************************************
228 * wglDescribeLayerPlane (OPENGL32.@)
230 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
231 int iPixelFormat,
232 int iLayerPlane,
233 UINT nBytes,
234 LPLAYERPLANEDESCRIPTOR plpd) {
235 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
237 return FALSE;
240 /***********************************************************************
241 * wglGetCurrentContext (OPENGL32.@)
243 HGLRC WINAPI wglGetCurrentContext(void) {
244 GLXContext gl_ctx;
245 Wine_GLContext *ret;
247 TRACE("()\n");
249 ENTER_GL();
250 gl_ctx = glXGetCurrentContext();
251 ret = get_context_from_GLXContext(gl_ctx);
252 LEAVE_GL();
254 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
256 return ret;
259 /***********************************************************************
260 * wglGetCurrentDC (OPENGL32.@)
262 HDC WINAPI wglGetCurrentDC(void) {
263 GLXContext gl_ctx;
264 Wine_GLContext *ret;
266 TRACE("()\n");
268 ENTER_GL();
269 gl_ctx = glXGetCurrentContext();
270 ret = get_context_from_GLXContext(gl_ctx);
271 LEAVE_GL();
273 if (ret) {
274 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
275 return ret->hdc;
276 } else {
277 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
278 return 0;
282 /***********************************************************************
283 * wglGetLayerPaletteEntries (OPENGL32.@)
285 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
286 int iLayerPlane,
287 int iStart,
288 int cEntries,
289 const COLORREF *pcr) {
290 FIXME("(): stub !\n");
292 return 0;
295 /***********************************************************************
296 * wglGetProcAddress (OPENGL32.@)
298 static int compar(const void *elt_a, const void *elt_b) {
299 return strcmp(((OpenGL_extension *) elt_a)->name,
300 ((OpenGL_extension *) elt_b)->name);
303 void* WINAPI wglGetProcAddress(LPCSTR lpszProc) {
304 void *local_func;
305 static HMODULE hm = 0;
306 OpenGL_extension ext;
307 OpenGL_extension *ext_ret;
310 TRACE("(%s)\n", lpszProc);
312 if (hm == 0)
313 hm = GetModuleHandleA("opengl32");
315 /* First, look if it's not already defined in the 'standard' OpenGL functions */
316 if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
317 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
318 return local_func;
321 if (p_glXGetProcAddressARB == NULL) {
322 ERR("Warning : dynamic GL extension loading not supported by native GL library.");
323 return NULL;
326 /* After that, search in the thunks to find the real name of the extension */
327 ext.name = (char *) lpszProc;
328 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
329 extension_registry_size, sizeof(OpenGL_extension), compar);
331 if (ext_ret == NULL) {
332 /* Some sanity checks :-) */
333 ENTER_GL();
334 local_func = p_glXGetProcAddressARB(lpszProc);
335 LEAVE_GL();
336 if (local_func != NULL) {
337 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
338 return NULL;
341 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
342 return NULL;
343 } else {
344 ENTER_GL();
345 local_func = p_glXGetProcAddressARB(ext_ret->glx_name);
346 LEAVE_GL();
348 /* After that, look at the extensions defined in the Linux OpenGL library */
349 if (local_func == NULL) {
350 char buf[256];
351 void *ret = NULL;
353 /* Remove the 3 last letters (EXT, ARB, ...).
355 I know that some extensions have more than 3 letters (MESA, NV,
356 INTEL, ...), but this is only a stop-gap measure to fix buggy
357 OpenGL drivers (moreover, it is only useful for old 1.0 apps
358 that query the glBindTextureEXT extension).
360 strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
361 buf[strlen(ext_ret->glx_name) - 3] = '\0';
362 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
364 ret = GetProcAddress(hm, buf);
365 if (ret != NULL) {
366 TRACE(" found function in main OpenGL library (%p) !\n", ret);
367 } else {
368 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
371 return ret;
372 } else {
373 TRACE(" returning function (%p)\n", ext_ret->func);
374 *(ext_ret->func_ptr) = local_func;
376 return ext_ret->func;
381 /***********************************************************************
382 * wglMakeCurrent (OPENGL32.@)
384 BOOL WINAPI wglMakeCurrent(HDC hdc,
385 HGLRC hglrc) {
386 BOOL ret;
388 TRACE("(%p,%p)\n", hdc, hglrc);
390 ENTER_GL();
391 if (hglrc == NULL) {
392 ret = glXMakeCurrent(default_display, None, NULL);
393 } else {
394 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
395 Drawable drawable = get_drawable( hdc );
397 if (ctx->ctx == NULL) {
398 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
399 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
401 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
403 LEAVE_GL();
404 TRACE(" returning %s\n", (ret ? "True" : "False"));
405 return ret;
408 /***********************************************************************
409 * wglRealizeLayerPalette (OPENGL32.@)
411 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
412 int iLayerPlane,
413 BOOL bRealize) {
414 FIXME("()\n");
416 return FALSE;
419 /***********************************************************************
420 * wglSetLayerPaletteEntries (OPENGL32.@)
422 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
423 int iLayerPlane,
424 int iStart,
425 int cEntries,
426 const COLORREF *pcr) {
427 FIXME("(): stub !\n");
429 return 0;
432 /***********************************************************************
433 * wglShareLists (OPENGL32.@)
435 BOOL WINAPI wglShareLists(HGLRC hglrc1,
436 HGLRC hglrc2) {
437 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
438 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
440 TRACE("(%p, %p)\n", org, dest);
442 if (dest->ctx != NULL) {
443 ERR("Could not share display lists, context already created !\n");
444 return FALSE;
445 } else {
446 if (org->ctx == NULL) {
447 ENTER_GL();
448 org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
449 LEAVE_GL();
450 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
453 ENTER_GL();
454 /* Create the destination context with display lists shared */
455 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
456 LEAVE_GL();
457 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
460 return TRUE;
463 /***********************************************************************
464 * wglSwapLayerBuffers (OPENGL32.@)
466 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
467 UINT fuPlanes) {
468 TRACE("(%p, %08x)\n", hdc, fuPlanes);
470 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
471 if (!SwapBuffers(hdc)) return FALSE;
472 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
475 if (fuPlanes) {
476 WARN("Following layers unhandled : %08x\n", fuPlanes);
479 return TRUE;
482 /***********************************************************************
483 * wglUseFontBitmapsA (OPENGL32.@)
485 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
486 DWORD first,
487 DWORD count,
488 DWORD listBase)
490 Font fid = get_font( hdc );
492 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
494 if (fid == 0) {
495 /* We are running using client-side rendering fonts... */
496 GLYPHMETRICS gm;
497 static const MAT2 id = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
498 int glyph;
499 int size = 0;
500 void *bitmap = NULL, *gl_bitmap = NULL;
501 int org_alignment;
503 ENTER_GL();
504 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
505 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
506 LEAVE_GL();
508 for (glyph = first; glyph < first + count; glyph++) {
509 int needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &id);
510 int height, width_int;
512 if (needed_size == GDI_ERROR) goto error;
513 if (needed_size > size) {
514 size = needed_size;
515 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
516 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
517 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
518 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
520 if (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &id) == GDI_ERROR) goto error;
521 if (TRACE_ON(opengl)) {
522 unsigned int height, width, bitmask;
523 unsigned char *bitmap_ = (unsigned char *) bitmap;
525 DPRINTF("Glyph : %d\n", glyph);
526 DPRINTF(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
527 DPRINTF(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
528 DPRINTF(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
529 DPRINTF(" - size : %d\n", needed_size);
530 DPRINTF(" - bitmap : \n");
531 for (height = 0; height < gm.gmBlackBoxY; height++) {
532 DPRINTF(" ");
533 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
534 if (bitmask == 0) {
535 bitmap_ += 1;
536 bitmask = 0x80;
538 if (*bitmap_ & bitmask)
539 DPRINTF("*");
540 else
541 DPRINTF(" ");
543 bitmap_ += (4 - (((unsigned int) bitmap_) & 0x03));
544 DPRINTF("\n");
548 /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
549 As Wine does not seem to support the MAT2 field, I need to do it myself.... */
550 width_int = (gm.gmBlackBoxX + 31) / 32;
551 for (height = 0; height < gm.gmBlackBoxY; height++) {
552 int width;
553 for (width = 0; width < width_int; width++) {
554 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
555 ((int *) bitmap)[height * width_int + width];
559 ENTER_GL();
560 glNewList(listBase++, GL_COMPILE);
561 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x, gm.gmBlackBoxY - gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY, gl_bitmap);
562 glEndList();
563 LEAVE_GL();
566 ENTER_GL();
567 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
568 LEAVE_GL();
570 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
571 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
572 return TRUE;
574 error:
575 ENTER_GL();
576 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
577 LEAVE_GL();
579 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
580 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
581 return FALSE;
584 ENTER_GL();
585 /* I assume that the glyphs are at the same position for X and for Windows */
586 glXUseXFont(fid, first, count, listBase);
587 LEAVE_GL();
588 return TRUE;
591 /***********************************************************************
592 * wglUseFontOutlinesA (OPENGL32.@)
594 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
595 DWORD first,
596 DWORD count,
597 DWORD listBase,
598 FLOAT deviation,
599 FLOAT extrusion,
600 int format,
601 LPGLYPHMETRICSFLOAT lpgmf) {
602 FIXME("(): stub !\n");
604 return FALSE;
607 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
608 include all dependencies
610 #ifndef SONAME_LIBGL
611 #define SONAME_LIBGL "libGL.so"
612 #endif
614 /* This is for brain-dead applications that use OpenGL functions before even
615 creating a rendering context.... */
616 static BOOL process_attach(void)
618 XWindowAttributes win_attr;
619 Visual *rootVisual;
620 int num;
621 XVisualInfo template;
622 HDC hdc;
623 XVisualInfo *vis = NULL;
624 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
625 HMODULE mod = GetModuleHandleA( "x11drv.dll" );
626 void *opengl_handle;
627 const char *extensions = NULL;
629 if (!root || !mod)
631 ERR("X11DRV not loaded. Cannot create default context.\n");
632 return FALSE;
635 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
636 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
638 hdc = GetDC(0);
639 default_display = get_display( hdc );
640 ReleaseDC( 0, hdc );
641 if (!default_display)
643 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
644 return FALSE;
647 ENTER_GL();
649 /* Try to get the visual from the Root Window. We can't use the standard (presumably
650 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
651 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
652 with mismatched visuals. Note that the Root Window visual may not be double
653 buffered, so apps actually attempting to render this way may flicker */
654 if (XGetWindowAttributes( default_display, root, &win_attr ))
656 rootVisual = win_attr.visual;
658 else
660 /* Get the default visual, since we can't seem to get the attributes from the
661 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
662 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
665 template.visualid = XVisualIDFromVisual(rootVisual);
666 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
667 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
668 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
669 extensions = glXQueryExtensionsString(default_display, DefaultScreen(default_display));
670 XFree(vis);
671 LEAVE_GL();
673 if ((extensions != NULL) && (strstr(extensions, "GLX_ARB_get_proc_address"))) {
674 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
675 if (opengl_handle != NULL) {
676 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
677 wine_dlclose(opengl_handle, NULL, 0);
681 if (default_cx == NULL) {
682 ERR("Could not create default context.\n");
684 return TRUE;
687 /**********************************************************************/
689 /* Some WGL extensions... */
690 static const char *WGL_extensions = "WGL_ARB_extensions_string WGL_EXT_extensions_string";
692 /**********************************************************************/
694 const char * WINAPI wglGetExtensionsStringEXT(void) {
695 TRACE("() returning \"%s\"\n", WGL_extensions);
697 return WGL_extensions;
700 /**********************************************************************/
702 static void process_detach(void)
704 glXDestroyContext(default_display, default_cx);
707 /***********************************************************************
708 * wglGetExtensionsStringARB(OPENGL32.@)
710 const char * WINAPI wglGetExtensionsStringARB(HDC hdc) {
712 return wglGetExtensionsStringEXT();
716 /***********************************************************************
717 * OpenGL initialisation routine
719 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
721 switch(reason)
723 case DLL_PROCESS_ATTACH:
724 DisableThreadLibraryCalls(hinst);
725 return process_attach();
726 case DLL_PROCESS_DETACH:
727 process_detach();
728 break;
730 return TRUE;