Make sure PostScript floats are printed with LC_NUMERIC="C".
[wine] / dlls / opengl32 / wgl.c
1 /* Window-specific OpenGL functions implementation.
2  *
3  * Copyright (c) 1999 Lionel Ulmer
4  *
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.
9  *
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.
14  *
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
18  */
19
20 #include "config.h"
21 #include "wine/port.h"
22
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winerror.h"
31
32 #include "wgl.h"
33 #include "wgl_ext.h"
34 #include "opengl_ext.h"
35 #include "wine/library.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
39
40 /* x11drv GDI escapes */
41 #define X11DRV_ESCAPE 6789
42 enum x11drv_escape_codes
43 {
44     X11DRV_GET_DISPLAY,   /* get X11 display for a DC */
45     X11DRV_GET_DRAWABLE,  /* get current drawable for a DC */
46     X11DRV_GET_FONT,      /* get current X font for a DC */
47 };
48
49 void (*wine_tsx11_lock_ptr)(void) = NULL;
50 void (*wine_tsx11_unlock_ptr)(void) = NULL;
51
52 static GLXContext default_cx = NULL;
53 static Display *default_display;  /* display to use for default context */
54
55 static HMODULE opengl32_handle;
56
57 static void *(*p_glXGetProcAddressARB)(const GLubyte *);
58
59 typedef struct wine_glcontext {
60   HDC hdc;
61   Display *display;
62   GLXContext ctx;
63   XVisualInfo *vis;
64   struct wine_glcontext *next;
65   struct wine_glcontext *prev;
66 } Wine_GLContext;
67 static Wine_GLContext *context_list;
68
69 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
70 {
71     Wine_GLContext *ret;
72     for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
73     return ret;
74 }
75
76 static inline void free_context(Wine_GLContext *context)
77 {
78   if (context->next != NULL) context->next->prev = context->prev;
79   if (context->prev != NULL) context->prev->next = context->next;
80   else context_list = context->next;
81
82   HeapFree(GetProcessHeap(), 0, context);
83 }
84
85 static inline Wine_GLContext *alloc_context(void)
86 {
87   Wine_GLContext *ret;
88
89   if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
90   {
91       ret->next = context_list;
92       if (context_list) context_list->prev = ret;
93       context_list = ret;
94   }
95   return ret;
96 }
97
98 inline static BOOL is_valid_context( Wine_GLContext *ctx )
99 {
100     Wine_GLContext *ptr;
101     for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
102     return (ptr != NULL);
103 }
104
105 /* retrieve the X display to use on a given DC */
106 inline static Display *get_display( HDC hdc )
107 {
108     Display *display;
109     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
110
111     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
112                     sizeof(display), (LPSTR)&display )) display = NULL;
113     return display;
114 }
115
116
117 /* retrieve the X drawable to use on a given DC */
118 inline static Drawable get_drawable( HDC hdc )
119 {
120     Drawable drawable;
121     enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
122
123     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
124                     sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
125     return drawable;
126 }
127
128
129 /* retrieve the X drawable to use on a given DC */
130 inline static Font get_font( HDC hdc )
131 {
132     Font font;
133     enum x11drv_escape_codes escape = X11DRV_GET_FONT;
134
135     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
136                     sizeof(font), (LPSTR)&font )) font = 0;
137     return font;
138 }
139
140
141 /***********************************************************************
142  *              wglCreateContext (OPENGL32.@)
143  */
144 HGLRC WINAPI wglCreateContext(HDC hdc)
145 {
146   XVisualInfo *vis;
147   Wine_GLContext *ret;
148   int num;
149   XVisualInfo template;
150   Display *display = get_display( hdc );
151
152   TRACE("(%p)\n", hdc);
153
154   /* First, get the visual in use by the X11DRV */
155   if (!display) return 0;
156   template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
157   vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
158
159   if (vis == NULL) {
160     ERR("NULL visual !!!\n");
161     /* Need to set errors here */
162     return NULL;
163   }
164
165   /* The context will be allocated in the wglMakeCurrent call */
166   ENTER_GL();
167   ret = alloc_context();
168   LEAVE_GL();
169   ret->hdc = hdc;
170   ret->display = display;
171   ret->vis = vis;
172
173   TRACE(" creating context %p (GL context creation delayed)\n", ret);
174   return (HGLRC) ret;
175 }
176
177 /***********************************************************************
178  *              wglCreateLayerContext (OPENGL32.@)
179  */
180 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
181                                    int iLayerPlane) {
182   TRACE("(%p,%d)\n", hdc, iLayerPlane);
183
184   if (iLayerPlane == 0) {
185       return wglCreateContext(hdc);
186   }
187   FIXME(" no handler for layer %d\n", iLayerPlane);
188
189   return NULL;
190 }
191
192 /***********************************************************************
193  *              wglCopyContext (OPENGL32.@)
194  */
195 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
196                            HGLRC hglrcDst,
197                            UINT mask) {
198   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
199
200   return FALSE;
201 }
202
203 /***********************************************************************
204  *              wglDeleteContext (OPENGL32.@)
205  */
206 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
207 {
208   Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
209   BOOL ret = TRUE;
210
211   TRACE("(%p)\n", hglrc);
212
213   ENTER_GL();
214   /* A game (Half Life not to name it) deletes twice the same context,
215    * so make sure it is valid first */
216   if (is_valid_context( ctx ))
217   {
218       if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
219       free_context(ctx);
220   }
221   else
222   {
223     WARN("Error deleting context !\n");
224     SetLastError(ERROR_INVALID_HANDLE);
225     ret = FALSE;
226   }
227   LEAVE_GL();
228
229   return ret;
230 }
231
232 /***********************************************************************
233  *              wglDescribeLayerPlane (OPENGL32.@)
234  */
235 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
236                                   int iPixelFormat,
237                                   int iLayerPlane,
238                                   UINT nBytes,
239                                   LPLAYERPLANEDESCRIPTOR plpd) {
240   FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
241
242   return FALSE;
243 }
244
245 /***********************************************************************
246  *              wglGetCurrentContext (OPENGL32.@)
247  */
248 HGLRC WINAPI wglGetCurrentContext(void) {
249   GLXContext gl_ctx;
250   Wine_GLContext *ret;
251
252   TRACE("()\n");
253
254   ENTER_GL();
255   gl_ctx = glXGetCurrentContext();
256   ret = get_context_from_GLXContext(gl_ctx);
257   LEAVE_GL();
258
259   TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
260
261   return (HGLRC)ret;
262 }
263
264 /***********************************************************************
265  *              wglGetCurrentDC (OPENGL32.@)
266  */
267 HDC WINAPI wglGetCurrentDC(void) {
268   GLXContext gl_ctx;
269   Wine_GLContext *ret;
270
271   TRACE("()\n");
272
273   ENTER_GL();
274   gl_ctx = glXGetCurrentContext();
275   ret = get_context_from_GLXContext(gl_ctx);
276   LEAVE_GL();
277
278   if (ret) {
279     TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
280     return ret->hdc;
281   } else {
282     TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
283     return 0;
284   }
285 }
286
287 /***********************************************************************
288  *              wglGetLayerPaletteEntries (OPENGL32.@)
289  */
290 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
291                                      int iLayerPlane,
292                                      int iStart,
293                                      int cEntries,
294                                      const COLORREF *pcr) {
295   FIXME("(): stub !\n");
296
297   return 0;
298 }
299
300 /***********************************************************************
301  *              wglGetProcAddress (OPENGL32.@)
302  */
303 static int compar(const void *elt_a, const void *elt_b) {
304   return strcmp(((OpenGL_extension *) elt_a)->name,
305                 ((OpenGL_extension *) elt_b)->name);
306 }
307
308 static int wgl_compar(const void *elt_a, const void *elt_b) {
309   return strcmp(((WGL_extension *) elt_a)->func_name,
310                 ((WGL_extension *) elt_b)->func_name);
311 }
312
313 void* WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
314   void *local_func;
315   OpenGL_extension  ext;
316   OpenGL_extension *ext_ret;
317
318   TRACE("(%s)\n", lpszProc);
319
320   /* First, look if it's not already defined in the 'standard' OpenGL functions */
321   if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
322     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
323     return local_func;
324   }
325
326   if (p_glXGetProcAddressARB == NULL) {
327     ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
328     return NULL;
329   }
330   
331   /* After that, search in the thunks to find the real name of the extension */
332   ext.name = (char *) lpszProc;
333   ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
334                                          extension_registry_size, sizeof(OpenGL_extension), compar);
335
336   if (ext_ret == NULL) {
337     WGL_extension wgl_ext, *wgl_ext_ret;
338
339     /* Try to find the function in the WGL extensions ... */
340     wgl_ext.func_name = (char *) lpszProc;
341     wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
342                                             wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
343
344     if (wgl_ext_ret == NULL) {
345       /* Some sanity checks :-) */
346       ENTER_GL();
347       local_func = p_glXGetProcAddressARB(lpszProc);
348       LEAVE_GL();
349       if (local_func != NULL) {
350         WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
351         return NULL;
352       }
353       
354       WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
355       return NULL;
356     } else {
357         void *ret = NULL;
358
359         if (wgl_ext_ret->func_init != NULL) {
360             const char *err_msg;
361             if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
362                                                   wgl_ext_ret->context)) == NULL) {
363                 ret = wgl_ext_ret->func_address;
364             } else {
365                 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
366                 return NULL;
367             }
368         } else {
369           ret = wgl_ext_ret->func_address;
370         }
371
372         if (ret)
373             TRACE(" returning WGL function  (%p)\n", ret);
374         return ret;
375     }
376   } else {
377     ENTER_GL();
378     local_func = p_glXGetProcAddressARB(ext_ret->glx_name);
379     LEAVE_GL();
380     
381     /* After that, look at the extensions defined in the Linux OpenGL library */
382     if (local_func == NULL) {
383       char buf[256];
384       void *ret = NULL;
385
386       /* Remove the 3 last letters (EXT, ARB, ...).
387
388          I know that some extensions have more than 3 letters (MESA, NV,
389          INTEL, ...), but this is only a stop-gap measure to fix buggy
390          OpenGL drivers (moreover, it is only useful for old 1.0 apps
391          that query the glBindTextureEXT extension).
392       */
393       strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
394       buf[strlen(ext_ret->glx_name) - 3] = '\0';
395       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
396
397       ret = GetProcAddress(opengl32_handle, buf);
398       if (ret != NULL) {
399         TRACE(" found function in main OpenGL library (%p) !\n", ret);
400       } else {
401         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
402       }
403
404       return ret;
405     } else {
406       TRACE(" returning function  (%p)\n", ext_ret->func);
407       *(ext_ret->func_ptr) = local_func;
408
409       return ext_ret->func;
410     }
411   }
412 }
413
414 /***********************************************************************
415  *              wglMakeCurrent (OPENGL32.@)
416  */
417 BOOL WINAPI wglMakeCurrent(HDC hdc,
418                            HGLRC hglrc) {
419   BOOL ret;
420
421   TRACE("(%p,%p)\n", hdc, hglrc);
422
423   ENTER_GL();
424   if (hglrc == NULL) {
425       ret = glXMakeCurrent(default_display, None, NULL);
426   } else {
427       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
428       Drawable drawable = get_drawable( hdc );
429
430       if (ctx->ctx == NULL) {
431         ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
432         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
433       }
434       ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
435   }
436   LEAVE_GL();
437   TRACE(" returning %s\n", (ret ? "True" : "False"));
438   return ret;
439 }
440
441 /***********************************************************************
442  *              wglRealizeLayerPalette (OPENGL32.@)
443  */
444 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
445                                    int iLayerPlane,
446                                    BOOL bRealize) {
447   FIXME("()\n");
448
449   return FALSE;
450 }
451
452 /***********************************************************************
453  *              wglSetLayerPaletteEntries (OPENGL32.@)
454  */
455 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
456                                      int iLayerPlane,
457                                      int iStart,
458                                      int cEntries,
459                                      const COLORREF *pcr) {
460   FIXME("(): stub !\n");
461
462   return 0;
463 }
464
465 /***********************************************************************
466  *              wglShareLists (OPENGL32.@)
467  */
468 BOOL WINAPI wglShareLists(HGLRC hglrc1,
469                           HGLRC hglrc2) {
470   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
471   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
472
473   TRACE("(%p, %p)\n", org, dest);
474
475   if (dest->ctx != NULL) {
476     ERR("Could not share display lists, context already created !\n");
477     return FALSE;
478   } else {
479     if (org->ctx == NULL) {
480       ENTER_GL();
481       org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
482       LEAVE_GL();
483       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
484     }
485
486     ENTER_GL();
487     /* Create the destination context with display lists shared */
488     dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
489     LEAVE_GL();
490     TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
491   }
492
493   return TRUE;
494 }
495
496 /***********************************************************************
497  *              wglSwapLayerBuffers (OPENGL32.@)
498  */
499 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
500                                 UINT fuPlanes) {
501   TRACE("(%p, %08x)\n", hdc, fuPlanes);
502
503   if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
504     if (!SwapBuffers(hdc)) return FALSE;
505     fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
506   }
507
508   if (fuPlanes) {
509     WARN("Following layers unhandled : %08x\n", fuPlanes);
510   }
511
512   return TRUE;
513 }
514
515 static BOOL internal_wglUseFontBitmaps(HDC hdc,
516                                        DWORD first,
517                                        DWORD count,
518                                        DWORD listBase,
519                                        DWORD WINAPI (*GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
520 {
521     /* We are running using client-side rendering fonts... */
522     GLYPHMETRICS gm;
523     unsigned int glyph;
524     int size = 0;
525     void *bitmap = NULL, *gl_bitmap = NULL;
526     int org_alignment;
527
528     ENTER_GL();
529     glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
530     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
531     LEAVE_GL();
532
533     for (glyph = first; glyph < first + count; glyph++) {
534         unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
535         int height, width_int;
536
537         TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
538         if (needed_size == GDI_ERROR) {
539             TRACE("  - needed size : %d (GDI_ERROR)\n", needed_size);
540             goto error;
541         } else {
542             TRACE("  - needed size : %d\n", needed_size);
543         }
544
545         if (needed_size > size) {
546             size = needed_size;
547             if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
548             if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
549             bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
550             gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
551         }
552         if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
553         if (TRACE_ON(opengl)) {
554             unsigned int height, width, bitmask;
555             unsigned char *bitmap_ = (unsigned char *) bitmap;
556             
557             TRACE("  - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
558             TRACE("  - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
559             TRACE("  - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
560             if (needed_size != 0) {
561                 TRACE("  - bitmap : \n");
562                 for (height = 0; height < gm.gmBlackBoxY; height++) {
563                     TRACE("      ");
564                     for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
565                         if (bitmask == 0) {
566                             bitmap_ += 1;
567                             bitmask = 0x80;
568                         }
569                         if (*bitmap_ & bitmask)
570                             DPRINTF("*");
571                         else
572                             DPRINTF(" ");
573                     }
574                     bitmap_ += (4 - (((unsigned int) bitmap_) & 0x03));
575                     DPRINTF("\n");
576                 }
577             }
578         }
579         
580         /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
581          * glyph for it to be drawn properly.
582          */
583         if (needed_size != 0) {
584             width_int = (gm.gmBlackBoxX + 31) / 32;
585             for (height = 0; height < gm.gmBlackBoxY; height++) {
586                 int width;
587                 for (width = 0; width < width_int; width++) {
588                     ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
589                         ((int *) bitmap)[height * width_int + width];
590                 }
591             }
592         }
593         
594         ENTER_GL();
595         glNewList(listBase++, GL_COMPILE);
596         if (needed_size != 0) {
597             glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
598                      0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
599                      gm.gmCellIncX, gm.gmCellIncY,
600                      gl_bitmap);
601         } else {
602             /* This is the case of 'empty' glyphs like the space character */
603             glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
604         }
605         glEndList();
606         LEAVE_GL();
607     }
608     
609     ENTER_GL();
610     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
611     LEAVE_GL();
612     
613     if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
614     if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
615     return TRUE;
616
617   error:
618     ENTER_GL();
619     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
620     LEAVE_GL();
621
622     if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
623     if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
624     return FALSE;    
625 }
626
627 /***********************************************************************
628  *              wglUseFontBitmapsA (OPENGL32.@)
629  */
630 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
631                                DWORD first,
632                                DWORD count,
633                                DWORD listBase)
634 {
635   Font fid = get_font( hdc );
636
637   TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
638
639   if (fid == 0) {
640       return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
641   }
642
643   ENTER_GL();
644   /* I assume that the glyphs are at the same position for X and for Windows */
645   glXUseXFont(fid, first, count, listBase);
646   LEAVE_GL();
647   return TRUE;
648 }
649
650 /***********************************************************************
651  *              wglUseFontBitmapsW (OPENGL32.@)
652  */
653 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
654                                DWORD first,
655                                DWORD count,
656                                DWORD listBase)
657 {
658   Font fid = get_font( hdc );
659
660   TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
661
662   if (fid == 0) {
663       return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
664   }
665
666   WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
667   
668   ENTER_GL();
669   /* I assume that the glyphs are at the same position for X and for Windows */
670   glXUseXFont(fid, first, count, listBase);
671   LEAVE_GL();
672   return TRUE;
673 }
674
675 /***********************************************************************
676  *              wglUseFontOutlinesA (OPENGL32.@)
677  */
678 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
679                                 DWORD first,
680                                 DWORD count,
681                                 DWORD listBase,
682                                 FLOAT deviation,
683                                 FLOAT extrusion,
684                                 int format,
685                                 LPGLYPHMETRICSFLOAT lpgmf) {
686   FIXME("(): stub !\n");
687
688   return FALSE;
689 }
690
691 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
692    include all dependencies
693 */
694 #ifndef SONAME_LIBGL
695 #define SONAME_LIBGL "libGL.so"
696 #endif
697
698 /* This is for brain-dead applications that use OpenGL functions before even
699    creating a rendering context.... */
700 static BOOL process_attach(void)
701 {
702   XWindowAttributes win_attr;
703   Visual *rootVisual;
704   int num;
705   XVisualInfo template;
706   HDC hdc;
707   XVisualInfo *vis = NULL;
708   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
709   HMODULE mod = GetModuleHandleA( "x11drv.dll" );
710   void *opengl_handle;
711
712   if (!root || !mod)
713   {
714       ERR("X11DRV not loaded. Cannot create default context.\n");
715       return FALSE;
716   }
717
718   wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
719   wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
720
721   hdc = GetDC(0);
722   default_display = get_display( hdc );
723   ReleaseDC( 0, hdc );
724   if (!default_display)
725   {
726       ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
727       return FALSE;
728   }
729
730   ENTER_GL();
731
732   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
733      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
734      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
735      with mismatched visuals.  Note that the Root Window visual may not be double
736      buffered, so apps actually attempting to render this way may flicker */
737   if (XGetWindowAttributes( default_display, root, &win_attr ))
738   {
739     rootVisual = win_attr.visual;
740   }
741   else
742   {
743     /* Get the default visual, since we can't seem to get the attributes from the
744        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
745     rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
746   }
747
748   template.visualid = XVisualIDFromVisual(rootVisual);
749   vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
750   if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
751   if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
752   XFree(vis);
753   LEAVE_GL();
754
755   opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
756   if (opengl_handle != NULL) {
757    p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
758    wine_dlclose(opengl_handle, NULL, 0);
759    if (p_glXGetProcAddressARB == NULL)
760            TRACE("could not find glXGetProcAddressARB in libGL.\n");
761   }
762
763   /* Initialize also the list of supported WGL extensions. */
764   wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display));
765   
766   if (default_cx == NULL) {
767     ERR("Could not create default context.\n");
768   }
769   return TRUE;
770 }
771
772
773 /**********************************************************************/
774
775 static void process_detach(void)
776 {
777   glXDestroyContext(default_display, default_cx);
778
779   /* Do not leak memory... */
780   wgl_ext_finalize_extensions();
781 }
782
783 /***********************************************************************
784  *           OpenGL initialisation routine
785  */
786 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
787 {
788     switch(reason)
789     {
790     case DLL_PROCESS_ATTACH:
791         opengl32_handle = hinst;
792         DisableThreadLibraryCalls(hinst);
793         return process_attach();
794     case DLL_PROCESS_DETACH:
795         process_detach();
796         break;
797     }
798     return TRUE;
799 }