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