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