1 /****************************************************************************
2 * Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
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:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
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
21 ****************************************************************************/
26 #define LINE_BUF_QUANT 4000
27 #define VERT_BUF_QUANT 4000
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
;
39 /*****************************************************************************
42 * Appends one floating-point value to the global LineBuf array. Return value
43 * is non-zero for success, zero for failure.
44 *****************************************************************************/
46 INT
AppendToLineBuf(FLOAT value
)
48 if (LineBufIndex
>= LineBufSize
)
51 LineBufSize
+= LINE_BUF_QUANT
;
53 f
= (FLOAT
*) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, LineBuf
, (LineBufSize
) * sizeof(FLOAT
));
58 LineBuf
[LineBufIndex
++] = value
;
62 /*****************************************************************************
65 * Appends one floating-point value to the global VertBuf array. Return value
66 * is non-zero for success, zero for failure.
68 * Note that we can't realloc this one, because the tessellator is using
70 *****************************************************************************/
72 INT
AppendToVertBuf(FLOAT value
)
74 if (VertBufIndex
>= VertBufSize
)
76 VertBuf
[VertBufIndex
++] = value
;
80 /*****************************************************************************
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 *****************************************************************************/
87 LONG
GetWord(UCHAR
** p
)
91 value
= ((*p
)[1] << 8) + (*p
)[0];
96 /*****************************************************************************
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 *****************************************************************************/
103 LONG
GetDWord(UCHAR
** p
)
107 value
= ((*p
)[3] << 24) + ((*p
)[2] << 16) + ((*p
)[1] << 8) + (*p
)[0];
112 /*****************************************************************************
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
118 *****************************************************************************/
119 double GetFixed(UCHAR
** p
)
126 value
= (double) ((hiBits
<< 16) | loBits
) / 65536.0;
128 return value
* ScaleFactor
;
132 /*****************************************************************************
134 ** InvertGlyphBitmap.
136 ** Invert the bitmap so that it suits OpenGL's representation.
137 ** Each row starts on a double word boundary.
139 *****************************************************************************/
141 VOID
InvertGlyphBitmap(INT w
, INT h
, DWORD
*fptr
, DWORD
*tptr
)
143 INT dWordsInRow
= (w
+31)/32;
146 if (w
<= 0 || h
<= 0) {
150 tptr
+= ((h
-1)*dWordsInRow
);
151 for (i
= 0; i
< h
; i
++) {
152 for (j
= 0; j
< dWordsInRow
; j
++) {
153 *(tptr
+ j
) = *(fptr
+ j
);
160 /*****************************************************************************
161 * CreateHighResolutionFont
163 * Gets metrics for the current font and creates an equivalent font
164 * scaled to the design units of the font.
166 *****************************************************************************/
168 HFONT
CreateHighResolutionFont(HDC hDC
)
171 OUTLINETEXTMETRIC
*otm
;
172 LONG fontHeight
, fontWidth
, fontUnits
;
173 LOGFONTW logFont
, logFontFaceName
;
175 otmSize
= GetOutlineTextMetricsW(hDC
, 0, NULL
);
179 otm
= (OUTLINETEXTMETRIC
*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, otmSize
);
183 otm
->otmSize
= otmSize
;
184 if (!GetOutlineTextMetricsW(hDC
, otmSize
, otm
))
187 GetObjectW(GetCurrentObject(hDC
, OBJ_FONT
), sizeof(logFontFaceName
), &logFontFaceName
);
189 fontHeight
= otm
->otmTextMetrics
.tmHeight
-
190 otm
->otmTextMetrics
.tmInternalLeading
;
191 fontWidth
= otm
->otmTextMetrics
.tmAveCharWidth
;
192 fontUnits
= (LONG
) otm
->otmEMSquare
;
194 ScaleFactor
= 1.0F
/ (FLOAT
) fontUnits
;
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
);
212 hNewFont
= CreateFontIndirectW(&logFont
);
214 HeapFree(GetProcessHeap(), 0, otm
);
219 /*****************************************************************************
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
)
239 * Calculate midpoint of the curve by de Casteljau:
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
);
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.
256 deltaX
= midPointX
- x1
;
257 deltaY
= midPointY
- y1
;
259 if (deltaX
* deltaX
+ deltaY
* deltaY
> chordalDeviationSquared
)
261 MakeLinesFromArc( x0
, y0
,
263 midPointX
, midPointY
,
265 chordalDeviationSquared
);
267 MakeLinesFromArc( midPointX
, midPointY
,
271 chordalDeviationSquared
);
276 * The "pen" is already at (x0, y0), so we don't need to
277 * add that point to the LineBuf.
279 if (!AppendToLineBuf(x1
)
280 || !AppendToLineBuf(y1
)
281 || !AppendToLineBuf(x2
)
282 || !AppendToLineBuf(y2
))
284 LineBuf
[vertexCountIndex
] += 2.0F
;
290 /*****************************************************************************
291 * MakeLinesFromTTQSpline
293 * Converts points from the poly quadratic spline in a TT_PRIM_QSPLINE
294 * structure to polyline points in the global LineBuf.
295 *****************************************************************************/
297 INT
MakeLinesFromTTQSpline( UCHAR
** pp
, DWORD vertexCountIndex
, WORD pointCount
, FLOAT chordalDeviation
)
299 FLOAT x0
, y0
, x1
, y1
, x2
, y2
;
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.
312 for (point
= 0; point
< pointCount
- 1; ++point
)
314 x0
= LineBuf
[LineBufIndex
- 2];
315 y0
= LineBuf
[LineBufIndex
- 1];
317 x1
= (FLOAT
) GetFixed(pp
);
318 y1
= (FLOAT
) GetFixed(pp
);
320 if (point
== pointCount
- 2)
323 * This is the last arc in the QSpline. The final
324 * point is the end of the arc.
326 x2
= (FLOAT
) GetFixed(pp
);
327 y2
= (FLOAT
) GetFixed(pp
);
332 * Peek at the next point in the input to compute
333 * the end of the arc:
335 x2
= 0.5F
* (x1
+ (FLOAT
) GetFixed(pp
));
336 y2
= 0.5F
* (y1
+ (FLOAT
) GetFixed(pp
));
338 * Push the point back onto the input so it will
339 * be reused as the next off-curve point:
344 if (!MakeLinesFromArc( x0
, y0
,
348 chordalDeviation
* chordalDeviation
))
355 /*****************************************************************************
356 * MakeLinesFromTTLine
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
)
364 * Just copy the line segments into the line buffer (converting
367 LineBuf
[vertexCountIndex
] += pointCount
;
370 if (!AppendToLineBuf((FLOAT
) GetFixed(pp
)) /* X coord */
371 || !AppendToLineBuf((FLOAT
) GetFixed(pp
))) /* Y coord */
378 /*****************************************************************************
379 * MakeLinesFromTTPolyCurve
381 * Converts the lines and splines in a single TTPOLYCURVE structure to points
382 * in the global LineBuf.
383 *****************************************************************************/
385 INT
MakeLinesFromTTPolycurve(UCHAR
** pp
, DWORD vertexCountIndex
, FLOAT chordalDeviation
)
391 * Pick up the relevant fields of the TTPOLYCURVE structure:
393 type
= (WORD
) GetWord(pp
);
394 pointCount
= (WORD
) GetWord(pp
);
397 * Convert the "curve" to line segments:
399 if (type
== TT_PRIM_LINE
)
400 return MakeLinesFromTTLine( pp
,
403 else if (type
== TT_PRIM_QSPLINE
)
404 return MakeLinesFromTTQSpline( pp
,
412 /*****************************************************************************
413 * MakeLinesFromTTPolygon
415 * Converts a TTPOLYGONHEADER and its associated curve structures into a
416 * single polyline loop in the global LineBuf.
417 *****************************************************************************/
419 INT
MakeLinesFromTTPolygon(UCHAR
** pp
, FLOAT chordalDeviation
)
423 DWORD vertexCountIndex
;
426 * Record where the polygon data begins, and where the loop's
427 * vertex count resides:
430 vertexCountIndex
= LineBufIndex
;
431 if (!AppendToLineBuf(0.0F
))
435 * Extract relevant data from the TTPOLYGONHEADER:
437 polySize
= GetDWord(pp
);
438 if (GetDWord(pp
) != TT_POLYGON_TYPE
) /* polygon type */
440 if (!AppendToLineBuf((FLOAT
) GetFixed(pp
))) /* first X coord */
442 if (!AppendToLineBuf((FLOAT
) GetFixed(pp
))) /* first Y coord */
444 LineBuf
[vertexCountIndex
] += 1.0F
;
447 * Process each of the TTPOLYCURVE structures in the polygon:
449 while (*pp
< polyStart
+ polySize
)
450 if (!MakeLinesFromTTPolycurve( pp
,
458 /*****************************************************************************
461 * Used by tessellator to handle output vertexes.
462 *****************************************************************************/
464 VOID CALLBACK
TessVertexOutData(FLOAT p
[3], GLfloat z
)
467 v
[0] = (GLfloat
) p
[0];
468 v
[1] = (GLfloat
) p
[1];
473 /*****************************************************************************
476 * Used by tessellator to handle self-pointsecting contours and degenerate
478 *****************************************************************************/
479 VOID CALLBACK
TessCombine(double coords
[3], VOID
* vertex_data
[4], FLOAT weight
[4], VOID
** outData
)
481 if (!AppendToVertBuf((FLOAT
) coords
[0])
482 || !AppendToVertBuf((FLOAT
) coords
[1])
483 || !AppendToVertBuf((FLOAT
) coords
[2]))
484 TessErrorOccurred
= GL_OUT_OF_MEMORY
;
486 *outData
= VertBuf
+ (VertBufIndex
- 3);
489 /*****************************************************************************
492 * Saves the last tessellator error code in the global TessErrorOccurred.
493 *****************************************************************************/
495 VOID CALLBACK
TessError(GLenum error
)
497 TessErrorOccurred
= error
;
500 /*****************************************************************************
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.
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:
512 * 1., 3., 0., 0., 1., 0., 0., 1.
514 * #loops #verts x1 y1 x2 y2 x3 y3
516 * A two-loop glyph would look like this:
518 * 2., 3., 0.,0., 1.,0., 0.,1., 3., .2,.2, .4,.2, .2,.4
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 *****************************************************************************/
525 INT
MakeLinesFromGlyph(UCHAR
* glyphBuf
, DWORD glyphSize
, FLOAT chordalDeviation
)
531 * Pick up all the polygons (aka loops) that make up the glyph:
533 if (!AppendToLineBuf(0.0F
)) /* loop count at LineBuf[0] */
537 while (p
< glyphBuf
+ glyphSize
)
539 if (!MakeLinesFromTTPolygon(&p
, chordalDeviation
))
541 LineBuf
[0] += 1.0F
; /* increment loop count */
550 /*****************************************************************************
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".
558 * Return value is nonzero for success, zero for failure.
560 * Does not check for OpenGL errors, so if the caller needs to know about them,
561 * it should call glGetError().
562 *****************************************************************************/
564 INT
DrawGlyph(UCHAR
* glyphBuf
, DWORD glyphSize
, FLOAT chordalDeviation
, FLOAT extrusion
, INT format
)
570 GLUtesselator
* tess
= NULL
;
573 * Initialize the global buffer into which we place the outlines:
575 LineBuf
= (FLOAT
*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (LINE_BUF_QUANT
) * sizeof(FLOAT
));
580 LineBufSize
= LINE_BUF_QUANT
;
584 * Convert the glyph outlines to a set of polyline loops.
585 * (See MakeLinesFromGlyph() for the format of the loop data
588 if (!MakeLinesFromGlyph(glyphBuf
, glyphSize
, chordalDeviation
))
594 * Now draw the loops in the appropriate format:
596 if (format
== WGL_FONT_LINES
)
599 * This is the easy case. Just draw the outlines.
601 for (loop
= (DWORD
) *p
++; loop
; --loop
)
603 glBegin(GL_LINE_LOOP
);
604 for (point
= (DWORD
) *p
++; point
; --point
)
614 else if (format
== WGL_FONT_POLYGONS
)
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.
627 VertBuf
= (FLOAT
*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (VERT_BUF_QUANT
) * sizeof(FLOAT
));
632 VertBufSize
= VERT_BUF_QUANT
;
635 if (!(tess
= gluNewTess()))
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
);
645 TessErrorOccurred
= 0;
646 glNormal3f(0.0f
, 0.0f
, 1.0f
);
650 gluTessBeginPolygon(tess
, &z_value
);
652 for (loop
= (DWORD
) *p
++; loop
; --loop
)
654 gluTessBeginContour(tess
);
656 for (point
= (DWORD
) *p
++; point
; --point
)
660 gluTessVertex(tess
, v
, p
);
664 gluTessEndContour(tess
);
666 gluTessEndPolygon(tess
);
668 status
= !TessErrorOccurred
;
674 GLfloat thickness
= (GLfloat
) - extrusion
;
679 loops
= (DWORD
) *p
++;
681 for (loop
= 0; loop
< loops
; loop
++)
686 count
= (DWORD
) *p
++;
687 glBegin(GL_QUAD_STRIP
);
689 /* Check if the first and last vertex are identical
690 * so we don't draw the same quad twice.
692 vert
= p
+ (count
-1)*2;
693 last
= (p
[0] == vert
[0] && p
[1] == vert
[1]) ? count
-1 : count
;
695 for (point
= 0; point
<= last
; point
++)
697 vert
= p
+ 2 * (point
% last
);
698 vert2
= p
+ 2 * ((point
+1) % last
);
700 dx
= vert
[0] - vert2
[0];
701 dy
= vert
[1] - vert2
[1];
702 len
= (GLfloat
)sqrt(dx
* dx
+ dy
* dy
);
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
);
715 /* Draw the back face */
718 glNormal3f(0.0f
, 0.0f
, -1.0f
);
719 gluTessNormal(tess
, 0.0F
, 0.0F
, -1.0F
);
721 gluTessBeginPolygon(tess
, &thickness
);
723 for (loop
= (DWORD
) *p
++; loop
; --loop
)
725 count
= (DWORD
) *p
++;
727 gluTessBeginContour(tess
);
729 for (point
= 0; point
< count
; point
++)
731 vert
= p
+ ((count
-point
-1)<<1);
734 gluTessVertex(tess
, v
, vert
);
738 gluTessEndContour(tess
);
740 gluTessEndPolygon(tess
);
744 if (TessErrorOccurred
)
745 DBGPRINT("Tessellation error %s\n", gluErrorString(TessErrorOccurred
));
753 HeapFree(GetProcessHeap(), 0, LineBuf
);
756 HeapFree(GetProcessHeap(), 0, VertBuf
);
765 /*****************************************************************************
766 * MakeDisplayListFromGlyph
768 * Converts the outline of a glyph to an OpenGL display list.
770 * Return value is nonzero for success, zero for failure.
772 * Does not check for OpenGL errors, so if the caller needs to know about them,
773 * it should call glGetError().
774 *****************************************************************************/
776 INT
MakeDisplayListFromGlyph(DWORD listName
, UCHAR
* glyphBuf
, DWORD glyphSize
, LPGLYPHMETRICSFLOAT glyphMetricsFloat
,
777 FLOAT chordalDeviation
, FLOAT extrusion
, INT format
)
781 glNewList(listName
, GL_COMPILE
);
782 status
= DrawGlyph(glyphBuf
, glyphSize
, chordalDeviation
, extrusion
, format
);
783 glTranslatef(glyphMetricsFloat
->gmfCellIncX
, glyphMetricsFloat
->gmfCellIncY
, 0.0F
);
789 // ***********************************************************************
791 /*****************************************************************************
794 * Converts a subrange of the glyphs in a GDI font to OpenGL display
797 * Extended to support any GDI font, not just TrueType fonts. (DaveM)
799 *****************************************************************************/
801 BOOL APIENTRY
IntUseFontBitmapsW(HDC hDC
, DWORD first
, DWORD count
, DWORD listBase
)
803 INT i
, ox
, oy
, ix
, iy
;
805 INT iBufSize
, iCurBufSize
= 0;
806 DWORD
*bitmapBuffer
= NULL
;
807 DWORD
*invertedBitmapBuffer
= NULL
;
808 BOOL bSuccessOrFail
= TRUE
;
809 BOOL bTrueType
= FALSE
;
812 RASTERIZER_STATUS rs
;
821 // Set up a unity matrix.
822 ZeroMemory(&mat
, sizeof(mat
));
826 // Test to see if selected font is TrueType or not
827 ZeroMemory(&tm
, sizeof(tm
));
828 if (!GetTextMetrics(hDC
, &tm
))
830 DBGPRINT("Font metrics error\n");
833 bTrueType
= (tm
.tmPitchAndFamily
& TMPF_TRUETYPE
) ? TRUE
: FALSE
;
835 // Test to see if TRUE-TYPE capabilities are installed
836 // (only necessary if TrueType font selected)
837 ZeroMemory(&rs
, sizeof(rs
));
841 if (!GetRasterizerCaps (&rs
, sizeof (RASTERIZER_STATUS
)) || !(rs
.wFlags
& TT_ENABLED
))
843 DBGPRINT("No TrueType caps\n");
848 // Trick to get the current font handle
849 hFont
= SelectObject(hDC
, GetStockObject(SYSTEM_FONT
));
850 SelectObject(hDC
, hFont
);
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);
858 for (i
= first
; (DWORD
) i
< (first
+ count
); i
++)
860 // Find out how much space is needed for the bitmap so we can
861 // Set the buffer size correctly.
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
)
868 bSuccessOrFail
= FALSE
;
874 // Use generic GDI support to compute bitmap size of glyph
875 w
= tm
.tmMaxCharWidth
;
877 if (GetTextExtentPoint32(hDC
, (LPCTSTR
)&i
, 1, &size
))
883 // Use DWORD multiple for compatibility
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
)
895 HeapFree(GetProcessHeap(), 0, bitmapBuffer
);
897 if (invertedBitmapBuffer
)
899 HeapFree(GetProcessHeap(), 0, invertedBitmapBuffer
);
902 iCurBufSize
= iBufSize
* 2;
903 bitmapBuffer
= (DWORD
*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, iCurBufSize
);
904 invertedBitmapBuffer
= (DWORD
*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, iCurBufSize
);
906 if (bitmapBuffer
== NULL
|| invertedBitmapBuffer
== NULL
)
908 bSuccessOrFail
= FALSE
;
913 // If we fail to get the Glyph data, delete the display lists
914 // Created so far and return FALSE.
917 // Use TrueType support to get bitmap of glyph
918 if (GetGlyphOutline(hDC
, i
, GGO_BITMAP
, &gm
, iBufSize
, bitmapBuffer
, &mat
) == GDI_ERROR
)
920 bSuccessOrFail
= FALSE
;
924 // Setup glBitmap parameters for current font glyph
927 ox
= gm
.gmptGlyphOrigin
.x
;
928 oy
= gm
.gmptGlyphOrigin
.y
;
934 // Use generic GDI support to create bitmap of glyph
935 ZeroMemory(bitmapBuffer
, iBufSize
);
937 if (i
>= tm
.tmFirstChar
&& i
<= tm
.tmLastChar
)
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
);
959 // Otherwise use empty display list for non-existing glyph
963 // Setup glBitmap parameters for current font glyph
970 // Create an OpenGL display list.
971 glNewList((listBase
+ i
), GL_COMPILE
);
973 // Some fonts have no data for the space character, yet advertise
977 glBitmap(0, 0, 0.0f
, 0.0f
, (GLfloat
) ix
, (GLfloat
) iy
, NULL
);
981 // Invert the Glyph data.
982 InvertGlyphBitmap(w
, h
, bitmapBuffer
, invertedBitmapBuffer
);
984 // Render an OpenGL bitmap and invert the origin.
986 (GLfloat
) ox
, (GLfloat
) (h
-oy
),
987 (GLfloat
) ix
, (GLfloat
) iy
,
988 (GLubyte
*) invertedBitmapBuffer
);
991 // Close this display list.
995 if (bSuccessOrFail
== FALSE
)
997 DBGPRINT("DGL_UseFontBitmaps: Get glyph failed\n");
998 glDeleteLists((i
+listBase
), (i
-first
));
1001 // Release resources used
1002 DeleteObject(hFont
);
1006 HeapFree(GetProcessHeap(), 0, bitmapBuffer
);
1008 if (invertedBitmapBuffer
)
1009 HeapFree(GetProcessHeap(), 0, invertedBitmapBuffer
);
1011 return(bSuccessOrFail
);
1014 BOOL APIENTRY
IntUseFontBitmapsA(HDC hDC
, DWORD first
, DWORD count
, DWORD listBase
)
1016 /* Just call IntUseFontBitmapsW for now */
1017 return IntUseFontBitmapsW(hDC
, first
, count
, listBase
);
1022 /*****************************************************************************
1023 * IntUseFontOutlines
1025 * Converts a subrange of the glyphs in a TrueType font to OpenGL display
1027 *****************************************************************************/
1029 BOOL APIENTRY
IntUseFontOutlinesW(HDC hDC
, DWORD first
, DWORD count
, DWORD listBase
, FLOAT chordalDeviation
,
1030 FLOAT extrusion
, INT format
, GLYPHMETRICSFLOAT
*glyphMetricsFloatArray
)
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.
1040 while (glGetError() != GL_NO_ERROR
);
1043 * Make sure that the current font can be sampled accurately.
1045 hNewFont
= CreateHighResolutionFont(hDC
);
1050 hOldFont
= SelectObject(hDC
, hNewFont
);
1055 * Preallocate a buffer for the outline data, and track its size:
1057 glyphBuf
= (UCHAR
*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, glyphBufSize
= 10240);
1060 return FALSE
; /*WGL_STATUS_NOT_ENOUGH_MEMORY*/
1063 * Process each glyph in the given range:
1065 for (glyphIndex
= first
; glyphIndex
- first
< count
; ++glyphIndex
)
1067 GLYPHMETRICS glyphMetrics
;
1069 static MAT2 matrix
=
1074 LPGLYPHMETRICSFLOAT glyphMetricsFloat
= &glyphMetricsFloatArray
[glyphIndex
- first
];
1077 * Determine how much space is needed to store the glyph's
1078 * outlines. If our glyph buffer isn't large enough,
1082 glyphSize
= GetGlyphOutline(hDC
, glyphIndex
, GGO_NATIVE
, &glyphMetrics
, 0, NULL
, &matrix
);
1085 return FALSE
; /*WGL_STATUS_FAILURE*/
1087 if (glyphSize
> glyphBufSize
)
1089 HeapFree(GetProcessHeap(), 0, glyphBuf
);
1090 glyphBuf
= (UCHAR
*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, glyphBufSize
= glyphSize
);
1092 return FALSE
; /*WGL_STATUS_NOT_ENOUGH_MEMORY*/
1097 * Get the glyph's outlines.
1099 if (GetGlyphOutline(hDC
, glyphIndex
, GGO_NATIVE
, &glyphMetrics
, glyphBufSize
, glyphBuf
, &matrix
) < 0)
1101 HeapFree(GetProcessHeap(), 0, glyphBuf
);
1102 return FALSE
; /*WGL_STATUS_FAILURE*/
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
;
1119 * Turn the glyph into a display list:
1121 if (!MakeDisplayListFromGlyph((glyphIndex
- first
) + listBase
, glyphBuf
, glyphSize
, glyphMetricsFloat
,
1122 chordalDeviation
+ ScaleFactor
, extrusion
, format
))
1124 HeapFree(GetProcessHeap(), 0, glyphBuf
);
1125 return FALSE
; /*WGL_STATUS_FAILURE*/
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.
1134 HeapFree(GetProcessHeap(), 0, glyphBuf
);
1136 DeleteObject(SelectObject(hDC
, hOldFont
));
1138 if (glGetError() == GL_NO_ERROR
)
1140 return TRUE
; /*WGL_STATUS_SUCCESS*/
1144 while (glGetError() != GL_NO_ERROR
);
1146 return FALSE
; /*WGL_STATUS_FAILURE*/
1150 BOOL APIENTRY
IntUseFontOutlinesA(HDC hDC
, DWORD first
, DWORD count
, DWORD listBase
, FLOAT chordalDeviation
,
1151 FLOAT extrusion
, INT format
, GLYPHMETRICSFLOAT
*glyphMetricsFloatArray
)
1153 /* Just call IntUseFontOutlinesW for now */
1154 return IntUseFontOutlinesW(hDC
, first
, count
, listBase
, chordalDeviation
, extrusion
, format
, glyphMetricsFloatArray
);