Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfont.c
Go to the documentation of this file.
00001 /**************************************************************************** 00002 * Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved. 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00017 * SCITECH SOFTWARE INC BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 00018 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 00019 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00020 * SOFTWARE. 00021 ****************************************************************************/ 00022 00023 #include "opengl32.h" 00024 #include <math.h> 00025 00026 #define LINE_BUF_QUANT 4000 00027 #define VERT_BUF_QUANT 4000 00028 00029 static HFONT hNewFont, hOldFont; 00030 static FLOAT ScaleFactor; 00031 static FLOAT* LineBuf; 00032 static DWORD LineBufSize; 00033 static DWORD LineBufIndex; 00034 static FLOAT* VertBuf; 00035 static DWORD VertBufSize; 00036 static DWORD VertBufIndex; 00037 static GLenum TessErrorOccurred; 00038 00039 /***************************************************************************** 00040 * AppendToLineBuf 00041 * 00042 * Appends one floating-point value to the global LineBuf array. Return value 00043 * is non-zero for success, zero for failure. 00044 *****************************************************************************/ 00045 00046 INT AppendToLineBuf(FLOAT value) 00047 { 00048 if (LineBufIndex >= LineBufSize) 00049 { 00050 FLOAT* f; 00051 LineBufSize += LINE_BUF_QUANT; 00052 00053 f = (FLOAT*) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, LineBuf, (LineBufSize) * sizeof(FLOAT)); 00054 if (!f) 00055 return 0; 00056 LineBuf = f; 00057 } 00058 LineBuf[LineBufIndex++] = value; 00059 return 1; 00060 } 00061 00062 /***************************************************************************** 00063 * AppendToVertBuf 00064 * 00065 * Appends one floating-point value to the global VertBuf array. Return value 00066 * is non-zero for success, zero for failure. 00067 * 00068 * Note that we can't realloc this one, because the tessellator is using 00069 * pointers into it. 00070 *****************************************************************************/ 00071 00072 INT AppendToVertBuf(FLOAT value) 00073 { 00074 if (VertBufIndex >= VertBufSize) 00075 return 0; 00076 VertBuf[VertBufIndex++] = value; 00077 return 1; 00078 } 00079 00080 /***************************************************************************** 00081 * GetWord 00082 * 00083 * Fetch the next 16-bit word from a little-endian byte stream, and increment 00084 * the stream pointer to the next unscanned byte. 00085 *****************************************************************************/ 00086 00087 LONG GetWord(UCHAR** p) 00088 { 00089 LONG value; 00090 00091 value = ((*p)[1] << 8) + (*p)[0]; 00092 *p += 2; 00093 return value; 00094 } 00095 00096 /***************************************************************************** 00097 * GetDWord 00098 * 00099 * Fetch the next 32-bit word from a little-endian byte stream, and increment 00100 * the stream pointer to the next unscanned byte. 00101 *****************************************************************************/ 00102 00103 LONG GetDWord(UCHAR** p) 00104 { 00105 LONG value; 00106 00107 value = ((*p)[3] << 24) + ((*p)[2] << 16) + ((*p)[1] << 8) + (*p)[0]; 00108 *p += 4; 00109 return value; 00110 } 00111 00112 /***************************************************************************** 00113 * GetFixed 00114 * 00115 * Fetch the next 32-bit fixed-point value from a little-endian byte stream, 00116 * convert it to floating-point, and increment the stream pointer to the next 00117 * unscanned byte. 00118 *****************************************************************************/ 00119 double GetFixed(UCHAR** p) 00120 { 00121 LONG hiBits, loBits; 00122 double value; 00123 00124 loBits = GetWord(p); 00125 hiBits = GetWord(p); 00126 value = (double) ((hiBits << 16) | loBits) / 65536.0; 00127 00128 return value * ScaleFactor; 00129 } 00130 00131 00132 /***************************************************************************** 00133 ** 00134 ** InvertGlyphBitmap. 00135 ** 00136 ** Invert the bitmap so that it suits OpenGL's representation. 00137 ** Each row starts on a double word boundary. 00138 ** 00139 *****************************************************************************/ 00140 00141 VOID InvertGlyphBitmap(INT w, INT h, DWORD *fptr, DWORD *tptr) 00142 { 00143 INT dWordsInRow = (w+31)/32; 00144 INT i, j; 00145 00146 if (w <= 0 || h <= 0) { 00147 return; 00148 } 00149 00150 tptr += ((h-1)*dWordsInRow); 00151 for (i = 0; i < h; i++) { 00152 for (j = 0; j < dWordsInRow; j++) { 00153 *(tptr + j) = *(fptr + j); 00154 } 00155 tptr -= dWordsInRow; 00156 fptr += dWordsInRow; 00157 } 00158 } 00159 00160 /***************************************************************************** 00161 * CreateHighResolutionFont 00162 * 00163 * Gets metrics for the current font and creates an equivalent font 00164 * scaled to the design units of the font. 00165 * 00166 *****************************************************************************/ 00167 00168 HFONT CreateHighResolutionFont(HDC hDC) 00169 { 00170 UINT otmSize; 00171 OUTLINETEXTMETRIC *otm; 00172 LONG fontHeight, fontWidth, fontUnits; 00173 LOGFONTW logFont, logFontFaceName; 00174 00175 otmSize = GetOutlineTextMetricsW(hDC, 0, NULL); 00176 if (!otmSize) 00177 return NULL; 00178 00179 otm = (OUTLINETEXTMETRIC *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, otmSize); 00180 if (!otm) 00181 return NULL; 00182 00183 otm->otmSize = otmSize; 00184 if (!GetOutlineTextMetricsW(hDC, otmSize, otm)) 00185 return NULL; 00186 00187 GetObjectW(GetCurrentObject(hDC, OBJ_FONT), sizeof(logFontFaceName), &logFontFaceName); 00188 00189 fontHeight = otm->otmTextMetrics.tmHeight - 00190 otm->otmTextMetrics.tmInternalLeading; 00191 fontWidth = otm->otmTextMetrics.tmAveCharWidth; 00192 fontUnits = (LONG) otm->otmEMSquare; 00193 00194 ScaleFactor = 1.0F / (FLOAT) fontUnits; 00195 00196 logFont.lfHeight = - ((LONG) fontUnits); 00197 logFont.lfWidth = (LONG)((FLOAT) (fontWidth * fontUnits) / (FLOAT) fontHeight); 00198 logFont.lfEscapement = 0; 00199 logFont.lfOrientation = 0; 00200 logFont.lfWeight = otm->otmTextMetrics.tmWeight; 00201 logFont.lfItalic = otm->otmTextMetrics.tmItalic; 00202 logFont.lfUnderline = otm->otmTextMetrics.tmUnderlined; 00203 logFont.lfStrikeOut = otm->otmTextMetrics.tmStruckOut; 00204 logFont.lfCharSet = otm->otmTextMetrics.tmCharSet; 00205 logFont.lfOutPrecision = OUT_OUTLINE_PRECIS; 00206 logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; 00207 logFont.lfQuality = DEFAULT_QUALITY; 00208 logFont.lfPitchAndFamily = 00209 otm->otmTextMetrics.tmPitchAndFamily & 0xf0; 00210 wcscpy(logFont.lfFaceName, logFontFaceName.lfFaceName); 00211 00212 hNewFont = CreateFontIndirectW(&logFont); 00213 00214 HeapFree(GetProcessHeap(), 0, otm); 00215 00216 return hNewFont; 00217 } 00218 00219 /***************************************************************************** 00220 * MakeLinesFromArc 00221 * 00222 * Subdivides one arc of a quadratic spline until the chordal deviation 00223 * tolerance requirement is met, then places the resulting set of line 00224 * segments in the global LineBuf. 00225 *****************************************************************************/ 00226 INT MakeLinesFromArc(FLOAT x0, FLOAT y0, FLOAT x1, FLOAT y1, FLOAT x2, FLOAT y2, 00227 DWORD vertexCountIndex, FLOAT chordalDeviationSquared) 00228 { 00229 FLOAT x01; 00230 FLOAT y01; 00231 FLOAT x12; 00232 FLOAT y12; 00233 FLOAT midPointX; 00234 FLOAT midPointY; 00235 FLOAT deltaX; 00236 FLOAT deltaY; 00237 00238 /* 00239 * Calculate midpoint of the curve by de Casteljau: 00240 */ 00241 x01 = 0.5F * (x0 + x1); 00242 y01 = 0.5F * (y0 + y1); 00243 x12 = 0.5F * (x1 + x2); 00244 y12 = 0.5F * (y1 + y2); 00245 midPointX = 0.5F * (x01 + x12); 00246 midPointY = 0.5F * (y01 + y12); 00247 00248 00249 /* 00250 * Estimate chordal deviation by the distance from the midpoint 00251 * of the curve to its non-pointpolated control point. If this 00252 * distance is greater than the specified chordal deviation 00253 * constraint, then subdivide. Otherwise, generate polylines 00254 * from the three control points. 00255 */ 00256 deltaX = midPointX - x1; 00257 deltaY = midPointY - y1; 00258 00259 if (deltaX * deltaX + deltaY * deltaY > chordalDeviationSquared) 00260 { 00261 MakeLinesFromArc( x0, y0, 00262 x01, y01, 00263 midPointX, midPointY, 00264 vertexCountIndex, 00265 chordalDeviationSquared); 00266 00267 MakeLinesFromArc( midPointX, midPointY, 00268 x12, y12, 00269 x2, y2, 00270 vertexCountIndex, 00271 chordalDeviationSquared); 00272 } 00273 else 00274 { 00275 /* 00276 * The "pen" is already at (x0, y0), so we don't need to 00277 * add that point to the LineBuf. 00278 */ 00279 if (!AppendToLineBuf(x1) 00280 || !AppendToLineBuf(y1) 00281 || !AppendToLineBuf(x2) 00282 || !AppendToLineBuf(y2)) 00283 return 0; 00284 LineBuf[vertexCountIndex] += 2.0F; 00285 } 00286 00287 return 1; 00288 } 00289 00290 /***************************************************************************** 00291 * MakeLinesFromTTQSpline 00292 * 00293 * Converts points from the poly quadratic spline in a TT_PRIM_QSPLINE 00294 * structure to polyline points in the global LineBuf. 00295 *****************************************************************************/ 00296 00297 INT MakeLinesFromTTQSpline( UCHAR** pp, DWORD vertexCountIndex, WORD pointCount, FLOAT chordalDeviation) 00298 { 00299 FLOAT x0, y0, x1, y1, x2, y2; 00300 WORD point; 00301 00302 /* 00303 * Process each of the non-pointpolated points in the outline. 00304 * To do this, we need to generate two pointpolated points (the 00305 * start and end of the arc) for each non-pointpolated point. 00306 * The first pointpolated point is always the one most recently 00307 * stored in LineBuf, so we just extract it from there. The 00308 * second pointpolated point is either the average of the next 00309 * two points in the QSpline, or the last point in the QSpline 00310 * if only one remains. 00311 */ 00312 for (point = 0; point < pointCount - 1; ++point) 00313 { 00314 x0 = LineBuf[LineBufIndex - 2]; 00315 y0 = LineBuf[LineBufIndex - 1]; 00316 00317 x1 = (FLOAT) GetFixed(pp); 00318 y1 = (FLOAT) GetFixed(pp); 00319 00320 if (point == pointCount - 2) 00321 { 00322 /* 00323 * This is the last arc in the QSpline. The final 00324 * point is the end of the arc. 00325 */ 00326 x2 = (FLOAT) GetFixed(pp); 00327 y2 = (FLOAT) GetFixed(pp); 00328 } 00329 else 00330 { 00331 /* 00332 * Peek at the next point in the input to compute 00333 * the end of the arc: 00334 */ 00335 x2 = 0.5F * (x1 + (FLOAT) GetFixed(pp)); 00336 y2 = 0.5F * (y1 + (FLOAT) GetFixed(pp)); 00337 /* 00338 * Push the point back onto the input so it will 00339 * be reused as the next off-curve point: 00340 */ 00341 *pp -= 8; 00342 } 00343 00344 if (!MakeLinesFromArc( x0, y0, 00345 x1, y1, 00346 x2, y2, 00347 vertexCountIndex, 00348 chordalDeviation * chordalDeviation)) 00349 return 0; 00350 } 00351 00352 return 1; 00353 } 00354 00355 /***************************************************************************** 00356 * MakeLinesFromTTLine 00357 * 00358 * Converts points from the polyline in a TT_PRIM_LINE structure to 00359 * equivalent points in the global LineBuf. 00360 *****************************************************************************/ 00361 INT MakeLinesFromTTLine(UCHAR** pp, DWORD vertexCountIndex, WORD pointCount) 00362 { 00363 /* 00364 * Just copy the line segments into the line buffer (converting 00365 * type as we go): 00366 */ 00367 LineBuf[vertexCountIndex] += pointCount; 00368 while (pointCount--) 00369 { 00370 if (!AppendToLineBuf((FLOAT) GetFixed(pp)) /* X coord */ 00371 || !AppendToLineBuf((FLOAT) GetFixed(pp))) /* Y coord */ 00372 return 0; 00373 } 00374 00375 return 1; 00376 } 00377 00378 /***************************************************************************** 00379 * MakeLinesFromTTPolyCurve 00380 * 00381 * Converts the lines and splines in a single TTPOLYCURVE structure to points 00382 * in the global LineBuf. 00383 *****************************************************************************/ 00384 00385 INT MakeLinesFromTTPolycurve(UCHAR** pp, DWORD vertexCountIndex, FLOAT chordalDeviation) 00386 { 00387 WORD type; 00388 WORD pointCount; 00389 00390 /* 00391 * Pick up the relevant fields of the TTPOLYCURVE structure: 00392 */ 00393 type = (WORD) GetWord(pp); 00394 pointCount = (WORD) GetWord(pp); 00395 00396 /* 00397 * Convert the "curve" to line segments: 00398 */ 00399 if (type == TT_PRIM_LINE) 00400 return MakeLinesFromTTLine( pp, 00401 vertexCountIndex, 00402 pointCount); 00403 else if (type == TT_PRIM_QSPLINE) 00404 return MakeLinesFromTTQSpline( pp, 00405 vertexCountIndex, 00406 pointCount, 00407 chordalDeviation); 00408 else 00409 return 0; 00410 } 00411 00412 /***************************************************************************** 00413 * MakeLinesFromTTPolygon 00414 * 00415 * Converts a TTPOLYGONHEADER and its associated curve structures into a 00416 * single polyline loop in the global LineBuf. 00417 *****************************************************************************/ 00418 00419 INT MakeLinesFromTTPolygon(UCHAR** pp, FLOAT chordalDeviation) 00420 { 00421 DWORD polySize; 00422 UCHAR* polyStart; 00423 DWORD vertexCountIndex; 00424 00425 /* 00426 * Record where the polygon data begins, and where the loop's 00427 * vertex count resides: 00428 */ 00429 polyStart = *pp; 00430 vertexCountIndex = LineBufIndex; 00431 if (!AppendToLineBuf(0.0F)) 00432 return 0; 00433 00434 /* 00435 * Extract relevant data from the TTPOLYGONHEADER: 00436 */ 00437 polySize = GetDWord(pp); 00438 if (GetDWord(pp) != TT_POLYGON_TYPE) /* polygon type */ 00439 return 0; 00440 if (!AppendToLineBuf((FLOAT) GetFixed(pp))) /* first X coord */ 00441 return 0; 00442 if (!AppendToLineBuf((FLOAT) GetFixed(pp))) /* first Y coord */ 00443 return 0; 00444 LineBuf[vertexCountIndex] += 1.0F; 00445 00446 /* 00447 * Process each of the TTPOLYCURVE structures in the polygon: 00448 */ 00449 while (*pp < polyStart + polySize) 00450 if (!MakeLinesFromTTPolycurve( pp, 00451 vertexCountIndex, 00452 chordalDeviation)) 00453 return 0; 00454 00455 return 1; 00456 } 00457 00458 /***************************************************************************** 00459 * TessVertexOut 00460 * 00461 * Used by tessellator to handle output vertexes. 00462 *****************************************************************************/ 00463 00464 VOID CALLBACK TessVertexOutData(FLOAT p[3], GLfloat *pz) 00465 { 00466 GLfloat v[3]; 00467 v[0] = (GLfloat) p[0]; 00468 v[1] = (GLfloat) p[1]; 00469 v[2] = *pz; 00470 glVertex3fv(v); 00471 } 00472 00473 /***************************************************************************** 00474 * TessCombine 00475 * 00476 * Used by tessellator to handle self-pointsecting contours and degenerate 00477 * geometry. 00478 *****************************************************************************/ 00479 VOID CALLBACK TessCombine(double coords[3], VOID* vertex_data[4], FLOAT weight[4], VOID** outData) 00480 { 00481 if (!AppendToVertBuf((FLOAT) coords[0]) 00482 || !AppendToVertBuf((FLOAT) coords[1]) 00483 || !AppendToVertBuf((FLOAT) coords[2])) 00484 TessErrorOccurred = GL_OUT_OF_MEMORY; 00485 00486 *outData = VertBuf + (VertBufIndex - 3); 00487 } 00488 00489 /***************************************************************************** 00490 * TessError 00491 * 00492 * Saves the last tessellator error code in the global TessErrorOccurred. 00493 *****************************************************************************/ 00494 00495 VOID CALLBACK TessError(GLenum error) 00496 { 00497 TessErrorOccurred = error; 00498 } 00499 00500 /***************************************************************************** 00501 * MakeLinesFromGlyph 00502 * 00503 * Converts the outline of a glyph from the TTPOLYGON format to a simple 00504 * array of floating-point values containing one or more loops. 00505 * 00506 * The first element of the output array is a count of the number of loops. 00507 * The loop data follows this count. Each loop consists of a count of the 00508 * number of vertices it contains, followed by the vertices. Each vertex 00509 * is an X and Y coordinate. For example, a single triangle might be 00510 * described by this array: 00511 * 00512 * 1., 3., 0., 0., 1., 0., 0., 1. 00513 * ^ ^ ^ ^ ^ ^ ^ ^ 00514 * #loops #verts x1 y1 x2 y2 x3 y3 00515 * 00516 * A two-loop glyph would look like this: 00517 * 00518 * 2., 3., 0.,0., 1.,0., 0.,1., 3., .2,.2, .4,.2, .2,.4 00519 * 00520 * Line segments from the TTPOLYGON are transferred to the output array in 00521 * the obvious way. Quadratic splines in the TTPOLYGON are converted to 00522 * collections of line segments 00523 *****************************************************************************/ 00524 00525 INT MakeLinesFromGlyph(UCHAR* glyphBuf, DWORD glyphSize, FLOAT chordalDeviation) 00526 { 00527 UCHAR* p; 00528 INT status = 0; 00529 00530 /* 00531 * Pick up all the polygons (aka loops) that make up the glyph: 00532 */ 00533 if (!AppendToLineBuf(0.0F)) /* loop count at LineBuf[0] */ 00534 goto exit; 00535 00536 p = glyphBuf; 00537 while (p < glyphBuf + glyphSize) 00538 { 00539 if (!MakeLinesFromTTPolygon(&p, chordalDeviation)) 00540 goto exit; 00541 LineBuf[0] += 1.0F; /* increment loop count */ 00542 } 00543 00544 status = 1; 00545 00546 exit: 00547 return status; 00548 } 00549 00550 /***************************************************************************** 00551 * DrawGlyph 00552 * 00553 * Converts the outline of a glyph to OpenGL drawing primitives, tessellating 00554 * as needed, and then draws the glyph. Tessellation of the quadratic splines 00555 * in the outline is controlled by "chordalDeviation", and the drawing 00556 * primitives (lines or polygons) are selected by "format". 00557 * 00558 * Return value is nonzero for success, zero for failure. 00559 * 00560 * Does not check for OpenGL errors, so if the caller needs to know about them, 00561 * it should call glGetError(). 00562 *****************************************************************************/ 00563 00564 INT DrawGlyph(UCHAR* glyphBuf, DWORD glyphSize, FLOAT chordalDeviation, FLOAT extrusion, INT format) 00565 { 00566 INT status = 0; 00567 FLOAT* p; 00568 DWORD loop; 00569 DWORD point; 00570 GLUtesselator* tess = NULL; 00571 00572 /* 00573 * Initialize the global buffer into which we place the outlines: 00574 */ 00575 LineBuf = (FLOAT*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (LINE_BUF_QUANT) * sizeof(FLOAT)); 00576 00577 if(!LineBuf) 00578 goto exit; 00579 00580 LineBufSize = LINE_BUF_QUANT; 00581 LineBufIndex = 0; 00582 00583 /* 00584 * Convert the glyph outlines to a set of polyline loops. 00585 * (See MakeLinesFromGlyph() for the format of the loop data 00586 * structure.) 00587 */ 00588 if (!MakeLinesFromGlyph(glyphBuf, glyphSize, chordalDeviation)) 00589 goto exit; 00590 p = LineBuf; 00591 00592 00593 /* 00594 * Now draw the loops in the appropriate format: 00595 */ 00596 if (format == WGL_FONT_LINES) 00597 { 00598 /* 00599 * This is the easy case. Just draw the outlines. 00600 */ 00601 for (loop = (DWORD) *p++; loop; --loop) 00602 { 00603 glBegin(GL_LINE_LOOP); 00604 for (point = (DWORD) *p++; point; --point) 00605 { 00606 glVertex2fv(p); 00607 p += 2; 00608 } 00609 glEnd(); 00610 } 00611 status = 1; 00612 } 00613 00614 else if (format == WGL_FONT_POLYGONS) 00615 { 00616 double v[3]; 00617 FLOAT *save_p = p; 00618 GLfloat z_value; 00619 00620 /* 00621 * This is the hard case. We have to set up a tessellator 00622 * to convert the outlines into a set of polygonal 00623 * primitives, which the tessellator passes to some 00624 * auxiliary routines for drawing. 00625 */ 00626 00627 VertBuf = (FLOAT*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (VERT_BUF_QUANT) * sizeof(FLOAT)); 00628 00629 if (!VertBuf) 00630 goto exit; 00631 00632 VertBufSize = VERT_BUF_QUANT; 00633 VertBufIndex = 0; 00634 00635 if (!(tess = gluNewTess())) 00636 goto exit; 00637 00638 gluTessCallback(tess, GLU_BEGIN, (VOID(CALLBACK *)()) glBegin); 00639 gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (VOID(CALLBACK *)()) TessVertexOutData); 00640 gluTessCallback(tess, GLU_END, (VOID(CALLBACK *)()) glEnd); 00641 gluTessCallback(tess, GLU_ERROR, (VOID(CALLBACK *)()) TessError); 00642 gluTessCallback(tess, GLU_TESS_COMBINE, (VOID(CALLBACK *)()) TessCombine); 00643 gluTessNormal(tess, 0.0F, 0.0F, 1.0F); 00644 00645 TessErrorOccurred = 0; 00646 glNormal3f(0.0f, 0.0f, 1.0f); 00647 v[2] = 0.0; 00648 z_value = 0.0f; 00649 00650 gluTessBeginPolygon(tess, &z_value); 00651 00652 for (loop = (DWORD) *p++; loop; --loop) 00653 { 00654 gluTessBeginContour(tess); 00655 00656 for (point = (DWORD) *p++; point; --point) 00657 { 00658 v[0] = p[0]; 00659 v[1] = p[1]; 00660 gluTessVertex(tess, v, p); 00661 p += 2; 00662 } 00663 00664 gluTessEndContour(tess); 00665 } 00666 gluTessEndPolygon(tess); 00667 00668 status = !TessErrorOccurred; 00669 00670 /* Extrusion code */ 00671 if (extrusion) 00672 { 00673 DWORD loops; 00674 GLfloat thickness = (GLfloat) - extrusion; 00675 FLOAT *vert, *vert2; 00676 DWORD count; 00677 00678 p = save_p; 00679 loops = (DWORD) *p++; 00680 00681 for (loop = 0; loop < loops; loop++) 00682 { 00683 GLfloat dx, dy, len; 00684 DWORD last; 00685 00686 count = (DWORD) *p++; 00687 glBegin(GL_QUAD_STRIP); 00688 00689 /* Check if the first and last vertex are identical 00690 * so we don't draw the same quad twice. 00691 */ 00692 vert = p + (count-1)*2; 00693 last = (p[0] == vert[0] && p[1] == vert[1]) ? count-1 : count; 00694 00695 for (point = 0; point <= last; point++) 00696 { 00697 vert = p + 2 * (point % last); 00698 vert2 = p + 2 * ((point+1) % last); 00699 00700 dx = vert[0] - vert2[0]; 00701 dy = vert[1] - vert2[1]; 00702 len = (GLfloat)sqrt(dx * dx + dy * dy); 00703 00704 glNormal3f(dy / len, -dx / len, 0.0f); 00705 glVertex3f((GLfloat) vert[0], 00706 (GLfloat) vert[1], thickness); 00707 glVertex3f((GLfloat) vert[0], 00708 (GLfloat) vert[1], 0.0f); 00709 } 00710 00711 glEnd(); 00712 p += count*2; 00713 } 00714 00715 /* Draw the back face */ 00716 p = save_p; 00717 v[2] = thickness; 00718 glNormal3f(0.0f, 0.0f, -1.0f); 00719 gluTessNormal(tess, 0.0F, 0.0F, -1.0F); 00720 00721 gluTessBeginPolygon(tess, &thickness); 00722 00723 for (loop = (DWORD) *p++; loop; --loop) 00724 { 00725 count = (DWORD) *p++; 00726 00727 gluTessBeginContour(tess); 00728 00729 for (point = 0; point < count; point++) 00730 { 00731 vert = p + ((count-point-1)<<1); 00732 v[0] = vert[0]; 00733 v[1] = vert[1]; 00734 gluTessVertex(tess, v, vert); 00735 } 00736 p += count*2; 00737 00738 gluTessEndContour(tess); 00739 } 00740 gluTessEndPolygon(tess); 00741 } 00742 00743 #if !defined(NDEBUG) 00744 if (TessErrorOccurred) 00745 DBGPRINT("Tessellation error %s\n", gluErrorString(TessErrorOccurred)); 00746 #endif 00747 } 00748 00749 00750 exit: 00751 00752 if(LineBuf) 00753 HeapFree(GetProcessHeap(), 0, LineBuf); 00754 00755 if(VertBuf) 00756 HeapFree(GetProcessHeap(), 0, VertBuf); 00757 00758 if (tess) 00759 gluDeleteTess(tess); 00760 00761 return status; 00762 } 00763 00764 00765 /***************************************************************************** 00766 * MakeDisplayListFromGlyph 00767 * 00768 * Converts the outline of a glyph to an OpenGL display list. 00769 * 00770 * Return value is nonzero for success, zero for failure. 00771 * 00772 * Does not check for OpenGL errors, so if the caller needs to know about them, 00773 * it should call glGetError(). 00774 *****************************************************************************/ 00775 00776 INT MakeDisplayListFromGlyph(DWORD listName, UCHAR* glyphBuf, DWORD glyphSize, LPGLYPHMETRICSFLOAT glyphMetricsFloat, 00777 FLOAT chordalDeviation, FLOAT extrusion, INT format) 00778 { 00779 INT status; 00780 00781 glNewList(listName, GL_COMPILE); 00782 status = DrawGlyph(glyphBuf, glyphSize, chordalDeviation, extrusion, format); 00783 glTranslatef(glyphMetricsFloat->gmfCellIncX, glyphMetricsFloat->gmfCellIncY, 0.0F); 00784 glEndList(); 00785 00786 return status; 00787 } 00788 00789 // *********************************************************************** 00790 00791 /***************************************************************************** 00792 * IntUseFontBitmaps 00793 * 00794 * Converts a subrange of the glyphs in a GDI font to OpenGL display 00795 * lists. 00796 * 00797 * Extended to support any GDI font, not just TrueType fonts. (DaveM) 00798 * 00799 *****************************************************************************/ 00800 00801 BOOL APIENTRY IntUseFontBitmapsW(HDC hDC, DWORD first, DWORD count, DWORD listBase) 00802 { 00803 INT i, ox, oy, ix, iy; 00804 INT w = 0, h = 0; 00805 INT iBufSize, iCurBufSize = 0; 00806 DWORD *bitmapBuffer = NULL; 00807 DWORD *invertedBitmapBuffer = NULL; 00808 BOOL bSuccessOrFail = TRUE; 00809 BOOL bTrueType = FALSE; 00810 TEXTMETRIC tm; 00811 GLYPHMETRICS gm; 00812 RASTERIZER_STATUS rs; 00813 MAT2 mat; 00814 SIZE size; 00815 RECT rect; 00816 HDC hDCMem; 00817 HBITMAP hBitmap; 00818 BITMAPINFO bmi; 00819 HFONT hFont; 00820 00821 // Set up a unity matrix. 00822 ZeroMemory(&mat, sizeof(mat)); 00823 mat.eM11.value = 1; 00824 mat.eM22.value = 1; 00825 00826 // Test to see if selected font is TrueType or not 00827 ZeroMemory(&tm, sizeof(tm)); 00828 if (!GetTextMetrics(hDC, &tm)) 00829 { 00830 DBGPRINT("Font metrics error\n"); 00831 return FALSE; 00832 } 00833 bTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) ? TRUE : FALSE; 00834 00835 // Test to see if TRUE-TYPE capabilities are installed 00836 // (only necessary if TrueType font selected) 00837 ZeroMemory(&rs, sizeof(rs)); 00838 00839 if (bTrueType) 00840 { 00841 if (!GetRasterizerCaps (&rs, sizeof (RASTERIZER_STATUS)) || !(rs.wFlags & TT_ENABLED)) 00842 { 00843 DBGPRINT("No TrueType caps\n"); 00844 bTrueType = FALSE; 00845 } 00846 } 00847 00848 // Trick to get the current font handle 00849 hFont = SelectObject(hDC, GetStockObject(SYSTEM_FONT)); 00850 SelectObject(hDC, hFont); 00851 00852 // Have memory device context available for holding bitmaps of font glyphs 00853 hDCMem = CreateCompatibleDC(hDC); 00854 SelectObject(hDCMem, hFont); 00855 SetTextColor(hDCMem, RGB(0xFF, 0xFF, 0xFF)); 00856 SetBkColor(hDCMem, 0); 00857 00858 for (i = first; (DWORD) i < (first + count); i++) 00859 { 00860 // Find out how much space is needed for the bitmap so we can 00861 // Set the buffer size correctly. 00862 if (bTrueType) 00863 { 00864 // Use TrueType support to get bitmap size of glyph 00865 iBufSize = GetGlyphOutline(hDC, i, GGO_BITMAP, &gm, 0, NULL, &mat); 00866 if (iBufSize == GDI_ERROR) 00867 { 00868 bSuccessOrFail = FALSE; 00869 break; 00870 } 00871 } 00872 else 00873 { 00874 // Use generic GDI support to compute bitmap size of glyph 00875 w = tm.tmMaxCharWidth; 00876 h = tm.tmHeight; 00877 if (GetTextExtentPoint32(hDC, (LPCTSTR)&i, 1, &size)) 00878 { 00879 w = size.cx; 00880 h = size.cy; 00881 } 00882 iBufSize = w * h; 00883 // Use DWORD multiple for compatibility 00884 iBufSize += 3; 00885 iBufSize /= 4; 00886 iBufSize *= 4; 00887 } 00888 00889 // If we need to allocate Larger Buffers, then do so - but allocate 00890 // An extra 50 % so that we don't do too many mallocs ! 00891 if (iBufSize > iCurBufSize) 00892 { 00893 if (bitmapBuffer) 00894 { 00895 HeapFree(GetProcessHeap(), 0, bitmapBuffer); 00896 } 00897 if (invertedBitmapBuffer) 00898 { 00899 HeapFree(GetProcessHeap(), 0, invertedBitmapBuffer); 00900 } 00901 00902 iCurBufSize = iBufSize * 2; 00903 bitmapBuffer = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iCurBufSize); 00904 invertedBitmapBuffer = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iCurBufSize); 00905 00906 if (bitmapBuffer == NULL || invertedBitmapBuffer == NULL) 00907 { 00908 bSuccessOrFail = FALSE; 00909 break; 00910 } 00911 } 00912 00913 // If we fail to get the Glyph data, delete the display lists 00914 // Created so far and return FALSE. 00915 if (bTrueType) 00916 { 00917 // Use TrueType support to get bitmap of glyph 00918 if (GetGlyphOutline(hDC, i, GGO_BITMAP, &gm, iBufSize, bitmapBuffer, &mat) == GDI_ERROR) 00919 { 00920 bSuccessOrFail = FALSE; 00921 break; 00922 } 00923 00924 // Setup glBitmap parameters for current font glyph 00925 w = gm.gmBlackBoxX; 00926 h = gm.gmBlackBoxY; 00927 ox = gm.gmptGlyphOrigin.x; 00928 oy = gm.gmptGlyphOrigin.y; 00929 ix = gm.gmCellIncX; 00930 iy = gm.gmCellIncY; 00931 } 00932 else 00933 { 00934 // Use generic GDI support to create bitmap of glyph 00935 ZeroMemory(bitmapBuffer, iBufSize); 00936 00937 if (i >= tm.tmFirstChar && i <= tm.tmLastChar) 00938 { 00939 // Only create bitmaps for actual font glyphs 00940 hBitmap = CreateBitmap(w, h, 1, 1, NULL); 00941 SelectObject(hDCMem, hBitmap); 00942 // Make bitmap of current font glyph 00943 SetRect(&rect, 0, 0, w, h); 00944 DrawText(hDCMem, (LPCTSTR)&i, 1, &rect, 00945 DT_LEFT | DT_BOTTOM | DT_SINGLELINE | DT_NOCLIP); 00946 // Make copy of bitmap in our local buffer 00947 ZeroMemory(&bmi, sizeof(bmi)); 00948 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 00949 bmi.bmiHeader.biWidth = w; 00950 bmi.bmiHeader.biHeight = -h; 00951 bmi.bmiHeader.biPlanes = 1; 00952 bmi.bmiHeader.biBitCount = 1; 00953 bmi.bmiHeader.biCompression = BI_RGB; 00954 GetDIBits(hDCMem, hBitmap, 0, h, bitmapBuffer, &bmi, 0); 00955 DeleteObject(hBitmap); 00956 } 00957 else 00958 { 00959 // Otherwise use empty display list for non-existing glyph 00960 iBufSize = 0; 00961 } 00962 00963 // Setup glBitmap parameters for current font glyph 00964 ox = 0; 00965 oy = tm.tmDescent; 00966 ix = w; 00967 iy = 0; 00968 } 00969 00970 // Create an OpenGL display list. 00971 glNewList((listBase + i), GL_COMPILE); 00972 00973 // Some fonts have no data for the space character, yet advertise 00974 // a non-zero size. 00975 if (0 == iBufSize) 00976 { 00977 glBitmap(0, 0, 0.0f, 0.0f, (GLfloat) ix, (GLfloat) iy, NULL); 00978 } 00979 else 00980 { 00981 // Invert the Glyph data. 00982 InvertGlyphBitmap(w, h, bitmapBuffer, invertedBitmapBuffer); 00983 00984 // Render an OpenGL bitmap and invert the origin. 00985 glBitmap(w, h, 00986 (GLfloat) ox, (GLfloat) (h-oy), 00987 (GLfloat) ix, (GLfloat) iy, 00988 (GLubyte *) invertedBitmapBuffer); 00989 } 00990 00991 // Close this display list. 00992 glEndList(); 00993 } 00994 00995 if (bSuccessOrFail == FALSE) 00996 { 00997 DBGPRINT("DGL_UseFontBitmaps: Get glyph failed\n"); 00998 glDeleteLists((i+listBase), (i-first)); 00999 } 01000 01001 // Release resources used 01002 DeleteObject(hFont); 01003 DeleteDC(hDCMem); 01004 01005 if (bitmapBuffer) 01006 HeapFree(GetProcessHeap(), 0, bitmapBuffer); 01007 01008 if (invertedBitmapBuffer) 01009 HeapFree(GetProcessHeap(), 0, invertedBitmapBuffer); 01010 01011 return(bSuccessOrFail); 01012 } 01013 01014 BOOL APIENTRY IntUseFontBitmapsA(HDC hDC, DWORD first, DWORD count, DWORD listBase) 01015 { 01016 /* Just call IntUseFontBitmapsW for now */ 01017 return IntUseFontBitmapsW(hDC, first, count, listBase); 01018 } 01019 01020 01021 01022 /***************************************************************************** 01023 * IntUseFontOutlines 01024 * 01025 * Converts a subrange of the glyphs in a TrueType font to OpenGL display 01026 * lists. 01027 *****************************************************************************/ 01028 01029 BOOL APIENTRY IntUseFontOutlinesW(HDC hDC, DWORD first, DWORD count, DWORD listBase, FLOAT chordalDeviation, 01030 FLOAT extrusion, INT format, GLYPHMETRICSFLOAT *glyphMetricsFloatArray) 01031 { 01032 DWORD glyphIndex; 01033 UCHAR* glyphBuf; 01034 DWORD glyphBufSize; 01035 01036 /* 01037 * Flush any previous OpenGL errors. This allows us to check for 01038 * new errors so they can be reported via the function return value. 01039 */ 01040 while (glGetError() != GL_NO_ERROR); 01041 01042 /* 01043 * Make sure that the current font can be sampled accurately. 01044 */ 01045 hNewFont = CreateHighResolutionFont(hDC); 01046 01047 if (!hNewFont) 01048 return FALSE; 01049 01050 hOldFont = SelectObject(hDC, hNewFont); 01051 if (!hOldFont) 01052 return FALSE; 01053 01054 /* 01055 * Preallocate a buffer for the outline data, and track its size: 01056 */ 01057 glyphBuf = (UCHAR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, glyphBufSize = 10240); 01058 01059 if (!glyphBuf) 01060 return FALSE; /*WGL_STATUS_NOT_ENOUGH_MEMORY*/ 01061 01062 /* 01063 * Process each glyph in the given range: 01064 */ 01065 for (glyphIndex = first; glyphIndex - first < count; ++glyphIndex) 01066 { 01067 GLYPHMETRICS glyphMetrics; 01068 DWORD glyphSize; 01069 static MAT2 matrix = 01070 { 01071 {0, 1}, {0, 0}, 01072 {0, 0}, {0, 1} 01073 }; 01074 LPGLYPHMETRICSFLOAT glyphMetricsFloat = &glyphMetricsFloatArray[glyphIndex - first]; 01075 01076 /* 01077 * Determine how much space is needed to store the glyph's 01078 * outlines. If our glyph buffer isn't large enough, 01079 * resize it. 01080 */ 01081 01082 glyphSize = GetGlyphOutline(hDC, glyphIndex, GGO_NATIVE, &glyphMetrics, 0, NULL, &matrix); 01083 01084 if (glyphSize == GDI_ERROR) 01085 return FALSE; /*WGL_STATUS_FAILURE*/ 01086 01087 if (glyphSize > glyphBufSize) 01088 { 01089 HeapFree(GetProcessHeap(), 0, glyphBuf); 01090 glyphBuf = (UCHAR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, glyphBufSize = glyphSize); 01091 if (!glyphBuf) 01092 return FALSE; /*WGL_STATUS_NOT_ENOUGH_MEMORY*/ 01093 } 01094 01095 01096 /* 01097 * Get the glyph's outlines. 01098 */ 01099 if (GetGlyphOutline(hDC, glyphIndex, GGO_NATIVE, &glyphMetrics, glyphBufSize, glyphBuf, &matrix) == GDI_ERROR) 01100 { 01101 HeapFree(GetProcessHeap(), 0, glyphBuf); 01102 return FALSE; /*WGL_STATUS_FAILURE*/ 01103 } 01104 01105 glyphMetricsFloat->gmfBlackBoxX = 01106 (FLOAT) glyphMetrics.gmBlackBoxX * ScaleFactor; 01107 glyphMetricsFloat->gmfBlackBoxY = 01108 (FLOAT) glyphMetrics.gmBlackBoxY * ScaleFactor; 01109 glyphMetricsFloat->gmfptGlyphOrigin.x = 01110 (FLOAT) glyphMetrics.gmptGlyphOrigin.x * ScaleFactor; 01111 glyphMetricsFloat->gmfptGlyphOrigin.y = 01112 (FLOAT) glyphMetrics.gmptGlyphOrigin.y * ScaleFactor; 01113 glyphMetricsFloat->gmfCellIncX = 01114 (FLOAT) glyphMetrics.gmCellIncX * ScaleFactor; 01115 glyphMetricsFloat->gmfCellIncY = 01116 (FLOAT) glyphMetrics.gmCellIncY * ScaleFactor; 01117 01118 /* 01119 * Turn the glyph into a display list: 01120 */ 01121 if (!MakeDisplayListFromGlyph((glyphIndex - first) + listBase, glyphBuf, glyphSize, glyphMetricsFloat, 01122 chordalDeviation + ScaleFactor, extrusion, format)) 01123 { 01124 HeapFree(GetProcessHeap(), 0, glyphBuf); 01125 return FALSE; /*WGL_STATUS_FAILURE*/ 01126 } 01127 } 01128 01129 /* 01130 * Clean up temporary storage and return. If an error occurred, 01131 * clear all OpenGL error flags and return FAILURE status; 01132 * otherwise just return SUCCESS. 01133 */ 01134 HeapFree(GetProcessHeap(), 0, glyphBuf); 01135 01136 DeleteObject(SelectObject(hDC, hOldFont)); 01137 01138 if (glGetError() == GL_NO_ERROR) 01139 { 01140 return TRUE; /*WGL_STATUS_SUCCESS*/ 01141 } 01142 else 01143 { 01144 while (glGetError() != GL_NO_ERROR); 01145 01146 return FALSE; /*WGL_STATUS_FAILURE*/ 01147 } 01148 } 01149 01150 BOOL APIENTRY IntUseFontOutlinesA(HDC hDC, DWORD first, DWORD count, DWORD listBase, FLOAT chordalDeviation, 01151 FLOAT extrusion, INT format, GLYPHMETRICSFLOAT *glyphMetricsFloatArray) 01152 { 01153 /* Just call IntUseFontOutlinesW for now */ 01154 return IntUseFontOutlinesW(hDC, first, count, listBase, chordalDeviation, extrusion, format, glyphMetricsFloatArray); 01155 } Generated on Thu May 24 2012 04:21:05 for ReactOS by
1.7.6.1
|