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 /** global glx object */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY
, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE
, /* get current drawable for a DC */
59 X11DRV_GET_FONT
, /* get current X font for a DC */
60 X11DRV_SET_DRAWABLE
, /* set current drawable for a DC */
61 X11DRV_START_EXPOSURES
, /* start graphics exposures */
62 X11DRV_END_EXPOSURES
, /* end graphics exposures */
63 X11DRV_GET_DCE
, /* get the DCE pointer */
64 X11DRV_SET_DCE
, /* set the DCE pointer */
65 X11DRV_GET_GLX_DRAWABLE
, /* get current glx drawable for a DC */
66 X11DRV_SYNC_PIXMAP
/* sync the dibsection to its pixmap */
69 void (*wine_tsx11_lock_ptr
)(void) = NULL
;
70 void (*wine_tsx11_unlock_ptr
)(void) = NULL
;
72 static GLXContext default_cx
= NULL
;
73 static Display
*default_display
; /* display to use for default context */
75 static HMODULE opengl32_handle
;
77 static glXGetProcAddressARB_t p_glXGetProcAddressARB
= NULL
;
79 static char internal_gl_disabled_extensions
[512];
80 static char* internal_gl_extensions
= NULL
;
82 typedef struct wine_glcontext
{
89 struct wine_glcontext
*next
;
90 struct wine_glcontext
*prev
;
92 static Wine_GLContext
*context_list
;
94 static inline Wine_GLContext
*get_context_from_GLXContext(GLXContext ctx
)
97 if (!ctx
) return NULL
;
98 for (ret
= context_list
; ret
; ret
= ret
->next
) if (ctx
== ret
->ctx
) break;
104 Wine_GLContext
*curctx
= (Wine_GLContext
*) NtCurrentTeb()->glContext
;
106 if (curctx
&& curctx
->do_escape
)
108 enum x11drv_escape_codes escape
= X11DRV_SYNC_PIXMAP
;
109 ExtEscape(curctx
->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 const 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 */
418 ext_ret
= (const 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
);
462 const char *glx_name
= ext_ret
->glx_name
? ext_ret
->glx_name
: ext_ret
->name
;
464 local_func
= p_glXGetProcAddressARB( (const GLubyte
*)glx_name
);
467 /* After that, look at the extensions defined in the Linux OpenGL library */
468 if (local_func
== NULL
) {
472 /* Remove the 3 last letters (EXT, ARB, ...).
474 I know that some extensions have more than 3 letters (MESA, NV,
475 INTEL, ...), but this is only a stop-gap measure to fix buggy
476 OpenGL drivers (moreover, it is only useful for old 1.0 apps
477 that query the glBindTextureEXT extension).
479 memcpy(buf
, glx_name
, strlen(glx_name
) - 3);
480 buf
[strlen(glx_name
) - 3] = '\0';
481 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf
);
483 ret
= GetProcAddress(opengl32_handle
, buf
);
485 TRACE(" found function in main OpenGL library (%p) !\n", ret
);
487 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc
, glx_name
);
492 TRACE(" returning function (%p)\n", ext_ret
->func
);
493 extension_funcs
[ext_ret
- extension_registry
] = local_func
;
495 return ext_ret
->func
;
500 static int describeContext(Wine_GLContext
* ctx
) {
503 TRACE(" Context %p have (vis:%p):\n", ctx
, ctx
->vis
);
504 wine_glx
.p_glXGetFBConfigAttrib(ctx
->display
, ctx
->fb_conf
, GLX_FBCONFIG_ID
, &tmp
);
505 TRACE(" - FBCONFIG_ID 0x%x\n", tmp
);
506 wine_glx
.p_glXGetFBConfigAttrib(ctx
->display
, ctx
->fb_conf
, GLX_VISUAL_ID
, &tmp
);
507 TRACE(" - VISUAL_ID 0x%x\n", tmp
);
512 static int describeDrawable(Wine_GLContext
* ctx
, Drawable drawable
) {
515 int attribList
[3] = { GLX_FBCONFIG_ID
, 0, None
};
518 if (3 > wine_glx
.version
|| NULL
== wine_glx
.p_glXQueryDrawable
) {
519 /** glXQueryDrawable not available so returns not supported */
523 TRACE(" Drawable %p have :\n", (void*) drawable
);
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
);
528 wine_glx
.p_glXQueryDrawable(ctx
->display
, drawable
, GLX_FBCONFIG_ID
, (unsigned int*) &tmp
);
529 TRACE(" - FBCONFIG_ID as 0x%x\n", tmp
);
532 fbCfgs
= wine_glx
.p_glXChooseFBConfig(ctx
->display
, DefaultScreen(ctx
->display
), attribList
, &nElements
);
533 if (fbCfgs
== NULL
) {
537 wine_glx
.p_glXGetFBConfigAttrib(ctx
->display
, fbCfgs
[0], GLX_VISUAL_ID
, &tmp
);
538 TRACE(" - VISUAL_ID as 0x%x\n", tmp
);
545 /***********************************************************************
546 * wglMakeCurrent (OPENGL32.@)
548 BOOL WINAPI
wglMakeCurrent(HDC hdc
,
551 DWORD type
= GetObjectType(hdc
);
553 TRACE("(%p,%p)\n", hdc
, hglrc
);
557 ret
= glXMakeCurrent(default_display
, None
, NULL
);
558 NtCurrentTeb()->glContext
= NULL
;
560 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
561 Drawable drawable
= get_drawable( hdc
);
562 if (ctx
->ctx
== NULL
) {
563 int draw_vis_id
, ctx_vis_id
;
564 VisualID visualid
= (VisualID
)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
565 TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid
);
566 draw_vis_id
= describeDrawable(ctx
, drawable
);
567 ctx_vis_id
= describeContext(ctx
);
569 if (-1 == draw_vis_id
|| (draw_vis_id
== visualid
&& draw_vis_id
!= ctx_vis_id
)) {
571 * Inherits from root window so reuse desktop visual
573 XVisualInfo
template;
576 template.visualid
= visualid
;
577 vis
= XGetVisualInfo(ctx
->display
, VisualIDMask
, &template, &num
);
579 TRACE(" Creating GLX Context\n");
580 ctx
->ctx
= glXCreateContext(ctx
->display
, vis
, NULL
, type
== OBJ_MEMDC
? False
: True
);
582 TRACE(" Creating GLX Context\n");
583 ctx
->ctx
= glXCreateContext(ctx
->display
, ctx
->vis
, NULL
, type
== OBJ_MEMDC
? False
: True
);
585 TRACE(" created a delayed OpenGL context (%p)\n", ctx
->ctx
);
587 TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx
->display
, (void*) drawable
, ctx
->ctx
);
588 ret
= glXMakeCurrent(ctx
->display
, drawable
, ctx
->ctx
);
589 NtCurrentTeb()->glContext
= ctx
;
590 if(ret
&& type
== OBJ_MEMDC
)
592 ctx
->do_escape
= TRUE
;
593 glDrawBuffer(GL_FRONT_LEFT
);
597 TRACE(" returning %s\n", (ret
? "True" : "False"));
601 /***********************************************************************
602 * wglMakeContextCurrentARB (OPENGL32.@)
604 BOOL WINAPI
wglMakeContextCurrentARB(HDC hDrawDC
, HDC hReadDC
, HGLRC hglrc
)
607 TRACE("(%p,%p,%p)\n", hDrawDC
, hReadDC
, hglrc
);
611 ret
= glXMakeCurrent(default_display
, None
, NULL
);
613 if (NULL
== wine_glx
.p_glXMakeContextCurrent
) {
616 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
617 Drawable d_draw
= get_drawable( hDrawDC
);
618 Drawable d_read
= get_drawable( hReadDC
);
620 if (ctx
->ctx
== NULL
) {
621 ctx
->ctx
= glXCreateContext(ctx
->display
, ctx
->vis
, NULL
, GetObjectType(hDrawDC
) == OBJ_MEMDC
? False
: True
);
622 TRACE(" created a delayed OpenGL context (%p)\n", ctx
->ctx
);
624 ret
= wine_glx
.p_glXMakeContextCurrent(ctx
->display
, d_draw
, d_read
, ctx
->ctx
);
629 TRACE(" returning %s\n", (ret
? "True" : "False"));
633 /***********************************************************************
634 * wglGetCurrentReadDCARB (OPENGL32.@)
636 HDC WINAPI
wglGetCurrentReadDCARB(void)
644 gl_d
= glXGetCurrentReadDrawable();
645 ret
= get_hdc_from_Drawable(gl_d
);
648 TRACE(" returning %p (GL drawable %lu)\n", ret
, gl_d
);
654 /***********************************************************************
655 * wglRealizeLayerPalette (OPENGL32.@)
657 BOOL WINAPI
wglRealizeLayerPalette(HDC hdc
,
665 /***********************************************************************
666 * wglSetLayerPaletteEntries (OPENGL32.@)
668 int WINAPI
wglSetLayerPaletteEntries(HDC hdc
,
672 const COLORREF
*pcr
) {
673 FIXME("(): stub !\n");
678 /***********************************************************************
679 * wglShareLists (OPENGL32.@)
681 BOOL WINAPI
wglShareLists(HGLRC hglrc1
,
683 Wine_GLContext
*org
= (Wine_GLContext
*) hglrc1
;
684 Wine_GLContext
*dest
= (Wine_GLContext
*) hglrc2
;
686 TRACE("(%p, %p)\n", org
, dest
);
688 if (NULL
!= dest
&& dest
->ctx
!= NULL
) {
689 ERR("Could not share display lists, context already created !\n");
692 if (org
->ctx
== NULL
) {
694 describeContext(org
);
695 org
->ctx
= glXCreateContext(org
->display
, org
->vis
, NULL
, GetObjectType(org
->hdc
) == OBJ_MEMDC
? False
: True
);
697 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org
->ctx
, org
);
701 describeContext(dest
);
702 /* Create the destination context with display lists shared */
703 dest
->ctx
= glXCreateContext(org
->display
, dest
->vis
, org
->ctx
, GetObjectType(org
->hdc
) == OBJ_MEMDC
? False
: True
);
705 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest
->ctx
, dest
, org
->ctx
);
712 /***********************************************************************
713 * wglSwapLayerBuffers (OPENGL32.@)
715 BOOL WINAPI
wglSwapLayerBuffers(HDC hdc
,
717 TRACE_(opengl
)("(%p, %08x)\n", hdc
, fuPlanes
);
719 if (fuPlanes
& WGL_SWAP_MAIN_PLANE
) {
720 if (!SwapBuffers(hdc
)) return FALSE
;
721 fuPlanes
&= ~WGL_SWAP_MAIN_PLANE
;
725 WARN("Following layers unhandled : %08x\n", fuPlanes
);
731 static BOOL
internal_wglUseFontBitmaps(HDC hdc
,
735 DWORD (WINAPI
*GetGlyphOutline_ptr
)(HDC
,UINT
,UINT
,LPGLYPHMETRICS
,DWORD
,LPVOID
,const MAT2
*))
737 /* We are running using client-side rendering fonts... */
741 void *bitmap
= NULL
, *gl_bitmap
= NULL
;
745 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &org_alignment
);
746 glPixelStorei(GL_UNPACK_ALIGNMENT
, 4);
749 for (glyph
= first
; glyph
< first
+ count
; glyph
++) {
750 unsigned int needed_size
= GetGlyphOutline_ptr(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, NULL
);
751 int height
, width_int
;
753 TRACE("Glyph : %3d / List : %ld\n", glyph
, listBase
);
754 if (needed_size
== GDI_ERROR
) {
755 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size
);
758 TRACE(" - needed size : %d\n", needed_size
);
761 if (needed_size
> size
) {
763 HeapFree(GetProcessHeap(), 0, bitmap
);
764 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
765 bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
766 gl_bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
768 if (GetGlyphOutline_ptr(hdc
, glyph
, GGO_BITMAP
, &gm
, size
, bitmap
, NULL
) == GDI_ERROR
) goto error
;
769 if (TRACE_ON(opengl
)) {
770 unsigned int height
, width
, bitmask
;
771 unsigned char *bitmap_
= (unsigned char *) bitmap
;
773 TRACE(" - bbox : %d x %d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
774 TRACE(" - origin : (%ld , %ld)\n", gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
775 TRACE(" - increment : %d - %d\n", gm
.gmCellIncX
, gm
.gmCellIncY
);
776 if (needed_size
!= 0) {
777 TRACE(" - bitmap :\n");
778 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
780 for (width
= 0, bitmask
= 0x80; width
< gm
.gmBlackBoxX
; width
++, bitmask
>>= 1) {
785 if (*bitmap_
& bitmask
)
790 bitmap_
+= (4 - ((UINT_PTR
)bitmap_
& 0x03));
796 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
797 * glyph for it to be drawn properly.
799 if (needed_size
!= 0) {
800 width_int
= (gm
.gmBlackBoxX
+ 31) / 32;
801 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
803 for (width
= 0; width
< width_int
; width
++) {
804 ((int *) gl_bitmap
)[(gm
.gmBlackBoxY
- height
- 1) * width_int
+ width
] =
805 ((int *) bitmap
)[height
* width_int
+ width
];
811 glNewList(listBase
++, GL_COMPILE
);
812 if (needed_size
!= 0) {
813 glBitmap(gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
814 0 - (int) gm
.gmptGlyphOrigin
.x
, (int) gm
.gmBlackBoxY
- (int) gm
.gmptGlyphOrigin
.y
,
815 gm
.gmCellIncX
, gm
.gmCellIncY
,
818 /* This is the case of 'empty' glyphs like the space character */
819 glBitmap(0, 0, 0, 0, gm
.gmCellIncX
, gm
.gmCellIncY
, NULL
);
826 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
829 HeapFree(GetProcessHeap(), 0, bitmap
);
830 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
835 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
838 HeapFree(GetProcessHeap(), 0, bitmap
);
839 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
843 /***********************************************************************
844 * wglUseFontBitmapsA (OPENGL32.@)
846 BOOL WINAPI
wglUseFontBitmapsA(HDC hdc
,
851 Font fid
= get_font( hdc
);
853 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc
, first
, count
, listBase
, fid
);
856 return internal_wglUseFontBitmaps(hdc
, first
, count
, listBase
, GetGlyphOutlineA
);
860 /* I assume that the glyphs are at the same position for X and for Windows */
861 glXUseXFont(fid
, first
, count
, listBase
);
866 /***********************************************************************
867 * wglUseFontBitmapsW (OPENGL32.@)
869 BOOL WINAPI
wglUseFontBitmapsW(HDC hdc
,
874 Font fid
= get_font( hdc
);
876 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc
, first
, count
, listBase
, fid
);
879 return internal_wglUseFontBitmaps(hdc
, first
, count
, listBase
, GetGlyphOutlineW
);
882 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
885 /* I assume that the glyphs are at the same position for X and for Windows */
886 glXUseXFont(fid
, first
, count
, listBase
);
893 static void fixed_to_double(POINTFX fixed
, UINT em_size
, GLdouble vertex
[3])
895 vertex
[0] = (fixed
.x
.value
+ (GLdouble
)fixed
.x
.fract
/ (1 << 16)) / em_size
;
896 vertex
[1] = (fixed
.y
.value
+ (GLdouble
)fixed
.y
.fract
/ (1 << 16)) / em_size
;
900 static void tess_callback_vertex(GLvoid
*vertex
)
902 GLdouble
*dbl
= vertex
;
903 TRACE("%f, %f, %f\n", dbl
[0], dbl
[1], dbl
[2]);
907 static void tess_callback_begin(GLenum which
)
909 TRACE("%d\n", which
);
913 static void tess_callback_end(void)
919 /***********************************************************************
920 * wglUseFontOutlines_common
922 BOOL WINAPI
wglUseFontOutlines_common(HDC hdc
,
929 LPGLYPHMETRICSFLOAT lpgmf
,
933 const MAT2 identity
= {{0,1},{0,0},{0,0},{0,1}};
936 HFONT old_font
, unscaled_font
;
940 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc
, first
, count
,
941 listBase
, deviation
, extrusion
, format
, lpgmf
, unicode
? "W" : "A");
948 gluTessCallback(tess
, GLU_TESS_VERTEX
, (_GLUfuncptr
)tess_callback_vertex
);
949 gluTessCallback(tess
, GLU_TESS_BEGIN
, (_GLUfuncptr
)tess_callback_begin
);
950 gluTessCallback(tess
, GLU_TESS_END
, tess_callback_end
);
954 if(!tess
) return FALSE
;
956 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
957 rc
.left
= rc
.right
= rc
.bottom
= 0;
959 DPtoLP(hdc
, (POINT
*)&rc
, 2);
960 lf
.lfHeight
= -abs(rc
.top
- rc
.bottom
);
961 lf
.lfOrientation
= lf
.lfEscapement
= 0;
962 unscaled_font
= CreateFontIndirectW(&lf
);
963 old_font
= SelectObject(hdc
, unscaled_font
);
965 for (glyph
= first
; glyph
< first
+ count
; glyph
++)
970 TTPOLYGONHEADER
*pph
;
975 needed
= GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
977 needed
= GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
979 if(needed
== GDI_ERROR
)
982 buf
= HeapAlloc(GetProcessHeap(), 0, needed
);
983 vertices
= HeapAlloc(GetProcessHeap(), 0, needed
/ sizeof(POINTFX
) * 3 * sizeof(GLdouble
));
986 GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
988 GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
990 TRACE("glyph %d\n", glyph
);
994 lpgmf
->gmfBlackBoxX
= (float)gm
.gmBlackBoxX
/ em_size
;
995 lpgmf
->gmfBlackBoxY
= (float)gm
.gmBlackBoxY
/ em_size
;
996 lpgmf
->gmfptGlyphOrigin
.x
= (float)gm
.gmptGlyphOrigin
.x
/ em_size
;
997 lpgmf
->gmfptGlyphOrigin
.y
= (float)gm
.gmptGlyphOrigin
.y
/ em_size
;
998 lpgmf
->gmfCellIncX
= (float)gm
.gmCellIncX
/ em_size
;
999 lpgmf
->gmfCellIncY
= (float)gm
.gmCellIncY
/ em_size
;
1001 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf
->gmfBlackBoxX
, lpgmf
->gmfBlackBoxY
,
1002 lpgmf
->gmfptGlyphOrigin
.x
, lpgmf
->gmfptGlyphOrigin
.y
, lpgmf
->gmfCellIncX
, lpgmf
->gmfCellIncY
);
1007 glNewList(listBase
++, GL_COMPILE
);
1008 gluTessBeginPolygon(tess
, NULL
);
1010 pph
= (TTPOLYGONHEADER
*)buf
;
1011 while((BYTE
*)pph
< buf
+ needed
)
1013 TRACE("\tstart %d, %d\n", pph
->pfxStart
.x
.value
, pph
->pfxStart
.y
.value
);
1015 gluTessBeginContour(tess
);
1017 fixed_to_double(pph
->pfxStart
, em_size
, vertices
);
1018 gluTessVertex(tess
, vertices
, vertices
);
1021 ppc
= (TTPOLYCURVE
*)((char*)pph
+ sizeof(*pph
));
1022 while((char*)ppc
< (char*)pph
+ pph
->cb
)
1026 switch(ppc
->wType
) {
1028 for(i
= 0; i
< ppc
->cpfx
; i
++)
1030 TRACE("\t\tline to %d, %d\n", ppc
->apfx
[i
].x
.value
, ppc
->apfx
[i
].y
.value
);
1031 fixed_to_double(ppc
->apfx
[i
], em_size
, vertices
);
1032 gluTessVertex(tess
, vertices
, vertices
);
1037 case TT_PRIM_QSPLINE
:
1038 for(i
= 0; i
< ppc
->cpfx
/2; i
++)
1040 /* FIXME just connecting the control points for now */
1041 TRACE("\t\tcurve %d,%d %d,%d\n",
1042 ppc
->apfx
[i
* 2].x
.value
, ppc
->apfx
[i
* 3].y
.value
,
1043 ppc
->apfx
[i
* 2 + 1].x
.value
, ppc
->apfx
[i
* 3 + 1].y
.value
);
1044 fixed_to_double(ppc
->apfx
[i
* 2], em_size
, vertices
);
1045 gluTessVertex(tess
, vertices
, vertices
);
1047 fixed_to_double(ppc
->apfx
[i
* 2 + 1], em_size
, vertices
);
1048 gluTessVertex(tess
, vertices
, vertices
);
1053 ERR("\t\tcurve type = %d\n", ppc
->wType
);
1054 gluTessEndContour(tess
);
1058 ppc
= (TTPOLYCURVE
*)((char*)ppc
+ sizeof(*ppc
) +
1059 (ppc
->cpfx
- 1) * sizeof(POINTFX
));
1061 gluTessEndContour(tess
);
1062 pph
= (TTPOLYGONHEADER
*)((char*)pph
+ pph
->cb
);
1066 gluTessEndPolygon(tess
);
1067 glTranslated((GLdouble
)gm
.gmCellIncX
/ em_size
, (GLdouble
)gm
.gmCellIncY
/ em_size
, 0.0);
1070 HeapFree(GetProcessHeap(), 0, buf
);
1071 HeapFree(GetProcessHeap(), 0, vertices
);
1075 DeleteObject(SelectObject(hdc
, old_font
));
1076 gluDeleteTess(tess
);
1081 #else /* HAVE_GL_GLU_H */
1083 BOOL WINAPI
wglUseFontOutlines_common(HDC hdc
,
1090 LPGLYPHMETRICSFLOAT lpgmf
,
1093 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1097 #endif /* HAVE_GL_GLU_H */
1099 /***********************************************************************
1100 * wglUseFontOutlinesA (OPENGL32.@)
1102 BOOL WINAPI
wglUseFontOutlinesA(HDC hdc
,
1109 LPGLYPHMETRICSFLOAT lpgmf
)
1111 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, FALSE
);
1114 /***********************************************************************
1115 * wglUseFontOutlinesW (OPENGL32.@)
1117 BOOL WINAPI
wglUseFontOutlinesW(HDC hdc
,
1124 LPGLYPHMETRICSFLOAT lpgmf
)
1126 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, TRUE
);
1129 const GLubyte
* internal_glGetString(GLenum name
) {
1130 const char* GL_Extensions
= NULL
;
1132 if (GL_EXTENSIONS
!= name
) {
1133 return glGetString(name
);
1136 if (NULL
== internal_gl_extensions
) {
1137 GL_Extensions
= (const char *) glGetString(GL_EXTENSIONS
);
1139 TRACE("GL_EXTENSIONS reported:\n");
1140 if (NULL
== GL_Extensions
) {
1141 ERR("GL_EXTENSIONS returns NULL\n");
1144 size_t len
= strlen(GL_Extensions
);
1145 internal_gl_extensions
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
+ 2);
1147 while (*GL_Extensions
!= 0x00) {
1148 const char* Start
= GL_Extensions
;
1151 memset(ThisExtn
, 0x00, sizeof(ThisExtn
));
1152 while (*GL_Extensions
!= ' ' && *GL_Extensions
!= 0x00) {
1155 memcpy(ThisExtn
, Start
, (GL_Extensions
- Start
));
1156 TRACE("- %s:", ThisExtn
);
1158 /* test if supported API is disabled by config */
1159 if (NULL
== strstr(internal_gl_disabled_extensions
, ThisExtn
)) {
1160 strcat(internal_gl_extensions
, " ");
1161 strcat(internal_gl_extensions
, ThisExtn
);
1164 TRACE(" deactived (by config)\n");
1167 if (*GL_Extensions
== ' ') GL_Extensions
++;
1171 return (const GLubyte
*) internal_gl_extensions
;
1174 void internal_glGetIntegerv(GLenum pname
, GLint
* params
) {
1175 glGetIntegerv(pname
, params
);
1176 if (pname
== GL_DEPTH_BITS
) {
1177 GLXContext gl_ctx
= glXGetCurrentContext();
1178 Wine_GLContext
* ret
= get_context_from_GLXContext(gl_ctx
);
1179 /*TRACE("returns Wine Ctx as %p\n", ret);*/
1181 * if we cannot find a Wine Context
1182 * we only have the default wine desktop context,
1183 * so if we have only a 24 depth say we have 32
1185 if (NULL
== ret
&& 24 == *params
) {
1188 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params
);
1190 if (pname
== GL_ALPHA_BITS
) {
1192 GLXContext gl_ctx
= glXGetCurrentContext();
1193 Wine_GLContext
* ret
= get_context_from_GLXContext(gl_ctx
);
1194 glXGetFBConfigAttrib(ret
->display
, ret
->fb_conf
, GLX_ALPHA_SIZE
, &tmp
);
1195 TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp
);
1201 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1202 include all dependencies
1204 #ifndef SONAME_LIBGL
1205 #define SONAME_LIBGL "libGL.so"
1208 static void wgl_initialize_glx(Display
*display
, int screen
, glXGetProcAddressARB_t proc
)
1210 const char *server_glx_version
= glXQueryServerString(display
, screen
, GLX_VERSION
);
1211 const char *server_glx_extensions
= glXQueryServerString(display
, screen
, GLX_EXTENSIONS
);
1213 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1214 const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1215 const char *glx_extensions = glXQueryExtensionsString(display, screen);
1218 memset(&wine_glx
, 0, sizeof(wine_glx
));
1220 if (!strcmp("1.2", server_glx_version
)) {
1221 wine_glx
.version
= 2;
1223 wine_glx
.version
= 3;
1226 if (2 < wine_glx
.version
) {
1227 wine_glx
.p_glXChooseFBConfig
= proc( (const GLubyte
*) "glXChooseFBConfig");
1228 wine_glx
.p_glXGetFBConfigAttrib
= proc( (const GLubyte
*) "glXGetFBConfigAttrib");
1229 wine_glx
.p_glXGetVisualFromFBConfig
= proc( (const GLubyte
*) "glXGetVisualFromFBConfig");
1231 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1232 wine_glx
.p_glXQueryDrawable
= proc( (const GLubyte
*) "glXQueryDrawable");
1234 if (NULL
!= strstr(server_glx_extensions
, "GLX_SGIX_fbconfig")) {
1235 wine_glx
.p_glXChooseFBConfig
= proc( (const GLubyte
*) "glXChooseFBConfigSGIX");
1236 wine_glx
.p_glXGetFBConfigAttrib
= proc( (const GLubyte
*) "glXGetFBConfigAttribSGIX");
1237 wine_glx
.p_glXGetVisualFromFBConfig
= proc( (const GLubyte
*) "glXGetVisualFromFBConfigSGIX");
1239 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version
);
1242 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1243 wine_glx
.p_glXGetFBConfigs
= proc( (const GLubyte
*) "glXGetFBConfigs");
1244 wine_glx
.p_glXMakeContextCurrent
= proc( (const GLubyte
*) "glXMakeContextCurrent");
1247 /* This is for brain-dead applications that use OpenGL functions before even
1248 creating a rendering context.... */
1249 static BOOL
process_attach(void)
1251 XWindowAttributes win_attr
;
1254 XVisualInfo
template;
1256 XVisualInfo
*vis
= NULL
;
1257 Window root
= (Window
)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1258 HMODULE mod
= GetModuleHandleA( "winex11.drv" );
1259 void *opengl_handle
;
1260 DWORD size
= sizeof(internal_gl_disabled_extensions
);
1265 ERR("X11DRV not loaded. Cannot create default context.\n");
1269 wine_tsx11_lock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_lock" );
1270 wine_tsx11_unlock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_unlock" );
1273 default_display
= get_display( hdc
);
1274 ReleaseDC( 0, hdc
);
1275 if (!default_display
)
1277 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1283 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1284 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1285 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1286 with mismatched visuals. Note that the Root Window visual may not be double
1287 buffered, so apps actually attempting to render this way may flicker */
1288 if (XGetWindowAttributes( default_display
, root
, &win_attr
))
1290 rootVisual
= win_attr
.visual
;
1294 /* Get the default visual, since we can't seem to get the attributes from the
1295 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1296 rootVisual
= DefaultVisual( default_display
, DefaultScreen(default_display
) );
1299 template.visualid
= XVisualIDFromVisual(rootVisual
);
1300 vis
= XGetVisualInfo(default_display
, VisualIDMask
, &template, &num
);
1301 if (vis
!= NULL
) default_cx
= glXCreateContext(default_display
, vis
, 0, GL_TRUE
);
1302 if (default_cx
!= NULL
) glXMakeCurrent(default_display
, root
, default_cx
);
1306 opengl_handle
= wine_dlopen(SONAME_LIBGL
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0);
1307 if (opengl_handle
!= NULL
) {
1308 p_glXGetProcAddressARB
= wine_dlsym(opengl_handle
, "glXGetProcAddressARB", NULL
, 0);
1309 wine_dlclose(opengl_handle
, NULL
, 0);
1310 if (p_glXGetProcAddressARB
== NULL
)
1311 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1314 internal_gl_disabled_extensions
[0] = 0;
1315 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\OpenGL", &hkey
)) {
1316 if (!RegQueryValueExA( hkey
, "DisabledExtensions", 0, NULL
, (LPBYTE
)internal_gl_disabled_extensions
, &size
)) {
1317 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions
);
1322 if (default_cx
== NULL
) {
1323 ERR("Could not create default context.\n");
1327 /* After context initialize also the list of supported WGL extensions. */
1328 wgl_initialize_glx(default_display
, DefaultScreen(default_display
), p_glXGetProcAddressARB
);
1329 wgl_ext_initialize_extensions(default_display
, DefaultScreen(default_display
), p_glXGetProcAddressARB
, internal_gl_disabled_extensions
);
1335 /**********************************************************************/
1337 static void process_detach(void)
1339 glXDestroyContext(default_display
, default_cx
);
1341 /* Do not leak memory... */
1342 wgl_ext_finalize_extensions();
1343 HeapFree(GetProcessHeap(), 0, internal_gl_extensions
);
1346 /***********************************************************************
1347 * OpenGL initialisation routine
1349 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
1353 case DLL_PROCESS_ATTACH
:
1354 opengl32_handle
= hinst
;
1355 DisableThreadLibraryCalls(hinst
);
1356 return process_attach();
1357 case DLL_PROCESS_DETACH
: