crypt32: Implement file stores.
[wine] / dlls / opengl32 / wgl.c
1 /* Window-specific OpenGL functions implementation.
2  *
3  * Copyright (c) 1999 Lionel Ulmer
4  * Copyright (c) 2005 Raphael Junqueira
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "wingdi.h"
34 #include "winternl.h"
35 #include "winnt.h"
36
37 #include "wgl_ext.h"
38 #include "opengl_ext.h"
39 #ifdef HAVE_GL_GLU_H
40 #undef far
41 #undef near
42 #include <GL/glu.h>
43 #endif
44 #include "wine/library.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
48 WINE_DECLARE_DEBUG_CHANNEL(opengl);
49
50 /** global glx object */
51 wine_glx_t wine_glx;
52
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
56 {
57     X11DRV_GET_DISPLAY,         /* get X11 display for a DC */
58     X11DRV_GET_DRAWABLE,        /* get current drawable for a DC */
59     X11DRV_GET_FONT,            /* get current X font for a DC */
60     X11DRV_SET_DRAWABLE,        /* set current drawable for a DC */
61     X11DRV_START_EXPOSURES,     /* start graphics exposures */
62     X11DRV_END_EXPOSURES,       /* end graphics exposures */
63     X11DRV_GET_DCE,             /* get the DCE pointer */
64     X11DRV_SET_DCE,             /* set the DCE pointer */
65     X11DRV_GET_GLX_DRAWABLE,    /* get current glx drawable for a DC */
66     X11DRV_SYNC_PIXMAP          /* sync the dibsection to its pixmap */
67 };
68
69 void (*wine_tsx11_lock_ptr)(void) = NULL;
70 void (*wine_tsx11_unlock_ptr)(void) = NULL;
71
72 static GLXContext default_cx = NULL;
73 static Display *default_display;  /* display to use for default context */
74
75 static HMODULE opengl32_handle;
76
77 static glXGetProcAddressARB_t p_glXGetProcAddressARB = NULL;
78
79 static char  internal_gl_disabled_extensions[512];
80 static char* internal_gl_extensions = NULL;
81
82 typedef struct wine_glcontext {
83   HDC hdc;
84   Display *display;
85   XVisualInfo *vis;
86   GLXFBConfig fb_conf;
87   GLXContext ctx;
88   BOOL do_escape;
89   struct wine_glcontext *next;
90   struct wine_glcontext *prev;
91 } Wine_GLContext;
92 static Wine_GLContext *context_list;
93
94 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
95 {
96     Wine_GLContext *ret;
97     if (!ctx) return NULL;
98     for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
99     return ret;
100 }
101
102 void enter_gl(void)
103 {
104     Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
105     
106     if (curctx && curctx->do_escape)
107     {
108         enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
109         ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
110     }
111
112     wine_tsx11_lock_ptr();
113     return;
114 }
115
116 static inline void free_context(Wine_GLContext *context)
117 {
118   if (context->next != NULL) context->next->prev = context->prev;
119   if (context->prev != NULL) context->prev->next = context->next;
120   else context_list = context->next;
121
122   HeapFree(GetProcessHeap(), 0, context);
123 }
124
125 static inline Wine_GLContext *alloc_context(void)
126 {
127   Wine_GLContext *ret;
128
129   if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
130   {
131       ret->next = context_list;
132       if (context_list) context_list->prev = ret;
133       context_list = ret;
134   }
135   return ret;
136 }
137
138 inline static BOOL is_valid_context( Wine_GLContext *ctx )
139 {
140     Wine_GLContext *ptr;
141     for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
142     return (ptr != NULL);
143 }
144
145 /* retrieve the X display to use on a given DC */
146 inline static Display *get_display( HDC hdc )
147 {
148     Display *display;
149     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
150
151     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
152                     sizeof(display), (LPSTR)&display )) display = NULL;
153     return display;
154 }
155
156
157 /* retrieve the GLX drawable to use on a given DC */
158 inline static Drawable get_drawable( HDC hdc )
159 {
160     GLXDrawable drawable;
161     enum x11drv_escape_codes escape = X11DRV_GET_GLX_DRAWABLE;
162
163     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
164                     sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
165     return drawable;
166 }
167
168 /** for use of wglGetCurrentReadDCARB */
169 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
170 {
171   Wine_GLContext *ret;
172   for (ret = context_list; ret; ret = ret->next) {  
173     if (d == get_drawable( ret->hdc )) {
174       return ret->hdc;
175     }
176   }
177   return NULL;
178 }
179
180 /* retrieve the X font to use on a given DC */
181 inline static Font get_font( HDC hdc )
182 {
183     Font font;
184     enum x11drv_escape_codes escape = X11DRV_GET_FONT;
185
186     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
187                     sizeof(font), (LPSTR)&font )) font = 0;
188     return font;
189 }
190
191
192 /***********************************************************************
193  *              wglCreateContext (OPENGL32.@)
194  */
195 HGLRC WINAPI wglCreateContext(HDC hdc)
196 {
197   Wine_GLContext *ret;
198   int num;
199   XVisualInfo template;
200   XVisualInfo *vis = NULL;
201   Display *display = get_display( hdc );
202   int hdcPF = GetPixelFormat(hdc);
203   GLXFBConfig cur_cfg;
204
205   TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
206
207   /* First, get the visual in use by the X11DRV */
208   if (!display) return 0;
209   template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
210   vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
211
212   if (vis == NULL) {
213     ERR("NULL visual !!!\n");
214     /* Need to set errors here */
215     return NULL;
216   }
217   if (0 >= hdcPF) {
218     SetLastError(ERROR_INVALID_PIXEL_FORMAT);
219     return NULL;
220   }
221
222   {
223     int nCfgs_fmt = 0;
224     GLXFBConfig* cfgs_fmt = NULL;
225     int value;
226     int gl_test = 0;
227     cfgs_fmt = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs_fmt);
228     if (NULL == cfgs_fmt || 0 == nCfgs_fmt) {
229       ERR("Cannot get FB Configs, expect problems.\n");
230       SetLastError(ERROR_INVALID_PIXEL_FORMAT);
231       return NULL;
232     }
233     if (nCfgs_fmt < hdcPF) {
234       ERR("(%p): unexpected pixelFormat(%d) > nFormats(%d), returns NULL\n", hdc, hdcPF, nCfgs_fmt);
235       SetLastError(ERROR_INVALID_PIXEL_FORMAT);
236       return NULL;
237     }
238     cur_cfg = cfgs_fmt[hdcPF - 1];
239     gl_test = wine_glx.p_glXGetFBConfigAttrib(display, cur_cfg, GLX_FBCONFIG_ID, &value);
240     if (gl_test) {
241       ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
242       SetLastError(ERROR_INVALID_PIXEL_FORMAT);
243       return NULL;
244     }
245     XFree(cfgs_fmt);
246   }
247
248   /* The context will be allocated in the wglMakeCurrent call */
249   ENTER_GL();
250   ret = alloc_context();
251   LEAVE_GL();
252   ret->hdc = hdc;
253   ret->display = display;
254   ret->fb_conf = cur_cfg;
255   /*ret->vis = vis;*/
256   ret->vis = wine_glx.p_glXGetVisualFromFBConfig(display, cur_cfg);
257
258   TRACE(" creating context %p (GL context creation delayed)\n", ret);
259   return (HGLRC) ret;
260 }
261
262 /***********************************************************************
263  *              wglCreateLayerContext (OPENGL32.@)
264  */
265 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
266                                    int iLayerPlane) {
267   TRACE("(%p,%d)\n", hdc, iLayerPlane);
268
269   if (iLayerPlane == 0) {
270       return wglCreateContext(hdc);
271   }
272   FIXME(" no handler for layer %d\n", iLayerPlane);
273
274   return NULL;
275 }
276
277 /***********************************************************************
278  *              wglCopyContext (OPENGL32.@)
279  */
280 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
281                            HGLRC hglrcDst,
282                            UINT mask) {
283   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
284
285   return FALSE;
286 }
287
288 /***********************************************************************
289  *              wglDeleteContext (OPENGL32.@)
290  */
291 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
292 {
293   Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
294   BOOL ret = TRUE;
295
296   TRACE("(%p)\n", hglrc);
297
298   ENTER_GL();
299   /* A game (Half Life not to name it) deletes twice the same context,
300    * so make sure it is valid first */
301   if (is_valid_context( ctx ))
302   {
303       if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
304       free_context(ctx);
305   }
306   else
307   {
308     WARN("Error deleting context !\n");
309     SetLastError(ERROR_INVALID_HANDLE);
310     ret = FALSE;
311   }
312   LEAVE_GL();
313
314   return ret;
315 }
316
317 /***********************************************************************
318  *              wglDescribeLayerPlane (OPENGL32.@)
319  */
320 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
321                                   int iPixelFormat,
322                                   int iLayerPlane,
323                                   UINT nBytes,
324                                   LPLAYERPLANEDESCRIPTOR plpd) {
325   FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
326
327   return FALSE;
328 }
329
330 /***********************************************************************
331  *              wglGetCurrentContext (OPENGL32.@)
332  */
333 HGLRC WINAPI wglGetCurrentContext(void) {
334   GLXContext gl_ctx;
335   Wine_GLContext *ret;
336
337   TRACE("()\n");
338
339   ENTER_GL();
340   gl_ctx = glXGetCurrentContext();
341   ret = get_context_from_GLXContext(gl_ctx);
342   LEAVE_GL();
343
344   TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
345
346   return (HGLRC)ret;
347 }
348
349 /***********************************************************************
350  *              wglGetCurrentDC (OPENGL32.@)
351  */
352 HDC WINAPI wglGetCurrentDC(void) {
353   GLXContext gl_ctx;
354   Wine_GLContext *ret;
355
356   TRACE("()\n");
357
358   ENTER_GL();
359   gl_ctx = glXGetCurrentContext();
360   ret = get_context_from_GLXContext(gl_ctx);
361   LEAVE_GL();
362
363   if (ret) {
364     TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
365     return ret->hdc;
366   } else {
367     TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
368     return 0;
369   }
370 }
371
372 /***********************************************************************
373  *              wglGetLayerPaletteEntries (OPENGL32.@)
374  */
375 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
376                                      int iLayerPlane,
377                                      int iStart,
378                                      int cEntries,
379                                      const COLORREF *pcr) {
380   FIXME("(): stub !\n");
381
382   return 0;
383 }
384
385 /***********************************************************************
386  *              wglGetProcAddress (OPENGL32.@)
387  */
388 static int compar(const void *elt_a, const void *elt_b) {
389   return strcmp(((const OpenGL_extension *) elt_a)->name,
390                 ((const OpenGL_extension *) elt_b)->name);
391 }
392
393 static int wgl_compar(const void *elt_a, const void *elt_b) {
394   return strcmp(((const WGL_extension *) elt_a)->func_name,
395                 ((const WGL_extension *) elt_b)->func_name);
396 }
397
398 PROC WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
399   void *local_func;
400   OpenGL_extension  ext;
401   const OpenGL_extension *ext_ret;
402
403   TRACE("(%s)\n", lpszProc);
404
405   /* First, look if it's not already defined in the 'standard' OpenGL functions */
406   if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
407     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
408     return local_func;
409   }
410
411   if (p_glXGetProcAddressARB == NULL) {
412     ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
413     return NULL;
414   }
415   
416   /* After that, search in the thunks to find the real name of the extension */
417   ext.name = lpszProc;
418   ext_ret = (const OpenGL_extension *) bsearch(&ext, extension_registry,
419                                          extension_registry_size, sizeof(OpenGL_extension), compar);
420
421   if (ext_ret == NULL) {
422     WGL_extension wgl_ext, *wgl_ext_ret;
423
424     /* Try to find the function in the WGL extensions ... */
425     wgl_ext.func_name = (char *) lpszProc;
426     wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
427                                             wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
428
429     if (wgl_ext_ret == NULL) {
430       /* Some sanity checks :-) */
431       ENTER_GL();
432       local_func = p_glXGetProcAddressARB( (const GLubyte *) lpszProc);
433       LEAVE_GL();
434       if (local_func != NULL) {
435         WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
436         return NULL;
437       }
438       
439       WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
440       return NULL;
441     } else {
442         void *ret = NULL;
443
444         if (wgl_ext_ret->func_init != NULL) {
445             const char *err_msg;
446             if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
447                                                   wgl_ext_ret->context)) == NULL) {
448                 ret = wgl_ext_ret->func_address;
449             } else {
450                 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
451                 return NULL;
452             }
453         } else {
454           ret = wgl_ext_ret->func_address;
455         }
456
457         if (ret)
458             TRACE(" returning WGL function  (%p)\n", ret);
459         return ret;
460     }
461   } else {
462     const char *glx_name = ext_ret->glx_name ? ext_ret->glx_name : ext_ret->name;
463     ENTER_GL();
464     local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
465     LEAVE_GL();
466     
467     /* After that, look at the extensions defined in the Linux OpenGL library */
468     if (local_func == NULL) {
469       char buf[256];
470       void *ret = NULL;
471
472       /* Remove the 3 last letters (EXT, ARB, ...).
473
474          I know that some extensions have more than 3 letters (MESA, NV,
475          INTEL, ...), but this is only a stop-gap measure to fix buggy
476          OpenGL drivers (moreover, it is only useful for old 1.0 apps
477          that query the glBindTextureEXT extension).
478       */
479       memcpy(buf, glx_name, strlen(glx_name) - 3);
480       buf[strlen(glx_name) - 3] = '\0';
481       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
482
483       ret = GetProcAddress(opengl32_handle, buf);
484       if (ret != NULL) {
485         TRACE(" found function in main OpenGL library (%p) !\n", ret);
486       } else {
487         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
488       }
489
490       return ret;
491     } else {
492       TRACE(" returning function  (%p)\n", ext_ret->func);
493       extension_funcs[ext_ret - extension_registry] = local_func;
494
495       return ext_ret->func;
496     }
497   }
498 }
499
500 static int describeContext(Wine_GLContext* ctx) {
501   int tmp;
502   int ctx_vis_id;
503   TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
504   wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
505   TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
506   wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
507   TRACE(" - VISUAL_ID 0x%x\n", tmp);
508   ctx_vis_id = tmp;
509   return ctx_vis_id;
510 }
511
512 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
513   int tmp;
514   int nElements;
515   int attribList[3] = { GLX_FBCONFIG_ID, 0, None };
516   GLXFBConfig *fbCfgs;
517
518   if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable)  {
519     /** glXQueryDrawable not available so returns not supported */
520     return -1;
521   }
522
523   TRACE(" Drawable %p have :\n", (void*) drawable);
524   wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
525   TRACE(" - WIDTH as %d\n", tmp);
526   wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
527   TRACE(" - HEIGHT as %d\n", tmp);
528   wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
529   TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
530
531   attribList[1] = tmp;
532   fbCfgs = wine_glx.p_glXChooseFBConfig(ctx->display, DefaultScreen(ctx->display), attribList, &nElements);
533   if (fbCfgs == NULL) {
534     return -1;
535   }
536  
537   wine_glx.p_glXGetFBConfigAttrib(ctx->display, fbCfgs[0], GLX_VISUAL_ID, &tmp);
538   TRACE(" - VISUAL_ID as 0x%x\n", tmp);
539
540   XFree(fbCfgs);
541  
542   return tmp;
543 }
544
545 /***********************************************************************
546  *              wglMakeCurrent (OPENGL32.@)
547  */
548 BOOL WINAPI wglMakeCurrent(HDC hdc,
549                            HGLRC hglrc) {
550   BOOL ret;
551   DWORD type = GetObjectType(hdc);
552
553   TRACE("(%p,%p)\n", hdc, hglrc);
554
555   ENTER_GL();
556   if (hglrc == NULL) {
557       ret = glXMakeCurrent(default_display, None, NULL);
558       NtCurrentTeb()->glContext = NULL;
559   } else {
560       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
561       Drawable drawable = get_drawable( hdc );
562       if (ctx->ctx == NULL) {
563         int draw_vis_id, ctx_vis_id;
564         VisualID visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
565         TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid);
566         draw_vis_id = describeDrawable(ctx, drawable);
567         ctx_vis_id = describeContext(ctx);
568
569         if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
570           /**
571            * Inherits from root window so reuse desktop visual
572            */
573           XVisualInfo template;
574           XVisualInfo *vis;
575           int num;
576           template.visualid = visualid;
577           vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
578
579           TRACE(" Creating GLX Context\n");
580           ctx->ctx = glXCreateContext(ctx->display, vis, NULL, type == OBJ_MEMDC ? False : True);
581         } else {
582           TRACE(" Creating GLX Context\n");
583           ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, type == OBJ_MEMDC ? False : True);
584         }
585         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
586       }
587       TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
588       ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
589       NtCurrentTeb()->glContext = ctx;
590       if(ret && type == OBJ_MEMDC)
591       {
592           ctx->do_escape = TRUE;
593           glDrawBuffer(GL_FRONT_LEFT);
594       }
595   }
596   LEAVE_GL();
597   TRACE(" returning %s\n", (ret ? "True" : "False"));
598   return ret;
599 }
600
601 /***********************************************************************
602  *              wglMakeContextCurrentARB (OPENGL32.@)
603  */
604 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc) 
605 {
606   BOOL ret;
607   TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
608
609   ENTER_GL();
610   if (hglrc == NULL) {
611     ret = glXMakeCurrent(default_display, None, NULL);
612   } else {
613     if (NULL == wine_glx.p_glXMakeContextCurrent) {
614       ret = FALSE;
615     } else {
616       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
617       Drawable d_draw = get_drawable( hDrawDC );
618       Drawable d_read = get_drawable( hReadDC );
619       
620       if (ctx->ctx == NULL) {
621         ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, GetObjectType(hDrawDC) == OBJ_MEMDC ? False : True);
622         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
623       }
624       ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
625     }
626   }
627   LEAVE_GL();
628   
629   TRACE(" returning %s\n", (ret ? "True" : "False"));
630   return ret;
631 }
632
633 /***********************************************************************
634  *              wglGetCurrentReadDCARB (OPENGL32.@)
635  */
636 HDC WINAPI wglGetCurrentReadDCARB(void) 
637 {
638   GLXDrawable gl_d;
639   HDC ret;
640
641   TRACE("()\n");
642
643   ENTER_GL();
644   gl_d = glXGetCurrentReadDrawable();
645   ret = get_hdc_from_Drawable(gl_d);
646   LEAVE_GL();
647
648   TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
649   return ret;
650 }
651
652
653
654 /***********************************************************************
655  *              wglRealizeLayerPalette (OPENGL32.@)
656  */
657 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
658                                    int iLayerPlane,
659                                    BOOL bRealize) {
660   FIXME("()\n");
661
662   return FALSE;
663 }
664
665 /***********************************************************************
666  *              wglSetLayerPaletteEntries (OPENGL32.@)
667  */
668 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
669                                      int iLayerPlane,
670                                      int iStart,
671                                      int cEntries,
672                                      const COLORREF *pcr) {
673   FIXME("(): stub !\n");
674
675   return 0;
676 }
677
678 /***********************************************************************
679  *              wglShareLists (OPENGL32.@)
680  */
681 BOOL WINAPI wglShareLists(HGLRC hglrc1,
682                           HGLRC hglrc2) {
683   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
684   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
685
686   TRACE("(%p, %p)\n", org, dest);
687
688   if (NULL != dest && dest->ctx != NULL) {
689     ERR("Could not share display lists, context already created !\n");
690     return FALSE;
691   } else {
692     if (org->ctx == NULL) {
693       ENTER_GL();
694       describeContext(org);
695       org->ctx = glXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
696       LEAVE_GL();
697       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
698     }
699     if (NULL != dest) {
700       ENTER_GL();
701       describeContext(dest);
702       /* Create the destination context with display lists shared */
703       dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
704       LEAVE_GL();
705       TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
706       return TRUE;
707     }
708   }
709   return FALSE;
710 }
711
712 /***********************************************************************
713  *              wglSwapLayerBuffers (OPENGL32.@)
714  */
715 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
716                                 UINT fuPlanes) {
717   TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
718
719   if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
720     if (!SwapBuffers(hdc)) return FALSE;
721     fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
722   }
723
724   if (fuPlanes) {
725     WARN("Following layers unhandled : %08x\n", fuPlanes);
726   }
727
728   return TRUE;
729 }
730
731 static BOOL internal_wglUseFontBitmaps(HDC hdc,
732                                        DWORD first,
733                                        DWORD count,
734                                        DWORD listBase,
735                                        DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
736 {
737     /* We are running using client-side rendering fonts... */
738     GLYPHMETRICS gm;
739     unsigned int glyph;
740     int size = 0;
741     void *bitmap = NULL, *gl_bitmap = NULL;
742     int org_alignment;
743
744     ENTER_GL();
745     glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
746     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
747     LEAVE_GL();
748
749     for (glyph = first; glyph < first + count; glyph++) {
750         unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
751         int height, width_int;
752
753         TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
754         if (needed_size == GDI_ERROR) {
755             TRACE("  - needed size : %d (GDI_ERROR)\n", needed_size);
756             goto error;
757         } else {
758             TRACE("  - needed size : %d\n", needed_size);
759         }
760
761         if (needed_size > size) {
762             size = needed_size;
763             HeapFree(GetProcessHeap(), 0, bitmap);
764             HeapFree(GetProcessHeap(), 0, gl_bitmap);
765             bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
766             gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
767         }
768         if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
769         if (TRACE_ON(opengl)) {
770             unsigned int height, width, bitmask;
771             unsigned char *bitmap_ = (unsigned char *) bitmap;
772             
773             TRACE("  - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
774             TRACE("  - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
775             TRACE("  - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
776             if (needed_size != 0) {
777                 TRACE("  - bitmap :\n");
778                 for (height = 0; height < gm.gmBlackBoxY; height++) {
779                     TRACE("      ");
780                     for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
781                         if (bitmask == 0) {
782                             bitmap_ += 1;
783                             bitmask = 0x80;
784                         }
785                         if (*bitmap_ & bitmask)
786                             TRACE("*");
787                         else
788                             TRACE(" ");
789                     }
790                     bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
791                     TRACE("\n");
792                 }
793             }
794         }
795         
796         /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
797          * glyph for it to be drawn properly.
798          */
799         if (needed_size != 0) {
800             width_int = (gm.gmBlackBoxX + 31) / 32;
801             for (height = 0; height < gm.gmBlackBoxY; height++) {
802                 int width;
803                 for (width = 0; width < width_int; width++) {
804                     ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
805                         ((int *) bitmap)[height * width_int + width];
806                 }
807             }
808         }
809         
810         ENTER_GL();
811         glNewList(listBase++, GL_COMPILE);
812         if (needed_size != 0) {
813             glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
814                      0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
815                      gm.gmCellIncX, gm.gmCellIncY,
816                      gl_bitmap);
817         } else {
818             /* This is the case of 'empty' glyphs like the space character */
819             glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
820         }
821         glEndList();
822         LEAVE_GL();
823     }
824     
825     ENTER_GL();
826     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
827     LEAVE_GL();
828     
829     HeapFree(GetProcessHeap(), 0, bitmap);
830     HeapFree(GetProcessHeap(), 0, gl_bitmap);
831     return TRUE;
832
833   error:
834     ENTER_GL();
835     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
836     LEAVE_GL();
837
838     HeapFree(GetProcessHeap(), 0, bitmap);
839     HeapFree(GetProcessHeap(), 0, gl_bitmap);
840     return FALSE;    
841 }
842
843 /***********************************************************************
844  *              wglUseFontBitmapsA (OPENGL32.@)
845  */
846 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
847                                DWORD first,
848                                DWORD count,
849                                DWORD listBase)
850 {
851   Font fid = get_font( hdc );
852
853   TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
854
855   if (fid == 0) {
856       return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
857   }
858
859   ENTER_GL();
860   /* I assume that the glyphs are at the same position for X and for Windows */
861   glXUseXFont(fid, first, count, listBase);
862   LEAVE_GL();
863   return TRUE;
864 }
865
866 /***********************************************************************
867  *              wglUseFontBitmapsW (OPENGL32.@)
868  */
869 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
870                                DWORD first,
871                                DWORD count,
872                                DWORD listBase)
873 {
874   Font fid = get_font( hdc );
875
876   TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
877
878   if (fid == 0) {
879       return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
880   }
881
882   WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
883   
884   ENTER_GL();
885   /* I assume that the glyphs are at the same position for X and for Windows */
886   glXUseXFont(fid, first, count, listBase);
887   LEAVE_GL();
888   return TRUE;
889 }
890
891 #ifdef HAVE_GL_GLU_H
892
893 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
894 {
895     vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;  
896     vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;  
897     vertex[2] = 0.0;
898 }
899
900 static void tess_callback_vertex(GLvoid *vertex)
901 {
902     GLdouble *dbl = vertex;
903     TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
904     glVertex3dv(vertex);
905 }
906
907 static void tess_callback_begin(GLenum which)
908 {
909     TRACE("%d\n", which);
910     glBegin(which);
911 }
912
913 static void tess_callback_end(void)
914 {
915     TRACE("\n");
916     glEnd();
917 }
918
919 /***********************************************************************
920  *              wglUseFontOutlines_common
921  */
922 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
923                                       DWORD first,
924                                       DWORD count,
925                                       DWORD listBase,
926                                       FLOAT deviation,
927                                       FLOAT extrusion,
928                                       int format,
929                                       LPGLYPHMETRICSFLOAT lpgmf,
930                                       BOOL unicode)
931 {
932     UINT glyph;
933     const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
934     GLUtesselator *tess;
935     LOGFONTW lf;
936     HFONT old_font, unscaled_font;
937     UINT em_size = 1024;
938     RECT rc;
939
940     TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
941           listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
942
943
944     ENTER_GL();
945     tess = gluNewTess();
946     if(tess)
947     {
948         gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
949         gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
950         gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
951     }
952     LEAVE_GL();
953
954     if(!tess) return FALSE;
955
956     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
957     rc.left = rc.right = rc.bottom = 0;
958     rc.top = em_size;
959     DPtoLP(hdc, (POINT*)&rc, 2);
960     lf.lfHeight = -abs(rc.top - rc.bottom);
961     lf.lfOrientation = lf.lfEscapement = 0;
962     unscaled_font = CreateFontIndirectW(&lf);
963     old_font = SelectObject(hdc, unscaled_font);
964
965     for (glyph = first; glyph < first + count; glyph++)
966     {
967         DWORD needed;
968         GLYPHMETRICS gm;
969         BYTE *buf;
970         TTPOLYGONHEADER *pph;
971         TTPOLYCURVE *ppc;
972         GLdouble *vertices;
973
974         if(unicode)
975             needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
976         else
977             needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
978
979         if(needed == GDI_ERROR)
980             goto error;
981
982         buf = HeapAlloc(GetProcessHeap(), 0, needed);
983         vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
984
985         if(unicode)
986             GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
987         else
988             GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
989
990         TRACE("glyph %d\n", glyph);
991
992         if(lpgmf)
993         {
994             lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
995             lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
996             lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
997             lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
998             lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
999             lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
1000
1001             TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
1002                   lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY); 
1003             lpgmf++;
1004         }
1005
1006         ENTER_GL();
1007         glNewList(listBase++, GL_COMPILE);
1008         gluTessBeginPolygon(tess, NULL);
1009
1010         pph = (TTPOLYGONHEADER*)buf;
1011         while((BYTE*)pph < buf + needed)
1012         {
1013             TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
1014
1015             gluTessBeginContour(tess);
1016
1017             fixed_to_double(pph->pfxStart, em_size, vertices);
1018             gluTessVertex(tess, vertices, vertices);
1019             vertices += 3;
1020
1021             ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1022             while((char*)ppc < (char*)pph + pph->cb)
1023             {
1024                 int i;
1025
1026                 switch(ppc->wType) {
1027                 case TT_PRIM_LINE:
1028                     for(i = 0; i < ppc->cpfx; i++)
1029                     {
1030                         TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1031                         fixed_to_double(ppc->apfx[i], em_size, vertices); 
1032                         gluTessVertex(tess, vertices, vertices);
1033                         vertices += 3;
1034                     }
1035                     break;
1036
1037                 case TT_PRIM_QSPLINE:
1038                     for(i = 0; i < ppc->cpfx/2; i++)
1039                     {
1040                         /* FIXME just connecting the control points for now */
1041                         TRACE("\t\tcurve  %d,%d %d,%d\n",
1042                               ppc->apfx[i * 2].x.value,     ppc->apfx[i * 3].y.value,
1043                               ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
1044                         fixed_to_double(ppc->apfx[i * 2], em_size, vertices); 
1045                         gluTessVertex(tess, vertices, vertices);
1046                         vertices += 3;
1047                         fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices); 
1048                         gluTessVertex(tess, vertices, vertices);
1049                         vertices += 3;
1050                     }
1051                     break;
1052                 default:
1053                     ERR("\t\tcurve type = %d\n", ppc->wType);
1054                     gluTessEndContour(tess);
1055                     goto error_in_list;
1056                 }
1057
1058                 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1059                                      (ppc->cpfx - 1) * sizeof(POINTFX));
1060             }
1061             gluTessEndContour(tess);
1062             pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1063         }
1064
1065 error_in_list:
1066         gluTessEndPolygon(tess);
1067         glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
1068         glEndList();
1069         LEAVE_GL();
1070         HeapFree(GetProcessHeap(), 0, buf);
1071         HeapFree(GetProcessHeap(), 0, vertices);
1072     }
1073
1074  error:
1075     DeleteObject(SelectObject(hdc, old_font));
1076     gluDeleteTess(tess);
1077     return TRUE;
1078
1079 }
1080
1081 #else /* HAVE_GL_GLU_H */
1082
1083 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
1084                                       DWORD first,
1085                                       DWORD count,
1086                                       DWORD listBase,
1087                                       FLOAT deviation,
1088                                       FLOAT extrusion,
1089                                       int format,
1090                                       LPGLYPHMETRICSFLOAT lpgmf,
1091                                       BOOL unicode)
1092 {
1093     FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1094     return FALSE;
1095 }
1096
1097 #endif /* HAVE_GL_GLU_H */
1098
1099 /***********************************************************************
1100  *              wglUseFontOutlinesA (OPENGL32.@)
1101  */
1102 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1103                                 DWORD first,
1104                                 DWORD count,
1105                                 DWORD listBase,
1106                                 FLOAT deviation,
1107                                 FLOAT extrusion,
1108                                 int format,
1109                                 LPGLYPHMETRICSFLOAT lpgmf)
1110 {
1111     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1112 }
1113
1114 /***********************************************************************
1115  *              wglUseFontOutlinesW (OPENGL32.@)
1116  */
1117 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
1118                                 DWORD first,
1119                                 DWORD count,
1120                                 DWORD listBase,
1121                                 FLOAT deviation,
1122                                 FLOAT extrusion,
1123                                 int format,
1124                                 LPGLYPHMETRICSFLOAT lpgmf)
1125 {
1126     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1127 }
1128
1129 const GLubyte * internal_glGetString(GLenum name) {
1130   const char* GL_Extensions = NULL;
1131   
1132   if (GL_EXTENSIONS != name) {
1133     return glGetString(name);
1134   }
1135
1136   if (NULL == internal_gl_extensions) {
1137     GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1138
1139     TRACE("GL_EXTENSIONS reported:\n");  
1140     if (NULL == GL_Extensions) {
1141       ERR("GL_EXTENSIONS returns NULL\n");      
1142       return NULL;
1143     } else {
1144       size_t len = strlen(GL_Extensions);
1145       internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1146
1147       while (*GL_Extensions != 0x00) {
1148         const char* Start = GL_Extensions;
1149         char        ThisExtn[256];
1150          
1151         memset(ThisExtn, 0x00, sizeof(ThisExtn));
1152         while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1153           GL_Extensions++;
1154         }
1155         memcpy(ThisExtn, Start, (GL_Extensions - Start));
1156         TRACE("- %s:", ThisExtn);
1157         
1158         /* test if supported API is disabled by config */
1159         if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
1160           strcat(internal_gl_extensions, " ");
1161           strcat(internal_gl_extensions, ThisExtn);
1162           TRACE(" active\n");
1163         } else {
1164           TRACE(" deactived (by config)\n");
1165         }
1166
1167         if (*GL_Extensions == ' ') GL_Extensions++;
1168       }
1169     }
1170   }
1171   return (const GLubyte *) internal_gl_extensions;
1172 }
1173
1174 void internal_glGetIntegerv(GLenum pname, GLint* params) {
1175   glGetIntegerv(pname, params);
1176   if (pname == GL_DEPTH_BITS) { 
1177     GLXContext gl_ctx = glXGetCurrentContext();
1178     Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1179     /*TRACE("returns Wine Ctx as %p\n", ret);*/
1180     /** 
1181      * if we cannot find a Wine Context
1182      * we only have the default wine desktop context, 
1183      * so if we have only a 24 depth say we have 32
1184      */
1185     if (NULL == ret && 24 == *params) { 
1186       *params = 32;
1187     }
1188     TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
1189   }
1190   if (pname == GL_ALPHA_BITS) {
1191     GLint tmp;
1192     GLXContext gl_ctx = glXGetCurrentContext();
1193     Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1194     glXGetFBConfigAttrib(ret->display, ret->fb_conf, GLX_ALPHA_SIZE, &tmp);
1195     TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp);
1196     *params = tmp;
1197   }
1198 }
1199
1200
1201 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1202    include all dependencies
1203 */
1204 #ifndef SONAME_LIBGL
1205 #define SONAME_LIBGL "libGL.so"
1206 #endif
1207
1208 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc) 
1209 {
1210   const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
1211   const char *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1212   /*
1213   const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1214   const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1215   const char *glx_extensions = glXQueryExtensionsString(display, screen);
1216   */
1217
1218   memset(&wine_glx, 0, sizeof(wine_glx));
1219
1220   if (!strcmp("1.2", server_glx_version)) {
1221     wine_glx.version = 2;
1222   } else {
1223     wine_glx.version = 3;
1224   }
1225
1226   if (2 < wine_glx.version) {
1227     wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
1228     wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
1229     wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
1230
1231     /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1232     wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
1233   } else {
1234     if (NULL != strstr(server_glx_extensions, "GLX_SGIX_fbconfig")) {
1235       wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
1236       wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
1237       wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
1238     } else {
1239       ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version);
1240     }
1241   }
1242   /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1243   wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
1244   wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
1245 }
1246
1247 /* This is for brain-dead applications that use OpenGL functions before even
1248    creating a rendering context.... */
1249 static BOOL process_attach(void)
1250 {
1251   XWindowAttributes win_attr;
1252   Visual *rootVisual;
1253   int num;
1254   XVisualInfo template;
1255   HDC hdc;
1256   XVisualInfo *vis = NULL;
1257   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1258   HMODULE mod = GetModuleHandleA( "winex11.drv" );
1259   void *opengl_handle;
1260   DWORD size = sizeof(internal_gl_disabled_extensions);
1261   HKEY hkey = 0;
1262
1263   if (!root || !mod)
1264   {
1265       ERR("X11DRV not loaded. Cannot create default context.\n");
1266       return FALSE;
1267   }
1268
1269   wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1270   wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1271
1272   hdc = GetDC(0);
1273   default_display = get_display( hdc );
1274   ReleaseDC( 0, hdc );
1275   if (!default_display)
1276   {
1277       ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1278       return FALSE;
1279   }
1280
1281   ENTER_GL();
1282
1283   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
1284      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1285      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1286      with mismatched visuals.  Note that the Root Window visual may not be double
1287      buffered, so apps actually attempting to render this way may flicker */
1288   if (XGetWindowAttributes( default_display, root, &win_attr ))
1289   {
1290     rootVisual = win_attr.visual;
1291   }
1292   else
1293   {
1294     /* Get the default visual, since we can't seem to get the attributes from the
1295        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
1296     rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1297   }
1298
1299   template.visualid = XVisualIDFromVisual(rootVisual);
1300   vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1301   if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1302   if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1303   XFree(vis);
1304   LEAVE_GL();
1305
1306   opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1307   if (opengl_handle != NULL) {
1308    p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1309    wine_dlclose(opengl_handle, NULL, 0);
1310    if (p_glXGetProcAddressARB == NULL)
1311            TRACE("could not find glXGetProcAddressARB in libGL.\n");
1312   }
1313
1314   internal_gl_disabled_extensions[0] = 0;
1315   if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1316     if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1317       TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1318     }
1319     RegCloseKey(hkey);
1320   }
1321
1322   if (default_cx == NULL) {
1323     ERR("Could not create default context.\n");
1324   }
1325   else
1326   {
1327     /* After context initialize also the list of supported WGL extensions. */
1328     wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1329     wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1330   }
1331   return TRUE;
1332 }
1333
1334
1335 /**********************************************************************/
1336
1337 static void process_detach(void)
1338 {
1339   glXDestroyContext(default_display, default_cx);
1340
1341   /* Do not leak memory... */
1342   wgl_ext_finalize_extensions();
1343   HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1344 }
1345
1346 /***********************************************************************
1347  *           OpenGL initialisation routine
1348  */
1349 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1350 {
1351     switch(reason)
1352     {
1353     case DLL_PROCESS_ATTACH:
1354         opengl32_handle = hinst;
1355         DisableThreadLibraryCalls(hinst);
1356         return process_attach();
1357     case DLL_PROCESS_DETACH:
1358         process_detach();
1359         break;
1360     }
1361     return TRUE;
1362 }