- get rid of some cast frenzy, by Physicus
[reactos.git] / reactos / dll / win32 / opengl32 / font.c
1 /****************************************************************************
2 * Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * SCITECH SOFTWARE INC BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 ****************************************************************************/
22
23 #include "opengl32.h"
24 #include <math.h>
25
26 #define LINE_BUF_QUANT 4000
27 #define VERT_BUF_QUANT 4000
28
29 static HFONT hNewFont, hOldFont;
30 static FLOAT ScaleFactor;
31 static FLOAT* LineBuf;
32 static DWORD LineBufSize;
33 static DWORD LineBufIndex;
34 static FLOAT* VertBuf;
35 static DWORD VertBufSize;
36 static DWORD VertBufIndex;
37 static GLenum TessErrorOccurred;
38
39 /*****************************************************************************
40 * AppendToLineBuf
41 *
42 * Appends one floating-point value to the global LineBuf array. Return value
43 * is non-zero for success, zero for failure.
44 *****************************************************************************/
45
46 INT AppendToLineBuf(FLOAT value)
47 {
48 if (LineBufIndex >= LineBufSize)
49 {
50 FLOAT* f;
51 LineBufSize += LINE_BUF_QUANT;
52
53 f = (FLOAT*) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, LineBuf, (LineBufSize) * sizeof(FLOAT));
54 if (!f)
55 return 0;
56 LineBuf = f;
57 }
58 LineBuf[LineBufIndex++] = value;
59 return 1;
60 }
61
62 /*****************************************************************************
63 * AppendToVertBuf
64 *
65 * Appends one floating-point value to the global VertBuf array. Return value
66 * is non-zero for success, zero for failure.
67 *
68 * Note that we can't realloc this one, because the tessellator is using
69 * pointers into it.
70 *****************************************************************************/
71
72 INT AppendToVertBuf(FLOAT value)
73 {
74 if (VertBufIndex >= VertBufSize)
75 return 0;
76 VertBuf[VertBufIndex++] = value;
77 return 1;
78 }
79
80 /*****************************************************************************
81 * GetWord
82 *
83 * Fetch the next 16-bit word from a little-endian byte stream, and increment
84 * the stream pointer to the next unscanned byte.
85 *****************************************************************************/
86
87 LONG GetWord(UCHAR** p)
88 {
89 LONG value;
90
91 value = ((*p)[1] << 8) + (*p)[0];
92 *p += 2;
93 return value;
94 }
95
96 /*****************************************************************************
97 * GetDWord
98 *
99 * Fetch the next 32-bit word from a little-endian byte stream, and increment
100 * the stream pointer to the next unscanned byte.
101 *****************************************************************************/
102
103 LONG GetDWord(UCHAR** p)
104 {
105 LONG value;
106
107 value = ((*p)[3] << 24) + ((*p)[2] << 16) + ((*p)[1] << 8) + (*p)[0];
108 *p += 4;
109 return value;
110 }
111
112 /*****************************************************************************
113 * GetFixed
114 *
115 * Fetch the next 32-bit fixed-point value from a little-endian byte stream,
116 * convert it to floating-point, and increment the stream pointer to the next
117 * unscanned byte.
118 *****************************************************************************/
119 double GetFixed(UCHAR** p)
120 {
121 LONG hiBits, loBits;
122 double value;
123
124 loBits = GetWord(p);
125 hiBits = GetWord(p);
126 value = (double) ((hiBits << 16) | loBits) / 65536.0;
127
128 return value * ScaleFactor;
129 }
130
131
132 /*****************************************************************************
133 **
134 ** InvertGlyphBitmap.
135 **
136 ** Invert the bitmap so that it suits OpenGL's representation.
137 ** Each row starts on a double word boundary.
138 **
139 *****************************************************************************/
140
141 VOID InvertGlyphBitmap(INT w, INT h, DWORD *fptr, DWORD *tptr)
142 {
143 INT dWordsInRow = (w+31)/32;
144 INT i, j;
145
146 if (w <= 0 || h <= 0) {
147 return;
148 }
149
150 tptr += ((h-1)*dWordsInRow);
151 for (i = 0; i < h; i++) {
152 for (j = 0; j < dWordsInRow; j++) {
153 *(tptr + j) = *(fptr + j);
154 }
155 tptr -= dWordsInRow;
156 fptr += dWordsInRow;
157 }
158 }
159
160 /*****************************************************************************
161 * CreateHighResolutionFont
162 *
163 * Gets metrics for the current font and creates an equivalent font
164 * scaled to the design units of the font.
165 *
166 *****************************************************************************/
167
168 HFONT CreateHighResolutionFont(HDC hDC)
169 {
170 UINT otmSize;
171 OUTLINETEXTMETRIC *otm;
172 LONG fontHeight, fontWidth, fontUnits;
173 LOGFONTW logFont, logFontFaceName;
174
175 otmSize = GetOutlineTextMetricsW(hDC, 0, NULL);
176 if (!otmSize)
177 return NULL;
178
179 otm = (OUTLINETEXTMETRIC *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, otmSize);
180 if (!otm)
181 return NULL;
182
183 otm->otmSize = otmSize;
184 if (!GetOutlineTextMetricsW(hDC, otmSize, otm))
185 return NULL;
186
187 GetObjectW(GetCurrentObject(hDC, OBJ_FONT), sizeof(logFontFaceName), &logFontFaceName);
188
189 fontHeight = otm->otmTextMetrics.tmHeight -
190 otm->otmTextMetrics.tmInternalLeading;
191 fontWidth = otm->otmTextMetrics.tmAveCharWidth;
192 fontUnits = (LONG) otm->otmEMSquare;
193
194 ScaleFactor = 1.0F / (FLOAT) fontUnits;
195
196 logFont.lfHeight = - ((LONG) fontUnits);
197 logFont.lfWidth = (LONG)((FLOAT) (fontWidth * fontUnits) / (FLOAT) fontHeight);
198 logFont.lfEscapement = 0;
199 logFont.lfOrientation = 0;
200 logFont.lfWeight = otm->otmTextMetrics.tmWeight;
201 logFont.lfItalic = otm->otmTextMetrics.tmItalic;
202 logFont.lfUnderline = otm->otmTextMetrics.tmUnderlined;
203 logFont.lfStrikeOut = otm->otmTextMetrics.tmStruckOut;
204 logFont.lfCharSet = otm->otmTextMetrics.tmCharSet;
205 logFont.lfOutPrecision = OUT_OUTLINE_PRECIS;
206 logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
207 logFont.lfQuality = DEFAULT_QUALITY;
208 logFont.lfPitchAndFamily =
209 otm->otmTextMetrics.tmPitchAndFamily & 0xf0;
210 wcscpy(logFont.lfFaceName, logFontFaceName.lfFaceName);
211
212 hNewFont = CreateFontIndirectW(&logFont);
213
214 HeapFree(GetProcessHeap(), 0, otm);
215
216 return hNewFont;
217 }
218
219 /*****************************************************************************
220 * MakeLinesFromArc
221 *
222 * Subdivides one arc of a quadratic spline until the chordal deviation
223 * tolerance requirement is met, then places the resulting set of line
224 * segments in the global LineBuf.
225 *****************************************************************************/
226 INT MakeLinesFromArc(FLOAT x0, FLOAT y0, FLOAT x1, FLOAT y1, FLOAT x2, FLOAT y2,
227 DWORD vertexCountIndex, FLOAT chordalDeviationSquared)
228 {
229 FLOAT x01;
230 FLOAT y01;
231 FLOAT x12;
232 FLOAT y12;
233 FLOAT midPointX;
234 FLOAT midPointY;
235 FLOAT deltaX;
236 FLOAT deltaY;
237
238 /*
239 * Calculate midpoint of the curve by de Casteljau:
240 */
241 x01 = 0.5F * (x0 + x1);
242 y01 = 0.5F * (y0 + y1);
243 x12 = 0.5F * (x1 + x2);
244 y12 = 0.5F * (y1 + y2);
245 midPointX = 0.5F * (x01 + x12);
246 midPointY = 0.5F * (y01 + y12);
247
248
249 /*
250 * Estimate chordal deviation by the distance from the midpoint
251 * of the curve to its non-pointpolated control point. If this
252 * distance is greater than the specified chordal deviation
253 * constraint, then subdivide. Otherwise, generate polylines
254 * from the three control points.
255 */
256 deltaX = midPointX - x1;
257 deltaY = midPointY - y1;
258
259 if (deltaX * deltaX + deltaY * deltaY > chordalDeviationSquared)
260 {
261 MakeLinesFromArc( x0, y0,
262 x01, y01,
263 midPointX, midPointY,
264 vertexCountIndex,
265 chordalDeviationSquared);
266
267 MakeLinesFromArc( midPointX, midPointY,
268 x12, y12,
269 x2, y2,
270 vertexCountIndex,
271 chordalDeviationSquared);
272 }
273 else
274 {
275 /*
276 * The "pen" is already at (x0, y0), so we don't need to
277 * add that point to the LineBuf.
278 */
279 if (!AppendToLineBuf(x1)
280 || !AppendToLineBuf(y1)
281 || !AppendToLineBuf(x2)
282 || !AppendToLineBuf(y2))
283 return 0;
284 LineBuf[vertexCountIndex] += 2.0F;
285 }
286
287 return 1;
288 }
289
290 /*****************************************************************************
291 * MakeLinesFromTTQSpline
292 *
293 * Converts points from the poly quadratic spline in a TT_PRIM_QSPLINE
294 * structure to polyline points in the global LineBuf.
295 *****************************************************************************/
296
297 INT MakeLinesFromTTQSpline( UCHAR** pp, DWORD vertexCountIndex, WORD pointCount, FLOAT chordalDeviation)
298 {
299 FLOAT x0, y0, x1, y1, x2, y2;
300 WORD point;
301
302 /*
303 * Process each of the non-pointpolated points in the outline.
304 * To do this, we need to generate two pointpolated points (the
305 * start and end of the arc) for each non-pointpolated point.
306 * The first pointpolated point is always the one most recently
307 * stored in LineBuf, so we just extract it from there. The
308 * second pointpolated point is either the average of the next
309 * two points in the QSpline, or the last point in the QSpline
310 * if only one remains.
311 */
312 for (point = 0; point < pointCount - 1; ++point)
313 {
314 x0 = LineBuf[LineBufIndex - 2];
315 y0 = LineBuf[LineBufIndex - 1];
316
317 x1 = (FLOAT) GetFixed(pp);
318 y1 = (FLOAT) GetFixed(pp);
319
320 if (point == pointCount - 2)
321 {
322 /*
323 * This is the last arc in the QSpline. The final
324 * point is the end of the arc.
325 */
326 x2 = (FLOAT) GetFixed(pp);
327 y2 = (FLOAT) GetFixed(pp);
328 }
329 else
330 {
331 /*
332 * Peek at the next point in the input to compute
333 * the end of the arc:
334 */
335 x2 = 0.5F * (x1 + (FLOAT) GetFixed(pp));
336 y2 = 0.5F * (y1 + (FLOAT) GetFixed(pp));
337 /*
338 * Push the point back onto the input so it will
339 * be reused as the next off-curve point:
340 */
341 *pp -= 8;
342 }
343
344 if (!MakeLinesFromArc( x0, y0,
345 x1, y1,
346 x2, y2,
347 vertexCountIndex,
348 chordalDeviation * chordalDeviation))
349 return 0;
350 }
351
352 return 1;
353 }
354
355 /*****************************************************************************
356 * MakeLinesFromTTLine
357 *
358 * Converts points from the polyline in a TT_PRIM_LINE structure to
359 * equivalent points in the global LineBuf.
360 *****************************************************************************/
361 INT MakeLinesFromTTLine(UCHAR** pp, DWORD vertexCountIndex, WORD pointCount)
362 {
363 /*
364 * Just copy the line segments into the line buffer (converting
365 * type as we go):
366 */
367 LineBuf[vertexCountIndex] += pointCount;
368 while (pointCount--)
369 {
370 if (!AppendToLineBuf((FLOAT) GetFixed(pp)) /* X coord */
371 || !AppendToLineBuf((FLOAT) GetFixed(pp))) /* Y coord */
372 return 0;
373 }
374
375 return 1;
376 }
377
378 /*****************************************************************************
379 * MakeLinesFromTTPolyCurve
380 *
381 * Converts the lines and splines in a single TTPOLYCURVE structure to points
382 * in the global LineBuf.
383 *****************************************************************************/
384
385 INT MakeLinesFromTTPolycurve(UCHAR** pp, DWORD vertexCountIndex, FLOAT chordalDeviation)
386 {
387 WORD type;
388 WORD pointCount;
389
390 /*
391 * Pick up the relevant fields of the TTPOLYCURVE structure:
392 */
393 type = (WORD) GetWord(pp);
394 pointCount = (WORD) GetWord(pp);
395
396 /*
397 * Convert the "curve" to line segments:
398 */
399 if (type == TT_PRIM_LINE)
400 return MakeLinesFromTTLine( pp,
401 vertexCountIndex,
402 pointCount);
403 else if (type == TT_PRIM_QSPLINE)
404 return MakeLinesFromTTQSpline( pp,
405 vertexCountIndex,
406 pointCount,
407 chordalDeviation);
408 else
409 return 0;
410 }
411
412 /*****************************************************************************
413 * MakeLinesFromTTPolygon
414 *
415 * Converts a TTPOLYGONHEADER and its associated curve structures into a
416 * single polyline loop in the global LineBuf.
417 *****************************************************************************/
418
419 INT MakeLinesFromTTPolygon(UCHAR** pp, FLOAT chordalDeviation)
420 {
421 DWORD polySize;
422 UCHAR* polyStart;
423 DWORD vertexCountIndex;
424
425 /*
426 * Record where the polygon data begins, and where the loop's
427 * vertex count resides:
428 */
429 polyStart = *pp;
430 vertexCountIndex = LineBufIndex;
431 if (!AppendToLineBuf(0.0F))
432 return 0;
433
434 /*
435 * Extract relevant data from the TTPOLYGONHEADER:
436 */
437 polySize = GetDWord(pp);
438 if (GetDWord(pp) != TT_POLYGON_TYPE) /* polygon type */
439 return 0;
440 if (!AppendToLineBuf((FLOAT) GetFixed(pp))) /* first X coord */
441 return 0;
442 if (!AppendToLineBuf((FLOAT) GetFixed(pp))) /* first Y coord */
443 return 0;
444 LineBuf[vertexCountIndex] += 1.0F;
445
446 /*
447 * Process each of the TTPOLYCURVE structures in the polygon:
448 */
449 while (*pp < polyStart + polySize)
450 if (!MakeLinesFromTTPolycurve( pp,
451 vertexCountIndex,
452 chordalDeviation))
453 return 0;
454
455 return 1;
456 }
457
458 /*****************************************************************************
459 * TessVertexOut
460 *
461 * Used by tessellator to handle output vertexes.
462 *****************************************************************************/
463
464 VOID CALLBACK TessVertexOutData(FLOAT p[3], GLfloat z)
465 {
466 GLfloat v[3];
467 v[0] = (GLfloat) p[0];
468 v[1] = (GLfloat) p[1];
469 v[2] = z;
470 glVertex3fv(v);
471 }
472
473 /*****************************************************************************
474 * TessCombine
475 *
476 * Used by tessellator to handle self-pointsecting contours and degenerate
477 * geometry.
478 *****************************************************************************/
479 VOID CALLBACK TessCombine(double coords[3], VOID* vertex_data[4], FLOAT weight[4], VOID** outData)
480 {
481 if (!AppendToVertBuf((FLOAT) coords[0])
482 || !AppendToVertBuf((FLOAT) coords[1])
483 || !AppendToVertBuf((FLOAT) coords[2]))
484 TessErrorOccurred = GL_OUT_OF_MEMORY;
485
486 *outData = VertBuf + (VertBufIndex - 3);
487 }
488
489 /*****************************************************************************
490 * TessError
491 *
492 * Saves the last tessellator error code in the global TessErrorOccurred.
493 *****************************************************************************/
494
495 VOID CALLBACK TessError(GLenum error)
496 {
497 TessErrorOccurred = error;
498 }
499
500 /*****************************************************************************
501 * MakeLinesFromGlyph
502 *
503 * Converts the outline of a glyph from the TTPOLYGON format to a simple
504 * array of floating-point values containing one or more loops.
505 *
506 * The first element of the output array is a count of the number of loops.
507 * The loop data follows this count. Each loop consists of a count of the
508 * number of vertices it contains, followed by the vertices. Each vertex
509 * is an X and Y coordinate. For example, a single triangle might be
510 * described by this array:
511 *
512 * 1., 3., 0., 0., 1., 0., 0., 1.
513 * ^ ^ ^ ^ ^ ^ ^ ^
514 * #loops #verts x1 y1 x2 y2 x3 y3
515 *
516 * A two-loop glyph would look like this:
517 *
518 * 2., 3., 0.,0., 1.,0., 0.,1., 3., .2,.2, .4,.2, .2,.4
519 *
520 * Line segments from the TTPOLYGON are transferred to the output array in
521 * the obvious way. Quadratic splines in the TTPOLYGON are converted to
522 * collections of line segments
523 *****************************************************************************/
524
525 INT MakeLinesFromGlyph(UCHAR* glyphBuf, DWORD glyphSize, FLOAT chordalDeviation)
526 {
527 UCHAR* p;
528 INT status = 0;
529
530 /*
531 * Pick up all the polygons (aka loops) that make up the glyph:
532 */
533 if (!AppendToLineBuf(0.0F)) /* loop count at LineBuf[0] */
534 goto exit;
535
536 p = glyphBuf;
537 while (p < glyphBuf + glyphSize)
538 {
539 if (!MakeLinesFromTTPolygon(&p, chordalDeviation))
540 goto exit;
541 LineBuf[0] += 1.0F; /* increment loop count */
542 }
543
544 status = 1;
545
546 exit:
547 return status;
548 }
549
550 /*****************************************************************************
551 * DrawGlyph
552 *
553 * Converts the outline of a glyph to OpenGL drawing primitives, tessellating
554 * as needed, and then draws the glyph. Tessellation of the quadratic splines
555 * in the outline is controlled by "chordalDeviation", and the drawing
556 * primitives (lines or polygons) are selected by "format".
557 *
558 * Return value is nonzero for success, zero for failure.
559 *
560 * Does not check for OpenGL errors, so if the caller needs to know about them,
561 * it should call glGetError().
562 *****************************************************************************/
563
564 INT DrawGlyph(UCHAR* glyphBuf, DWORD glyphSize, FLOAT chordalDeviation, FLOAT extrusion, INT format)
565 {
566 INT status = 0;
567 FLOAT* p;
568 DWORD loop;
569 DWORD point;
570 GLUtesselator* tess = NULL;
571
572 /*
573 * Initialize the global buffer into which we place the outlines:
574 */
575 LineBuf = (FLOAT*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (LINE_BUF_QUANT) * sizeof(FLOAT));
576
577 if(!LineBuf)
578 goto exit;
579
580 LineBufSize = LINE_BUF_QUANT;
581 LineBufIndex = 0;
582
583 /*
584 * Convert the glyph outlines to a set of polyline loops.
585 * (See MakeLinesFromGlyph() for the format of the loop data
586 * structure.)
587 */
588 if (!MakeLinesFromGlyph(glyphBuf, glyphSize, chordalDeviation))
589 goto exit;
590 p = LineBuf;
591
592
593 /*
594 * Now draw the loops in the appropriate format:
595 */
596 if (format == WGL_FONT_LINES)
597 {
598 /*
599 * This is the easy case. Just draw the outlines.
600 */
601 for (loop = (DWORD) *p++; loop; --loop)
602 {
603 glBegin(GL_LINE_LOOP);
604 for (point = (DWORD) *p++; point; --point)
605 {
606 glVertex2fv(p);
607 p += 2;
608 }
609 glEnd();
610 }
611 status = 1;
612 }
613
614 else if (format == WGL_FONT_POLYGONS)
615 {
616 double v[3];
617 FLOAT *save_p = p;
618 GLfloat z_value;
619
620 /*
621 * This is the hard case. We have to set up a tessellator
622 * to convert the outlines into a set of polygonal
623 * primitives, which the tessellator passes to some
624 * auxiliary routines for drawing.
625 */
626
627 VertBuf = (FLOAT*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (VERT_BUF_QUANT) * sizeof(FLOAT));
628
629 if (!VertBuf)
630 goto exit;
631
632 VertBufSize = VERT_BUF_QUANT;
633 VertBufIndex = 0;
634
635 if (!(tess = gluNewTess()))
636 goto exit;
637
638 gluTessCallback(tess, GLU_BEGIN, (VOID(CALLBACK *)()) glBegin);
639 gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (VOID(CALLBACK *)()) TessVertexOutData);
640 gluTessCallback(tess, GLU_END, (VOID(CALLBACK *)()) glEnd);
641 gluTessCallback(tess, GLU_ERROR, (VOID(CALLBACK *)()) TessError);
642 gluTessCallback(tess, GLU_TESS_COMBINE, (VOID(CALLBACK *)()) TessCombine);
643 gluTessNormal(tess, 0.0F, 0.0F, 1.0F);
644
645 TessErrorOccurred = 0;
646 glNormal3f(0.0f, 0.0f, 1.0f);
647 v[2] = 0.0;
648 z_value = 0.0f;
649
650 gluTessBeginPolygon(tess, &z_value);
651
652 for (loop = (DWORD) *p++; loop; --loop)
653 {
654 gluTessBeginContour(tess);
655
656 for (point = (DWORD) *p++; point; --point)
657 {
658 v[0] = p[0];
659 v[1] = p[1];
660 gluTessVertex(tess, v, p);
661 p += 2;
662 }
663
664 gluTessEndContour(tess);
665 }
666 gluTessEndPolygon(tess);
667
668 status = !TessErrorOccurred;
669
670 /* Extrusion code */
671 if (extrusion)
672 {
673 DWORD loops;
674 GLfloat thickness = (GLfloat) - extrusion;
675 FLOAT *vert, *vert2;
676 DWORD count;
677
678 p = save_p;
679 loops = (DWORD) *p++;
680
681 for (loop = 0; loop < loops; loop++)
682 {
683 GLfloat dx, dy, len;
684 DWORD last;
685
686 count = (DWORD) *p++;
687 glBegin(GL_QUAD_STRIP);
688
689 /* Check if the first and last vertex are identical
690 * so we don't draw the same quad twice.
691 */
692 vert = p + (count-1)*2;
693 last = (p[0] == vert[0] && p[1] == vert[1]) ? count-1 : count;
694
695 for (point = 0; point <= last; point++)
696 {
697 vert = p + 2 * (point % last);
698 vert2 = p + 2 * ((point+1) % last);
699
700 dx = vert[0] - vert2[0];
701 dy = vert[1] - vert2[1];
702 len = (GLfloat)sqrt(dx * dx + dy * dy);
703
704 glNormal3f(dy / len, -dx / len, 0.0f);
705 glVertex3f((GLfloat) vert[0],
706 (GLfloat) vert[1], thickness);
707 glVertex3f((GLfloat) vert[0],
708 (GLfloat) vert[1], 0.0f);
709 }
710
711 glEnd();
712 p += count*2;
713 }
714
715 /* Draw the back face */
716 p = save_p;
717 v[2] = thickness;
718 glNormal3f(0.0f, 0.0f, -1.0f);
719 gluTessNormal(tess, 0.0F, 0.0F, -1.0F);
720
721 gluTessBeginPolygon(tess, &thickness);
722
723 for (loop = (DWORD) *p++; loop; --loop)
724 {
725 count = (DWORD) *p++;
726
727 gluTessBeginContour(tess);
728
729 for (point = 0; point < count; point++)
730 {
731 vert = p + ((count-point-1)<<1);
732 v[0] = vert[0];
733 v[1] = vert[1];
734 gluTessVertex(tess, v, vert);
735 }
736 p += count*2;
737
738 gluTessEndContour(tess);
739 }
740 gluTessEndPolygon(tess);
741 }
742
743 #if !defined(NDEBUG)
744 if (TessErrorOccurred)
745 DBGPRINT("Tessellation error %s\n", gluErrorString(TessErrorOccurred));
746 #endif
747 }
748
749
750 exit:
751
752 if(LineBuf)
753 HeapFree(GetProcessHeap(), 0, LineBuf);
754
755 if(VertBuf)
756 HeapFree(GetProcessHeap(), 0, VertBuf);
757
758 if (tess)
759 gluDeleteTess(tess);
760
761 return status;
762 }
763
764
765 /*****************************************************************************
766 * MakeDisplayListFromGlyph
767 *
768 * Converts the outline of a glyph to an OpenGL display list.
769 *
770 * Return value is nonzero for success, zero for failure.
771 *
772 * Does not check for OpenGL errors, so if the caller needs to know about them,
773 * it should call glGetError().
774 *****************************************************************************/
775
776 INT MakeDisplayListFromGlyph(DWORD listName, UCHAR* glyphBuf, DWORD glyphSize, LPGLYPHMETRICSFLOAT glyphMetricsFloat,
777 FLOAT chordalDeviation, FLOAT extrusion, INT format)
778 {
779 INT status;
780
781 glNewList(listName, GL_COMPILE);
782 status = DrawGlyph(glyphBuf, glyphSize, chordalDeviation, extrusion, format);
783 glTranslatef(glyphMetricsFloat->gmfCellIncX, glyphMetricsFloat->gmfCellIncY, 0.0F);
784 glEndList();
785
786 return status;
787 }
788
789 // ***********************************************************************
790
791 /*****************************************************************************
792 * IntUseFontBitmaps
793 *
794 * Converts a subrange of the glyphs in a GDI font to OpenGL display
795 * lists.
796 *
797 * Extended to support any GDI font, not just TrueType fonts. (DaveM)
798 *
799 *****************************************************************************/
800
801 BOOL APIENTRY IntUseFontBitmapsW(HDC hDC, DWORD first, DWORD count, DWORD listBase)
802 {
803 INT i, ox, oy, ix, iy;
804 INT w = 0, h = 0;
805 INT iBufSize, iCurBufSize = 0;
806 DWORD *bitmapBuffer = NULL;
807 DWORD *invertedBitmapBuffer = NULL;
808 BOOL bSuccessOrFail = TRUE;
809 BOOL bTrueType = FALSE;
810 TEXTMETRIC tm;
811 GLYPHMETRICS gm;
812 RASTERIZER_STATUS rs;
813 MAT2 mat;
814 SIZE size;
815 RECT rect;
816 HDC hDCMem;
817 HBITMAP hBitmap;
818 BITMAPINFO bmi;
819 HFONT hFont;
820
821 // Set up a unity matrix.
822 ZeroMemory(&mat, sizeof(mat));
823 mat.eM11.value = 1;
824 mat.eM22.value = 1;
825
826 // Test to see if selected font is TrueType or not
827 ZeroMemory(&tm, sizeof(tm));
828 if (!GetTextMetrics(hDC, &tm))
829 {
830 DBGPRINT("Font metrics error\n");
831 return FALSE;
832 }
833 bTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) ? TRUE : FALSE;
834
835 // Test to see if TRUE-TYPE capabilities are installed
836 // (only necessary if TrueType font selected)
837 ZeroMemory(&rs, sizeof(rs));
838
839 if (bTrueType)
840 {
841 if (!GetRasterizerCaps (&rs, sizeof (RASTERIZER_STATUS)) || !(rs.wFlags & TT_ENABLED))
842 {
843 DBGPRINT("No TrueType caps\n");
844 bTrueType = FALSE;
845 }
846 }
847
848 // Trick to get the current font handle
849 hFont = SelectObject(hDC, GetStockObject(SYSTEM_FONT));
850 SelectObject(hDC, hFont);
851
852 // Have memory device context available for holding bitmaps of font glyphs
853 hDCMem = CreateCompatibleDC(hDC);
854 SelectObject(hDCMem, hFont);
855 SetTextColor(hDCMem, RGB(0xFF, 0xFF, 0xFF));
856 SetBkColor(hDCMem, 0);
857
858 for (i = first; (DWORD) i < (first + count); i++)
859 {
860 // Find out how much space is needed for the bitmap so we can
861 // Set the buffer size correctly.
862 if (bTrueType)
863 {
864 // Use TrueType support to get bitmap size of glyph
865 iBufSize = GetGlyphOutline(hDC, i, GGO_BITMAP, &gm, 0, NULL, &mat);
866 if (iBufSize == GDI_ERROR)
867 {
868 bSuccessOrFail = FALSE;
869 break;
870 }
871 }
872 else
873 {
874 // Use generic GDI support to compute bitmap size of glyph
875 w = tm.tmMaxCharWidth;
876 h = tm.tmHeight;
877 if (GetTextExtentPoint32(hDC, (LPCTSTR)&i, 1, &size))
878 {
879 w = size.cx;
880 h = size.cy;
881 }
882 iBufSize = w * h;
883 // Use DWORD multiple for compatibility
884 iBufSize += 3;
885 iBufSize /= 4;
886 iBufSize *= 4;
887 }
888
889 // If we need to allocate Larger Buffers, then do so - but allocate
890 // An extra 50 % so that we don't do too many mallocs !
891 if (iBufSize > iCurBufSize)
892 {
893 if (bitmapBuffer)
894 {
895 HeapFree(GetProcessHeap(), 0, bitmapBuffer);
896 }
897 if (invertedBitmapBuffer)
898 {
899 HeapFree(GetProcessHeap(), 0, invertedBitmapBuffer);
900 }
901
902 iCurBufSize = iBufSize * 2;
903 bitmapBuffer = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iCurBufSize);
904 invertedBitmapBuffer = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iCurBufSize);
905
906 if (bitmapBuffer == NULL || invertedBitmapBuffer == NULL)
907 {
908 bSuccessOrFail = FALSE;
909 break;
910 }
911 }
912
913 // If we fail to get the Glyph data, delete the display lists
914 // Created so far and return FALSE.
915 if (bTrueType)
916 {
917 // Use TrueType support to get bitmap of glyph
918 if (GetGlyphOutline(hDC, i, GGO_BITMAP, &gm, iBufSize, bitmapBuffer, &mat) == GDI_ERROR)
919 {
920 bSuccessOrFail = FALSE;
921 break;
922 }
923
924 // Setup glBitmap parameters for current font glyph
925 w = gm.gmBlackBoxX;
926 h = gm.gmBlackBoxY;
927 ox = gm.gmptGlyphOrigin.x;
928 oy = gm.gmptGlyphOrigin.y;
929 ix = gm.gmCellIncX;
930 iy = gm.gmCellIncY;
931 }
932 else
933 {
934 // Use generic GDI support to create bitmap of glyph
935 ZeroMemory(bitmapBuffer, iBufSize);
936
937 if (i >= tm.tmFirstChar && i <= tm.tmLastChar)
938 {
939 // Only create bitmaps for actual font glyphs
940 hBitmap = CreateBitmap(w, h, 1, 1, NULL);
941 SelectObject(hDCMem, hBitmap);
942 // Make bitmap of current font glyph
943 SetRect(&rect, 0, 0, w, h);
944 DrawText(hDCMem, (LPCTSTR)&i, 1, &rect,
945 DT_LEFT | DT_BOTTOM | DT_SINGLELINE | DT_NOCLIP);
946 // Make copy of bitmap in our local buffer
947 ZeroMemory(&bmi, sizeof(bmi));
948 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
949 bmi.bmiHeader.biWidth = w;
950 bmi.bmiHeader.biHeight = -h;
951 bmi.bmiHeader.biPlanes = 1;
952 bmi.bmiHeader.biBitCount = 1;
953 bmi.bmiHeader.biCompression = BI_RGB;
954 GetDIBits(hDCMem, hBitmap, 0, h, bitmapBuffer, &bmi, 0);
955 DeleteObject(hBitmap);
956 }
957 else
958 {
959 // Otherwise use empty display list for non-existing glyph
960 iBufSize = 0;
961 }
962
963 // Setup glBitmap parameters for current font glyph
964 ox = 0;
965 oy = tm.tmDescent;
966 ix = w;
967 iy = 0;
968 }
969
970 // Create an OpenGL display list.
971 glNewList((listBase + i), GL_COMPILE);
972
973 // Some fonts have no data for the space character, yet advertise
974 // a non-zero size.
975 if (0 == iBufSize)
976 {
977 glBitmap(0, 0, 0.0f, 0.0f, (GLfloat) ix, (GLfloat) iy, NULL);
978 }
979 else
980 {
981 // Invert the Glyph data.
982 InvertGlyphBitmap(w, h, bitmapBuffer, invertedBitmapBuffer);
983
984 // Render an OpenGL bitmap and invert the origin.
985 glBitmap(w, h,
986 (GLfloat) ox, (GLfloat) (h-oy),
987 (GLfloat) ix, (GLfloat) iy,
988 (GLubyte *) invertedBitmapBuffer);
989 }
990
991 // Close this display list.
992 glEndList();
993 }
994
995 if (bSuccessOrFail == FALSE)
996 {
997 DBGPRINT("DGL_UseFontBitmaps: Get glyph failed\n");
998 glDeleteLists((i+listBase), (i-first));
999 }
1000
1001 // Release resources used
1002 DeleteObject(hFont);
1003 DeleteDC(hDCMem);
1004
1005 if (bitmapBuffer)
1006 HeapFree(GetProcessHeap(), 0, bitmapBuffer);
1007
1008 if (invertedBitmapBuffer)
1009 HeapFree(GetProcessHeap(), 0, invertedBitmapBuffer);
1010
1011 return(bSuccessOrFail);
1012 }
1013
1014 BOOL APIENTRY IntUseFontBitmapsA(HDC hDC, DWORD first, DWORD count, DWORD listBase)
1015 {
1016 /* Just call IntUseFontBitmapsW for now */
1017 return IntUseFontBitmapsW(hDC, first, count, listBase);
1018 }
1019
1020
1021
1022 /*****************************************************************************
1023 * IntUseFontOutlines
1024 *
1025 * Converts a subrange of the glyphs in a TrueType font to OpenGL display
1026 * lists.
1027 *****************************************************************************/
1028
1029 BOOL APIENTRY IntUseFontOutlinesW(HDC hDC, DWORD first, DWORD count, DWORD listBase, FLOAT chordalDeviation,
1030 FLOAT extrusion, INT format, GLYPHMETRICSFLOAT *glyphMetricsFloatArray)
1031 {
1032 DWORD glyphIndex;
1033 UCHAR* glyphBuf;
1034 DWORD glyphBufSize;
1035
1036 /*
1037 * Flush any previous OpenGL errors. This allows us to check for
1038 * new errors so they can be reported via the function return value.
1039 */
1040 while (glGetError() != GL_NO_ERROR);
1041
1042 /*
1043 * Make sure that the current font can be sampled accurately.
1044 */
1045 hNewFont = CreateHighResolutionFont(hDC);
1046
1047 if (!hNewFont)
1048 return FALSE;
1049
1050 hOldFont = SelectObject(hDC, hNewFont);
1051 if (!hOldFont)
1052 return FALSE;
1053
1054 /*
1055 * Preallocate a buffer for the outline data, and track its size:
1056 */
1057 glyphBuf = (UCHAR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, glyphBufSize = 10240);
1058
1059 if (!glyphBuf)
1060 return FALSE; /*WGL_STATUS_NOT_ENOUGH_MEMORY*/
1061
1062 /*
1063 * Process each glyph in the given range:
1064 */
1065 for (glyphIndex = first; glyphIndex - first < count; ++glyphIndex)
1066 {
1067 GLYPHMETRICS glyphMetrics;
1068 DWORD glyphSize;
1069 static MAT2 matrix =
1070 {
1071 {0, 1}, {0, 0},
1072 {0, 0}, {0, 1}
1073 };
1074 LPGLYPHMETRICSFLOAT glyphMetricsFloat = &glyphMetricsFloatArray[glyphIndex - first];
1075
1076 /*
1077 * Determine how much space is needed to store the glyph's
1078 * outlines. If our glyph buffer isn't large enough,
1079 * resize it.
1080 */
1081
1082 glyphSize = GetGlyphOutline(hDC, glyphIndex, GGO_NATIVE, &glyphMetrics, 0, NULL, &matrix);
1083
1084 if (glyphSize < 0)
1085 return FALSE; /*WGL_STATUS_FAILURE*/
1086
1087 if (glyphSize > glyphBufSize)
1088 {
1089 HeapFree(GetProcessHeap(), 0, glyphBuf);
1090 glyphBuf = (UCHAR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, glyphBufSize = glyphSize);
1091 if (!glyphBuf)
1092 return FALSE; /*WGL_STATUS_NOT_ENOUGH_MEMORY*/
1093 }
1094
1095
1096 /*
1097 * Get the glyph's outlines.
1098 */
1099 if (GetGlyphOutline(hDC, glyphIndex, GGO_NATIVE, &glyphMetrics, glyphBufSize, glyphBuf, &matrix) < 0)
1100 {
1101 HeapFree(GetProcessHeap(), 0, glyphBuf);
1102 return FALSE; /*WGL_STATUS_FAILURE*/
1103 }
1104
1105 glyphMetricsFloat->gmfBlackBoxX =
1106 (FLOAT) glyphMetrics.gmBlackBoxX * ScaleFactor;
1107 glyphMetricsFloat->gmfBlackBoxY =
1108 (FLOAT) glyphMetrics.gmBlackBoxY * ScaleFactor;
1109 glyphMetricsFloat->gmfptGlyphOrigin.x =
1110 (FLOAT) glyphMetrics.gmptGlyphOrigin.x * ScaleFactor;
1111 glyphMetricsFloat->gmfptGlyphOrigin.y =
1112 (FLOAT) glyphMetrics.gmptGlyphOrigin.y * ScaleFactor;
1113 glyphMetricsFloat->gmfCellIncX =
1114 (FLOAT) glyphMetrics.gmCellIncX * ScaleFactor;
1115 glyphMetricsFloat->gmfCellIncY =
1116 (FLOAT) glyphMetrics.gmCellIncY * ScaleFactor;
1117
1118 /*
1119 * Turn the glyph into a display list:
1120 */
1121 if (!MakeDisplayListFromGlyph((glyphIndex - first) + listBase, glyphBuf, glyphSize, glyphMetricsFloat,
1122 chordalDeviation + ScaleFactor, extrusion, format))
1123 {
1124 HeapFree(GetProcessHeap(), 0, glyphBuf);
1125 return FALSE; /*WGL_STATUS_FAILURE*/
1126 }
1127 }
1128
1129 /*
1130 * Clean up temporary storage and return. If an error occurred,
1131 * clear all OpenGL error flags and return FAILURE status;
1132 * otherwise just return SUCCESS.
1133 */
1134 HeapFree(GetProcessHeap(), 0, glyphBuf);
1135
1136 DeleteObject(SelectObject(hDC, hOldFont));
1137
1138 if (glGetError() == GL_NO_ERROR)
1139 {
1140 return TRUE; /*WGL_STATUS_SUCCESS*/
1141 }
1142 else
1143 {
1144 while (glGetError() != GL_NO_ERROR);
1145
1146 return FALSE; /*WGL_STATUS_FAILURE*/
1147 }
1148 }
1149
1150 BOOL APIENTRY IntUseFontOutlinesA(HDC hDC, DWORD first, DWORD count, DWORD listBase, FLOAT chordalDeviation,
1151 FLOAT extrusion, INT format, GLYPHMETRICSFLOAT *glyphMetricsFloatArray)
1152 {
1153 /* Just call IntUseFontOutlinesW for now */
1154 return IntUseFontOutlinesW(hDC, first, count, listBase, chordalDeviation, extrusion, format, glyphMetricsFloatArray);
1155 }