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
25 WINE_DEFAULT_DEBUG_CHANNEL(wgl
);
27 /***********************************************************************
28 * wglUseFontBitmaps_common
30 static BOOL
wglUseFontBitmaps_common( HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
, BOOL unicode
)
32 const GLDISPATCHTABLE
* funcs
= IntGetCurrentDispatchTable();
34 unsigned int glyph
, size
= 0;
35 void *bitmap
= NULL
, *gl_bitmap
= NULL
;
39 funcs
->GetIntegerv(GL_UNPACK_ALIGNMENT
, &org_alignment
);
40 funcs
->PixelStorei(GL_UNPACK_ALIGNMENT
, 4);
42 for (glyph
= first
; glyph
< first
+ count
; glyph
++) {
43 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
44 unsigned int needed_size
, height
, width
, width_int
;
47 needed_size
= GetGlyphOutlineW(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, &identity
);
49 needed_size
= GetGlyphOutlineA(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, &identity
);
51 TRACE("Glyph: %3d / List: %d size %d\n", glyph
, listBase
, needed_size
);
52 if (needed_size
== GDI_ERROR
) {
57 if (needed_size
> size
) {
59 HeapFree(GetProcessHeap(), 0, bitmap
);
60 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
61 bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
62 gl_bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
65 ret
= (GetGlyphOutlineW(hdc
, glyph
, GGO_BITMAP
, &gm
, size
, bitmap
, &identity
) != GDI_ERROR
);
67 ret
= (GetGlyphOutlineA(hdc
, glyph
, GGO_BITMAP
, &gm
, size
, bitmap
, &identity
) != GDI_ERROR
);
72 unsigned char *bitmap_
= bitmap
;
74 TRACE(" - bbox: %d x %d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
75 TRACE(" - origin: (%d, %d)\n", gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
76 TRACE(" - increment: %d - %d\n", gm
.gmCellIncX
, gm
.gmCellIncY
);
77 if (needed_size
!= 0) {
78 TRACE(" - bitmap:\n");
79 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
81 for (width
= 0, bitmask
= 0x80; width
< gm
.gmBlackBoxX
; width
++, bitmask
>>= 1) {
86 if (*bitmap_
& bitmask
)
91 bitmap_
+= (4 - ((UINT_PTR
)bitmap_
& 0x03));
97 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
98 * glyph for it to be drawn properly.
100 if (needed_size
!= 0) {
101 width_int
= (gm
.gmBlackBoxX
+ 31) / 32;
102 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
103 for (width
= 0; width
< width_int
; width
++) {
104 ((int *) gl_bitmap
)[(gm
.gmBlackBoxY
- height
- 1) * width_int
+ width
] =
105 ((int *) bitmap
)[height
* width_int
+ width
];
110 funcs
->NewList(listBase
++, GL_COMPILE
);
111 if (needed_size
!= 0) {
112 funcs
->Bitmap(gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
113 0 - gm
.gmptGlyphOrigin
.x
, (int) gm
.gmBlackBoxY
- gm
.gmptGlyphOrigin
.y
,
114 gm
.gmCellIncX
, gm
.gmCellIncY
,
117 /* This is the case of 'empty' glyphs like the space character */
118 funcs
->Bitmap(0, 0, 0, 0, gm
.gmCellIncX
, gm
.gmCellIncY
, NULL
);
123 funcs
->PixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
124 HeapFree(GetProcessHeap(), 0, bitmap
);
125 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
129 /***********************************************************************
130 * wglUseFontBitmapsA (OPENGL32.@)
132 BOOL WINAPI
wglUseFontBitmapsA(HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
)
134 return wglUseFontBitmaps_common( hdc
, first
, count
, listBase
, FALSE
);
137 /***********************************************************************
138 * wglUseFontBitmapsW (OPENGL32.@)
140 BOOL WINAPI
wglUseFontBitmapsW(HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
)
142 return wglUseFontBitmaps_common( hdc
, first
, count
, listBase
, TRUE
);
145 /* FIXME: should probably have a glu.h header */
147 typedef struct GLUtesselator GLUtesselator
;
148 typedef void (WINAPI
*_GLUfuncptr
)(void);
150 #define GLU_TESS_BEGIN 100100
151 #define GLU_TESS_VERTEX 100101
152 #define GLU_TESS_END 100102
154 static GLUtesselator
* (WINAPI
*pgluNewTess
)(void);
155 static void (WINAPI
*pgluDeleteTess
)(GLUtesselator
*tess
);
156 static void (WINAPI
*pgluTessNormal
)(GLUtesselator
*tess
, GLdouble x
, GLdouble y
, GLdouble z
);
157 static void (WINAPI
*pgluTessBeginPolygon
)(GLUtesselator
*tess
, void *polygon_data
);
158 static void (WINAPI
*pgluTessEndPolygon
)(GLUtesselator
*tess
);
159 static void (WINAPI
*pgluTessCallback
)(GLUtesselator
*tess
, GLenum which
, _GLUfuncptr fn
);
160 static void (WINAPI
*pgluTessBeginContour
)(GLUtesselator
*tess
);
161 static void (WINAPI
*pgluTessEndContour
)(GLUtesselator
*tess
);
162 static void (WINAPI
*pgluTessVertex
)(GLUtesselator
*tess
, GLdouble
*location
, GLvoid
* data
);
164 static HMODULE
load_libglu(void)
166 static const WCHAR glu32W
[] = {'g','l','u','3','2','.','d','l','l',0};
167 static int already_loaded
;
168 static HMODULE module
;
170 if (already_loaded
) return module
;
173 TRACE("Trying to load GLU library\n");
174 module
= LoadLibraryW( glu32W
);
177 WARN("Failed to load glu32\n");
180 #define LOAD_FUNCPTR(f) p##f = (void *)GetProcAddress( module, #f )
181 LOAD_FUNCPTR(gluNewTess
);
182 LOAD_FUNCPTR(gluDeleteTess
);
183 LOAD_FUNCPTR(gluTessBeginContour
);
184 LOAD_FUNCPTR(gluTessNormal
);
185 LOAD_FUNCPTR(gluTessBeginPolygon
);
186 LOAD_FUNCPTR(gluTessCallback
);
187 LOAD_FUNCPTR(gluTessEndContour
);
188 LOAD_FUNCPTR(gluTessEndPolygon
);
189 LOAD_FUNCPTR(gluTessVertex
);
194 static void fixed_to_double(POINTFX fixed
, UINT em_size
, GLdouble vertex
[3])
196 vertex
[0] = (fixed
.x
.value
+ (GLdouble
)fixed
.x
.fract
/ (1 << 16)) / em_size
;
197 vertex
[1] = (fixed
.y
.value
+ (GLdouble
)fixed
.y
.fract
/ (1 << 16)) / em_size
;
201 static void WINAPI
tess_callback_vertex(GLvoid
*vertex
)
203 const GLDISPATCHTABLE
* funcs
= IntGetCurrentDispatchTable();
204 GLdouble
*dbl
= vertex
;
205 TRACE("%f, %f, %f\n", dbl
[0], dbl
[1], dbl
[2]);
206 funcs
->Vertex3dv(vertex
);
209 static void WINAPI
tess_callback_begin(GLenum which
)
211 const GLDISPATCHTABLE
* funcs
= IntGetCurrentDispatchTable();
212 TRACE("%d\n", which
);
216 static void WINAPI
tess_callback_end(void)
218 const GLDISPATCHTABLE
* funcs
= IntGetCurrentDispatchTable();
223 typedef struct _bezier_vector
{
228 static double bezier_deviation_squared(const bezier_vector
*p
)
230 bezier_vector deviation
;
231 bezier_vector vertex
;
236 vertex
.x
= (p
[0].x
+ p
[1].x
*2 + p
[2].x
)/4 - p
[0].x
;
237 vertex
.y
= (p
[0].y
+ p
[1].y
*2 + p
[2].y
)/4 - p
[0].y
;
239 base
.x
= p
[2].x
- p
[0].x
;
240 base
.y
= p
[2].y
- p
[0].y
;
242 base_length
= sqrt(base
.x
*base
.x
+ base
.y
*base
.y
);
243 base
.x
/= base_length
;
244 base
.y
/= base_length
;
246 dot
= base
.x
*vertex
.x
+ base
.y
*vertex
.y
;
247 dot
= min(max(dot
, 0.0), base_length
);
251 deviation
.x
= vertex
.x
-base
.x
;
252 deviation
.y
= vertex
.y
-base
.y
;
254 return deviation
.x
*deviation
.x
+ deviation
.y
*deviation
.y
;
257 static int bezier_approximate(const bezier_vector
*p
, bezier_vector
*points
, FLOAT deviation
)
259 bezier_vector first_curve
[3];
260 bezier_vector second_curve
[3];
261 bezier_vector vertex
;
264 if(bezier_deviation_squared(p
) <= deviation
*deviation
)
271 vertex
.x
= (p
[0].x
+ p
[1].x
*2 + p
[2].x
)/4;
272 vertex
.y
= (p
[0].y
+ p
[1].y
*2 + p
[2].y
)/4;
274 first_curve
[0] = p
[0];
275 first_curve
[1].x
= (p
[0].x
+ p
[1].x
)/2;
276 first_curve
[1].y
= (p
[0].y
+ p
[1].y
)/2;
277 first_curve
[2] = vertex
;
279 second_curve
[0] = vertex
;
280 second_curve
[1].x
= (p
[2].x
+ p
[1].x
)/2;
281 second_curve
[1].y
= (p
[2].y
+ p
[1].y
)/2;
282 second_curve
[2] = p
[2];
284 total_vertices
= bezier_approximate(first_curve
, points
, deviation
);
286 points
+= total_vertices
;
287 total_vertices
+= bezier_approximate(second_curve
, points
, deviation
);
288 return total_vertices
;
291 /***********************************************************************
292 * wglUseFontOutlines_common
294 static BOOL
wglUseFontOutlines_common(HDC hdc
,
301 LPGLYPHMETRICSFLOAT lpgmf
,
304 const GLDISPATCHTABLE
* funcs
= IntGetCurrentDispatchTable();
306 const MAT2 identity
= {{0,1},{0,0},{0,0},{0,1}};
307 GLUtesselator
*tess
= NULL
;
309 HFONT old_font
, unscaled_font
;
313 TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc
, first
, count
,
314 listBase
, deviation
, extrusion
, format
, lpgmf
, unicode
? "W" : "A");
317 deviation
= 1.0/em_size
;
319 if(format
== WGL_FONT_POLYGONS
)
323 ERR("glu32 is required for this function but isn't available\n");
327 tess
= pgluNewTess();
328 if(!tess
) return FALSE
;
329 pgluTessCallback(tess
, GLU_TESS_VERTEX
, (_GLUfuncptr
)tess_callback_vertex
);
330 pgluTessCallback(tess
, GLU_TESS_BEGIN
, (_GLUfuncptr
)tess_callback_begin
);
331 pgluTessCallback(tess
, GLU_TESS_END
, tess_callback_end
);
334 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
335 rc
.left
= rc
.right
= rc
.bottom
= 0;
337 DPtoLP(hdc
, (POINT
*)&rc
, 2);
338 lf
.lfHeight
= -abs(rc
.top
- rc
.bottom
);
339 lf
.lfOrientation
= lf
.lfEscapement
= 0;
340 unscaled_font
= CreateFontIndirectW(&lf
);
341 old_font
= SelectObject(hdc
, unscaled_font
);
343 for (glyph
= first
; glyph
< first
+ count
; glyph
++)
348 TTPOLYGONHEADER
*pph
;
350 GLdouble
*vertices
= NULL
, *vertices_temp
= NULL
;
351 int vertex_total
= -1;
354 needed
= GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
356 needed
= GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
358 if(needed
== GDI_ERROR
)
361 buf
= HeapAlloc(GetProcessHeap(), 0, needed
);
367 GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
369 GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
371 TRACE("glyph %d\n", glyph
);
375 lpgmf
->gmfBlackBoxX
= (float)gm
.gmBlackBoxX
/ em_size
;
376 lpgmf
->gmfBlackBoxY
= (float)gm
.gmBlackBoxY
/ em_size
;
377 lpgmf
->gmfptGlyphOrigin
.x
= (float)gm
.gmptGlyphOrigin
.x
/ em_size
;
378 lpgmf
->gmfptGlyphOrigin
.y
= (float)gm
.gmptGlyphOrigin
.y
/ em_size
;
379 lpgmf
->gmfCellIncX
= (float)gm
.gmCellIncX
/ em_size
;
380 lpgmf
->gmfCellIncY
= (float)gm
.gmCellIncY
/ em_size
;
382 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf
->gmfBlackBoxX
, lpgmf
->gmfBlackBoxY
,
383 lpgmf
->gmfptGlyphOrigin
.x
, lpgmf
->gmfptGlyphOrigin
.y
, lpgmf
->gmfCellIncX
, lpgmf
->gmfCellIncY
);
387 funcs
->NewList(listBase
++, GL_COMPILE
);
388 funcs
->FrontFace(GL_CCW
);
389 if(format
== WGL_FONT_POLYGONS
)
391 funcs
->Normal3d(0.0, 0.0, 1.0);
392 pgluTessNormal(tess
, 0, 0, 1);
393 pgluTessBeginPolygon(tess
, NULL
);
398 if(vertex_total
!= -1)
399 vertices_temp
= vertices
= HeapAlloc(GetProcessHeap(), 0, vertex_total
* 3 * sizeof(GLdouble
));
402 pph
= (TTPOLYGONHEADER
*)buf
;
403 while((BYTE
*)pph
< buf
+ needed
)
405 GLdouble previous
[3];
406 fixed_to_double(pph
->pfxStart
, em_size
, previous
);
409 TRACE("\tstart %d, %d\n", pph
->pfxStart
.x
.value
, pph
->pfxStart
.y
.value
);
411 if(format
== WGL_FONT_POLYGONS
)
412 pgluTessBeginContour(tess
);
414 funcs
->Begin(GL_LINE_LOOP
);
418 fixed_to_double(pph
->pfxStart
, em_size
, vertices
);
419 if(format
== WGL_FONT_POLYGONS
)
420 pgluTessVertex(tess
, vertices
, vertices
);
422 funcs
->Vertex3d(vertices
[0], vertices
[1], vertices
[2]);
427 ppc
= (TTPOLYCURVE
*)((char*)pph
+ sizeof(*pph
));
428 while((char*)ppc
< (char*)pph
+ pph
->cb
)
435 for(i
= 0; i
< ppc
->cpfx
; i
++)
439 TRACE("\t\tline to %d, %d\n",
440 ppc
->apfx
[i
].x
.value
, ppc
->apfx
[i
].y
.value
);
441 fixed_to_double(ppc
->apfx
[i
], em_size
, vertices
);
442 if(format
== WGL_FONT_POLYGONS
)
443 pgluTessVertex(tess
, vertices
, vertices
);
445 funcs
->Vertex3d(vertices
[0], vertices
[1], vertices
[2]);
448 fixed_to_double(ppc
->apfx
[i
], em_size
, previous
);
453 case TT_PRIM_QSPLINE
:
454 for(i
= 0; i
< ppc
->cpfx
-1; i
++)
456 bezier_vector curve
[3];
457 bezier_vector
*points
;
458 GLdouble curve_vertex
[3];
461 TRACE("\t\tcurve %d,%d %d,%d\n",
462 ppc
->apfx
[i
].x
.value
, ppc
->apfx
[i
].y
.value
,
463 ppc
->apfx
[i
+ 1].x
.value
, ppc
->apfx
[i
+ 1].y
.value
);
465 curve
[0].x
= previous
[0];
466 curve
[0].y
= previous
[1];
467 fixed_to_double(ppc
->apfx
[i
], em_size
, curve_vertex
);
468 curve
[1].x
= curve_vertex
[0];
469 curve
[1].y
= curve_vertex
[1];
470 fixed_to_double(ppc
->apfx
[i
+ 1], em_size
, curve_vertex
);
471 curve
[2].x
= curve_vertex
[0];
472 curve
[2].y
= curve_vertex
[1];
475 curve
[2].x
= (curve
[1].x
+ curve
[2].x
)/2;
476 curve
[2].y
= (curve
[1].y
+ curve
[2].y
)/2;
478 num
= bezier_approximate(curve
, NULL
, deviation
);
479 points
= HeapAlloc(GetProcessHeap(), 0, num
*sizeof(bezier_vector
));
480 num
= bezier_approximate(curve
, points
, deviation
);
486 TRACE("\t\t\tvertex at %f,%f\n", points
[j
].x
, points
[j
].y
);
487 vertices
[0] = points
[j
].x
;
488 vertices
[1] = points
[j
].y
;
490 if(format
== WGL_FONT_POLYGONS
)
491 pgluTessVertex(tess
, vertices
, vertices
);
493 funcs
->Vertex3d(vertices
[0], vertices
[1], vertices
[2]);
497 HeapFree(GetProcessHeap(), 0, points
);
498 previous
[0] = curve
[2].x
;
499 previous
[1] = curve
[2].y
;
503 ERR("\t\tcurve type = %d\n", ppc
->wType
);
504 if(format
== WGL_FONT_POLYGONS
)
505 pgluTessEndContour(tess
);
511 ppc
= (TTPOLYCURVE
*)((char*)ppc
+ sizeof(*ppc
) +
512 (ppc
->cpfx
- 1) * sizeof(POINTFX
));
514 if(format
== WGL_FONT_POLYGONS
)
515 pgluTessEndContour(tess
);
518 pph
= (TTPOLYGONHEADER
*)((char*)pph
+ pph
->cb
);
523 if(format
== WGL_FONT_POLYGONS
)
524 pgluTessEndPolygon(tess
);
525 funcs
->Translated((GLdouble
)gm
.gmCellIncX
/ em_size
, (GLdouble
)gm
.gmCellIncY
/ em_size
, 0.0);
528 HeapFree(GetProcessHeap(), 0, buf
);
531 HeapFree(GetProcessHeap(), 0, vertices_temp
);
535 DeleteObject(SelectObject(hdc
, old_font
));
536 if(format
== WGL_FONT_POLYGONS
)
537 pgluDeleteTess(tess
);
542 /***********************************************************************
543 * wglUseFontOutlinesA (OPENGL32.@)
545 BOOL WINAPI
wglUseFontOutlinesA(HDC hdc
,
552 LPGLYPHMETRICSFLOAT lpgmf
)
554 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, FALSE
);
557 /***********************************************************************
558 * wglUseFontOutlinesW (OPENGL32.@)
560 BOOL WINAPI
wglUseFontOutlinesW(HDC hdc
,
567 LPGLYPHMETRICSFLOAT lpgmf
)
569 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, TRUE
);