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"
38 #include "opengl_ext.h"
44 #include "wine/library.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
49 /** global glx object */
52 /* x11drv GDI escapes */
53 #define X11DRV_ESCAPE 6789
54 enum x11drv_escape_codes
56 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
57 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
58 X11DRV_GET_FONT, /* get current X font for a DC */
59 X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
60 X11DRV_START_EXPOSURES, /* start graphics exposures */
61 X11DRV_END_EXPOSURES, /* end graphics exposures */
62 X11DRV_GET_DCE, /* get the DCE pointer */
63 X11DRV_SET_DCE, /* set the DCE pointer */
64 X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */
65 X11DRV_SYNC_PIXMAP /* sync the dibsection to its pixmap */
68 void (*wine_tsx11_lock_ptr)(void) = NULL;
69 void (*wine_tsx11_unlock_ptr)(void) = NULL;
71 static GLXContext default_cx = NULL;
72 static Display *default_display; /* display to use for default context */
74 static HMODULE opengl32_handle;
76 static glXGetProcAddressARB_t p_glXGetProcAddressARB = NULL;
78 static char internal_gl_disabled_extensions[512];
79 static char* internal_gl_extensions = NULL;
81 typedef struct wine_glcontext {
88 struct wine_glcontext *next;
89 struct wine_glcontext *prev;
91 static Wine_GLContext *context_list;
93 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
96 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
102 Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
104 if (curctx && curctx->do_escape)
106 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
107 ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
110 wine_tsx11_lock_ptr();
114 static inline void free_context(Wine_GLContext *context)
116 if (context->next != NULL) context->next->prev = context->prev;
117 if (context->prev != NULL) context->prev->next = context->next;
118 else context_list = context->next;
120 HeapFree(GetProcessHeap(), 0, context);
123 static inline Wine_GLContext *alloc_context(void)
127 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
129 ret->next = context_list;
130 if (context_list) context_list->prev = ret;
136 inline static BOOL is_valid_context( Wine_GLContext *ctx )
139 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
140 return (ptr != NULL);
143 /* retrieve the X display to use on a given DC */
144 inline static Display *get_display( HDC hdc )
147 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
149 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
150 sizeof(display), (LPSTR)&display )) display = NULL;
155 /* retrieve the GLX drawable to use on a given DC */
156 inline static Drawable get_drawable( HDC hdc )
158 GLXDrawable drawable;
159 enum x11drv_escape_codes escape = X11DRV_GET_GLX_DRAWABLE;
161 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
162 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
166 /** for use of wglGetCurrentReadDCARB */
167 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
170 for (ret = context_list; ret; ret = ret->next) {
171 if (d == get_drawable( ret->hdc )) {
178 /* retrieve the X font to use on a given DC */
179 inline static Font get_font( HDC hdc )
182 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
184 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
185 sizeof(font), (LPSTR)&font )) font = 0;
190 /***********************************************************************
191 * wglCreateContext (OPENGL32.@)
193 HGLRC WINAPI wglCreateContext(HDC hdc)
197 XVisualInfo template;
198 XVisualInfo *vis = NULL;
199 Display *display = get_display( hdc );
200 int hdcPF = GetPixelFormat(hdc);
203 TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
205 /* First, get the visual in use by the X11DRV */
206 if (!display) return 0;
207 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
208 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
211 ERR("NULL visual !!!\n");
212 /* Need to set errors here */
216 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
222 GLXFBConfig* cfgs_fmt = NULL;
225 cfgs_fmt = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs_fmt);
226 if (NULL == cfgs_fmt || 0 == nCfgs_fmt) {
227 ERR("Cannot get FB Configs, expect problems.\n");
228 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
231 if (nCfgs_fmt < hdcPF) {
232 ERR("(%p): unexpected pixelFormat(%d) > nFormats(%d), returns NULL\n", hdc, hdcPF, nCfgs_fmt);
233 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
236 cur_cfg = cfgs_fmt[hdcPF - 1];
237 gl_test = wine_glx.p_glXGetFBConfigAttrib(display, cur_cfg, GLX_FBCONFIG_ID, &value);
239 ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
240 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
246 /* The context will be allocated in the wglMakeCurrent call */
248 ret = alloc_context();
251 ret->display = display;
252 ret->fb_conf = cur_cfg;
254 ret->vis = wine_glx.p_glXGetVisualFromFBConfig(display, cur_cfg);
256 TRACE(" creating context %p (GL context creation delayed)\n", ret);
260 /***********************************************************************
261 * wglCreateLayerContext (OPENGL32.@)
263 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
265 TRACE("(%p,%d)\n", hdc, iLayerPlane);
267 if (iLayerPlane == 0) {
268 return wglCreateContext(hdc);
270 FIXME(" no handler for layer %d\n", iLayerPlane);
275 /***********************************************************************
276 * wglCopyContext (OPENGL32.@)
278 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
281 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
286 /***********************************************************************
287 * wglDeleteContext (OPENGL32.@)
289 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
291 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
294 TRACE("(%p)\n", hglrc);
297 /* A game (Half Life not to name it) deletes twice the same context,
298 * so make sure it is valid first */
299 if (is_valid_context( ctx ))
301 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
306 WARN("Error deleting context !\n");
307 SetLastError(ERROR_INVALID_HANDLE);
315 /***********************************************************************
316 * wglDescribeLayerPlane (OPENGL32.@)
318 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
322 LPLAYERPLANEDESCRIPTOR plpd) {
323 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
328 /***********************************************************************
329 * wglGetCurrentContext (OPENGL32.@)
331 HGLRC WINAPI wglGetCurrentContext(void) {
338 gl_ctx = glXGetCurrentContext();
339 ret = get_context_from_GLXContext(gl_ctx);
342 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
347 /***********************************************************************
348 * wglGetCurrentDC (OPENGL32.@)
350 HDC WINAPI wglGetCurrentDC(void) {
357 gl_ctx = glXGetCurrentContext();
358 ret = get_context_from_GLXContext(gl_ctx);
362 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
365 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
370 /***********************************************************************
371 * wglGetLayerPaletteEntries (OPENGL32.@)
373 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
377 const COLORREF *pcr) {
378 FIXME("(): stub !\n");
383 /***********************************************************************
384 * wglGetProcAddress (OPENGL32.@)
386 static int compar(const void *elt_a, const void *elt_b) {
387 return strcmp(((const OpenGL_extension *) elt_a)->name,
388 ((const OpenGL_extension *) elt_b)->name);
391 static int wgl_compar(const void *elt_a, const void *elt_b) {
392 return strcmp(((const WGL_extension *) elt_a)->func_name,
393 ((const WGL_extension *) elt_b)->func_name);
396 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
398 OpenGL_extension ext;
399 OpenGL_extension *ext_ret;
401 TRACE("(%s)\n", lpszProc);
403 /* First, look if it's not already defined in the 'standard' OpenGL functions */
404 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
405 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
409 if (p_glXGetProcAddressARB == NULL) {
410 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
414 /* After that, search in the thunks to find the real name of the extension */
415 ext.name = (char *) lpszProc;
416 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
417 extension_registry_size, sizeof(OpenGL_extension), compar);
419 if (ext_ret == NULL) {
420 WGL_extension wgl_ext, *wgl_ext_ret;
422 /* Try to find the function in the WGL extensions ... */
423 wgl_ext.func_name = (char *) lpszProc;
424 wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
425 wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
427 if (wgl_ext_ret == NULL) {
428 /* Some sanity checks :-) */
430 local_func = p_glXGetProcAddressARB( (const GLubyte *) lpszProc);
432 if (local_func != NULL) {
433 WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
437 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
442 if (wgl_ext_ret->func_init != NULL) {
444 if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
445 wgl_ext_ret->context)) == NULL) {
446 ret = wgl_ext_ret->func_address;
448 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
452 ret = wgl_ext_ret->func_address;
456 TRACE(" returning WGL function (%p)\n", ret);
461 local_func = p_glXGetProcAddressARB( (const GLubyte*) ext_ret->glx_name);
464 /* After that, look at the extensions defined in the Linux OpenGL library */
465 if (local_func == NULL) {
469 /* Remove the 3 last letters (EXT, ARB, ...).
471 I know that some extensions have more than 3 letters (MESA, NV,
472 INTEL, ...), but this is only a stop-gap measure to fix buggy
473 OpenGL drivers (moreover, it is only useful for old 1.0 apps
474 that query the glBindTextureEXT extension).
476 memcpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
477 buf[strlen(ext_ret->glx_name) - 3] = '\0';
478 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
480 ret = GetProcAddress(opengl32_handle, buf);
482 TRACE(" found function in main OpenGL library (%p) !\n", ret);
484 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
489 TRACE(" returning function (%p)\n", ext_ret->func);
490 *(ext_ret->func_ptr) = local_func;
492 return ext_ret->func;
497 static int describeContext(Wine_GLContext* ctx) {
500 TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
501 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
502 TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
503 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
504 TRACE(" - VISUAL_ID 0x%x\n", tmp);
509 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
512 if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable) {
513 /** glXQueryDrawable not available so returns not supported */
516 TRACE(" Drawable %p have :\n", (void*) drawable);
517 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
518 TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
519 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_VISUAL_ID, (unsigned int*) &tmp);
520 TRACE(" - VISUAL_ID as 0x%x\n", tmp);
522 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
523 TRACE(" - WIDTH as %d\n", tmp);
524 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
525 TRACE(" - HEIGHT as %d\n", tmp);
529 /***********************************************************************
530 * wglMakeCurrent (OPENGL32.@)
532 BOOL WINAPI wglMakeCurrent(HDC hdc,
535 DWORD type = GetObjectType(hdc);
537 TRACE("(%p,%p)\n", hdc, hglrc);
541 ret = glXMakeCurrent(default_display, None, NULL);
542 NtCurrentTeb()->glContext = NULL;
544 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
545 Drawable drawable = get_drawable( hdc );
546 if (ctx->ctx == NULL) {
547 int draw_vis_id, ctx_vis_id;
548 VisualID visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
549 TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid);
550 draw_vis_id = describeDrawable(ctx, drawable);
551 ctx_vis_id = describeContext(ctx);
553 if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
555 * Inherits from root window so reuse desktop visual
557 XVisualInfo template;
560 template.visualid = visualid;
561 vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
563 TRACE(" Creating GLX Context\n");
564 ctx->ctx = glXCreateContext(ctx->display, vis, NULL, type == OBJ_MEMDC ? False : True);
566 TRACE(" Creating GLX Context\n");
567 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, type == OBJ_MEMDC ? False : True);
569 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
571 TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
572 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
573 NtCurrentTeb()->glContext = ctx;
574 if(ret && type == OBJ_MEMDC)
576 ctx->do_escape = TRUE;
577 glDrawBuffer(GL_FRONT_LEFT);
581 TRACE(" returning %s\n", (ret ? "True" : "False"));
585 /***********************************************************************
586 * wglMakeContextCurrentARB (OPENGL32.@)
588 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
591 TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
595 ret = glXMakeCurrent(default_display, None, NULL);
597 if (NULL == wine_glx.p_glXMakeContextCurrent) {
600 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
601 Drawable d_draw = get_drawable( hDrawDC );
602 Drawable d_read = get_drawable( hReadDC );
604 if (ctx->ctx == NULL) {
605 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, GetObjectType(hDrawDC) == OBJ_MEMDC ? False : True);
606 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
608 ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
613 TRACE(" returning %s\n", (ret ? "True" : "False"));
617 /***********************************************************************
618 * wglGetCurrentReadDCARB (OPENGL32.@)
620 HDC WINAPI wglGetCurrentReadDCARB(void)
628 gl_d = glXGetCurrentReadDrawable();
629 ret = get_hdc_from_Drawable(gl_d);
632 TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
638 /***********************************************************************
639 * wglRealizeLayerPalette (OPENGL32.@)
641 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
649 /***********************************************************************
650 * wglSetLayerPaletteEntries (OPENGL32.@)
652 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
656 const COLORREF *pcr) {
657 FIXME("(): stub !\n");
662 /***********************************************************************
663 * wglShareLists (OPENGL32.@)
665 BOOL WINAPI wglShareLists(HGLRC hglrc1,
667 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
668 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
670 TRACE("(%p, %p)\n", org, dest);
672 if (NULL != dest && dest->ctx != NULL) {
673 ERR("Could not share display lists, context already created !\n");
676 if (org->ctx == NULL) {
678 describeContext(org);
679 org->ctx = glXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
681 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
685 describeContext(dest);
686 /* Create the destination context with display lists shared */
687 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
689 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
696 /***********************************************************************
697 * wglSwapLayerBuffers (OPENGL32.@)
699 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
701 TRACE("(%p, %08x)\n", hdc, fuPlanes);
703 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
704 if (!SwapBuffers(hdc)) return FALSE;
705 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
709 WARN("Following layers unhandled : %08x\n", fuPlanes);
715 static BOOL internal_wglUseFontBitmaps(HDC hdc,
719 DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
721 /* We are running using client-side rendering fonts... */
725 void *bitmap = NULL, *gl_bitmap = NULL;
729 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
730 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
733 for (glyph = first; glyph < first + count; glyph++) {
734 unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
735 int height, width_int;
737 TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
738 if (needed_size == GDI_ERROR) {
739 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size);
742 TRACE(" - needed size : %d\n", needed_size);
745 if (needed_size > size) {
747 HeapFree(GetProcessHeap(), 0, bitmap);
748 HeapFree(GetProcessHeap(), 0, gl_bitmap);
749 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
750 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
752 if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
753 if (TRACE_ON(opengl)) {
754 unsigned int height, width, bitmask;
755 unsigned char *bitmap_ = (unsigned char *) bitmap;
757 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
758 TRACE(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
759 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
760 if (needed_size != 0) {
761 TRACE(" - bitmap :\n");
762 for (height = 0; height < gm.gmBlackBoxY; height++) {
764 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
769 if (*bitmap_ & bitmask)
774 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
780 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
781 * glyph for it to be drawn properly.
783 if (needed_size != 0) {
784 width_int = (gm.gmBlackBoxX + 31) / 32;
785 for (height = 0; height < gm.gmBlackBoxY; height++) {
787 for (width = 0; width < width_int; width++) {
788 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
789 ((int *) bitmap)[height * width_int + width];
795 glNewList(listBase++, GL_COMPILE);
796 if (needed_size != 0) {
797 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
798 0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
799 gm.gmCellIncX, gm.gmCellIncY,
802 /* This is the case of 'empty' glyphs like the space character */
803 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
810 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
813 HeapFree(GetProcessHeap(), 0, bitmap);
814 HeapFree(GetProcessHeap(), 0, gl_bitmap);
819 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
822 HeapFree(GetProcessHeap(), 0, bitmap);
823 HeapFree(GetProcessHeap(), 0, gl_bitmap);
827 /***********************************************************************
828 * wglUseFontBitmapsA (OPENGL32.@)
830 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
835 Font fid = get_font( hdc );
837 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
840 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
844 /* I assume that the glyphs are at the same position for X and for Windows */
845 glXUseXFont(fid, first, count, listBase);
850 /***********************************************************************
851 * wglUseFontBitmapsW (OPENGL32.@)
853 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
858 Font fid = get_font( hdc );
860 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
863 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
866 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
869 /* I assume that the glyphs are at the same position for X and for Windows */
870 glXUseXFont(fid, first, count, listBase);
877 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
879 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
880 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
884 static void tess_callback_vertex(GLvoid *vertex)
886 GLdouble *dbl = vertex;
887 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
891 static void tess_callback_begin(GLenum which)
893 TRACE("%d\n", which);
897 static void tess_callback_end(void)
903 /***********************************************************************
904 * wglUseFontOutlines_common
906 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
913 LPGLYPHMETRICSFLOAT lpgmf,
917 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
920 HFONT old_font, unscaled_font;
924 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
925 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
932 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
933 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
934 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
938 if(!tess) return FALSE;
940 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
941 rc.left = rc.right = rc.bottom = 0;
943 DPtoLP(hdc, (POINT*)&rc, 2);
944 lf.lfHeight = -abs(rc.top - rc.bottom);
945 lf.lfOrientation = lf.lfEscapement = 0;
946 unscaled_font = CreateFontIndirectW(&lf);
947 old_font = SelectObject(hdc, unscaled_font);
949 for (glyph = first; glyph < first + count; glyph++)
954 TTPOLYGONHEADER *pph;
959 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
961 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
963 if(needed == GDI_ERROR)
966 buf = HeapAlloc(GetProcessHeap(), 0, needed);
967 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
970 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
972 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
974 TRACE("glyph %d\n", glyph);
978 lpgmf->gmfBlackBoxX = gm.gmBlackBoxX / em_size;
979 lpgmf->gmfBlackBoxY = gm.gmBlackBoxY / em_size;
980 lpgmf->gmfptGlyphOrigin.x = gm.gmptGlyphOrigin.x / em_size;
981 lpgmf->gmfptGlyphOrigin.y = gm.gmptGlyphOrigin.y / em_size;
982 lpgmf->gmfCellIncX = gm.gmCellIncX / em_size;
983 lpgmf->gmfCellIncY = gm.gmCellIncY / em_size;
984 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
985 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
990 glNewList(listBase++, GL_COMPILE);
991 gluTessBeginPolygon(tess, NULL);
993 pph = (TTPOLYGONHEADER*)buf;
994 while((BYTE*)pph < buf + needed)
996 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
998 gluTessBeginContour(tess);
1000 fixed_to_double(pph->pfxStart, em_size, vertices);
1001 gluTessVertex(tess, vertices, vertices);
1004 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1005 while((char*)ppc < (char*)pph + pph->cb)
1009 switch(ppc->wType) {
1011 for(i = 0; i < ppc->cpfx; i++)
1013 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1014 fixed_to_double(ppc->apfx[i], em_size, vertices);
1015 gluTessVertex(tess, vertices, vertices);
1020 case TT_PRIM_QSPLINE:
1021 for(i = 0; i < ppc->cpfx/2; i++)
1023 /* FIXME just connecting the control points for now */
1024 TRACE("\t\tcurve %d,%d %d,%d\n",
1025 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
1026 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
1027 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
1028 gluTessVertex(tess, vertices, vertices);
1030 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
1031 gluTessVertex(tess, vertices, vertices);
1036 ERR("\t\tcurve type = %d\n", ppc->wType);
1037 gluTessEndContour(tess);
1041 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1042 (ppc->cpfx - 1) * sizeof(POINTFX));
1044 gluTessEndContour(tess);
1045 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1049 gluTessEndPolygon(tess);
1052 HeapFree(GetProcessHeap(), 0, buf);
1053 HeapFree(GetProcessHeap(), 0, vertices);
1057 DeleteObject(SelectObject(hdc, old_font));
1058 gluDeleteTess(tess);
1063 #else /* HAVE_GL_GLU_H */
1065 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
1072 LPGLYPHMETRICSFLOAT lpgmf,
1075 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1079 #endif /* HAVE_GL_GLU_H */
1081 /***********************************************************************
1082 * wglUseFontOutlinesA (OPENGL32.@)
1084 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1091 LPGLYPHMETRICSFLOAT lpgmf)
1093 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1096 /***********************************************************************
1097 * wglUseFontOutlinesW (OPENGL32.@)
1099 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
1106 LPGLYPHMETRICSFLOAT lpgmf)
1108 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1111 const GLubyte * internal_glGetString(GLenum name) {
1112 const char* GL_Extensions = NULL;
1114 if (GL_EXTENSIONS != name) {
1115 return glGetString(name);
1118 if (NULL == internal_gl_extensions) {
1119 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1121 TRACE("GL_EXTENSIONS reported:\n");
1122 if (NULL == GL_Extensions) {
1123 ERR("GL_EXTENSIONS returns NULL\n");
1126 size_t len = strlen(GL_Extensions);
1127 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1129 while (*GL_Extensions != 0x00) {
1130 const char* Start = GL_Extensions;
1133 memset(ThisExtn, 0x00, sizeof(ThisExtn));
1134 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1137 memcpy(ThisExtn, Start, (GL_Extensions - Start));
1138 TRACE("- %s:", ThisExtn);
1140 /* test if supported API is disabled by config */
1141 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
1142 strcat(internal_gl_extensions, " ");
1143 strcat(internal_gl_extensions, ThisExtn);
1146 TRACE(" deactived (by config)\n");
1149 if (*GL_Extensions == ' ') GL_Extensions++;
1153 return (const GLubyte *) internal_gl_extensions;
1156 void internal_glGetIntegerv(GLenum pname, GLint* params) {
1157 glGetIntegerv(pname, params);
1158 if (pname == GL_DEPTH_BITS) {
1159 GLXContext gl_ctx = glXGetCurrentContext();
1160 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1161 /*TRACE("returns Wine Ctx as %p\n", ret);*/
1163 * if we cannot find a Wine Context
1164 * we only have the default wine desktop context,
1165 * so if we have only a 24 depth say we have 32
1167 if (NULL == ret && 24 == *params) {
1170 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
1172 if (pname == GL_ALPHA_BITS) {
1174 GLXContext gl_ctx = glXGetCurrentContext();
1175 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1176 glXGetFBConfigAttrib(ret->display, ret->fb_conf, GLX_ALPHA_SIZE, &tmp);
1177 TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp);
1183 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1184 include all dependencies
1186 #ifndef SONAME_LIBGL
1187 #define SONAME_LIBGL "libGL.so"
1190 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc)
1192 const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
1193 const char *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1195 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1196 const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1197 const char *glx_extensions = glXQueryExtensionsString(display, screen);
1200 memset(&wine_glx, 0, sizeof(wine_glx));
1202 if (!strcmp("1.2", server_glx_version)) {
1203 wine_glx.version = 2;
1205 wine_glx.version = 3;
1208 if (2 < wine_glx.version) {
1209 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
1210 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
1211 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
1213 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1214 wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
1216 if (NULL != strstr(server_glx_extensions, "GLX_SGIX_fbconfig")) {
1217 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
1218 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
1219 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
1221 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version);
1224 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1225 wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
1226 wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
1229 /* This is for brain-dead applications that use OpenGL functions before even
1230 creating a rendering context.... */
1231 static BOOL process_attach(void)
1233 XWindowAttributes win_attr;
1236 XVisualInfo template;
1238 XVisualInfo *vis = NULL;
1239 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1240 HMODULE mod = GetModuleHandleA( "winex11.drv" );
1241 void *opengl_handle;
1242 DWORD size = sizeof(internal_gl_disabled_extensions);
1247 ERR("X11DRV not loaded. Cannot create default context.\n");
1251 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1252 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1255 default_display = get_display( hdc );
1256 ReleaseDC( 0, hdc );
1257 if (!default_display)
1259 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1265 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1266 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1267 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1268 with mismatched visuals. Note that the Root Window visual may not be double
1269 buffered, so apps actually attempting to render this way may flicker */
1270 if (XGetWindowAttributes( default_display, root, &win_attr ))
1272 rootVisual = win_attr.visual;
1276 /* Get the default visual, since we can't seem to get the attributes from the
1277 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1278 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1281 template.visualid = XVisualIDFromVisual(rootVisual);
1282 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1283 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1284 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1288 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1289 if (opengl_handle != NULL) {
1290 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1291 wine_dlclose(opengl_handle, NULL, 0);
1292 if (p_glXGetProcAddressARB == NULL)
1293 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1296 internal_gl_disabled_extensions[0] = 0;
1297 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1298 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1299 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1304 if (default_cx == NULL) {
1305 ERR("Could not create default context.\n");
1309 /* After context initialize also the list of supported WGL extensions. */
1310 wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1311 wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1317 /**********************************************************************/
1319 static void process_detach(void)
1321 glXDestroyContext(default_display, default_cx);
1323 /* Do not leak memory... */
1324 wgl_ext_finalize_extensions();
1325 if (NULL != internal_gl_extensions) {
1326 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1330 /***********************************************************************
1331 * OpenGL initialisation routine
1333 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1337 case DLL_PROCESS_ATTACH:
1338 opengl32_handle = hinst;
1339 DisableThreadLibraryCalls(hinst);
1340 return process_attach();
1341 case DLL_PROCESS_DETACH: