1 /* Window-specific OpenGL functions implementation.
3 * Copyright (c) 1999 Lionel Ulmer
4 * Copyright (c) 2005 Raphael Junqueira
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
38 #include "opengl_ext.h"
44 #include "wine/library.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
48 WINE_DECLARE_DEBUG_CHANNEL(opengl);
50 typedef struct wine_glx_s {
53 GLXFBConfig* (*p_glXChooseFBConfig) (Display *dpy, int screen, const int *attrib_list, int *nelements);
54 int (*p_glXGetFBConfigAttrib) (Display *dpy, GLXFBConfig config, int attribute, int *value);
55 XVisualInfo* (*p_glXGetVisualFromFBConfig) (Display *dpy, GLXFBConfig config);
57 GLXFBConfig* (*p_glXGetFBConfigs) (Display *dpy, int screen, int *nelements);
58 void (*p_glXQueryDrawable) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
59 Bool (*p_glXMakeContextCurrent) (Display *, GLXDrawable, GLXDrawable, GLXContext);
62 /** global glx object */
63 static wine_glx_t wine_glx;
65 /* x11drv GDI escapes */
66 #define X11DRV_ESCAPE 6789
67 enum x11drv_escape_codes
69 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
70 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
71 X11DRV_GET_FONT, /* get current X font for a DC */
72 X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
73 X11DRV_START_EXPOSURES, /* start graphics exposures */
74 X11DRV_END_EXPOSURES, /* end graphics exposures */
75 X11DRV_GET_DCE, /* get the DCE pointer */
76 X11DRV_SET_DCE, /* set the DCE pointer */
77 X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */
78 X11DRV_SYNC_PIXMAP /* sync the dibsection to its pixmap */
81 void (*wine_tsx11_lock_ptr)(void) = NULL;
82 void (*wine_tsx11_unlock_ptr)(void) = NULL;
84 static GLXContext default_cx = NULL;
85 static Display *default_display; /* display to use for default context */
87 static HMODULE opengl32_handle;
89 static glXGetProcAddressARB_t p_glXGetProcAddressARB = NULL;
91 static char internal_gl_disabled_extensions[512];
92 static char* internal_gl_extensions = NULL;
94 typedef struct wine_glcontext {
101 struct wine_glcontext *next;
102 struct wine_glcontext *prev;
104 static Wine_GLContext *context_list;
106 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
109 if (!ctx) return NULL;
110 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
116 Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
118 if (curctx && curctx->do_escape)
120 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
121 ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
124 wine_tsx11_lock_ptr();
128 static inline void free_context(Wine_GLContext *context)
130 if (context->next != NULL) context->next->prev = context->prev;
131 if (context->prev != NULL) context->prev->next = context->next;
132 else context_list = context->next;
134 HeapFree(GetProcessHeap(), 0, context);
137 static inline Wine_GLContext *alloc_context(void)
141 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
143 ret->next = context_list;
144 if (context_list) context_list->prev = ret;
150 inline static BOOL is_valid_context( Wine_GLContext *ctx )
153 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
154 return (ptr != NULL);
157 /* retrieve the X display to use on a given DC */
158 inline static Display *get_display( HDC hdc )
161 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
163 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
164 sizeof(display), (LPSTR)&display )) display = NULL;
169 /* retrieve the GLX drawable to use on a given DC */
170 inline static Drawable get_drawable( HDC hdc )
172 GLXDrawable drawable;
173 enum x11drv_escape_codes escape = X11DRV_GET_GLX_DRAWABLE;
175 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
176 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
180 /** for use of wglGetCurrentReadDCARB */
181 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
184 for (ret = context_list; ret; ret = ret->next) {
185 if (d == get_drawable( ret->hdc )) {
192 /* retrieve the X font to use on a given DC */
193 inline static Font get_font( HDC hdc )
196 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
198 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
199 sizeof(font), (LPSTR)&font )) font = 0;
204 /***********************************************************************
205 * wglCreateContext (OPENGL32.@)
207 HGLRC WINAPI wglCreateContext(HDC hdc)
211 XVisualInfo template;
212 XVisualInfo *vis = NULL;
213 Display *display = get_display( hdc );
214 int hdcPF = GetPixelFormat(hdc);
217 TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
219 /* First, get the visual in use by the X11DRV */
220 if (!display) return 0;
221 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
222 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
225 ERR("NULL visual !!!\n");
226 /* Need to set errors here */
230 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
236 GLXFBConfig* cfgs_fmt = NULL;
239 cfgs_fmt = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs_fmt);
240 if (NULL == cfgs_fmt || 0 == nCfgs_fmt) {
241 ERR("Cannot get FB Configs, expect problems.\n");
242 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
245 if (nCfgs_fmt < hdcPF) {
246 ERR("(%p): unexpected pixelFormat(%d) > nFormats(%d), returns NULL\n", hdc, hdcPF, nCfgs_fmt);
247 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
250 cur_cfg = cfgs_fmt[hdcPF - 1];
251 gl_test = wine_glx.p_glXGetFBConfigAttrib(display, cur_cfg, GLX_FBCONFIG_ID, &value);
253 ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
254 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
260 /* The context will be allocated in the wglMakeCurrent call */
262 ret = alloc_context();
265 ret->display = display;
266 ret->fb_conf = cur_cfg;
268 ret->vis = wine_glx.p_glXGetVisualFromFBConfig(display, cur_cfg);
270 TRACE(" creating context %p (GL context creation delayed)\n", ret);
274 /***********************************************************************
275 * wglCreateLayerContext (OPENGL32.@)
277 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
279 TRACE("(%p,%d)\n", hdc, iLayerPlane);
281 if (iLayerPlane == 0) {
282 return wglCreateContext(hdc);
284 FIXME(" no handler for layer %d\n", iLayerPlane);
289 /***********************************************************************
290 * wglCopyContext (OPENGL32.@)
292 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
295 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
300 /***********************************************************************
301 * wglDeleteContext (OPENGL32.@)
303 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
305 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
308 TRACE("(%p)\n", hglrc);
311 /* A game (Half Life not to name it) deletes twice the same context,
312 * so make sure it is valid first */
313 if (is_valid_context( ctx ))
315 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
320 WARN("Error deleting context !\n");
321 SetLastError(ERROR_INVALID_HANDLE);
329 /***********************************************************************
330 * wglDescribeLayerPlane (OPENGL32.@)
332 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
336 LPLAYERPLANEDESCRIPTOR plpd) {
337 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
342 /***********************************************************************
343 * wglGetCurrentContext (OPENGL32.@)
345 HGLRC WINAPI wglGetCurrentContext(void) {
352 gl_ctx = glXGetCurrentContext();
353 ret = get_context_from_GLXContext(gl_ctx);
356 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
361 /***********************************************************************
362 * wglGetCurrentDC (OPENGL32.@)
364 HDC WINAPI wglGetCurrentDC(void) {
371 gl_ctx = glXGetCurrentContext();
372 ret = get_context_from_GLXContext(gl_ctx);
376 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
379 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
384 /***********************************************************************
385 * wglGetLayerPaletteEntries (OPENGL32.@)
387 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
391 const COLORREF *pcr) {
392 FIXME("(): stub !\n");
397 /***********************************************************************
398 * wglGetProcAddress (OPENGL32.@)
400 static int compar(const void *elt_a, const void *elt_b) {
401 return strcmp(((const OpenGL_extension *) elt_a)->name,
402 ((const OpenGL_extension *) elt_b)->name);
405 static int wgl_compar(const void *elt_a, const void *elt_b) {
406 return strcmp(((const WGL_extension *) elt_a)->func_name,
407 ((const WGL_extension *) elt_b)->func_name);
410 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
412 OpenGL_extension ext;
413 const OpenGL_extension *ext_ret;
415 TRACE("(%s)\n", lpszProc);
417 /* First, look if it's not already defined in the 'standard' OpenGL functions */
418 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
419 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
423 if (p_glXGetProcAddressARB == NULL) {
424 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
428 /* After that, search in the thunks to find the real name of the extension */
430 ext_ret = (const OpenGL_extension *) bsearch(&ext, extension_registry,
431 extension_registry_size, sizeof(OpenGL_extension), compar);
433 if (ext_ret == NULL) {
434 WGL_extension wgl_ext, *wgl_ext_ret;
436 /* Try to find the function in the WGL extensions ... */
437 wgl_ext.func_name = (char *) lpszProc;
438 wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
439 wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
441 if (wgl_ext_ret == NULL) {
442 /* Some sanity checks :-) */
444 local_func = p_glXGetProcAddressARB( (const GLubyte *) lpszProc);
446 if (local_func != NULL) {
447 WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
451 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
456 if (wgl_ext_ret->func_init != NULL) {
458 if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
459 wgl_ext_ret->context)) == NULL) {
460 ret = wgl_ext_ret->func_address;
462 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
466 ret = wgl_ext_ret->func_address;
470 TRACE(" returning WGL function (%p)\n", ret);
474 const char *glx_name = ext_ret->glx_name ? ext_ret->glx_name : ext_ret->name;
476 local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
479 /* After that, look at the extensions defined in the Linux OpenGL library */
480 if (local_func == NULL) {
484 /* Remove the 3 last letters (EXT, ARB, ...).
486 I know that some extensions have more than 3 letters (MESA, NV,
487 INTEL, ...), but this is only a stop-gap measure to fix buggy
488 OpenGL drivers (moreover, it is only useful for old 1.0 apps
489 that query the glBindTextureEXT extension).
491 memcpy(buf, glx_name, strlen(glx_name) - 3);
492 buf[strlen(glx_name) - 3] = '\0';
493 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
495 ret = GetProcAddress(opengl32_handle, buf);
497 TRACE(" found function in main OpenGL library (%p) !\n", ret);
499 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
504 TRACE(" returning function (%p)\n", ext_ret->func);
505 extension_funcs[ext_ret - extension_registry] = local_func;
507 return ext_ret->func;
512 static int describeContext(Wine_GLContext* ctx) {
515 TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
516 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
517 TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
518 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
519 TRACE(" - VISUAL_ID 0x%x\n", tmp);
524 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
527 int attribList[3] = { GLX_FBCONFIG_ID, 0, None };
530 if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable) {
531 /** glXQueryDrawable not available so returns not supported */
535 TRACE(" Drawable %p have :\n", (void*) drawable);
536 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
537 TRACE(" - WIDTH as %d\n", tmp);
538 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
539 TRACE(" - HEIGHT as %d\n", tmp);
540 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
541 TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
544 fbCfgs = wine_glx.p_glXChooseFBConfig(ctx->display, DefaultScreen(ctx->display), attribList, &nElements);
545 if (fbCfgs == NULL) {
549 wine_glx.p_glXGetFBConfigAttrib(ctx->display, fbCfgs[0], GLX_VISUAL_ID, &tmp);
550 TRACE(" - VISUAL_ID as 0x%x\n", tmp);
557 /***********************************************************************
558 * wglMakeCurrent (OPENGL32.@)
560 BOOL WINAPI wglMakeCurrent(HDC hdc,
563 DWORD type = GetObjectType(hdc);
565 TRACE("(%p,%p)\n", hdc, hglrc);
569 ret = glXMakeCurrent(default_display, None, NULL);
570 NtCurrentTeb()->glContext = NULL;
572 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
573 Drawable drawable = get_drawable( hdc );
574 if (ctx->ctx == NULL) {
575 int draw_vis_id, ctx_vis_id;
576 VisualID visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
577 TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid);
578 draw_vis_id = describeDrawable(ctx, drawable);
579 ctx_vis_id = describeContext(ctx);
581 if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
583 * Inherits from root window so reuse desktop visual
585 XVisualInfo template;
588 template.visualid = visualid;
589 vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
591 TRACE(" Creating GLX Context\n");
592 ctx->ctx = glXCreateContext(ctx->display, vis, NULL, type == OBJ_MEMDC ? False : True);
594 TRACE(" Creating GLX Context\n");
595 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, type == OBJ_MEMDC ? False : True);
597 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
599 TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
600 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
601 NtCurrentTeb()->glContext = ctx;
602 if(ret && type == OBJ_MEMDC)
604 ctx->do_escape = TRUE;
605 glDrawBuffer(GL_FRONT_LEFT);
609 TRACE(" returning %s\n", (ret ? "True" : "False"));
613 /***********************************************************************
614 * wglMakeContextCurrentARB (OPENGL32.@)
616 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
619 TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
623 ret = glXMakeCurrent(default_display, None, NULL);
625 if (NULL == wine_glx.p_glXMakeContextCurrent) {
628 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
629 Drawable d_draw = get_drawable( hDrawDC );
630 Drawable d_read = get_drawable( hReadDC );
632 if (ctx->ctx == NULL) {
633 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, GetObjectType(hDrawDC) == OBJ_MEMDC ? False : True);
634 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
636 ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
641 TRACE(" returning %s\n", (ret ? "True" : "False"));
645 /***********************************************************************
646 * wglGetCurrentReadDCARB (OPENGL32.@)
648 HDC WINAPI wglGetCurrentReadDCARB(void)
656 gl_d = glXGetCurrentReadDrawable();
657 ret = get_hdc_from_Drawable(gl_d);
660 TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
666 /***********************************************************************
667 * wglRealizeLayerPalette (OPENGL32.@)
669 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
677 /***********************************************************************
678 * wglSetLayerPaletteEntries (OPENGL32.@)
680 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
684 const COLORREF *pcr) {
685 FIXME("(): stub !\n");
690 /***********************************************************************
691 * wglShareLists (OPENGL32.@)
693 BOOL WINAPI wglShareLists(HGLRC hglrc1,
695 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
696 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
698 TRACE("(%p, %p)\n", org, dest);
700 if (NULL != dest && dest->ctx != NULL) {
701 ERR("Could not share display lists, context already created !\n");
704 if (org->ctx == NULL) {
706 describeContext(org);
707 org->ctx = glXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
709 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
713 describeContext(dest);
714 /* Create the destination context with display lists shared */
715 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
717 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
724 /***********************************************************************
725 * wglSwapLayerBuffers (OPENGL32.@)
727 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
729 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
731 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
732 if (!SwapBuffers(hdc)) return FALSE;
733 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
737 WARN("Following layers unhandled : %08x\n", fuPlanes);
743 static BOOL internal_wglUseFontBitmaps(HDC hdc,
747 DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
749 /* We are running using client-side rendering fonts... */
753 void *bitmap = NULL, *gl_bitmap = NULL;
757 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
758 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
761 for (glyph = first; glyph < first + count; glyph++) {
762 unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
763 int height, width_int;
765 TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
766 if (needed_size == GDI_ERROR) {
767 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size);
770 TRACE(" - needed size : %d\n", needed_size);
773 if (needed_size > size) {
775 HeapFree(GetProcessHeap(), 0, bitmap);
776 HeapFree(GetProcessHeap(), 0, gl_bitmap);
777 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
778 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
780 if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
781 if (TRACE_ON(opengl)) {
782 unsigned int height, width, bitmask;
783 unsigned char *bitmap_ = (unsigned char *) bitmap;
785 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
786 TRACE(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
787 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
788 if (needed_size != 0) {
789 TRACE(" - bitmap :\n");
790 for (height = 0; height < gm.gmBlackBoxY; height++) {
792 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
797 if (*bitmap_ & bitmask)
802 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
808 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
809 * glyph for it to be drawn properly.
811 if (needed_size != 0) {
812 width_int = (gm.gmBlackBoxX + 31) / 32;
813 for (height = 0; height < gm.gmBlackBoxY; height++) {
815 for (width = 0; width < width_int; width++) {
816 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
817 ((int *) bitmap)[height * width_int + width];
823 glNewList(listBase++, GL_COMPILE);
824 if (needed_size != 0) {
825 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
826 0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
827 gm.gmCellIncX, gm.gmCellIncY,
830 /* This is the case of 'empty' glyphs like the space character */
831 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
838 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
841 HeapFree(GetProcessHeap(), 0, bitmap);
842 HeapFree(GetProcessHeap(), 0, gl_bitmap);
847 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
850 HeapFree(GetProcessHeap(), 0, bitmap);
851 HeapFree(GetProcessHeap(), 0, gl_bitmap);
855 /***********************************************************************
856 * wglUseFontBitmapsA (OPENGL32.@)
858 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
863 Font fid = get_font( hdc );
865 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
868 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
872 /* I assume that the glyphs are at the same position for X and for Windows */
873 glXUseXFont(fid, first, count, listBase);
878 /***********************************************************************
879 * wglUseFontBitmapsW (OPENGL32.@)
881 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
886 Font fid = get_font( hdc );
888 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
891 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
894 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
897 /* I assume that the glyphs are at the same position for X and for Windows */
898 glXUseXFont(fid, first, count, listBase);
905 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
907 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
908 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
912 static void tess_callback_vertex(GLvoid *vertex)
914 GLdouble *dbl = vertex;
915 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
919 static void tess_callback_begin(GLenum which)
921 TRACE("%d\n", which);
925 static void tess_callback_end(void)
931 /***********************************************************************
932 * wglUseFontOutlines_common
934 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
941 LPGLYPHMETRICSFLOAT lpgmf,
945 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
948 HFONT old_font, unscaled_font;
952 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
953 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
960 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
961 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
962 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
966 if(!tess) return FALSE;
968 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
969 rc.left = rc.right = rc.bottom = 0;
971 DPtoLP(hdc, (POINT*)&rc, 2);
972 lf.lfHeight = -abs(rc.top - rc.bottom);
973 lf.lfOrientation = lf.lfEscapement = 0;
974 unscaled_font = CreateFontIndirectW(&lf);
975 old_font = SelectObject(hdc, unscaled_font);
977 for (glyph = first; glyph < first + count; glyph++)
982 TTPOLYGONHEADER *pph;
987 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
989 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
991 if(needed == GDI_ERROR)
994 buf = HeapAlloc(GetProcessHeap(), 0, needed);
995 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
998 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
1000 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
1002 TRACE("glyph %d\n", glyph);
1006 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
1007 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
1008 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
1009 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
1010 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
1011 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
1013 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
1014 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
1019 glNewList(listBase++, GL_COMPILE);
1020 gluTessBeginPolygon(tess, NULL);
1022 pph = (TTPOLYGONHEADER*)buf;
1023 while((BYTE*)pph < buf + needed)
1025 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
1027 gluTessBeginContour(tess);
1029 fixed_to_double(pph->pfxStart, em_size, vertices);
1030 gluTessVertex(tess, vertices, vertices);
1033 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1034 while((char*)ppc < (char*)pph + pph->cb)
1038 switch(ppc->wType) {
1040 for(i = 0; i < ppc->cpfx; i++)
1042 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1043 fixed_to_double(ppc->apfx[i], em_size, vertices);
1044 gluTessVertex(tess, vertices, vertices);
1049 case TT_PRIM_QSPLINE:
1050 for(i = 0; i < ppc->cpfx/2; i++)
1052 /* FIXME just connecting the control points for now */
1053 TRACE("\t\tcurve %d,%d %d,%d\n",
1054 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
1055 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
1056 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
1057 gluTessVertex(tess, vertices, vertices);
1059 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
1060 gluTessVertex(tess, vertices, vertices);
1065 ERR("\t\tcurve type = %d\n", ppc->wType);
1066 gluTessEndContour(tess);
1070 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1071 (ppc->cpfx - 1) * sizeof(POINTFX));
1073 gluTessEndContour(tess);
1074 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1078 gluTessEndPolygon(tess);
1079 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
1082 HeapFree(GetProcessHeap(), 0, buf);
1083 HeapFree(GetProcessHeap(), 0, vertices);
1087 DeleteObject(SelectObject(hdc, old_font));
1088 gluDeleteTess(tess);
1093 #else /* HAVE_GL_GLU_H */
1095 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
1102 LPGLYPHMETRICSFLOAT lpgmf,
1105 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1109 #endif /* HAVE_GL_GLU_H */
1111 /***********************************************************************
1112 * wglUseFontOutlinesA (OPENGL32.@)
1114 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1121 LPGLYPHMETRICSFLOAT lpgmf)
1123 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1126 /***********************************************************************
1127 * wglUseFontOutlinesW (OPENGL32.@)
1129 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
1136 LPGLYPHMETRICSFLOAT lpgmf)
1138 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1141 const GLubyte * internal_glGetString(GLenum name) {
1142 const char* GL_Extensions = NULL;
1144 if (GL_EXTENSIONS != name) {
1145 return glGetString(name);
1148 if (NULL == internal_gl_extensions) {
1149 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1151 TRACE("GL_EXTENSIONS reported:\n");
1152 if (NULL == GL_Extensions) {
1153 ERR("GL_EXTENSIONS returns NULL\n");
1156 size_t len = strlen(GL_Extensions);
1157 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1159 while (*GL_Extensions != 0x00) {
1160 const char* Start = GL_Extensions;
1163 memset(ThisExtn, 0x00, sizeof(ThisExtn));
1164 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1167 memcpy(ThisExtn, Start, (GL_Extensions - Start));
1168 TRACE("- %s:", ThisExtn);
1170 /* test if supported API is disabled by config */
1171 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
1172 strcat(internal_gl_extensions, " ");
1173 strcat(internal_gl_extensions, ThisExtn);
1176 TRACE(" deactived (by config)\n");
1179 if (*GL_Extensions == ' ') GL_Extensions++;
1183 return (const GLubyte *) internal_gl_extensions;
1186 void internal_glGetIntegerv(GLenum pname, GLint* params) {
1187 glGetIntegerv(pname, params);
1188 if (pname == GL_DEPTH_BITS) {
1189 GLXContext gl_ctx = glXGetCurrentContext();
1190 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1191 /*TRACE("returns Wine Ctx as %p\n", ret);*/
1193 * if we cannot find a Wine Context
1194 * we only have the default wine desktop context,
1195 * so if we have only a 24 depth say we have 32
1197 if (NULL == ret && 24 == *params) {
1200 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
1202 if (pname == GL_ALPHA_BITS) {
1204 GLXContext gl_ctx = glXGetCurrentContext();
1205 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1206 glXGetFBConfigAttrib(ret->display, ret->fb_conf, GLX_ALPHA_SIZE, &tmp);
1207 TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp);
1213 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1214 include all dependencies
1216 #ifndef SONAME_LIBGL
1217 #define SONAME_LIBGL "libGL.so"
1220 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc)
1222 const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
1223 const char *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1225 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1226 const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1227 const char *glx_extensions = glXQueryExtensionsString(display, screen);
1230 memset(&wine_glx, 0, sizeof(wine_glx));
1232 if (!strcmp("1.2", server_glx_version)) {
1233 wine_glx.version = 2;
1235 wine_glx.version = 3;
1238 if (2 < wine_glx.version) {
1239 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
1240 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
1241 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
1243 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1244 wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
1246 if (NULL != strstr(server_glx_extensions, "GLX_SGIX_fbconfig")) {
1247 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
1248 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
1249 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
1251 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version);
1254 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1255 wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
1256 wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
1259 /* This is for brain-dead applications that use OpenGL functions before even
1260 creating a rendering context.... */
1261 static BOOL process_attach(void)
1263 XWindowAttributes win_attr;
1266 XVisualInfo template;
1268 XVisualInfo *vis = NULL;
1269 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1270 HMODULE mod = GetModuleHandleA( "winex11.drv" );
1271 void *opengl_handle;
1272 DWORD size = sizeof(internal_gl_disabled_extensions);
1277 ERR("X11DRV not loaded. Cannot create default context.\n");
1281 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1282 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1285 default_display = get_display( hdc );
1286 ReleaseDC( 0, hdc );
1287 if (!default_display)
1289 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1295 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1296 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1297 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1298 with mismatched visuals. Note that the Root Window visual may not be double
1299 buffered, so apps actually attempting to render this way may flicker */
1300 if (XGetWindowAttributes( default_display, root, &win_attr ))
1302 rootVisual = win_attr.visual;
1306 /* Get the default visual, since we can't seem to get the attributes from the
1307 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1308 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1311 template.visualid = XVisualIDFromVisual(rootVisual);
1312 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1313 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1314 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1318 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1319 if (opengl_handle != NULL) {
1320 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1321 wine_dlclose(opengl_handle, NULL, 0);
1322 if (p_glXGetProcAddressARB == NULL)
1323 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1326 internal_gl_disabled_extensions[0] = 0;
1327 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1328 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1329 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1334 if (default_cx == NULL) {
1335 ERR("Could not create default context.\n");
1339 /* After context initialize also the list of supported WGL extensions. */
1340 wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1341 wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1347 /**********************************************************************/
1349 static void process_detach(void)
1351 glXDestroyContext(default_display, default_cx);
1353 /* Do not leak memory... */
1354 wgl_ext_finalize_extensions();
1355 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1358 /***********************************************************************
1359 * OpenGL initialisation routine
1361 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1365 case DLL_PROCESS_ATTACH:
1366 opengl32_handle = hinst;
1367 DisableThreadLibraryCalls(hinst);
1368 return process_attach();
1369 case DLL_PROCESS_DETACH: