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
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(wgl
);
33 /***********************************************************************
34 * wglUseFontBitmaps_common
36 static BOOL
wglUseFontBitmaps_common( HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
, BOOL unicode
)
39 unsigned int glyph
, size
= 0;
40 void *bitmap
= NULL
, *gl_bitmap
= NULL
;
44 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &org_alignment
);
45 glPixelStorei(GL_UNPACK_ALIGNMENT
, 4);
47 for (glyph
= first
; glyph
< first
+ count
; glyph
++) {
48 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
49 unsigned int needed_size
, height
, width
, width_int
;
52 needed_size
= GetGlyphOutlineW(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, &identity
);
54 needed_size
= GetGlyphOutlineA(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, &identity
);
56 TRACE("Glyph: %3d / List: %d size %d\n", glyph
, listBase
, needed_size
);
57 if (needed_size
== GDI_ERROR
) {
62 if (needed_size
> size
) {
64 HeapFree(GetProcessHeap(), 0, bitmap
);
65 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
66 bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
67 gl_bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
70 ret
= (GetGlyphOutlineW(hdc
, glyph
, GGO_BITMAP
, &gm
, size
, bitmap
, &identity
) != GDI_ERROR
);
72 ret
= (GetGlyphOutlineA(hdc
, glyph
, GGO_BITMAP
, &gm
, size
, bitmap
, &identity
) != GDI_ERROR
);
77 unsigned char *bitmap_
= bitmap
;
79 TRACE(" - bbox: %d x %d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
80 TRACE(" - origin: (%d, %d)\n", gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
81 TRACE(" - increment: %d - %d\n", gm
.gmCellIncX
, gm
.gmCellIncY
);
82 if (needed_size
!= 0) {
83 TRACE(" - bitmap:\n");
84 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
86 for (width
= 0, bitmask
= 0x80; width
< gm
.gmBlackBoxX
; width
++, bitmask
>>= 1) {
91 if (*bitmap_
& bitmask
)
96 bitmap_
+= (4 - ((UINT_PTR
)bitmap_
& 0x03));
102 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
103 * glyph for it to be drawn properly.
105 if (needed_size
!= 0) {
106 width_int
= (gm
.gmBlackBoxX
+ 31) / 32;
107 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
108 for (width
= 0; width
< width_int
; width
++) {
109 ((int *) gl_bitmap
)[(gm
.gmBlackBoxY
- height
- 1) * width_int
+ width
] =
110 ((int *) bitmap
)[height
* width_int
+ width
];
115 glNewList(listBase
++, GL_COMPILE
);
116 if (needed_size
!= 0) {
117 glBitmap(gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
118 0 - gm
.gmptGlyphOrigin
.x
, (int) gm
.gmBlackBoxY
- gm
.gmptGlyphOrigin
.y
,
119 gm
.gmCellIncX
, gm
.gmCellIncY
,
122 /* This is the case of 'empty' glyphs like the space character */
123 glBitmap(0, 0, 0, 0, gm
.gmCellIncX
, gm
.gmCellIncY
, NULL
);
128 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
129 HeapFree(GetProcessHeap(), 0, bitmap
);
130 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
134 /***********************************************************************
135 * wglUseFontBitmapsA (OPENGL32.@)
137 BOOL WINAPI
wglUseFontBitmapsA(HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
)
139 return wglUseFontBitmaps_common( hdc
, first
, count
, listBase
, FALSE
);
142 /***********************************************************************
143 * wglUseFontBitmapsW (OPENGL32.@)
145 BOOL WINAPI
wglUseFontBitmapsW(HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
)
147 return wglUseFontBitmaps_common( hdc
, first
, count
, listBase
, TRUE
);
150 /* FIXME: should probably have a glu.h header */
152 typedef struct GLUtesselator GLUtesselator
;
153 typedef void (WINAPI
*_GLUfuncptr
)(void);
155 #define GLU_TESS_BEGIN 100100
156 #define GLU_TESS_VERTEX 100101
157 #define GLU_TESS_END 100102
159 static GLUtesselator
* (WINAPI
*pgluNewTess
)(void);
160 static void (WINAPI
*pgluDeleteTess
)(GLUtesselator
*tess
);
161 static void (WINAPI
*pgluTessNormal
)(GLUtesselator
*tess
, GLdouble x
, GLdouble y
, GLdouble z
);
162 static void (WINAPI
*pgluTessBeginPolygon
)(GLUtesselator
*tess
, void *polygon_data
);
163 static void (WINAPI
*pgluTessEndPolygon
)(GLUtesselator
*tess
);
164 static void (WINAPI
*pgluTessCallback
)(GLUtesselator
*tess
, GLenum which
, _GLUfuncptr fn
);
165 static void (WINAPI
*pgluTessBeginContour
)(GLUtesselator
*tess
);
166 static void (WINAPI
*pgluTessEndContour
)(GLUtesselator
*tess
);
167 static void (WINAPI
*pgluTessVertex
)(GLUtesselator
*tess
, GLdouble
*location
, GLvoid
* data
);
169 static HMODULE
load_libglu(void)
171 static const WCHAR glu32W
[] = {'g','l','u','3','2','.','d','l','l',0};
172 static int already_loaded
;
173 static HMODULE module
;
175 if (already_loaded
) return module
;
178 TRACE("Trying to load GLU library\n");
179 module
= LoadLibraryW( glu32W
);
182 WARN("Failed to load glu32\n");
185 #define LOAD_FUNCPTR(f) p##f = (void *)GetProcAddress( module, #f )
186 LOAD_FUNCPTR(gluNewTess
);
187 LOAD_FUNCPTR(gluDeleteTess
);
188 LOAD_FUNCPTR(gluTessBeginContour
);
189 LOAD_FUNCPTR(gluTessNormal
);
190 LOAD_FUNCPTR(gluTessBeginPolygon
);
191 LOAD_FUNCPTR(gluTessCallback
);
192 LOAD_FUNCPTR(gluTessEndContour
);
193 LOAD_FUNCPTR(gluTessEndPolygon
);
194 LOAD_FUNCPTR(gluTessVertex
);
199 static void fixed_to_double(POINTFX fixed
, UINT em_size
, GLdouble vertex
[3])
201 vertex
[0] = (fixed
.x
.value
+ (GLdouble
)fixed
.x
.fract
/ (1 << 16)) / em_size
;
202 vertex
[1] = (fixed
.y
.value
+ (GLdouble
)fixed
.y
.fract
/ (1 << 16)) / em_size
;
206 static void WINAPI
tess_callback_vertex(GLvoid
*vertex
)
208 GLdouble
*dbl
= vertex
;
209 TRACE("%f, %f, %f\n", dbl
[0], dbl
[1], dbl
[2]);
213 static void WINAPI
tess_callback_begin(GLenum which
)
215 TRACE("%d\n", which
);
219 static void WINAPI
tess_callback_end(void)
225 typedef struct _bezier_vector
{
230 static double bezier_deviation_squared(const bezier_vector
*p
)
232 bezier_vector deviation
;
233 bezier_vector vertex
;
238 vertex
.x
= (p
[0].x
+ p
[1].x
*2 + p
[2].x
)/4 - p
[0].x
;
239 vertex
.y
= (p
[0].y
+ p
[1].y
*2 + p
[2].y
)/4 - p
[0].y
;
241 base
.x
= p
[2].x
- p
[0].x
;
242 base
.y
= p
[2].y
- p
[0].y
;
244 base_length
= sqrt(base
.x
*base
.x
+ base
.y
*base
.y
);
245 base
.x
/= base_length
;
246 base
.y
/= base_length
;
248 dot
= base
.x
*vertex
.x
+ base
.y
*vertex
.y
;
249 dot
= min(max(dot
, 0.0), base_length
);
253 deviation
.x
= vertex
.x
-base
.x
;
254 deviation
.y
= vertex
.y
-base
.y
;
256 return deviation
.x
*deviation
.x
+ deviation
.y
*deviation
.y
;
259 static int bezier_approximate(const bezier_vector
*p
, bezier_vector
*points
, FLOAT deviation
)
261 bezier_vector first_curve
[3];
262 bezier_vector second_curve
[3];
263 bezier_vector vertex
;
266 if(bezier_deviation_squared(p
) <= deviation
*deviation
)
273 vertex
.x
= (p
[0].x
+ p
[1].x
*2 + p
[2].x
)/4;
274 vertex
.y
= (p
[0].y
+ p
[1].y
*2 + p
[2].y
)/4;
276 first_curve
[0] = p
[0];
277 first_curve
[1].x
= (p
[0].x
+ p
[1].x
)/2;
278 first_curve
[1].y
= (p
[0].y
+ p
[1].y
)/2;
279 first_curve
[2] = vertex
;
281 second_curve
[0] = vertex
;
282 second_curve
[1].x
= (p
[2].x
+ p
[1].x
)/2;
283 second_curve
[1].y
= (p
[2].y
+ p
[1].y
)/2;
284 second_curve
[2] = p
[2];
286 total_vertices
= bezier_approximate(first_curve
, points
, deviation
);
288 points
+= total_vertices
;
289 total_vertices
+= bezier_approximate(second_curve
, points
, deviation
);
290 return total_vertices
;
293 /***********************************************************************
294 * wglUseFontOutlines_common
296 static BOOL
wglUseFontOutlines_common(HDC hdc
,
303 LPGLYPHMETRICSFLOAT lpgmf
,
307 const MAT2 identity
= {{0,1},{0,0},{0,0},{0,1}};
308 GLUtesselator
*tess
= NULL
;
310 HFONT old_font
, unscaled_font
;
314 TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc
, first
, count
,
315 listBase
, deviation
, extrusion
, format
, lpgmf
, unicode
? "W" : "A");
318 deviation
= 1.0/em_size
;
320 if(format
== WGL_FONT_POLYGONS
)
324 ERR("glu32 is required for this function but isn't available\n");
328 tess
= pgluNewTess();
329 if(!tess
) return FALSE
;
330 pgluTessCallback(tess
, GLU_TESS_VERTEX
, (_GLUfuncptr
)tess_callback_vertex
);
331 pgluTessCallback(tess
, GLU_TESS_BEGIN
, (_GLUfuncptr
)tess_callback_begin
);
332 pgluTessCallback(tess
, GLU_TESS_END
, tess_callback_end
);
335 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
336 rc
.left
= rc
.right
= rc
.bottom
= 0;
338 DPtoLP(hdc
, (POINT
*)&rc
, 2);
339 lf
.lfHeight
= -abs(rc
.top
- rc
.bottom
);
340 lf
.lfOrientation
= lf
.lfEscapement
= 0;
341 unscaled_font
= CreateFontIndirectW(&lf
);
342 old_font
= SelectObject(hdc
, unscaled_font
);
344 for (glyph
= first
; glyph
< first
+ count
; glyph
++)
349 TTPOLYGONHEADER
*pph
;
351 GLdouble
*vertices
= NULL
;
352 int vertex_total
= -1;
355 needed
= GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
357 needed
= GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
359 if(needed
== GDI_ERROR
)
362 buf
= HeapAlloc(GetProcessHeap(), 0, needed
);
365 GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
367 GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
369 TRACE("glyph %d\n", glyph
);
373 lpgmf
->gmfBlackBoxX
= (float)gm
.gmBlackBoxX
/ em_size
;
374 lpgmf
->gmfBlackBoxY
= (float)gm
.gmBlackBoxY
/ em_size
;
375 lpgmf
->gmfptGlyphOrigin
.x
= (float)gm
.gmptGlyphOrigin
.x
/ em_size
;
376 lpgmf
->gmfptGlyphOrigin
.y
= (float)gm
.gmptGlyphOrigin
.y
/ em_size
;
377 lpgmf
->gmfCellIncX
= (float)gm
.gmCellIncX
/ em_size
;
378 lpgmf
->gmfCellIncY
= (float)gm
.gmCellIncY
/ em_size
;
380 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf
->gmfBlackBoxX
, lpgmf
->gmfBlackBoxY
,
381 lpgmf
->gmfptGlyphOrigin
.x
, lpgmf
->gmfptGlyphOrigin
.y
, lpgmf
->gmfCellIncX
, lpgmf
->gmfCellIncY
);
385 glNewList(listBase
++, GL_COMPILE
);
387 if(format
== WGL_FONT_POLYGONS
)
389 glNormal3d(0.0, 0.0, 1.0);
390 pgluTessNormal(tess
, 0, 0, 1);
391 pgluTessBeginPolygon(tess
, NULL
);
396 if(vertex_total
!= -1)
397 vertices
= HeapAlloc(GetProcessHeap(), 0, vertex_total
* 3 * sizeof(GLdouble
));
400 pph
= (TTPOLYGONHEADER
*)buf
;
401 while((BYTE
*)pph
< buf
+ needed
)
403 GLdouble previous
[3];
404 fixed_to_double(pph
->pfxStart
, em_size
, previous
);
407 TRACE("\tstart %d, %d\n", pph
->pfxStart
.x
.value
, pph
->pfxStart
.y
.value
);
409 if(format
== WGL_FONT_POLYGONS
)
410 pgluTessBeginContour(tess
);
412 glBegin(GL_LINE_LOOP
);
416 fixed_to_double(pph
->pfxStart
, em_size
, vertices
);
417 if(format
== WGL_FONT_POLYGONS
)
418 pgluTessVertex(tess
, vertices
, vertices
);
420 glVertex3d(vertices
[0], vertices
[1], vertices
[2]);
425 ppc
= (TTPOLYCURVE
*)((char*)pph
+ sizeof(*pph
));
426 while((char*)ppc
< (char*)pph
+ pph
->cb
)
433 for(i
= 0; i
< ppc
->cpfx
; i
++)
437 TRACE("\t\tline to %d, %d\n",
438 ppc
->apfx
[i
].x
.value
, ppc
->apfx
[i
].y
.value
);
439 fixed_to_double(ppc
->apfx
[i
], em_size
, vertices
);
440 if(format
== WGL_FONT_POLYGONS
)
441 pgluTessVertex(tess
, vertices
, vertices
);
443 glVertex3d(vertices
[0], vertices
[1], vertices
[2]);
446 fixed_to_double(ppc
->apfx
[i
], em_size
, previous
);
451 case TT_PRIM_QSPLINE
:
452 for(i
= 0; i
< ppc
->cpfx
-1; i
++)
454 bezier_vector curve
[3];
455 bezier_vector
*points
;
456 GLdouble curve_vertex
[3];
459 TRACE("\t\tcurve %d,%d %d,%d\n",
460 ppc
->apfx
[i
].x
.value
, ppc
->apfx
[i
].y
.value
,
461 ppc
->apfx
[i
+ 1].x
.value
, ppc
->apfx
[i
+ 1].y
.value
);
463 curve
[0].x
= previous
[0];
464 curve
[0].y
= previous
[1];
465 fixed_to_double(ppc
->apfx
[i
], em_size
, curve_vertex
);
466 curve
[1].x
= curve_vertex
[0];
467 curve
[1].y
= curve_vertex
[1];
468 fixed_to_double(ppc
->apfx
[i
+ 1], em_size
, curve_vertex
);
469 curve
[2].x
= curve_vertex
[0];
470 curve
[2].y
= curve_vertex
[1];
473 curve
[2].x
= (curve
[1].x
+ curve
[2].x
)/2;
474 curve
[2].y
= (curve
[1].y
+ curve
[2].y
)/2;
476 num
= bezier_approximate(curve
, NULL
, deviation
);
477 points
= HeapAlloc(GetProcessHeap(), 0, num
*sizeof(bezier_vector
));
478 num
= bezier_approximate(curve
, points
, deviation
);
484 TRACE("\t\t\tvertex at %f,%f\n", points
[j
].x
, points
[j
].y
);
485 vertices
[0] = points
[j
].x
;
486 vertices
[1] = points
[j
].y
;
488 if(format
== WGL_FONT_POLYGONS
)
489 pgluTessVertex(tess
, vertices
, vertices
);
491 glVertex3d(vertices
[0], vertices
[1], vertices
[2]);
495 HeapFree(GetProcessHeap(), 0, points
);
496 previous
[0] = curve
[2].x
;
497 previous
[1] = curve
[2].y
;
501 ERR("\t\tcurve type = %d\n", ppc
->wType
);
502 if(format
== WGL_FONT_POLYGONS
)
503 pgluTessEndContour(tess
);
509 ppc
= (TTPOLYCURVE
*)((char*)ppc
+ sizeof(*ppc
) +
510 (ppc
->cpfx
- 1) * sizeof(POINTFX
));
512 if(format
== WGL_FONT_POLYGONS
)
513 pgluTessEndContour(tess
);
516 pph
= (TTPOLYGONHEADER
*)((char*)pph
+ pph
->cb
);
521 if(format
== WGL_FONT_POLYGONS
)
522 pgluTessEndPolygon(tess
);
523 glTranslated((GLdouble
)gm
.gmCellIncX
/ em_size
, (GLdouble
)gm
.gmCellIncY
/ em_size
, 0.0);
525 HeapFree(GetProcessHeap(), 0, buf
);
526 HeapFree(GetProcessHeap(), 0, vertices
);
530 DeleteObject(SelectObject(hdc
, old_font
));
531 if(format
== WGL_FONT_POLYGONS
)
532 pgluDeleteTess(tess
);
537 /***********************************************************************
538 * wglUseFontOutlinesA (OPENGL32.@)
540 BOOL WINAPI
wglUseFontOutlinesA(HDC hdc
,
547 LPGLYPHMETRICSFLOAT lpgmf
)
549 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, FALSE
);
552 /***********************************************************************
553 * wglUseFontOutlinesW (OPENGL32.@)
555 BOOL WINAPI
wglUseFontOutlinesW(HDC hdc
,
562 LPGLYPHMETRICSFLOAT lpgmf
)
564 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, TRUE
);