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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
36 #include "opengl_ext.h"
42 #include "wine/library.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
47 /** global glx object */
50 /* x11drv GDI escapes */
51 #define X11DRV_ESCAPE 6789
52 enum x11drv_escape_codes
54 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
55 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
56 X11DRV_GET_FONT, /* get current X font for a DC */
57 X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
58 X11DRV_START_EXPOSURES, /* start graphics exposures */
59 X11DRV_END_EXPOSURES, /* end graphics exposures */
60 X11DRV_GET_DCE, /* get the DCE pointer */
61 X11DRV_SET_DCE, /* set the DCE pointer */
62 X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */
63 X11DRV_SYNC_PIXMAP /* sync the dibsection to its pixmap */
66 void (*wine_tsx11_lock_ptr)(void) = NULL;
67 void (*wine_tsx11_unlock_ptr)(void) = NULL;
69 static GLXContext default_cx = NULL;
70 static Display *default_display; /* display to use for default context */
72 static HMODULE opengl32_handle;
74 static glXGetProcAddressARB_t p_glXGetProcAddressARB = NULL;
76 static char internal_gl_disabled_extensions[512];
77 static char* internal_gl_extensions = NULL;
79 typedef struct wine_glcontext {
85 struct wine_glcontext *next;
86 struct wine_glcontext *prev;
88 static Wine_GLContext *context_list;
90 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
93 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
101 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
103 wine_tsx11_lock_ptr();
104 gl_ctx = glXGetCurrentContext();
106 ctx = get_context_from_GLXContext(gl_ctx);
107 wine_tsx11_unlock_ptr(); /* unlock before calling GDI apis */
109 if(ctx && GetObjectType(ctx->hdc) == OBJ_MEMDC)
110 ExtEscape(ctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
112 wine_tsx11_lock_ptr();
116 static inline void free_context(Wine_GLContext *context)
118 if (context->next != NULL) context->next->prev = context->prev;
119 if (context->prev != NULL) context->prev->next = context->next;
120 else context_list = context->next;
122 HeapFree(GetProcessHeap(), 0, context);
125 static inline Wine_GLContext *alloc_context(void)
129 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
131 ret->next = context_list;
132 if (context_list) context_list->prev = ret;
138 inline static BOOL is_valid_context( Wine_GLContext *ctx )
141 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
142 return (ptr != NULL);
145 /* retrieve the X display to use on a given DC */
146 inline static Display *get_display( HDC hdc )
149 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
151 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
152 sizeof(display), (LPSTR)&display )) display = NULL;
157 /* retrieve the GLX drawable to use on a given DC */
158 inline static Drawable get_drawable( HDC hdc )
160 GLXDrawable drawable;
161 enum x11drv_escape_codes escape = X11DRV_GET_GLX_DRAWABLE;
163 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
164 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
168 /** for use of wglGetCurrentReadDCARB */
169 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
172 for (ret = context_list; ret; ret = ret->next) {
173 if (d == get_drawable( ret->hdc )) {
180 /* retrieve the X font to use on a given DC */
181 inline static Font get_font( HDC hdc )
184 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
186 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
187 sizeof(font), (LPSTR)&font )) font = 0;
192 /***********************************************************************
193 * wglCreateContext (OPENGL32.@)
195 HGLRC WINAPI wglCreateContext(HDC hdc)
199 XVisualInfo template;
200 XVisualInfo *vis = NULL;
201 Display *display = get_display( hdc );
202 int hdcPF = GetPixelFormat(hdc);
205 TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
207 /* First, get the visual in use by the X11DRV */
208 if (!display) return 0;
209 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
210 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
213 ERR("NULL visual !!!\n");
214 /* Need to set errors here */
218 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
224 GLXFBConfig* cfgs_fmt = NULL;
227 cfgs_fmt = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs_fmt);
228 if (NULL == cfgs_fmt || 0 == nCfgs_fmt) {
229 ERR("Cannot get FB Configs, expect problems.\n");
230 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
233 if (nCfgs_fmt < hdcPF) {
234 ERR("(%p): unexpected pixelFormat(%d) > nFormats(%d), returns NULL\n", hdc, hdcPF, nCfgs_fmt);
235 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
238 cur_cfg = cfgs_fmt[hdcPF - 1];
239 gl_test = wine_glx.p_glXGetFBConfigAttrib(display, cur_cfg, GLX_FBCONFIG_ID, &value);
241 ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
242 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
248 /* The context will be allocated in the wglMakeCurrent call */
250 ret = alloc_context();
253 ret->display = display;
254 ret->fb_conf = cur_cfg;
256 ret->vis = wine_glx.p_glXGetVisualFromFBConfig(display, cur_cfg);
258 TRACE(" creating context %p (GL context creation delayed)\n", ret);
262 /***********************************************************************
263 * wglCreateLayerContext (OPENGL32.@)
265 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
267 TRACE("(%p,%d)\n", hdc, iLayerPlane);
269 if (iLayerPlane == 0) {
270 return wglCreateContext(hdc);
272 FIXME(" no handler for layer %d\n", iLayerPlane);
277 /***********************************************************************
278 * wglCopyContext (OPENGL32.@)
280 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
283 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
288 /***********************************************************************
289 * wglDeleteContext (OPENGL32.@)
291 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
293 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
296 TRACE("(%p)\n", hglrc);
299 /* A game (Half Life not to name it) deletes twice the same context,
300 * so make sure it is valid first */
301 if (is_valid_context( ctx ))
303 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
308 WARN("Error deleting context !\n");
309 SetLastError(ERROR_INVALID_HANDLE);
317 /***********************************************************************
318 * wglDescribeLayerPlane (OPENGL32.@)
320 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
324 LPLAYERPLANEDESCRIPTOR plpd) {
325 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
330 /***********************************************************************
331 * wglGetCurrentContext (OPENGL32.@)
333 HGLRC WINAPI wglGetCurrentContext(void) {
340 gl_ctx = glXGetCurrentContext();
341 ret = get_context_from_GLXContext(gl_ctx);
344 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
349 /***********************************************************************
350 * wglGetCurrentDC (OPENGL32.@)
352 HDC WINAPI wglGetCurrentDC(void) {
359 gl_ctx = glXGetCurrentContext();
360 ret = get_context_from_GLXContext(gl_ctx);
364 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
367 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
372 /***********************************************************************
373 * wglGetLayerPaletteEntries (OPENGL32.@)
375 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
379 const COLORREF *pcr) {
380 FIXME("(): stub !\n");
385 /***********************************************************************
386 * wglGetProcAddress (OPENGL32.@)
388 static int compar(const void *elt_a, const void *elt_b) {
389 return strcmp(((const OpenGL_extension *) elt_a)->name,
390 ((const OpenGL_extension *) elt_b)->name);
393 static int wgl_compar(const void *elt_a, const void *elt_b) {
394 return strcmp(((const WGL_extension *) elt_a)->func_name,
395 ((const WGL_extension *) elt_b)->func_name);
398 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
400 OpenGL_extension ext;
401 OpenGL_extension *ext_ret;
403 TRACE("(%s)\n", lpszProc);
405 /* First, look if it's not already defined in the 'standard' OpenGL functions */
406 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
407 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
411 if (p_glXGetProcAddressARB == NULL) {
412 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
416 /* After that, search in the thunks to find the real name of the extension */
417 ext.name = (char *) lpszProc;
418 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
419 extension_registry_size, sizeof(OpenGL_extension), compar);
421 if (ext_ret == NULL) {
422 WGL_extension wgl_ext, *wgl_ext_ret;
424 /* Try to find the function in the WGL extensions ... */
425 wgl_ext.func_name = (char *) lpszProc;
426 wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
427 wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
429 if (wgl_ext_ret == NULL) {
430 /* Some sanity checks :-) */
432 local_func = p_glXGetProcAddressARB( (const GLubyte *) lpszProc);
434 if (local_func != NULL) {
435 WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
439 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
444 if (wgl_ext_ret->func_init != NULL) {
446 if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
447 wgl_ext_ret->context)) == NULL) {
448 ret = wgl_ext_ret->func_address;
450 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
454 ret = wgl_ext_ret->func_address;
458 TRACE(" returning WGL function (%p)\n", ret);
463 local_func = p_glXGetProcAddressARB( (const GLubyte*) ext_ret->glx_name);
466 /* After that, look at the extensions defined in the Linux OpenGL library */
467 if (local_func == NULL) {
471 /* Remove the 3 last letters (EXT, ARB, ...).
473 I know that some extensions have more than 3 letters (MESA, NV,
474 INTEL, ...), but this is only a stop-gap measure to fix buggy
475 OpenGL drivers (moreover, it is only useful for old 1.0 apps
476 that query the glBindTextureEXT extension).
478 memcpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
479 buf[strlen(ext_ret->glx_name) - 3] = '\0';
480 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
482 ret = GetProcAddress(opengl32_handle, buf);
484 TRACE(" found function in main OpenGL library (%p) !\n", ret);
486 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
491 TRACE(" returning function (%p)\n", ext_ret->func);
492 *(ext_ret->func_ptr) = local_func;
494 return ext_ret->func;
499 static int describeContext(Wine_GLContext* ctx) {
502 TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
503 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
504 TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
505 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
506 TRACE(" - VISUAL_ID 0x%x\n", tmp);
511 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
514 if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable) {
515 /** glXQueryDrawable not available so returns not supported */
518 TRACE(" Drawable %p have :\n", (void*) drawable);
519 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
520 TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
521 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_VISUAL_ID, (unsigned int*) &tmp);
522 TRACE(" - VISUAL_ID as 0x%x\n", tmp);
524 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
525 TRACE(" - WIDTH as %d\n", tmp);
526 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
527 TRACE(" - HEIGHT as %d\n", tmp);
531 /***********************************************************************
532 * wglMakeCurrent (OPENGL32.@)
534 BOOL WINAPI wglMakeCurrent(HDC hdc,
537 DWORD type = GetObjectType(hdc);
539 TRACE("(%p,%p)\n", hdc, hglrc);
543 ret = glXMakeCurrent(default_display, None, NULL);
545 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
546 Drawable drawable = get_drawable( hdc );
547 if (ctx->ctx == NULL) {
548 int draw_vis_id, ctx_vis_id;
549 VisualID visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
550 TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid);
551 draw_vis_id = describeDrawable(ctx, drawable);
552 ctx_vis_id = describeContext(ctx);
554 if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
556 * Inherits from root window so reuse desktop visual
558 XVisualInfo template;
561 template.visualid = visualid;
562 vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
564 TRACE(" Creating GLX Context\n");
565 ctx->ctx = glXCreateContext(ctx->display, vis, NULL, type == OBJ_MEMDC ? False : True);
567 TRACE(" Creating GLX Context\n");
568 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, type == OBJ_MEMDC ? False : True);
570 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
572 TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
573 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
574 if(ret && type == OBJ_MEMDC)
575 glDrawBuffer(GL_FRONT_LEFT);
578 TRACE(" returning %s\n", (ret ? "True" : "False"));
582 /***********************************************************************
583 * wglMakeContextCurrentARB (OPENGL32.@)
585 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
588 TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
592 ret = glXMakeCurrent(default_display, None, NULL);
594 if (NULL == wine_glx.p_glXMakeContextCurrent) {
597 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
598 Drawable d_draw = get_drawable( hDrawDC );
599 Drawable d_read = get_drawable( hReadDC );
601 if (ctx->ctx == NULL) {
602 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, GetObjectType(hDrawDC) == OBJ_MEMDC ? False : True);
603 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
605 ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
610 TRACE(" returning %s\n", (ret ? "True" : "False"));
614 /***********************************************************************
615 * wglGetCurrentReadDCARB (OPENGL32.@)
617 HDC WINAPI wglGetCurrentReadDCARB(void)
625 gl_d = glXGetCurrentReadDrawable();
626 ret = get_hdc_from_Drawable(gl_d);
629 TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
635 /***********************************************************************
636 * wglRealizeLayerPalette (OPENGL32.@)
638 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
646 /***********************************************************************
647 * wglSetLayerPaletteEntries (OPENGL32.@)
649 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
653 const COLORREF *pcr) {
654 FIXME("(): stub !\n");
659 /***********************************************************************
660 * wglShareLists (OPENGL32.@)
662 BOOL WINAPI wglShareLists(HGLRC hglrc1,
664 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
665 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
667 TRACE("(%p, %p)\n", org, dest);
669 if (NULL != dest && dest->ctx != NULL) {
670 ERR("Could not share display lists, context already created !\n");
673 if (org->ctx == NULL) {
675 describeContext(org);
676 org->ctx = glXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
678 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
682 describeContext(dest);
683 /* Create the destination context with display lists shared */
684 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
686 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
693 /***********************************************************************
694 * wglSwapLayerBuffers (OPENGL32.@)
696 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
698 TRACE("(%p, %08x)\n", hdc, fuPlanes);
700 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
701 if (!SwapBuffers(hdc)) return FALSE;
702 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
706 WARN("Following layers unhandled : %08x\n", fuPlanes);
712 static BOOL internal_wglUseFontBitmaps(HDC hdc,
716 DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
718 /* We are running using client-side rendering fonts... */
722 void *bitmap = NULL, *gl_bitmap = NULL;
726 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
727 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
730 for (glyph = first; glyph < first + count; glyph++) {
731 unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
732 int height, width_int;
734 TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
735 if (needed_size == GDI_ERROR) {
736 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size);
739 TRACE(" - needed size : %d\n", needed_size);
742 if (needed_size > size) {
744 HeapFree(GetProcessHeap(), 0, bitmap);
745 HeapFree(GetProcessHeap(), 0, gl_bitmap);
746 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
747 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
749 if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
750 if (TRACE_ON(opengl)) {
751 unsigned int height, width, bitmask;
752 unsigned char *bitmap_ = (unsigned char *) bitmap;
754 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
755 TRACE(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
756 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
757 if (needed_size != 0) {
758 TRACE(" - bitmap :\n");
759 for (height = 0; height < gm.gmBlackBoxY; height++) {
761 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
766 if (*bitmap_ & bitmask)
771 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
777 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
778 * glyph for it to be drawn properly.
780 if (needed_size != 0) {
781 width_int = (gm.gmBlackBoxX + 31) / 32;
782 for (height = 0; height < gm.gmBlackBoxY; height++) {
784 for (width = 0; width < width_int; width++) {
785 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
786 ((int *) bitmap)[height * width_int + width];
792 glNewList(listBase++, GL_COMPILE);
793 if (needed_size != 0) {
794 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
795 0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
796 gm.gmCellIncX, gm.gmCellIncY,
799 /* This is the case of 'empty' glyphs like the space character */
800 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
807 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
810 HeapFree(GetProcessHeap(), 0, bitmap);
811 HeapFree(GetProcessHeap(), 0, gl_bitmap);
816 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
819 HeapFree(GetProcessHeap(), 0, bitmap);
820 HeapFree(GetProcessHeap(), 0, gl_bitmap);
824 /***********************************************************************
825 * wglUseFontBitmapsA (OPENGL32.@)
827 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
832 Font fid = get_font( hdc );
834 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
837 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
841 /* I assume that the glyphs are at the same position for X and for Windows */
842 glXUseXFont(fid, first, count, listBase);
847 /***********************************************************************
848 * wglUseFontBitmapsW (OPENGL32.@)
850 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
855 Font fid = get_font( hdc );
857 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
860 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
863 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
866 /* I assume that the glyphs are at the same position for X and for Windows */
867 glXUseXFont(fid, first, count, listBase);
874 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
876 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
877 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
881 static void tess_callback_vertex(GLvoid *vertex)
883 GLdouble *dbl = vertex;
884 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
888 static void tess_callback_begin(GLenum which)
890 TRACE("%d\n", which);
894 static void tess_callback_end(void)
900 /***********************************************************************
901 * wglUseFontOutlines_common
903 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
910 LPGLYPHMETRICSFLOAT lpgmf,
914 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
917 HFONT old_font, unscaled_font;
921 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
922 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
929 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
930 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
931 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
935 if(!tess) return FALSE;
937 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
938 rc.left = rc.right = rc.bottom = 0;
940 DPtoLP(hdc, (POINT*)&rc, 2);
941 lf.lfHeight = -abs(rc.top - rc.bottom);
942 lf.lfOrientation = lf.lfEscapement = 0;
943 unscaled_font = CreateFontIndirectW(&lf);
944 old_font = SelectObject(hdc, unscaled_font);
946 for (glyph = first; glyph < first + count; glyph++)
951 TTPOLYGONHEADER *pph;
956 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
958 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
960 if(needed == GDI_ERROR)
963 buf = HeapAlloc(GetProcessHeap(), 0, needed);
964 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
967 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
969 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
971 TRACE("glyph %d\n", glyph);
975 lpgmf->gmfBlackBoxX = gm.gmBlackBoxX / em_size;
976 lpgmf->gmfBlackBoxY = gm.gmBlackBoxY / em_size;
977 lpgmf->gmfptGlyphOrigin.x = gm.gmptGlyphOrigin.x / em_size;
978 lpgmf->gmfptGlyphOrigin.y = gm.gmptGlyphOrigin.y / em_size;
979 lpgmf->gmfCellIncX = gm.gmCellIncX / em_size;
980 lpgmf->gmfCellIncY = gm.gmCellIncY / em_size;
981 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
982 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
987 glNewList(listBase++, GL_COMPILE);
988 gluTessBeginPolygon(tess, NULL);
990 pph = (TTPOLYGONHEADER*)buf;
991 while((BYTE*)pph < buf + needed)
993 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
995 gluTessBeginContour(tess);
997 fixed_to_double(pph->pfxStart, em_size, vertices);
998 gluTessVertex(tess, vertices, vertices);
1001 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1002 while((char*)ppc < (char*)pph + pph->cb)
1006 switch(ppc->wType) {
1008 for(i = 0; i < ppc->cpfx; i++)
1010 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1011 fixed_to_double(ppc->apfx[i], em_size, vertices);
1012 gluTessVertex(tess, vertices, vertices);
1017 case TT_PRIM_QSPLINE:
1018 for(i = 0; i < ppc->cpfx/2; i++)
1020 /* FIXME just connecting the control points for now */
1021 TRACE("\t\tcurve %d,%d %d,%d\n",
1022 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
1023 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
1024 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
1025 gluTessVertex(tess, vertices, vertices);
1027 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
1028 gluTessVertex(tess, vertices, vertices);
1033 ERR("\t\tcurve type = %d\n", ppc->wType);
1034 gluTessEndContour(tess);
1038 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1039 (ppc->cpfx - 1) * sizeof(POINTFX));
1041 gluTessEndContour(tess);
1042 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1046 gluTessEndPolygon(tess);
1049 HeapFree(GetProcessHeap(), 0, buf);
1050 HeapFree(GetProcessHeap(), 0, vertices);
1054 DeleteObject(SelectObject(hdc, old_font));
1055 gluDeleteTess(tess);
1060 #else /* HAVE_GL_GLU_H */
1062 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
1069 LPGLYPHMETRICSFLOAT lpgmf,
1072 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1076 #endif /* HAVE_GL_GLU_H */
1078 /***********************************************************************
1079 * wglUseFontOutlinesA (OPENGL32.@)
1081 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1088 LPGLYPHMETRICSFLOAT lpgmf)
1090 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1093 /***********************************************************************
1094 * wglUseFontOutlinesW (OPENGL32.@)
1096 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
1103 LPGLYPHMETRICSFLOAT lpgmf)
1105 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1108 const GLubyte * internal_glGetString(GLenum name) {
1109 const char* GL_Extensions = NULL;
1111 if (GL_EXTENSIONS != name) {
1112 return glGetString(name);
1115 if (NULL == internal_gl_extensions) {
1116 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1118 TRACE("GL_EXTENSIONS reported:\n");
1119 if (NULL == GL_Extensions) {
1120 ERR("GL_EXTENSIONS returns NULL\n");
1123 size_t len = strlen(GL_Extensions);
1124 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1126 while (*GL_Extensions != 0x00) {
1127 const char* Start = GL_Extensions;
1130 memset(ThisExtn, 0x00, sizeof(ThisExtn));
1131 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1134 memcpy(ThisExtn, Start, (GL_Extensions - Start));
1135 TRACE("- %s:", ThisExtn);
1137 /* test if supported API is disabled by config */
1138 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
1139 strcat(internal_gl_extensions, " ");
1140 strcat(internal_gl_extensions, ThisExtn);
1143 TRACE(" deactived (by config)\n");
1146 if (*GL_Extensions == ' ') GL_Extensions++;
1150 return (const GLubyte *) internal_gl_extensions;
1153 void internal_glGetIntegerv(GLenum pname, GLint* params) {
1154 glGetIntegerv(pname, params);
1155 if (pname == GL_DEPTH_BITS) {
1156 GLXContext gl_ctx = glXGetCurrentContext();
1157 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1158 /*TRACE("returns Wine Ctx as %p\n", ret);*/
1160 * if we cannot find a Wine Context
1161 * we only have the default wine desktop context,
1162 * so if we have only a 24 depth say we have 32
1164 if (NULL == ret && 24 == *params) {
1167 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
1169 if (pname == GL_ALPHA_BITS) {
1171 GLXContext gl_ctx = glXGetCurrentContext();
1172 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1173 glXGetFBConfigAttrib(ret->display, ret->fb_conf, GLX_ALPHA_SIZE, &tmp);
1174 TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp);
1180 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1181 include all dependencies
1183 #ifndef SONAME_LIBGL
1184 #define SONAME_LIBGL "libGL.so"
1187 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc)
1189 const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
1190 const char *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1192 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1193 const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1194 const char *glx_extensions = glXQueryExtensionsString(display, screen);
1197 memset(&wine_glx, 0, sizeof(wine_glx));
1199 if (!strcmp("1.2", server_glx_version)) {
1200 wine_glx.version = 2;
1202 wine_glx.version = 3;
1205 if (2 < wine_glx.version) {
1206 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
1207 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
1208 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
1210 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1211 wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
1213 if (NULL != strstr(server_glx_extensions, "GLX_SGIX_fbconfig")) {
1214 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
1215 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
1216 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
1218 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version);
1221 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1222 wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
1223 wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
1226 /* This is for brain-dead applications that use OpenGL functions before even
1227 creating a rendering context.... */
1228 static BOOL process_attach(void)
1230 XWindowAttributes win_attr;
1233 XVisualInfo template;
1235 XVisualInfo *vis = NULL;
1236 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1237 HMODULE mod = GetModuleHandleA( "winex11.drv" );
1238 void *opengl_handle;
1239 DWORD size = sizeof(internal_gl_disabled_extensions);
1244 ERR("X11DRV not loaded. Cannot create default context.\n");
1248 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1249 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1252 default_display = get_display( hdc );
1253 ReleaseDC( 0, hdc );
1254 if (!default_display)
1256 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1262 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1263 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1264 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1265 with mismatched visuals. Note that the Root Window visual may not be double
1266 buffered, so apps actually attempting to render this way may flicker */
1267 if (XGetWindowAttributes( default_display, root, &win_attr ))
1269 rootVisual = win_attr.visual;
1273 /* Get the default visual, since we can't seem to get the attributes from the
1274 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1275 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1278 template.visualid = XVisualIDFromVisual(rootVisual);
1279 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1280 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1281 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1285 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1286 if (opengl_handle != NULL) {
1287 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1288 wine_dlclose(opengl_handle, NULL, 0);
1289 if (p_glXGetProcAddressARB == NULL)
1290 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1293 internal_gl_disabled_extensions[0] = 0;
1294 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1295 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1296 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1301 if (default_cx == NULL) {
1302 ERR("Could not create default context.\n");
1306 /* After context initialize also the list of supported WGL extensions. */
1307 wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1308 wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1314 /**********************************************************************/
1316 static void process_detach(void)
1318 glXDestroyContext(default_display, default_cx);
1320 /* Do not leak memory... */
1321 wgl_ext_finalize_extensions();
1322 if (NULL != internal_gl_extensions) {
1323 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1327 /***********************************************************************
1328 * OpenGL initialisation routine
1330 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1334 case DLL_PROCESS_ATTACH:
1335 opengl32_handle = hinst;
1336 DisableThreadLibraryCalls(hinst);
1337 return process_attach();
1338 case DLL_PROCESS_DETACH: