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
26 #define WIN32_NO_STATUS
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(opengl
);
40 WINE_DECLARE_DEBUG_CHANNEL(fps
);
42 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
46 static char **wow64_strings
;
47 static SIZE_T wow64_strings_count
;
49 static CRITICAL_SECTION wow64_cs
;
50 static CRITICAL_SECTION_DEBUG wow64_cs_debug
=
53 { &wow64_cs_debug
.ProcessLocksList
, &wow64_cs_debug
.ProcessLocksList
},
54 0, 0, { (DWORD_PTR
)(__FILE__
": wow64_cs") }
56 static CRITICAL_SECTION wow64_cs
= { &wow64_cs_debug
, -1, 0, 0, 0, 0 };
58 static void append_wow64_string( char *str
)
62 EnterCriticalSection( &wow64_cs
);
64 if (!(tmp
= realloc( wow64_strings
, (wow64_strings_count
+ 1) * sizeof(*wow64_strings
) )))
65 ERR( "Failed to allocate memory for wow64 strings\n" );
69 wow64_strings
[wow64_strings_count
] = str
;
70 wow64_strings_count
+= 1;
73 LeaveCriticalSection( &wow64_cs
);
76 static void cleanup_wow64_strings(void)
78 while (wow64_strings_count
--) free( wow64_strings
[wow64_strings_count
] );
79 free( wow64_strings
);
84 /***********************************************************************
85 * wglGetCurrentReadDCARB
87 * Provided by the WGL_ARB_make_current_read extension.
89 HDC WINAPI
wglGetCurrentReadDCARB(void)
91 if (!NtCurrentTeb()->glCurrentRC
) return 0;
92 return NtCurrentTeb()->glReserved1
[1];
95 /***********************************************************************
96 * wglGetCurrentDC (OPENGL32.@)
98 HDC WINAPI
wglGetCurrentDC(void)
100 if (!NtCurrentTeb()->glCurrentRC
) return 0;
101 return NtCurrentTeb()->glReserved1
[0];
104 /***********************************************************************
105 * wglGetCurrentContext (OPENGL32.@)
107 HGLRC WINAPI
wglGetCurrentContext(void)
109 return NtCurrentTeb()->glCurrentRC
;
112 /***********************************************************************
113 * wglChoosePixelFormat (OPENGL32.@)
115 INT WINAPI
wglChoosePixelFormat(HDC hdc
, const PIXELFORMATDESCRIPTOR
* ppfd
)
117 PIXELFORMATDESCRIPTOR format
, best
;
118 int i
, count
, best_format
;
119 int bestDBuffer
= -1, bestStereo
= -1;
121 TRACE( "%p %p: size %u version %u flags %lu type %u color %u %u,%u,%u,%u "
122 "accum %u depth %u stencil %u aux %u\n",
123 hdc
, ppfd
, ppfd
->nSize
, ppfd
->nVersion
, ppfd
->dwFlags
, ppfd
->iPixelType
,
124 ppfd
->cColorBits
, ppfd
->cRedBits
, ppfd
->cGreenBits
, ppfd
->cBlueBits
, ppfd
->cAlphaBits
,
125 ppfd
->cAccumBits
, ppfd
->cDepthBits
, ppfd
->cStencilBits
, ppfd
->cAuxBuffers
);
127 count
= wglDescribePixelFormat( hdc
, 0, 0, NULL
);
128 if (!count
) return 0;
132 best
.cAlphaBits
= -1;
133 best
.cColorBits
= -1;
134 best
.cDepthBits
= -1;
135 best
.cStencilBits
= -1;
136 best
.cAuxBuffers
= -1;
138 for (i
= 1; i
<= count
; i
++)
140 if (!wglDescribePixelFormat( hdc
, i
, sizeof(format
), &format
)) continue;
142 if ((ppfd
->iPixelType
== PFD_TYPE_COLORINDEX
) != (format
.iPixelType
== PFD_TYPE_COLORINDEX
))
144 TRACE( "pixel type mismatch for iPixelFormat=%d\n", i
);
148 if ((ppfd
->dwFlags
& PFD_DRAW_TO_BITMAP
) && !(format
.dwFlags
& PFD_DRAW_TO_BITMAP
))
150 TRACE( "PFD_DRAW_TO_BITMAP required but not found for iPixelFormat=%d\n", i
);
153 if ((ppfd
->dwFlags
& PFD_DRAW_TO_WINDOW
) && !(format
.dwFlags
& PFD_DRAW_TO_WINDOW
))
155 TRACE( "PFD_DRAW_TO_WINDOW required but not found for iPixelFormat=%d\n", i
);
159 if ((ppfd
->dwFlags
& PFD_SUPPORT_GDI
) && !(format
.dwFlags
& PFD_SUPPORT_GDI
))
161 TRACE( "PFD_SUPPORT_GDI required but not found for iPixelFormat=%d\n", i
);
164 if ((ppfd
->dwFlags
& PFD_SUPPORT_OPENGL
) && !(format
.dwFlags
& PFD_SUPPORT_OPENGL
))
166 TRACE( "PFD_SUPPORT_OPENGL required but not found for iPixelFormat=%d\n", i
);
170 /* The behavior of PDF_STEREO/PFD_STEREO_DONTCARE and PFD_DOUBLEBUFFER / PFD_DOUBLEBUFFER_DONTCARE
171 * is not very clear on MSDN. They specify that ChoosePixelFormat tries to match pixel formats
172 * with the flag (PFD_STEREO / PFD_DOUBLEBUFFERING) set. Otherwise it says that it tries to match
173 * formats without the given flag set.
174 * A test on Windows using a Radeon 9500pro on WinXP (the driver doesn't support Stereo)
175 * has indicated that a format without stereo is returned when stereo is unavailable.
176 * So in case PFD_STEREO is set, formats that support it should have priority above formats
177 * without. In case PFD_STEREO_DONTCARE is set, stereo is ignored.
179 * To summarize the following is most likely the correct behavior:
180 * stereo not set -> prefer non-stereo formats, but also accept stereo formats
181 * stereo set -> prefer stereo formats, but also accept non-stereo formats
182 * stereo don't care -> it doesn't matter whether we get stereo or not
184 * In Wine we will treat non-stereo the same way as don't care because it makes
185 * format selection even more complicated and second drivers with Stereo advertise
186 * each format twice anyway.
189 /* Doublebuffer, see the comments above */
190 if (!(ppfd
->dwFlags
& PFD_DOUBLEBUFFER_DONTCARE
))
192 if (((ppfd
->dwFlags
& PFD_DOUBLEBUFFER
) != bestDBuffer
) &&
193 ((format
.dwFlags
& PFD_DOUBLEBUFFER
) == (ppfd
->dwFlags
& PFD_DOUBLEBUFFER
)))
196 if (bestDBuffer
!= -1 && (format
.dwFlags
& PFD_DOUBLEBUFFER
) != bestDBuffer
) continue;
198 else if (!best_format
)
201 /* Stereo, see the comments above. */
202 if (!(ppfd
->dwFlags
& PFD_STEREO_DONTCARE
))
204 if (((ppfd
->dwFlags
& PFD_STEREO
) != bestStereo
) &&
205 ((format
.dwFlags
& PFD_STEREO
) == (ppfd
->dwFlags
& PFD_STEREO
)))
208 if (bestStereo
!= -1 && (format
.dwFlags
& PFD_STEREO
) != bestStereo
) continue;
210 else if (!best_format
)
213 /* Below we will do a number of checks to select the 'best' pixelformat.
214 * We assume the precedence cColorBits > cAlphaBits > cDepthBits > cStencilBits -> cAuxBuffers.
215 * The code works by trying to match the most important options as close as possible.
216 * When a reasonable format is found, we will try to match more options.
217 * It appears (see the opengl32 test) that Windows opengl drivers ignore options
218 * like cColorBits, cAlphaBits and friends if they are set to 0, so they are considered
219 * as DONTCARE. At least Serious Sam TSE relies on this behavior. */
221 if (ppfd
->cColorBits
)
223 if (((ppfd
->cColorBits
> best
.cColorBits
) && (format
.cColorBits
> best
.cColorBits
)) ||
224 ((format
.cColorBits
>= ppfd
->cColorBits
) && (format
.cColorBits
< best
.cColorBits
)))
227 if (best
.cColorBits
!= format
.cColorBits
) /* Do further checks if the format is compatible */
229 TRACE( "color mismatch for iPixelFormat=%d\n", i
);
233 if (ppfd
->cAlphaBits
)
235 if (((ppfd
->cAlphaBits
> best
.cAlphaBits
) && (format
.cAlphaBits
> best
.cAlphaBits
)) ||
236 ((format
.cAlphaBits
>= ppfd
->cAlphaBits
) && (format
.cAlphaBits
< best
.cAlphaBits
)))
239 if (best
.cAlphaBits
!= format
.cAlphaBits
)
241 TRACE( "alpha mismatch for iPixelFormat=%d\n", i
);
245 if (ppfd
->cStencilBits
)
247 if (((ppfd
->cStencilBits
> best
.cStencilBits
) && (format
.cStencilBits
> best
.cStencilBits
)) ||
248 ((format
.cStencilBits
>= ppfd
->cStencilBits
) && (format
.cStencilBits
< best
.cStencilBits
)))
251 if (best
.cStencilBits
!= format
.cStencilBits
)
253 TRACE( "stencil mismatch for iPixelFormat=%d\n", i
);
257 if (ppfd
->cDepthBits
&& !(ppfd
->dwFlags
& PFD_DEPTH_DONTCARE
))
259 if (((ppfd
->cDepthBits
> best
.cDepthBits
) && (format
.cDepthBits
> best
.cDepthBits
)) ||
260 ((format
.cDepthBits
>= ppfd
->cDepthBits
) && (format
.cDepthBits
< best
.cDepthBits
)))
263 if (best
.cDepthBits
!= format
.cDepthBits
)
265 TRACE( "depth mismatch for iPixelFormat=%d\n", i
);
269 if (ppfd
->cAuxBuffers
)
271 if (((ppfd
->cAuxBuffers
> best
.cAuxBuffers
) && (format
.cAuxBuffers
> best
.cAuxBuffers
)) ||
272 ((format
.cAuxBuffers
>= ppfd
->cAuxBuffers
) && (format
.cAuxBuffers
< best
.cAuxBuffers
)))
275 if (best
.cAuxBuffers
!= format
.cAuxBuffers
)
277 TRACE( "aux mismatch for iPixelFormat=%d\n", i
);
281 if (ppfd
->dwFlags
& PFD_DEPTH_DONTCARE
&& format
.cDepthBits
< best
.cDepthBits
)
289 bestDBuffer
= format
.dwFlags
& PFD_DOUBLEBUFFER
;
290 bestStereo
= format
.dwFlags
& PFD_STEREO
;
293 TRACE( "returning %u\n", best_format
);
297 /***********************************************************************
298 * wglGetPixelFormat (OPENGL32.@)
300 INT WINAPI
wglGetPixelFormat(HDC hdc
)
302 struct wglGetPixelFormat_params args
= { .teb
= NtCurrentTeb(), .hdc
= hdc
};
305 TRACE( "hdc %p\n", hdc
);
307 if ((status
= UNIX_CALL( wglGetPixelFormat
, &args
)))
309 WARN( "wglGetPixelFormat returned %#lx\n", status
);
310 SetLastError( ERROR_INVALID_PIXEL_FORMAT
);
316 /***********************************************************************
317 * wglSwapBuffers (OPENGL32.@)
319 BOOL WINAPI DECLSPEC_HOTPATCH
wglSwapBuffers( HDC hdc
)
321 struct wglSwapBuffers_params args
= { .teb
= NtCurrentTeb(), .hdc
= hdc
};
324 if ((status
= UNIX_CALL( wglSwapBuffers
, &args
))) WARN( "wglSwapBuffers returned %#lx\n", status
);
325 else if (TRACE_ON(fps
))
327 static long prev_time
, start_time
;
328 static unsigned long frames
, frames_total
;
330 DWORD time
= GetTickCount();
333 /* every 1.5 seconds */
334 if (time
- prev_time
> 1500)
336 TRACE_(fps
)("@ approx %.2ffps, total %.2ffps\n",
337 1000.0*frames
/(time
- prev_time
), 1000.0*frames_total
/(time
- start_time
));
340 if (start_time
== 0) start_time
= time
;
347 /***********************************************************************
348 * wglCreateLayerContext (OPENGL32.@)
350 HGLRC WINAPI
wglCreateLayerContext( HDC hdc
, int iLayerPlane
)
352 TRACE("(%p,%d)\n", hdc
, iLayerPlane
);
354 if (iLayerPlane
== 0) return wglCreateContext( hdc
);
356 FIXME("no handler for layer %d\n", iLayerPlane
);
360 /***********************************************************************
361 * wglDescribeLayerPlane (OPENGL32.@)
363 BOOL WINAPI
wglDescribeLayerPlane(HDC hdc
,
367 LPLAYERPLANEDESCRIPTOR plpd
) {
368 FIXME("(%p,%d,%d,%d,%p)\n", hdc
, iPixelFormat
, iLayerPlane
, nBytes
, plpd
);
373 /***********************************************************************
374 * wglGetLayerPaletteEntries (OPENGL32.@)
376 int WINAPI
wglGetLayerPaletteEntries(HDC hdc
,
380 const COLORREF
*pcr
) {
381 FIXME("(): stub!\n");
386 /***********************************************************************
387 * wglGetProcAddress (OPENGL32.@)
389 PROC WINAPI
wglGetProcAddress( LPCSTR name
)
391 struct wglGetProcAddress_params args
= { .teb
= NtCurrentTeb(), .lpszProc
= name
};
395 if (!name
) return NULL
;
396 if ((status
= UNIX_CALL( wglGetProcAddress
, &args
)))
397 WARN( "wglGetProcAddress %s returned %#lx\n", debugstr_a(name
), status
);
398 if (args
.ret
== (void *)-1) return NULL
;
400 proc
= extension_procs
[(UINT_PTR
)args
.ret
];
401 TRACE( "returning %s -> %p\n", name
, proc
);
405 /***********************************************************************
406 * wglRealizeLayerPalette (OPENGL32.@)
408 BOOL WINAPI
wglRealizeLayerPalette(HDC hdc
,
416 /***********************************************************************
417 * wglSetLayerPaletteEntries (OPENGL32.@)
419 int WINAPI
wglSetLayerPaletteEntries(HDC hdc
,
423 const COLORREF
*pcr
) {
424 FIXME("(): stub!\n");
429 /***********************************************************************
430 * wglGetDefaultProcAddress (OPENGL32.@)
432 PROC WINAPI
wglGetDefaultProcAddress( LPCSTR name
)
434 FIXME( "%s: stub\n", debugstr_a(name
));
438 /***********************************************************************
439 * wglSwapLayerBuffers (OPENGL32.@)
441 BOOL WINAPI
wglSwapLayerBuffers(HDC hdc
,
443 TRACE("(%p, %08x)\n", hdc
, fuPlanes
);
445 if (fuPlanes
& WGL_SWAP_MAIN_PLANE
) {
446 if (!wglSwapBuffers( hdc
)) return FALSE
;
447 fuPlanes
&= ~WGL_SWAP_MAIN_PLANE
;
451 WARN("Following layers unhandled: %08x\n", fuPlanes
);
457 /***********************************************************************
458 * wglUseFontBitmaps_common
460 static BOOL
wglUseFontBitmaps_common( HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
, BOOL unicode
)
463 unsigned int glyph
, size
= 0;
464 void *bitmap
= NULL
, *gl_bitmap
= NULL
;
468 glGetIntegerv( GL_UNPACK_ALIGNMENT
, &org_alignment
);
469 glPixelStorei( GL_UNPACK_ALIGNMENT
, 4 );
471 for (glyph
= first
; glyph
< first
+ count
; glyph
++) {
472 unsigned int needed_size
, height
, width
, width_int
;
475 needed_size
= GetGlyphOutlineW(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, &identity
);
477 needed_size
= GetGlyphOutlineA(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, &identity
);
479 TRACE("Glyph: %3d / List: %ld size %d\n", glyph
, listBase
, needed_size
);
480 if (needed_size
== GDI_ERROR
) {
485 if (needed_size
> size
) {
489 bitmap
= calloc( 1, size
);
490 gl_bitmap
= calloc( 1, size
);
492 if (needed_size
!= 0) {
494 ret
= (GetGlyphOutlineW(hdc
, glyph
, GGO_BITMAP
, &gm
,
495 size
, bitmap
, &identity
) != GDI_ERROR
);
497 ret
= (GetGlyphOutlineA(hdc
, glyph
, GGO_BITMAP
, &gm
,
498 size
, bitmap
, &identity
) != GDI_ERROR
);
502 if (TRACE_ON(opengl
))
504 unsigned int bitmask
;
505 unsigned char *bitmap_
= bitmap
;
507 TRACE(" - bbox: %d x %d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
508 TRACE(" - origin: (%ld, %ld)\n", gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
509 TRACE(" - increment: %d - %d\n", gm
.gmCellIncX
, gm
.gmCellIncY
);
510 if (needed_size
!= 0) {
511 TRACE(" - bitmap:\n");
512 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
514 for (width
= 0, bitmask
= 0x80; width
< gm
.gmBlackBoxX
; width
++, bitmask
>>= 1) {
519 if (*bitmap_
& bitmask
)
524 bitmap_
+= (4 - ((UINT_PTR
)bitmap_
& 0x03));
530 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
531 * glyph for it to be drawn properly.
533 if (needed_size
!= 0) {
534 width_int
= (gm
.gmBlackBoxX
+ 31) / 32;
535 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
536 for (width
= 0; width
< width_int
; width
++) {
537 ((int *) gl_bitmap
)[(gm
.gmBlackBoxY
- height
- 1) * width_int
+ width
] =
538 ((int *) bitmap
)[height
* width_int
+ width
];
543 glNewList( listBase
++, GL_COMPILE
);
544 if (needed_size
!= 0) {
545 glBitmap( gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, 0 - gm
.gmptGlyphOrigin
.x
,
546 (int)gm
.gmBlackBoxY
- gm
.gmptGlyphOrigin
.y
, gm
.gmCellIncX
, gm
.gmCellIncY
, gl_bitmap
);
548 /* This is the case of 'empty' glyphs like the space character */
549 glBitmap( 0, 0, 0, 0, gm
.gmCellIncX
, gm
.gmCellIncY
, NULL
);
554 glPixelStorei( GL_UNPACK_ALIGNMENT
, org_alignment
);
560 /***********************************************************************
561 * wglUseFontBitmapsA (OPENGL32.@)
563 BOOL WINAPI
wglUseFontBitmapsA(HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
)
565 return wglUseFontBitmaps_common( hdc
, first
, count
, listBase
, FALSE
);
568 /***********************************************************************
569 * wglUseFontBitmapsW (OPENGL32.@)
571 BOOL WINAPI
wglUseFontBitmapsW(HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
)
573 return wglUseFontBitmaps_common( hdc
, first
, count
, listBase
, TRUE
);
576 static void fixed_to_double(POINTFX fixed
, UINT em_size
, GLdouble vertex
[3])
578 vertex
[0] = (fixed
.x
.value
+ (GLdouble
)fixed
.x
.fract
/ (1 << 16)) / em_size
;
579 vertex
[1] = (fixed
.y
.value
+ (GLdouble
)fixed
.y
.fract
/ (1 << 16)) / em_size
;
583 typedef struct _bezier_vector
{
588 static double bezier_deviation_squared(const bezier_vector
*p
)
590 bezier_vector deviation
;
591 bezier_vector vertex
;
596 vertex
.x
= (p
[0].x
+ p
[1].x
*2 + p
[2].x
)/4 - p
[0].x
;
597 vertex
.y
= (p
[0].y
+ p
[1].y
*2 + p
[2].y
)/4 - p
[0].y
;
599 base
.x
= p
[2].x
- p
[0].x
;
600 base
.y
= p
[2].y
- p
[0].y
;
602 base_length
= sqrt(base
.x
*base
.x
+ base
.y
*base
.y
);
603 base
.x
/= base_length
;
604 base
.y
/= base_length
;
606 dot
= base
.x
*vertex
.x
+ base
.y
*vertex
.y
;
607 dot
= min(max(dot
, 0.0), base_length
);
611 deviation
.x
= vertex
.x
-base
.x
;
612 deviation
.y
= vertex
.y
-base
.y
;
614 return deviation
.x
*deviation
.x
+ deviation
.y
*deviation
.y
;
617 static int bezier_approximate(const bezier_vector
*p
, bezier_vector
*points
, FLOAT deviation
)
619 bezier_vector first_curve
[3];
620 bezier_vector second_curve
[3];
621 bezier_vector vertex
;
624 if(bezier_deviation_squared(p
) <= deviation
*deviation
)
631 vertex
.x
= (p
[0].x
+ p
[1].x
*2 + p
[2].x
)/4;
632 vertex
.y
= (p
[0].y
+ p
[1].y
*2 + p
[2].y
)/4;
634 first_curve
[0] = p
[0];
635 first_curve
[1].x
= (p
[0].x
+ p
[1].x
)/2;
636 first_curve
[1].y
= (p
[0].y
+ p
[1].y
)/2;
637 first_curve
[2] = vertex
;
639 second_curve
[0] = vertex
;
640 second_curve
[1].x
= (p
[2].x
+ p
[1].x
)/2;
641 second_curve
[1].y
= (p
[2].y
+ p
[1].y
)/2;
642 second_curve
[2] = p
[2];
644 total_vertices
= bezier_approximate(first_curve
, points
, deviation
);
646 points
+= total_vertices
;
647 total_vertices
+= bezier_approximate(second_curve
, points
, deviation
);
648 return total_vertices
;
651 /***********************************************************************
652 * wglUseFontOutlines_common
654 static BOOL
wglUseFontOutlines_common(HDC hdc
,
661 LPGLYPHMETRICSFLOAT lpgmf
,
665 GLUtesselator
*tess
= NULL
;
667 HFONT old_font
, unscaled_font
;
671 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc
, first
, count
,
672 listBase
, deviation
, extrusion
, format
, lpgmf
, unicode
? "W" : "A");
675 deviation
= 1.0/em_size
;
677 if(format
== WGL_FONT_POLYGONS
)
682 ERR("glu32 is required for this function but isn't available\n");
685 gluTessCallback( tess
, GLU_TESS_VERTEX
, (void *)glVertex3dv
);
686 gluTessCallback( tess
, GLU_TESS_BEGIN
, (void *)glBegin
);
687 gluTessCallback( tess
, GLU_TESS_END
, glEnd
);
690 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
691 rc
.left
= rc
.right
= rc
.bottom
= 0;
693 DPtoLP(hdc
, (POINT
*)&rc
, 2);
694 lf
.lfHeight
= -abs(rc
.top
- rc
.bottom
);
695 lf
.lfOrientation
= lf
.lfEscapement
= 0;
696 unscaled_font
= CreateFontIndirectW(&lf
);
697 old_font
= SelectObject(hdc
, unscaled_font
);
699 for (glyph
= first
; glyph
< first
+ count
; glyph
++)
704 TTPOLYGONHEADER
*pph
;
706 GLdouble
*vertices
= NULL
;
707 int vertex_total
= -1;
710 needed
= GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
712 needed
= GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
714 if(needed
== GDI_ERROR
)
717 buf
= malloc( needed
);
720 GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
722 GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
724 TRACE("glyph %d\n", glyph
);
728 lpgmf
->gmfBlackBoxX
= (float)gm
.gmBlackBoxX
/ em_size
;
729 lpgmf
->gmfBlackBoxY
= (float)gm
.gmBlackBoxY
/ em_size
;
730 lpgmf
->gmfptGlyphOrigin
.x
= (float)gm
.gmptGlyphOrigin
.x
/ em_size
;
731 lpgmf
->gmfptGlyphOrigin
.y
= (float)gm
.gmptGlyphOrigin
.y
/ em_size
;
732 lpgmf
->gmfCellIncX
= (float)gm
.gmCellIncX
/ em_size
;
733 lpgmf
->gmfCellIncY
= (float)gm
.gmCellIncY
/ em_size
;
735 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf
->gmfBlackBoxX
, lpgmf
->gmfBlackBoxY
,
736 lpgmf
->gmfptGlyphOrigin
.x
, lpgmf
->gmfptGlyphOrigin
.y
, lpgmf
->gmfCellIncX
, lpgmf
->gmfCellIncY
);
740 glNewList( listBase
++, GL_COMPILE
);
741 glFrontFace( GL_CCW
);
742 if(format
== WGL_FONT_POLYGONS
)
744 glNormal3d( 0.0, 0.0, 1.0 );
745 gluTessNormal(tess
, 0, 0, 1);
746 gluTessBeginPolygon(tess
, NULL
);
751 if (vertex_total
!= -1) vertices
= malloc( vertex_total
* 3 * sizeof(GLdouble
) );
754 pph
= (TTPOLYGONHEADER
*)buf
;
755 while((BYTE
*)pph
< buf
+ needed
)
757 GLdouble previous
[3];
758 fixed_to_double(pph
->pfxStart
, em_size
, previous
);
761 TRACE("\tstart %d, %d\n", pph
->pfxStart
.x
.value
, pph
->pfxStart
.y
.value
);
763 if (format
== WGL_FONT_POLYGONS
) gluTessBeginContour( tess
);
764 else glBegin( GL_LINE_LOOP
);
768 fixed_to_double(pph
->pfxStart
, em_size
, vertices
);
769 if (format
== WGL_FONT_POLYGONS
) gluTessVertex( tess
, vertices
, vertices
);
770 else glVertex3d( vertices
[0], vertices
[1], vertices
[2] );
775 ppc
= (TTPOLYCURVE
*)((char*)pph
+ sizeof(*pph
));
776 while((char*)ppc
< (char*)pph
+ pph
->cb
)
783 for(i
= 0; i
< ppc
->cpfx
; i
++)
787 TRACE("\t\tline to %d, %d\n",
788 ppc
->apfx
[i
].x
.value
, ppc
->apfx
[i
].y
.value
);
789 fixed_to_double(ppc
->apfx
[i
], em_size
, vertices
);
790 if (format
== WGL_FONT_POLYGONS
) gluTessVertex( tess
, vertices
, vertices
);
791 else glVertex3d( vertices
[0], vertices
[1], vertices
[2] );
794 fixed_to_double(ppc
->apfx
[i
], em_size
, previous
);
799 case TT_PRIM_QSPLINE
:
800 for(i
= 0; i
< ppc
->cpfx
-1; i
++)
802 bezier_vector curve
[3];
803 bezier_vector
*points
;
804 GLdouble curve_vertex
[3];
807 TRACE("\t\tcurve %d,%d %d,%d\n",
808 ppc
->apfx
[i
].x
.value
, ppc
->apfx
[i
].y
.value
,
809 ppc
->apfx
[i
+ 1].x
.value
, ppc
->apfx
[i
+ 1].y
.value
);
811 curve
[0].x
= previous
[0];
812 curve
[0].y
= previous
[1];
813 fixed_to_double(ppc
->apfx
[i
], em_size
, curve_vertex
);
814 curve
[1].x
= curve_vertex
[0];
815 curve
[1].y
= curve_vertex
[1];
816 fixed_to_double(ppc
->apfx
[i
+ 1], em_size
, curve_vertex
);
817 curve
[2].x
= curve_vertex
[0];
818 curve
[2].y
= curve_vertex
[1];
821 curve
[2].x
= (curve
[1].x
+ curve
[2].x
)/2;
822 curve
[2].y
= (curve
[1].y
+ curve
[2].y
)/2;
824 num
= bezier_approximate(curve
, NULL
, deviation
);
825 points
= malloc( num
* sizeof(bezier_vector
) );
826 num
= bezier_approximate(curve
, points
, deviation
);
832 TRACE("\t\t\tvertex at %f,%f\n", points
[j
].x
, points
[j
].y
);
833 vertices
[0] = points
[j
].x
;
834 vertices
[1] = points
[j
].y
;
836 if (format
== WGL_FONT_POLYGONS
) gluTessVertex( tess
, vertices
, vertices
);
837 else glVertex3d( vertices
[0], vertices
[1], vertices
[2] );
842 previous
[0] = curve
[2].x
;
843 previous
[1] = curve
[2].y
;
847 ERR("\t\tcurve type = %d\n", ppc
->wType
);
848 if (format
== WGL_FONT_POLYGONS
) gluTessEndContour( tess
);
853 ppc
= (TTPOLYCURVE
*)((char*)ppc
+ sizeof(*ppc
) +
854 (ppc
->cpfx
- 1) * sizeof(POINTFX
));
856 if (format
== WGL_FONT_POLYGONS
) gluTessEndContour( tess
);
858 pph
= (TTPOLYGONHEADER
*)((char*)pph
+ pph
->cb
);
863 if (format
== WGL_FONT_POLYGONS
) gluTessEndPolygon( tess
);
864 glTranslated( (GLdouble
)gm
.gmCellIncX
/ em_size
, (GLdouble
)gm
.gmCellIncY
/ em_size
, 0.0 );
871 DeleteObject(SelectObject(hdc
, old_font
));
872 if(format
== WGL_FONT_POLYGONS
)
878 /***********************************************************************
879 * wglUseFontOutlinesA (OPENGL32.@)
881 BOOL WINAPI
wglUseFontOutlinesA(HDC hdc
,
888 LPGLYPHMETRICSFLOAT lpgmf
)
890 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, FALSE
);
893 /***********************************************************************
894 * wglUseFontOutlinesW (OPENGL32.@)
896 BOOL WINAPI
wglUseFontOutlinesW(HDC hdc
,
903 LPGLYPHMETRICSFLOAT lpgmf
)
905 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, TRUE
);
908 /***********************************************************************
909 * glDebugEntry (OPENGL32.@)
911 GLint WINAPI
glDebugEntry( GLint unknown1
, GLint unknown2
)
916 const GLubyte
* WINAPI
glGetStringi( GLenum name
, GLuint index
)
918 struct glGetStringi_params args
=
920 .teb
= NtCurrentTeb(),
926 GLubyte
*wow64_str
= NULL
;
929 TRACE( "name %d, index %d\n", name
, index
);
932 if (UNIX_CALL( glGetStringi
, &args
) == STATUS_BUFFER_TOO_SMALL
) args
.ret
= wow64_str
= malloc( (size_t)args
.ret
);
934 if ((status
= UNIX_CALL( glGetStringi
, &args
))) WARN( "glGetStringi returned %#lx\n", status
);
936 if (args
.ret
!= wow64_str
) free( wow64_str
);
937 else if (args
.ret
) append_wow64_string( (char *)args
.ret
);
942 /***********************************************************************
943 * glGetString (OPENGL32.@)
945 const GLubyte
* WINAPI
glGetString( GLenum name
)
947 struct glGetString_params args
= { .teb
= NtCurrentTeb(), .name
= name
};
950 GLubyte
*wow64_str
= NULL
;
953 TRACE( "name %d\n", name
);
956 if (UNIX_CALL( glGetString
, &args
) == STATUS_BUFFER_TOO_SMALL
) args
.ret
= wow64_str
= malloc( (size_t)args
.ret
);
958 if ((status
= UNIX_CALL( glGetString
, &args
))) WARN( "glGetString returned %#lx\n", status
);
960 if (args
.ret
!= wow64_str
) free( wow64_str
);
961 else if (args
.ret
) append_wow64_string( (char *)args
.ret
);
966 const char * WINAPI
wglGetExtensionsStringARB( HDC hdc
)
968 struct wglGetExtensionsStringARB_params args
= { .teb
= NtCurrentTeb(), .hdc
= hdc
};
971 char *wow64_str
= NULL
;
974 TRACE( "hdc %p\n", hdc
);
977 if (UNIX_CALL( wglGetExtensionsStringARB
, &args
) == STATUS_BUFFER_TOO_SMALL
) args
.ret
= wow64_str
= malloc( (size_t)args
.ret
);
979 if ((status
= UNIX_CALL( wglGetExtensionsStringARB
, &args
))) WARN( "wglGetExtensionsStringARB returned %#lx\n", status
);
981 if (args
.ret
!= wow64_str
) free( wow64_str
);
982 else if (args
.ret
) append_wow64_string( wow64_str
);
987 const char * WINAPI
wglGetExtensionsStringEXT(void)
989 struct wglGetExtensionsStringEXT_params args
= { .teb
= NtCurrentTeb() };
992 char *wow64_str
= NULL
;
998 if (UNIX_CALL( wglGetExtensionsStringEXT
, &args
) == STATUS_BUFFER_TOO_SMALL
) args
.ret
= wow64_str
= malloc( (size_t)args
.ret
);
1000 if ((status
= UNIX_CALL( wglGetExtensionsStringEXT
, &args
))) WARN( "wglGetExtensionsStringEXT returned %#lx\n", status
);
1002 if (args
.ret
!= wow64_str
) free( wow64_str
);
1003 else if (args
.ret
) append_wow64_string( wow64_str
);
1008 const GLchar
* WINAPI
wglQueryCurrentRendererStringWINE( GLenum attribute
)
1010 struct wglQueryCurrentRendererStringWINE_params args
= { .teb
= NtCurrentTeb(), .attribute
= attribute
};
1013 char *wow64_str
= NULL
;
1016 TRACE( "attribute %d\n", attribute
);
1019 if (UNIX_CALL( wglQueryCurrentRendererStringWINE
, &args
) == STATUS_BUFFER_TOO_SMALL
) args
.ret
= wow64_str
= malloc( (size_t)args
.ret
);
1021 if ((status
= UNIX_CALL( wglQueryCurrentRendererStringWINE
, &args
))) WARN( "wglQueryCurrentRendererStringWINE returned %#lx\n", status
);
1023 if (args
.ret
!= wow64_str
) free( wow64_str
);
1024 else if (args
.ret
) append_wow64_string( wow64_str
);
1029 const GLchar
* WINAPI
wglQueryRendererStringWINE( HDC dc
, GLint renderer
, GLenum attribute
)
1031 struct wglQueryRendererStringWINE_params args
=
1033 .teb
= NtCurrentTeb(),
1035 .renderer
= renderer
,
1036 .attribute
= attribute
,
1040 char *wow64_str
= NULL
;
1043 TRACE( "dc %p, renderer %d, attribute %d\n", dc
, renderer
, attribute
);
1046 if (UNIX_CALL( wglQueryCurrentRendererStringWINE
, &args
) == STATUS_BUFFER_TOO_SMALL
) args
.ret
= wow64_str
= malloc( (size_t)args
.ret
);
1048 if ((status
= UNIX_CALL( wglQueryRendererStringWINE
, &args
))) WARN( "wglQueryRendererStringWINE returned %#lx\n", status
);
1050 if (args
.ret
!= wow64_str
) free( wow64_str
);
1051 else if (args
.ret
) append_wow64_string( wow64_str
);
1057 static void *get_buffer_pointer( GLenum target
)
1059 void (WINAPI
*p_glGetBufferPointerv
)( GLenum target
, GLenum pname
, void **params
);
1061 if (!(p_glGetBufferPointerv
= (void *)wglGetProcAddress( "glGetBufferPointerv" ))) return 0;
1062 p_glGetBufferPointerv( target
, GL_BUFFER_MAP_POINTER
, &ptr
);
1066 static void *get_named_buffer_pointer( GLint buffer
)
1068 void (WINAPI
*p_glGetNamedBufferPointerv
)( GLuint buffer
, GLenum pname
, void **params
);
1070 if (!(p_glGetNamedBufferPointerv
= (void *)wglGetProcAddress( "glGetNamedBufferPointerv" ))) return 0;
1071 p_glGetNamedBufferPointerv( buffer
, GL_BUFFER_MAP_POINTER
, &ptr
);
1076 static void *gl_map_buffer( enum unix_funcs code
, GLenum target
, GLenum access
)
1078 struct glMapBuffer_params args
=
1080 .teb
= NtCurrentTeb(),
1086 TRACE( "target %d, access %d\n", target
, access
);
1088 if (!(status
= WINE_UNIX_CALL( code
, &args
))) return args
.ret
;
1090 if (status
== STATUS_INVALID_ADDRESS
)
1092 TRACE( "Unable to map wow64 buffer directly, using copy buffer!\n" );
1093 if (!(args
.ret
= _aligned_malloc( (size_t)args
.ret
, 16 ))) status
= STATUS_NO_MEMORY
;
1094 else if (!(status
= WINE_UNIX_CALL( code
, &args
))) return args
.ret
;
1095 _aligned_free( args
.ret
);
1098 WARN( "glMapBuffer returned %#lx\n", status
);
1102 void * WINAPI
glMapBuffer( GLenum target
, GLenum access
)
1104 return gl_map_buffer( unix_glMapBuffer
, target
, access
);
1107 void * WINAPI
glMapBufferARB( GLenum target
, GLenum access
)
1109 return gl_map_buffer( unix_glMapBufferARB
, target
, access
);
1112 void * WINAPI
glMapBufferRange( GLenum target
, GLintptr offset
, GLsizeiptr length
, GLbitfield access
)
1114 struct glMapBufferRange_params args
=
1116 .teb
= NtCurrentTeb(),
1124 TRACE( "target %d, offset %Id, length %Id, access %d\n", target
, offset
, length
, access
);
1126 if (!(status
= UNIX_CALL( glMapBufferRange
, &args
))) return args
.ret
;
1128 if (status
== STATUS_INVALID_ADDRESS
)
1130 TRACE( "Unable to map wow64 buffer directly, using copy buffer!\n" );
1131 if (!(args
.ret
= _aligned_malloc( length
, 16 ))) status
= STATUS_NO_MEMORY
;
1132 else if (!(status
= UNIX_CALL( glMapBufferRange
, &args
))) return args
.ret
;
1133 _aligned_free( args
.ret
);
1136 WARN( "glMapBufferRange returned %#lx\n", status
);
1140 static void *gl_map_named_buffer( enum unix_funcs code
, GLuint buffer
, GLenum access
)
1142 struct glMapNamedBuffer_params args
=
1144 .teb
= NtCurrentTeb(),
1150 TRACE( "(%d, %d)\n", buffer
, access
);
1152 if (!(status
= WINE_UNIX_CALL( code
, &args
))) return args
.ret
;
1154 if (status
== STATUS_INVALID_ADDRESS
)
1156 TRACE( "Unable to map wow64 buffer directly, using copy buffer!\n" );
1157 if (!(args
.ret
= _aligned_malloc( (size_t)args
.ret
, 16 ))) status
= STATUS_NO_MEMORY
;
1158 else if (!(status
= WINE_UNIX_CALL( code
, &args
))) return args
.ret
;
1159 _aligned_free( args
.ret
);
1162 WARN( "glMapNamedBuffer returned %#lx\n", status
);
1166 void * WINAPI
glMapNamedBuffer( GLuint buffer
, GLenum access
)
1168 return gl_map_named_buffer( unix_glMapNamedBuffer
, buffer
, access
);
1171 void * WINAPI
glMapNamedBufferEXT( GLuint buffer
, GLenum access
)
1173 return gl_map_named_buffer( unix_glMapNamedBufferEXT
, buffer
, access
);
1176 static void *gl_map_named_buffer_range( enum unix_funcs code
, GLuint buffer
, GLintptr offset
, GLsizeiptr length
, GLbitfield access
)
1178 struct glMapNamedBufferRange_params args
=
1180 .teb
= NtCurrentTeb(),
1188 TRACE( "buffer %d, offset %Id, length %Id, access %d\n", buffer
, offset
, length
, access
);
1190 if (!(status
= WINE_UNIX_CALL( code
, &args
))) return args
.ret
;
1192 if (status
== STATUS_INVALID_ADDRESS
)
1194 TRACE( "Unable to map wow64 buffer directly, using copy buffer!\n" );
1195 if (!(args
.ret
= _aligned_malloc( length
, 16 ))) status
= STATUS_NO_MEMORY
;
1196 else if (!(status
= WINE_UNIX_CALL( code
, &args
))) return args
.ret
;
1197 _aligned_free( args
.ret
);
1200 WARN( "glMapNamedBufferRange returned %#lx\n", status
);
1204 void * WINAPI
glMapNamedBufferRange( GLuint buffer
, GLintptr offset
, GLsizeiptr length
, GLbitfield access
)
1206 return gl_map_named_buffer_range( unix_glMapNamedBufferRange
, buffer
, offset
, length
, access
);
1209 void * WINAPI
glMapNamedBufferRangeEXT( GLuint buffer
, GLintptr offset
, GLsizeiptr length
, GLbitfield access
)
1211 return gl_map_named_buffer_range( unix_glMapNamedBufferRangeEXT
, buffer
, offset
, length
, access
);
1214 static GLboolean
gl_unmap_buffer( enum unix_funcs code
, GLenum target
)
1216 struct glUnmapBuffer_params args
=
1218 .teb
= NtCurrentTeb(),
1223 void *ptr
= get_buffer_pointer( target
);
1226 TRACE( "target %d\n", target
);
1228 if (!(status
= WINE_UNIX_CALL( code
, &args
))) return args
.ret
;
1230 if (status
== STATUS_INVALID_ADDRESS
)
1232 TRACE( "Releasing wow64 copy buffer %p\n", ptr
);
1233 _aligned_free( ptr
);
1237 WARN( "glUnmapBuffer returned %#lx\n", status
);
1241 GLboolean WINAPI
glUnmapBuffer( GLenum target
)
1243 return gl_unmap_buffer( unix_glUnmapBuffer
, target
);
1246 GLboolean WINAPI
glUnmapBufferARB( GLenum target
)
1248 return gl_unmap_buffer( unix_glUnmapBufferARB
, target
);
1251 static GLboolean
gl_unmap_named_buffer( enum unix_funcs code
, GLuint buffer
)
1253 struct glUnmapNamedBuffer_params args
=
1255 .teb
= NtCurrentTeb(),
1260 void *ptr
= get_named_buffer_pointer( buffer
);
1263 TRACE( "buffer %d\n", buffer
);
1265 if (!(status
= WINE_UNIX_CALL( code
, &args
))) return args
.ret
;
1267 if (status
== STATUS_INVALID_ADDRESS
)
1269 TRACE( "Releasing wow64 copy buffer %p\n", ptr
);
1270 _aligned_free( ptr
);
1274 WARN( "glUnmapNamedBuffer returned %#lx\n", status
);
1278 GLboolean WINAPI
glUnmapNamedBuffer( GLuint buffer
)
1280 return gl_unmap_named_buffer( unix_glUnmapNamedBuffer
, buffer
);
1283 GLboolean WINAPI
glUnmapNamedBufferEXT( GLuint buffer
)
1285 return gl_unmap_named_buffer( unix_glUnmapNamedBufferEXT
, buffer
);
1288 static BOOL WINAPI
call_opengl_debug_message_callback( struct wine_gl_debug_message_params
*params
, ULONG size
)
1290 params
->user_callback( params
->source
, params
->type
, params
->id
, params
->severity
,
1291 params
->length
, params
->message
, params
->user_data
);
1295 /***********************************************************************
1296 * OpenGL initialisation routine
1298 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
1300 void **kernel_callback_table
;
1305 case DLL_PROCESS_ATTACH
:
1306 if ((status
= __wine_init_unix_call()))
1308 ERR( "Failed to load unixlib, status %#lx\n", status
);
1312 kernel_callback_table
= NtCurrentTeb()->Peb
->KernelCallbackTable
;
1313 kernel_callback_table
[NtUserCallOpenGLDebugMessageCallback
] = call_opengl_debug_message_callback
;
1315 case DLL_THREAD_ATTACH
:
1316 if ((status
= UNIX_CALL( thread_attach
, NtCurrentTeb() )))
1318 WARN( "Failed to initialize thread, status %#lx\n", status
);
1323 case DLL_PROCESS_DETACH
:
1324 if (reserved
) break;
1325 UNIX_CALL( process_detach
, NULL
);
1327 cleanup_wow64_strings();