DirectSoundEnumerateA() now passes a GUID to the callback if the first
[wine] / dlls / opengl32 / wgl.c
1 /* Window-specific OpenGL functions implementation.
2  *
3  * Copyright (c) 1999 Lionel Ulmer
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "config.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winerror.h"
29 #include "wine_gl.h"
30 #include "x11drv.h"
31
32 #include "wgl.h"
33 #include "opengl_ext.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
37
38 static GLXContext default_cx = NULL;
39 static Display *default_display;  /* display to use for default context */
40
41 typedef struct wine_glcontext {
42   HDC hdc;
43   Display *display;
44   GLXContext ctx;
45   XVisualInfo *vis;
46   struct wine_glcontext *next;
47   struct wine_glcontext *prev;
48 } Wine_GLContext;
49 static Wine_GLContext *context_list;
50
51 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
52 {
53     Wine_GLContext *ret;
54     for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
55     return ret;
56 }
57
58 static inline void free_context(Wine_GLContext *context)
59 {
60   if (context->next != NULL) context->next->prev = context->prev;
61   if (context->prev != NULL) context->prev->next = context->next;
62   else context_list = context->next;
63
64   HeapFree(GetProcessHeap(), 0, context);
65 }
66
67 static inline Wine_GLContext *alloc_context(void)
68 {
69   Wine_GLContext *ret;
70
71   if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
72   {
73       ret->next = context_list;
74       if (context_list) context_list->prev = ret;
75       context_list = ret;
76   }
77   return ret;
78 }
79
80 inline static BOOL is_valid_context( Wine_GLContext *ctx )
81 {
82     Wine_GLContext *ptr;
83     for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
84     return (ptr != NULL);
85 }
86
87 /* retrieve the X display to use on a given DC */
88 inline static Display *get_display( HDC hdc )
89 {
90     Display *display;
91     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
92
93     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
94                     sizeof(display), (LPSTR)&display )) display = NULL;
95     return display;
96 }
97
98
99 /* retrieve the X drawable to use on a given DC */
100 inline static Drawable get_drawable( HDC hdc )
101 {
102     Drawable drawable;
103     enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
104
105     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
106                     sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
107     return drawable;
108 }
109
110
111 /* retrieve the X drawable to use on a given DC */
112 inline static Font get_font( HDC hdc )
113 {
114     Font font;
115     enum x11drv_escape_codes escape = X11DRV_GET_FONT;
116
117     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
118                     sizeof(font), (LPSTR)&font )) font = 0;
119     return font;
120 }
121
122
123 /***********************************************************************
124  *              wglCreateContext (OPENGL32.@)
125  */
126 HGLRC WINAPI wglCreateContext(HDC hdc)
127 {
128   XVisualInfo *vis;
129   Wine_GLContext *ret;
130   int num;
131   XVisualInfo template;
132   Display *display = get_display( hdc );
133
134   TRACE("(%08x)\n", hdc);
135
136   /* First, get the visual in use by the X11DRV */
137   if (!display) return 0;
138   template.visualid = GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
139   vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
140
141   if (vis == NULL) {
142     ERR("NULL visual !!!\n");
143     /* Need to set errors here */
144     return NULL;
145   }
146
147   /* The context will be allocated in the wglMakeCurrent call */
148   ENTER_GL();
149   ret = alloc_context();
150   LEAVE_GL();
151   ret->hdc = hdc;
152   ret->display = display;
153   ret->vis = vis;
154
155   TRACE(" creating context %p (GL context creation delayed)\n", ret);
156   return (HGLRC) ret;
157 }
158
159 /***********************************************************************
160  *              wglCreateLayerContext (OPENGL32.@)
161  */
162 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
163                                    int iLayerPlane) {
164   FIXME("(%08x,%d): stub !\n", hdc, iLayerPlane);
165
166   return NULL;
167 }
168
169 /***********************************************************************
170  *              wglCopyContext (OPENGL32.@)
171  */
172 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
173                            HGLRC hglrcDst,
174                            UINT mask) {
175   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
176
177   return FALSE;
178 }
179
180 /***********************************************************************
181  *              wglDeleteContext (OPENGL32.@)
182  */
183 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
184 {
185   Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
186   BOOL ret = TRUE;
187
188   TRACE("(%p)\n", hglrc);
189   
190   ENTER_GL();
191   /* A game (Half Life not to name it) deletes twice the same context,
192    * so make sure it is valid first */
193   if (is_valid_context( ctx ))
194   {
195       if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
196       free_context(ctx);
197   }
198   else
199   {
200     WARN("Error deleting context !\n");
201     SetLastError(ERROR_INVALID_HANDLE);
202     ret = FALSE;
203   }
204   LEAVE_GL();
205   
206   return ret;
207 }
208
209 /***********************************************************************
210  *              wglDescribeLayerPlane (OPENGL32.@)
211  */
212 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
213                                   int iPixelFormat,
214                                   int iLayerPlane,
215                                   UINT nBytes,
216                                   LPLAYERPLANEDESCRIPTOR plpd) {
217   FIXME("(%08x,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
218
219   return FALSE;
220 }
221
222 /***********************************************************************
223  *              wglGetCurrentContext (OPENGL32.@)
224  */
225 HGLRC WINAPI wglGetCurrentContext(void) {
226   GLXContext gl_ctx;
227   Wine_GLContext *ret;
228
229   TRACE("()\n");
230
231   ENTER_GL();
232   gl_ctx = glXGetCurrentContext();
233   ret = get_context_from_GLXContext(gl_ctx);
234   LEAVE_GL();
235
236   TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
237   
238   return ret;
239 }
240
241 /***********************************************************************
242  *              wglGetCurrentDC (OPENGL32.@)
243  */
244 HDC WINAPI wglGetCurrentDC(void) {
245   GLXContext gl_ctx;
246   Wine_GLContext *ret;
247
248   TRACE("()\n");
249   
250   ENTER_GL();
251   gl_ctx = glXGetCurrentContext();
252   ret = get_context_from_GLXContext(gl_ctx);
253   LEAVE_GL();
254
255   if (ret) {
256     TRACE(" returning %08x (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
257     return ret->hdc;
258   } else {
259     TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
260     return 0;
261   }
262 }
263
264 /***********************************************************************
265  *              wglGetLayerPaletteEntries (OPENGL32.@)
266  */
267 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
268                                      int iLayerPlane,
269                                      int iStart,
270                                      int cEntries,
271                                      const COLORREF *pcr) {
272   FIXME("(): stub !\n");
273
274   return 0;
275 }
276
277 /***********************************************************************
278  *              wglGetProcAddress (OPENGL32.@)
279  */
280 static int compar(const void *elt_a, const void *elt_b) {
281   return strcmp(((OpenGL_extension *) elt_a)->name,
282                 ((OpenGL_extension *) elt_b)->name);
283 }
284
285 void* WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
286   void *local_func;
287   static HMODULE hm = 0;
288   OpenGL_extension  ext;
289   OpenGL_extension *ext_ret;
290
291
292   TRACE("(%s)\n", lpszProc);
293
294   if (hm == 0)
295       hm = GetModuleHandleA("opengl32");
296
297   /* First, look if it's not already defined in the 'standard' OpenGL functions */
298   if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
299     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
300     return local_func;
301   }
302
303   /* After that, search in the thunks to find the real name of the extension */
304   ext.name = (char *) lpszProc;
305   ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
306                                          extension_registry_size, sizeof(OpenGL_extension), compar);
307
308   if (ext_ret == NULL) {
309     /* Some sanity checks :-) */
310     if (glXGetProcAddressARB(lpszProc) != NULL) {
311       ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
312       return NULL;
313     }
314
315     WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
316     return NULL;
317   } else {
318     /* After that, look at the extensions defined in the Linux OpenGL library */
319     if ((local_func = glXGetProcAddressARB(ext_ret->glx_name)) == NULL) {
320       char buf[256];
321       void *ret = NULL;
322       
323       /* Remove the 3 last letters (EXT, ARB, ...).
324          
325          I know that some extensions have more than 3 letters (MESA, NV,
326          INTEL, ...), but this is only a stop-gap measure to fix buggy
327          OpenGL drivers (moreover, it is only useful for old 1.0 apps
328          that query the glBindTextureEXT extension).
329       */
330       strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
331       buf[strlen(ext_ret->glx_name) - 3] = '\0';
332       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
333       
334       ret = GetProcAddress(hm, buf);
335       if (ret != NULL) {
336         TRACE(" found function in main OpenGL library (%p) !\n", ret);
337       } else {
338         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
339       } 
340       
341       return ret;
342     } else {
343       TRACE(" returning function  (%p)\n", ext_ret->func);
344       *(ext_ret->func_ptr) = local_func;
345       
346       return ext_ret->func;
347     }
348   }
349 }
350
351 /***********************************************************************
352  *              wglMakeCurrent (OPENGL32.@)
353  */
354 BOOL WINAPI wglMakeCurrent(HDC hdc,
355                            HGLRC hglrc) {
356   BOOL ret;
357
358   TRACE("(%08x,%p)\n", hdc, hglrc);
359   
360   ENTER_GL();
361   if (hglrc == NULL) {
362       ret = glXMakeCurrent(default_display, None, NULL);
363   } else {
364       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
365       Drawable drawable = get_drawable( hdc );
366
367       if (ctx->ctx == NULL) {
368         ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
369         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
370       }
371       ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
372   }
373   LEAVE_GL();
374   TRACE(" returning %s\n", (ret ? "True" : "False"));
375   return ret;
376 }
377
378 /***********************************************************************
379  *              wglRealizeLayerPalette (OPENGL32.@)
380  */
381 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
382                                    int iLayerPlane,
383                                    BOOL bRealize) {
384   FIXME("()\n");
385
386   return FALSE;
387 }
388
389 /***********************************************************************
390  *              wglSetLayerPaletteEntries (OPENGL32.@)
391  */
392 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
393                                      int iLayerPlane,
394                                      int iStart,
395                                      int cEntries,
396                                      const COLORREF *pcr) {
397   FIXME("(): stub !\n");
398
399   return 0;
400 }
401
402 /***********************************************************************
403  *              wglShareLists (OPENGL32.@)
404  */
405 BOOL WINAPI wglShareLists(HGLRC hglrc1,
406                           HGLRC hglrc2) {
407   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
408   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
409   
410   TRACE("(%p, %p)\n", org, dest);
411
412   if (dest->ctx != NULL) {
413     ERR("Could not share display lists, context already created !\n");
414     return FALSE;
415   } else {
416     if (org->ctx == NULL) {
417       ENTER_GL();
418       org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
419       LEAVE_GL();
420       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
421     }
422
423     ENTER_GL();
424     /* Create the destination context with display lists shared */
425     dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
426     LEAVE_GL();
427     TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
428   }
429   
430   return TRUE;
431 }
432
433 /***********************************************************************
434  *              wglSwapLayerBuffers (OPENGL32.@)
435  */
436 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
437                                 UINT fuPlanes) {
438   FIXME("(): stub !\n");
439
440   return FALSE;
441 }
442
443 /***********************************************************************
444  *              wglUseFontBitmapsA (OPENGL32.@)
445  */
446 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
447                                DWORD first,
448                                DWORD count,
449                                DWORD listBase)
450 {
451   Font fid = get_font( hdc );
452
453   TRACE("(%08x, %ld, %ld, %ld)\n", hdc, first, count, listBase);
454
455   ENTER_GL();
456   /* I assume that the glyphs are at the same position for X and for Windows */
457   glXUseXFont(fid, first, count, listBase);
458   LEAVE_GL();
459   return TRUE;
460 }
461  
462 /***********************************************************************
463  *              wglUseFontOutlinesA (OPENGL32.@)
464  */
465 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
466                                 DWORD first,
467                                 DWORD count,
468                                 DWORD listBase,
469                                 FLOAT deviation,
470                                 FLOAT extrusion,
471                                 int format,
472                                 LPGLYPHMETRICSFLOAT lpgmf) {
473   FIXME("(): stub !\n");
474
475   return FALSE;
476 }
477
478
479 /* This is for brain-dead applications that use OpenGL functions before even
480    creating a rendering context.... */
481 static BOOL process_attach(void)
482 {
483   XWindowAttributes win_attr;
484   Visual *rootVisual;
485   int num;
486   XVisualInfo template;
487   HDC hdc;
488   XVisualInfo *vis = NULL;
489   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
490
491   if (!root)
492   {
493       ERR("X11DRV not loaded. Cannot create default context.\n");
494       return FALSE;
495   }
496
497   hdc = GetDC(0);
498   default_display = get_display( hdc );
499   ReleaseDC( 0, hdc );
500   if (!default_display)
501   {
502       ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
503       return FALSE;
504   }
505
506   ENTER_GL();
507
508   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
509      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
510      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal 
511      with mismatched visuals.  Note that the Root Window visual may not be double 
512      buffered, so apps actually attempting to render this way may flicker */
513   if (XGetWindowAttributes( default_display, root, &win_attr ))
514   {
515     rootVisual = win_attr.visual; 
516   }
517   else
518   {
519     /* Get the default visual, since we can't seem to get the attributes from the 
520        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
521     rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
522   }
523
524   template.visualid = XVisualIDFromVisual(rootVisual);
525   vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
526   if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
527   if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
528   XFree(vis);
529   LEAVE_GL();
530
531   if (default_cx == NULL) {
532     ERR("Could not create default context.\n");
533   }
534   return TRUE;
535 }
536
537 static void process_detach(void)
538 {
539   glXDestroyContext(default_display, default_cx);
540 }
541
542 /***********************************************************************
543  *           OpenGL initialisation routine
544  */
545 BOOL WINAPI OpenGL32_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
546 {
547     switch(reason)
548     {
549     case DLL_PROCESS_ATTACH:
550         return process_attach();
551     case DLL_PROCESS_DETACH:
552         process_detach();
553         break;
554     }
555     return TRUE;
556 }