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