Fixed warnings caused by conversion to -DSTRICT.
[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 "x11drv.h"
30
31 #include "wgl.h"
32 #include "opengl_ext.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
36
37 void (*wine_tsx11_lock_ptr)(void) = NULL;
38 void (*wine_tsx11_unlock_ptr)(void) = NULL;
39
40 static GLXContext default_cx = NULL;
41 static Display *default_display;  /* display to use for default context */
42
43 typedef struct wine_glcontext {
44   HDC hdc;
45   Display *display;
46   GLXContext ctx;
47   XVisualInfo *vis;
48   struct wine_glcontext *next;
49   struct wine_glcontext *prev;
50 } Wine_GLContext;
51 static Wine_GLContext *context_list;
52
53 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
54 {
55     Wine_GLContext *ret;
56     for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
57     return ret;
58 }
59
60 static inline void free_context(Wine_GLContext *context)
61 {
62   if (context->next != NULL) context->next->prev = context->prev;
63   if (context->prev != NULL) context->prev->next = context->next;
64   else context_list = context->next;
65
66   HeapFree(GetProcessHeap(), 0, context);
67 }
68
69 static inline Wine_GLContext *alloc_context(void)
70 {
71   Wine_GLContext *ret;
72
73   if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
74   {
75       ret->next = context_list;
76       if (context_list) context_list->prev = ret;
77       context_list = ret;
78   }
79   return ret;
80 }
81
82 inline static BOOL is_valid_context( Wine_GLContext *ctx )
83 {
84     Wine_GLContext *ptr;
85     for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
86     return (ptr != NULL);
87 }
88
89 /* retrieve the X display to use on a given DC */
90 inline static Display *get_display( HDC hdc )
91 {
92     Display *display;
93     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
94
95     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
96                     sizeof(display), (LPSTR)&display )) display = NULL;
97     return display;
98 }
99
100
101 /* retrieve the X drawable to use on a given DC */
102 inline static Drawable get_drawable( HDC hdc )
103 {
104     Drawable drawable;
105     enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
106
107     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
108                     sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
109     return drawable;
110 }
111
112
113 /* retrieve the X drawable to use on a given DC */
114 inline static Font get_font( HDC hdc )
115 {
116     Font font;
117     enum x11drv_escape_codes escape = X11DRV_GET_FONT;
118
119     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
120                     sizeof(font), (LPSTR)&font )) font = 0;
121     return font;
122 }
123
124
125 /***********************************************************************
126  *              wglCreateContext (OPENGL32.@)
127  */
128 HGLRC WINAPI wglCreateContext(HDC hdc)
129 {
130   XVisualInfo *vis;
131   Wine_GLContext *ret;
132   int num;
133   XVisualInfo template;
134   Display *display = get_display( hdc );
135
136   TRACE("(%p)\n", hdc);
137
138   /* First, get the visual in use by the X11DRV */
139   if (!display) return 0;
140   template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
141   vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
142
143   if (vis == NULL) {
144     ERR("NULL visual !!!\n");
145     /* Need to set errors here */
146     return NULL;
147   }
148
149   /* The context will be allocated in the wglMakeCurrent call */
150   ENTER_GL();
151   ret = alloc_context();
152   LEAVE_GL();
153   ret->hdc = hdc;
154   ret->display = display;
155   ret->vis = vis;
156
157   TRACE(" creating context %p (GL context creation delayed)\n", ret);
158   return (HGLRC) ret;
159 }
160
161 /***********************************************************************
162  *              wglCreateLayerContext (OPENGL32.@)
163  */
164 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
165                                    int iLayerPlane) {
166   FIXME("(%p,%d): stub !\n", hdc, iLayerPlane);
167
168   return NULL;
169 }
170
171 /***********************************************************************
172  *              wglCopyContext (OPENGL32.@)
173  */
174 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
175                            HGLRC hglrcDst,
176                            UINT mask) {
177   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
178
179   return FALSE;
180 }
181
182 /***********************************************************************
183  *              wglDeleteContext (OPENGL32.@)
184  */
185 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
186 {
187   Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
188   BOOL ret = TRUE;
189
190   TRACE("(%p)\n", hglrc);
191
192   ENTER_GL();
193   /* A game (Half Life not to name it) deletes twice the same context,
194    * so make sure it is valid first */
195   if (is_valid_context( ctx ))
196   {
197       if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
198       free_context(ctx);
199   }
200   else
201   {
202     WARN("Error deleting context !\n");
203     SetLastError(ERROR_INVALID_HANDLE);
204     ret = FALSE;
205   }
206   LEAVE_GL();
207
208   return ret;
209 }
210
211 /***********************************************************************
212  *              wglDescribeLayerPlane (OPENGL32.@)
213  */
214 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
215                                   int iPixelFormat,
216                                   int iLayerPlane,
217                                   UINT nBytes,
218                                   LPLAYERPLANEDESCRIPTOR plpd) {
219   FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
220
221   return FALSE;
222 }
223
224 /***********************************************************************
225  *              wglGetCurrentContext (OPENGL32.@)
226  */
227 HGLRC WINAPI wglGetCurrentContext(void) {
228   GLXContext gl_ctx;
229   Wine_GLContext *ret;
230
231   TRACE("()\n");
232
233   ENTER_GL();
234   gl_ctx = glXGetCurrentContext();
235   ret = get_context_from_GLXContext(gl_ctx);
236   LEAVE_GL();
237
238   TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
239
240   return ret;
241 }
242
243 /***********************************************************************
244  *              wglGetCurrentDC (OPENGL32.@)
245  */
246 HDC WINAPI wglGetCurrentDC(void) {
247   GLXContext gl_ctx;
248   Wine_GLContext *ret;
249
250   TRACE("()\n");
251
252   ENTER_GL();
253   gl_ctx = glXGetCurrentContext();
254   ret = get_context_from_GLXContext(gl_ctx);
255   LEAVE_GL();
256
257   if (ret) {
258     TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
259     return ret->hdc;
260   } else {
261     TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
262     return 0;
263   }
264 }
265
266 /***********************************************************************
267  *              wglGetLayerPaletteEntries (OPENGL32.@)
268  */
269 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
270                                      int iLayerPlane,
271                                      int iStart,
272                                      int cEntries,
273                                      const COLORREF *pcr) {
274   FIXME("(): stub !\n");
275
276   return 0;
277 }
278
279 /***********************************************************************
280  *              wglGetProcAddress (OPENGL32.@)
281  */
282 static int compar(const void *elt_a, const void *elt_b) {
283   return strcmp(((OpenGL_extension *) elt_a)->name,
284                 ((OpenGL_extension *) elt_b)->name);
285 }
286
287 void* WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
288   void *local_func;
289   static HMODULE hm = 0;
290   OpenGL_extension  ext;
291   OpenGL_extension *ext_ret;
292
293
294   TRACE("(%s)\n", lpszProc);
295
296   if (hm == 0)
297       hm = GetModuleHandleA("opengl32");
298
299   /* First, look if it's not already defined in the 'standard' OpenGL functions */
300   if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
301     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
302     return local_func;
303   }
304
305   /* After that, search in the thunks to find the real name of the extension */
306   ext.name = (char *) lpszProc;
307   ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
308                                          extension_registry_size, sizeof(OpenGL_extension), compar);
309
310   if (ext_ret == NULL) {
311     /* Some sanity checks :-) */
312     if (glXGetProcAddressARB(lpszProc) != NULL) {
313       ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
314       return NULL;
315     }
316
317     WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
318     return NULL;
319   } else {
320     /* After that, look at the extensions defined in the Linux OpenGL library */
321     if ((local_func = glXGetProcAddressARB(ext_ret->glx_name)) == NULL) {
322       char buf[256];
323       void *ret = NULL;
324
325       /* Remove the 3 last letters (EXT, ARB, ...).
326
327          I know that some extensions have more than 3 letters (MESA, NV,
328          INTEL, ...), but this is only a stop-gap measure to fix buggy
329          OpenGL drivers (moreover, it is only useful for old 1.0 apps
330          that query the glBindTextureEXT extension).
331       */
332       strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
333       buf[strlen(ext_ret->glx_name) - 3] = '\0';
334       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
335
336       ret = GetProcAddress(hm, buf);
337       if (ret != NULL) {
338         TRACE(" found function in main OpenGL library (%p) !\n", ret);
339       } else {
340         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
341       }
342
343       return ret;
344     } else {
345       TRACE(" returning function  (%p)\n", ext_ret->func);
346       *(ext_ret->func_ptr) = local_func;
347
348       return ext_ret->func;
349     }
350   }
351 }
352
353 /***********************************************************************
354  *              wglMakeCurrent (OPENGL32.@)
355  */
356 BOOL WINAPI wglMakeCurrent(HDC hdc,
357                            HGLRC hglrc) {
358   BOOL ret;
359
360   TRACE("(%p,%p)\n", hdc, hglrc);
361
362   ENTER_GL();
363   if (hglrc == NULL) {
364       ret = glXMakeCurrent(default_display, None, NULL);
365   } else {
366       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
367       Drawable drawable = get_drawable( hdc );
368
369       if (ctx->ctx == NULL) {
370         ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
371         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
372       }
373       ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
374   }
375   LEAVE_GL();
376   TRACE(" returning %s\n", (ret ? "True" : "False"));
377   return ret;
378 }
379
380 /***********************************************************************
381  *              wglRealizeLayerPalette (OPENGL32.@)
382  */
383 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
384                                    int iLayerPlane,
385                                    BOOL bRealize) {
386   FIXME("()\n");
387
388   return FALSE;
389 }
390
391 /***********************************************************************
392  *              wglSetLayerPaletteEntries (OPENGL32.@)
393  */
394 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
395                                      int iLayerPlane,
396                                      int iStart,
397                                      int cEntries,
398                                      const COLORREF *pcr) {
399   FIXME("(): stub !\n");
400
401   return 0;
402 }
403
404 /***********************************************************************
405  *              wglShareLists (OPENGL32.@)
406  */
407 BOOL WINAPI wglShareLists(HGLRC hglrc1,
408                           HGLRC hglrc2) {
409   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
410   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
411
412   TRACE("(%p, %p)\n", org, dest);
413
414   if (dest->ctx != NULL) {
415     ERR("Could not share display lists, context already created !\n");
416     return FALSE;
417   } else {
418     if (org->ctx == NULL) {
419       ENTER_GL();
420       org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
421       LEAVE_GL();
422       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
423     }
424
425     ENTER_GL();
426     /* Create the destination context with display lists shared */
427     dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
428     LEAVE_GL();
429     TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
430   }
431
432   return TRUE;
433 }
434
435 /***********************************************************************
436  *              wglSwapLayerBuffers (OPENGL32.@)
437  */
438 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
439                                 UINT fuPlanes) {
440   TRACE("(%p, %08x)\n", hdc, fuPlanes);
441
442   if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
443     if (!SwapBuffers(hdc)) return FALSE;
444     fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
445   }
446
447   if (fuPlanes) {
448     WARN("Following layers unhandled : %08x\n", fuPlanes);
449   }
450
451   return TRUE;
452 }
453
454 /***********************************************************************
455  *              wglUseFontBitmapsA (OPENGL32.@)
456  */
457 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
458                                DWORD first,
459                                DWORD count,
460                                DWORD listBase)
461 {
462   Font fid = get_font( hdc );
463
464   TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
465
466   if (fid == 0) {
467     /* We are running using client-side rendering fonts... */
468     GLYPHMETRICS gm;
469     static const MAT2 id = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
470     int glyph;
471     int size = 0;
472     void *bitmap = NULL, *gl_bitmap = NULL;
473     int org_alignment;
474
475     ENTER_GL();
476     glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
477     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
478     LEAVE_GL();
479
480     for (glyph = first; glyph < first + count; glyph++) {
481       int needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &id);
482       int height, width_int;
483
484       if (needed_size == GDI_ERROR) goto error;
485       if (needed_size > size) {
486         size = needed_size;
487         if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
488         if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
489         bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
490         gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
491       }
492       if (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &id) == GDI_ERROR) goto error;
493       if (TRACE_ON(opengl)) {
494         unsigned int height, width, bitmask;
495         unsigned char *bitmap_ = (unsigned char *) bitmap;
496
497         DPRINTF("Glyph : %d\n", glyph);
498         DPRINTF("  - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
499         DPRINTF("  - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
500         DPRINTF("  - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
501         DPRINTF("  - size : %d\n", needed_size);
502         DPRINTF("  - bitmap : \n");
503         for (height = 0; height < gm.gmBlackBoxY; height++) {
504           DPRINTF("      ");
505           for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
506             if (bitmask == 0) {
507               bitmap_ += 1;
508               bitmask = 0x80;
509             }
510             if (*bitmap_ & bitmask)
511               DPRINTF("*");
512             else
513               DPRINTF(" ");
514           }
515           bitmap_ += (4 - (((unsigned int) bitmap_) & 0x03));
516           DPRINTF("\n");
517         }
518       }
519
520       /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
521          As Wine does not seem to support the MAT2 field, I need to do it myself.... */
522       width_int = (gm.gmBlackBoxX + 31) / 32;
523       for (height = 0; height < gm.gmBlackBoxY; height++) {
524         int width;
525         for (width = 0; width < width_int; width++) {
526           ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
527             ((int *) bitmap)[height * width_int + width];
528         }
529       }
530
531       ENTER_GL();
532       glNewList(listBase++, GL_COMPILE);
533       glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x, gm.gmBlackBoxY - gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY, gl_bitmap);
534       glEndList();
535       LEAVE_GL();
536     }
537
538     ENTER_GL();
539     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
540     LEAVE_GL();
541
542     if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
543     if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
544     return TRUE;
545
546   error:
547     ENTER_GL();
548     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
549     LEAVE_GL();
550
551     if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
552     if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
553     return FALSE;
554   }
555
556   ENTER_GL();
557   /* I assume that the glyphs are at the same position for X and for Windows */
558   glXUseXFont(fid, first, count, listBase);
559   LEAVE_GL();
560   return TRUE;
561 }
562
563 /***********************************************************************
564  *              wglUseFontOutlinesA (OPENGL32.@)
565  */
566 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
567                                 DWORD first,
568                                 DWORD count,
569                                 DWORD listBase,
570                                 FLOAT deviation,
571                                 FLOAT extrusion,
572                                 int format,
573                                 LPGLYPHMETRICSFLOAT lpgmf) {
574   FIXME("(): stub !\n");
575
576   return FALSE;
577 }
578
579
580 /* This is for brain-dead applications that use OpenGL functions before even
581    creating a rendering context.... */
582 static BOOL process_attach(void)
583 {
584   XWindowAttributes win_attr;
585   Visual *rootVisual;
586   int num;
587   XVisualInfo template;
588   HDC hdc;
589   XVisualInfo *vis = NULL;
590   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
591   HMODULE mod = GetModuleHandleA( "x11drv.dll" );
592
593   if (!root || !mod)
594   {
595       ERR("X11DRV not loaded. Cannot create default context.\n");
596       return FALSE;
597   }
598
599   wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
600   wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
601
602   hdc = GetDC(0);
603   default_display = get_display( hdc );
604   ReleaseDC( 0, hdc );
605   if (!default_display)
606   {
607       ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
608       return FALSE;
609   }
610
611   ENTER_GL();
612
613   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
614      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
615      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
616      with mismatched visuals.  Note that the Root Window visual may not be double
617      buffered, so apps actually attempting to render this way may flicker */
618   if (XGetWindowAttributes( default_display, root, &win_attr ))
619   {
620     rootVisual = win_attr.visual;
621   }
622   else
623   {
624     /* Get the default visual, since we can't seem to get the attributes from the
625        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
626     rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
627   }
628
629   template.visualid = XVisualIDFromVisual(rootVisual);
630   vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
631   if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
632   if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
633   XFree(vis);
634   LEAVE_GL();
635
636   if (default_cx == NULL) {
637     ERR("Could not create default context.\n");
638   }
639   return TRUE;
640 }
641
642 static void process_detach(void)
643 {
644   glXDestroyContext(default_display, default_cx);
645 }
646
647 /***********************************************************************
648  *           OpenGL initialisation routine
649  */
650 BOOL WINAPI OpenGL32_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
651 {
652     switch(reason)
653     {
654     case DLL_PROCESS_ATTACH:
655         return process_attach();
656     case DLL_PROCESS_DETACH:
657         process_detach();
658         break;
659     }
660     return TRUE;
661 }