Implemented wglShareLists and wglGetCurrentDC.
[wine] / dlls / opengl32 / wgl.c
1 /* Window-specific OpenGL functions implementation.
2
3      Copyright (c) 1999 Lionel Ulmer
4 */
5
6 #include <stdlib.h>
7
8 #include "wine/exception.h"
9
10 #include "config.h"
11 #include "debugtools.h"
12 #include "gdi.h"
13 #include "dc.h"
14 #include "windef.h"
15 #include "winerror.h"
16 #include "wine_gl.h"
17 #include "x11drv.h"
18 #include "x11font.h"
19
20 #include "wgl.h"
21 #include "opengl_ext.h"
22
23 DEFAULT_DEBUG_CHANNEL(opengl);
24
25 typedef struct wine_glcontext {
26   HDC hdc;
27   GLXContext ctx;
28   XVisualInfo *vis;
29   struct wine_glcontext *next;
30   struct wine_glcontext *prev;
31 } Wine_GLContext;
32 static Wine_GLContext *context_array;
33
34 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx) {
35   Wine_GLContext *ret = context_array;
36   while (ret != NULL) if (ctx == ret->ctx) break; else ret = ret->next;
37   return ret;
38 }
39   
40 static inline void free_context(Wine_GLContext *context) {
41   if (context->next != NULL) context->next->prev = context->prev;
42   if (context->prev != NULL) context->prev->next = context->next;
43   else                       context_array = context->next;
44
45   HeapFree(GetProcessHeap(), 0, context);
46 }
47
48 static inline Wine_GLContext *alloc_context(void) {
49   Wine_GLContext *ret;
50
51   ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext));
52   ret->next = context_array;
53   if (context_array != NULL) context_array->prev = ret;
54   else                       context_array = ret;
55   
56   return ret;
57 }
58
59
60 static int XGLErrorFlag = 0;
61 static int XGLErrorHandler(Display *dpy, XErrorEvent *event) {
62     XGLErrorFlag = 1;
63     return 0;
64 }
65 /* filter for page-fault exceptions */
66 static WINE_EXCEPTION_FILTER(page_fault)
67 {
68   return EXCEPTION_EXECUTE_HANDLER;
69 }
70
71 /***********************************************************************
72  *              wglCreateContext
73  */
74 HGLRC WINAPI wglCreateContext(HDC hdc) {
75   DC * dc = DC_GetDCPtr( hdc );
76   X11DRV_PDEVICE *physDev;
77   XVisualInfo *vis;
78   Wine_GLContext *ret;
79
80   TRACE("(%08x)\n", hdc);
81
82   if (dc == NULL) {
83     ERR("Null DC !!!\n");
84     return NULL;
85   }
86   
87   physDev = (X11DRV_PDEVICE *)dc->physDev;
88
89   /* First, get the visual for the choosen pixel format */
90   vis = physDev->visuals[physDev->current_pf - 1];
91
92   if (vis == NULL) {
93     ERR("NULL visual !!!\n");
94     /* Need to set errors here */
95     return NULL;
96   }
97
98   /* The context will be allocated in the wglMakeCurrent call */
99   ENTER_GL();
100   ret = alloc_context();
101   LEAVE_GL();
102   ret->hdc = hdc;
103   ret->vis = vis;
104
105   TRACE(" creating context %p (GL context creation delayed)\n", ret);
106   
107   return (HGLRC) ret;
108 }
109
110 /***********************************************************************
111  *              wglCreateLayerContext
112  */
113 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
114                                    int iLayerPlane) {
115   FIXME("(%08x,%d): stub !\n", hdc, iLayerPlane);
116
117   return NULL;
118 }
119
120 /***********************************************************************
121  *              wglCopyContext
122  */
123 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
124                            HGLRC hglrcDst,
125                            UINT mask) {
126   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
127
128   return FALSE;
129 }
130
131 /***********************************************************************
132  *              wglDeleteContext
133  */
134 BOOL WINAPI wglDeleteContext(HGLRC hglrc) {
135   int (*WineXHandler)(Display *, XErrorEvent *);
136   Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
137   BOOL ret;
138   
139   TRACE("(%p)\n", hglrc);
140   
141   ENTER_GL();
142   /* A game (Half Life not to name it) deletes twice the same context. To prevent
143      crashes, run with our own error function enabled */
144   XSync(display, False);
145   XGLErrorFlag = 0;
146   WineXHandler = XSetErrorHandler(XGLErrorHandler);
147   __TRY {
148     glXDestroyContext(display, ctx->ctx);
149     XSync(display, False);
150     XFlush(display);
151
152     if (XGLErrorHandler == 0) free_context(ctx);
153   }
154   __EXCEPT(page_fault) {
155     XGLErrorFlag = 1;
156   }
157   __ENDTRY
158
159   ret = TRUE;
160   XSetErrorHandler(WineXHandler);
161   if (XGLErrorFlag) {
162     WARN("Error deleting context !\n");
163     SetLastError(ERROR_INVALID_HANDLE);
164     ret = FALSE;
165   }
166   LEAVE_GL();
167   
168   return ret;
169 }
170
171 /***********************************************************************
172  *              wglDescribeLayerPlane
173  */
174 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
175                                   int iPixelFormat,
176                                   int iLayerPlane,
177                                   UINT nBytes,
178                                   LPLAYERPLANEDESCRIPTOR plpd) {
179   FIXME("(%08x,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
180
181   return FALSE;
182 }
183
184 /***********************************************************************
185  *              wglGetCurrentContext
186  */
187 HGLRC WINAPI wglGetCurrentContext(void) {
188   GLXContext gl_ctx;
189   Wine_GLContext *ret;
190
191   TRACE("()\n");
192
193   ENTER_GL();
194   gl_ctx = glXGetCurrentContext();
195   ret = get_context_from_GLXContext(gl_ctx);
196   LEAVE_GL();
197
198   TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
199   
200   return ret;
201 }
202
203 /***********************************************************************
204  *              wglGetCurrentDC
205  */
206 HDC WINAPI wglGetCurrentDC(void) {
207   GLXContext gl_ctx;
208   Wine_GLContext *ret;
209
210   TRACE("()\n");
211   
212   ENTER_GL();
213   gl_ctx = glXGetCurrentContext();
214   ret = get_context_from_GLXContext(gl_ctx);
215   LEAVE_GL();
216
217   if (ret) {
218     TRACE(" returning %08x (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
219     return ret->hdc;
220   } else {
221     TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
222     return 0;
223   }
224 }
225
226 /***********************************************************************
227  *              wglGetLayerPaletteEntries
228  */
229 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
230                                      int iLayerPlane,
231                                      int iStart,
232                                      int cEntries,
233                                      const COLORREF *pcr) {
234   FIXME("(): stub !\n");
235
236   return 0;
237 }
238
239 static int compar(const void *elt_a, const void *elt_b) {
240   return strcmp(((OpenGL_extension *) elt_a)->name,
241                 ((OpenGL_extension *) elt_b)->name);
242 }
243
244 /***********************************************************************
245  *              wglGetProcAddress
246  */
247 void* WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
248   void *local_func;
249   static HMODULE hm = 0;
250
251   TRACE("(%s)\n", lpszProc);
252
253   if (hm == 0)
254       hm = GetModuleHandleA("opengl32");
255
256   /* First, look if it's not already defined in the 'standard' OpenGL functions */
257   if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
258     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
259     return local_func;
260   }
261
262   /* After that, look at the extensions defined in the Linux OpenGL library */
263   if ((local_func = glXGetProcAddressARB(lpszProc)) == NULL) {
264     char buf[256];
265     void *ret = NULL;
266     
267     /* Remove the 3 last letters (EXT, ARB, ...).
268        
269        I know that some extensions have more than 3 letters (MESA, NV,
270        INTEL, ...), but this is only a stop-gap measure to fix buggy
271        OpenGL drivers (moreover, it is only useful for old 1.0 apps
272        that query the glBindTextureEXT extension).
273     */
274     strncpy(buf, lpszProc, strlen(lpszProc) - 3);
275     buf[strlen(lpszProc) - 3] = '\0';
276     TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
277     
278     ret = GetProcAddress(hm, buf);
279     if (ret != NULL) {
280       TRACE(" found function in main OpenGL library (%p) !\n", ret);
281     }
282
283     return ret;
284   } else {
285     OpenGL_extension  ext;
286     OpenGL_extension *ret;
287
288     ext.name = (char *) lpszProc;
289     ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
290                                        extension_registry_size, sizeof(OpenGL_extension), compar);
291
292     if (ret != NULL) {
293       TRACE(" returning function  (%p)\n", ret->func);
294       *(ret->func_ptr) = local_func;
295
296       return ret->func;
297     } else {
298       ERR("Extension defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n");
299       return NULL;
300     }
301   }
302 }
303
304 /***********************************************************************
305  *              wglMakeCurrent
306  */
307 BOOL WINAPI wglMakeCurrent(HDC hdc,
308                            HGLRC hglrc) {
309   BOOL ret;
310
311   TRACE("(%08x,%p)\n", hdc, hglrc);
312   
313   if (hglrc == NULL) {
314     ENTER_GL();
315     ret = glXMakeCurrent(display,
316                          None,
317                          NULL);
318     LEAVE_GL();
319   } else {
320     DC * dc = DC_GetDCPtr( hdc );
321     
322     if (dc == NULL) {
323       ERR("Null DC !!!\n");
324       ret = FALSE;
325     } else {
326       X11DRV_PDEVICE *physDev;
327       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
328       
329       physDev =(X11DRV_PDEVICE *)dc->physDev;
330
331       if (ctx->ctx == NULL) {
332         ENTER_GL();
333         ctx->ctx = glXCreateContext(display, ctx->vis, NULL, True);
334         LEAVE_GL();
335         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
336       }
337       
338       ENTER_GL();
339       ret = glXMakeCurrent(display,
340                            physDev->drawable,
341                            ctx->ctx);
342       LEAVE_GL();
343     }
344   }
345   TRACE(" returning %s\n", (ret ? "True" : "False"));
346   return ret;
347 }
348
349 /***********************************************************************
350  *              wglRealizeLayerPalette
351  */
352 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
353                                    int iLayerPlane,
354                                    BOOL bRealize) {
355   FIXME("()\n");
356
357   return FALSE;
358 }
359
360 /***********************************************************************
361  *              wglSetLayerPaletteEntries
362  */
363 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
364                                      int iLayerPlane,
365                                      int iStart,
366                                      int cEntries,
367                                      const COLORREF *pcr) {
368   FIXME("(): stub !\n");
369
370   return 0;
371 }
372
373 /***********************************************************************
374  *              wglShareLists
375  */
376 BOOL WINAPI wglShareLists(HGLRC hglrc1,
377                           HGLRC hglrc2) {
378   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
379   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
380   
381   TRACE("(%p, %p)\n", org, dest);
382
383   if (dest->ctx != NULL) {
384     ERR("Could not share display lists, context already created !\n");
385     return FALSE;
386   } else {
387     if (org->ctx == NULL) {
388       ENTER_GL();
389       org->ctx = glXCreateContext(display, org->vis, NULL, True);
390       LEAVE_GL();
391       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
392     }
393
394     ENTER_GL();
395     /* Create the destination context with display lists shared */
396     dest->ctx = glXCreateContext(display, dest->vis, org->ctx, True);
397     LEAVE_GL();
398     TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
399   }
400   
401   return TRUE;
402 }
403
404 /***********************************************************************
405  *              wglSwapLayerBuffers
406  */
407 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
408                                 UINT fuPlanes) {
409   FIXME("(): stub !\n");
410
411   return FALSE;
412 }
413
414 /***********************************************************************
415  *              wglUseFontBitmapsA
416  */
417 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
418                                DWORD first,
419                                DWORD count,
420                                DWORD listBase) {
421   DC * dc = DC_GetDCPtr( hdc );
422   X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
423   fontObject* pfo = XFONT_GetFontObject( physDev->font );
424   Font fid = pfo->fs->fid;
425
426   TRACE("(%08x, %ld, %ld, %ld)\n", hdc, first, count, listBase);
427
428   ENTER_GL();
429   /* I assume that the glyphs are at the same position for X and for Windows */
430   glXUseXFont(fid, first, count, listBase);
431   LEAVE_GL();
432   
433   return TRUE;
434 }
435  
436 /***********************************************************************
437  *              wglUseFontOutlinesA
438  */
439 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
440                                 DWORD first,
441                                 DWORD count,
442                                 DWORD listBase,
443                                 FLOAT deviation,
444                                 FLOAT extrusion,
445                                 int format,
446                                 LPGLYPHMETRICSFLOAT lpgmf) {
447   FIXME("(): stub !\n");
448
449   return FALSE;
450 }
451
452 /* This is for brain-dead applications that use OpenGL functions before even
453    creating a rendering context.... */
454 DECL_GLOBAL_CONSTRUCTOR(OpenGL_create_default_context) {
455   int num;
456   XVisualInfo template;
457   XVisualInfo *vis;
458   GLXContext cx;
459
460   ENTER_GL();
461   template.visualid = XVisualIDFromVisual(visual);
462   vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
463   cx=glXCreateContext(display, vis, 0, GL_TRUE);
464   glXMakeCurrent(display, X11DRV_GetXRootWindow(), cx);
465   LEAVE_GL();
466
467   context_array = NULL;
468 }