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