Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1717 lines
49 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include <math.h>
  4. #include <GL\glu.h>
  5. #include "batchinf.h"
  6. #include "glteb.h"
  7. #include "glapi.h"
  8. #include "glsbcltu.h"
  9. #include "fontoutl.h"
  10. static OFContext* CreateOFContext( HDC hdc,
  11. FLOAT chordalDeviation,
  12. FLOAT extrusion,
  13. int type,
  14. BOOL bUnicode );
  15. static BOOL ScaleFont( HDC hdc,
  16. OFContext* ofc,
  17. BOOL bUnicode );
  18. static void DestroyOFContext( HDC hdc,
  19. OFContext* ofc );
  20. static BOOL DrawGlyph( OFContext* ofc );
  21. static BOOL MakeDisplayListFromGlyph( OFContext* ofc,
  22. DWORD listName,
  23. LPGLYPHMETRICS glyphMetrics );
  24. static BOOL MakeLinesFromArc( OFContext* ofc,
  25. LOOP* pLoop,
  26. PRIM* pPrim,
  27. POINT2D p0,
  28. POINT2D p1,
  29. POINT2D p2,
  30. FLOAT chordalDeviationSquared);
  31. static LOOP_LIST* MakeLinesFromGlyph( OFContext* ofc );
  32. static BOOL MakeLinesFromTTLine( OFContext* ofc,
  33. LOOP* pLoop,
  34. PRIM* pPrim,
  35. UCHAR** pp,
  36. WORD pointCount );
  37. static BOOL MakeLinesFromTTPolycurve( OFContext* ofc,
  38. LOOP* pLoop,
  39. UCHAR** pp );
  40. static BOOL MakeLinesFromTTPolygon( OFContext* ofc,
  41. LOOP_LIST* pLoopList,
  42. UCHAR** pp );
  43. static BOOL MakeLinesFromTTQSpline( OFContext* ofc,
  44. LOOP* pLoop,
  45. PRIM* pPrim,
  46. UCHAR** pp,
  47. WORD pointCount );
  48. static void CALLBACK TessError( GLenum error,
  49. void *data);
  50. static void CALLBACK TessCombine( GLdouble coord[3],
  51. POINT2D* data[4],
  52. GLfloat w[4],
  53. POINT2D** dataOut,
  54. void *userData);
  55. static void FreeCombinePool( MEM_POOL *combinePool );
  56. static void ApplyVertexFilter( LOOP_LIST *pLoopList );
  57. static void CheckRedundantVertices( LOOP* pLoop );
  58. static BOOL PointsColinear( POINT2D *p1,
  59. POINT2D *p2,
  60. POINT2D *p3 );
  61. static FLOAT GetFixed( UCHAR** p );
  62. static LOOP_LIST* InitLoopBuf( void );
  63. static LOOP* NewLoop( LOOP_LIST *Loops,
  64. POINT2D *pFirstPoint );
  65. static void FreeLoopList( LOOP_LIST *pLoopList );
  66. static PRIM* NewPrim( LOOP *pLoop,
  67. DWORD primType );
  68. static void CalcVertPtrs( LOOP *pLoop );
  69. static BOOL AppendToVertBuf( LOOP* pLoop,
  70. PRIM* pPrim,
  71. POINT2D *p );
  72. // macros to access data from byte streams:
  73. // get WORD from byte stream, increment stream ptr by WORD
  74. #define GetWord( p ) \
  75. ( *( ((UNALIGNED WORD *) *p)++ ) )
  76. // get DWORD from byte stream, increment stream ptr by DWORD
  77. #define GetDWord( p ) \
  78. ( *( ((UNALIGNED DWORD *) *p)++ ) )
  79. // get signed word (SHORT) from byte stream, increment stream ptr by SHORT
  80. #define GetSignedWord( p ) \
  81. ( *( ((UNALIGNED SHORT *) *p)++ ) )
  82. #define POINT2DEQUAL( p1, p2 ) \
  83. ( (p1->x == p2->x) && (p1->y == p2->y) )
  84. /******************************Public*Routine******************************\
  85. * wglUseFontOutlinesA
  86. * wglUseFontOutlinesW
  87. *
  88. * Stubs that call wglUseFontOutlinesAW with the bUnicode flag set
  89. * appropriately.
  90. *
  91. \**************************************************************************/
  92. BOOL WINAPI
  93. wglUseFontOutlinesAW( HDC hDC,
  94. DWORD first,
  95. DWORD count,
  96. DWORD listBase,
  97. FLOAT chordalDeviation,
  98. FLOAT extrusion,
  99. int format,
  100. LPGLYPHMETRICSFLOAT lpgmf,
  101. BOOL bUnicode );
  102. BOOL WINAPI
  103. wglUseFontOutlinesA( HDC hDC,
  104. DWORD first,
  105. DWORD count,
  106. DWORD listBase,
  107. FLOAT chordalDeviation,
  108. FLOAT extrusion,
  109. int format,
  110. LPGLYPHMETRICSFLOAT lpgmf )
  111. {
  112. return wglUseFontOutlinesAW( hDC, first, count, listBase, chordalDeviation,
  113. extrusion, format, lpgmf, FALSE );
  114. }
  115. BOOL WINAPI
  116. wglUseFontOutlinesW( HDC hDC,
  117. DWORD first,
  118. DWORD count,
  119. DWORD listBase,
  120. FLOAT chordalDeviation,
  121. FLOAT extrusion,
  122. int format,
  123. LPGLYPHMETRICSFLOAT lpgmf )
  124. {
  125. return wglUseFontOutlinesAW( hDC, first, count, listBase, chordalDeviation,
  126. extrusion, format, lpgmf, TRUE );
  127. }
  128. /*****************************************************************************
  129. * wglUseFontOutlinesAW
  130. *
  131. * Converts a subrange of the glyphs in a TrueType font to OpenGL display
  132. * lists.
  133. *
  134. * History:
  135. * 15-Dec-1994 -by- Marc Fortier [marcfo]
  136. * Wrote it.
  137. *****************************************************************************/
  138. BOOL WINAPI
  139. wglUseFontOutlinesAW( HDC hDC,
  140. DWORD first,
  141. DWORD count,
  142. DWORD listBase,
  143. FLOAT chordalDeviation,
  144. FLOAT extrusion,
  145. int format,
  146. LPGLYPHMETRICSFLOAT lpgmf,
  147. BOOL bUnicode
  148. )
  149. {
  150. DWORD glyphIndex;
  151. DWORD listIndex = listBase;
  152. UCHAR* glyphBuf;
  153. DWORD glyphBufSize, error;
  154. OFContext* ofc;
  155. BOOL status=WFO_FAILURE;
  156. // Return error if there is no current RC.
  157. if (!GLTEB_CLTCURRENTRC())
  158. {
  159. WARNING("wglUseFontOutlines: no current RC\n");
  160. SetLastError(ERROR_INVALID_HANDLE);
  161. return status;
  162. }
  163. /*
  164. * Flush any previous OpenGL errors. This allows us to check for
  165. * new errors so they can be reported.
  166. */
  167. while (glGetError() != GL_NO_ERROR)
  168. ;
  169. /*
  170. * Preallocate a buffer for the outline data, and track its size:
  171. */
  172. // XXX: do we need to start with such a big size for this buffer ?
  173. glyphBuf = (UCHAR*) ALLOC(glyphBufSize = 10240);
  174. if (!glyphBuf) {
  175. WARNING("Alloc of glyphBuf failed\n");
  176. return status;
  177. }
  178. /*
  179. * Create font outline context
  180. */
  181. ofc = CreateOFContext( hDC, chordalDeviation, extrusion, format,
  182. bUnicode );
  183. if( !ofc ) {
  184. WARNING("CreateOFContext failed\n");
  185. goto exit;
  186. }
  187. /*
  188. * Process each glyph in the given range:
  189. */
  190. for (glyphIndex = first; glyphIndex - first < count; ++glyphIndex)
  191. {
  192. GLYPHMETRICS glyphMetrics;
  193. DWORD glyphSize;
  194. static MAT2 matrix =
  195. {
  196. {0, 1}, {0, 0},
  197. {0, 0}, {0, 1}
  198. };
  199. /*
  200. * Determine how much space is needed to store the glyph's
  201. * outlines. If our glyph buffer isn't large enough,
  202. * resize it.
  203. */
  204. if( bUnicode )
  205. glyphSize = GetGlyphOutlineW( hDC, glyphIndex, GGO_NATIVE,
  206. &glyphMetrics, 0, NULL, &matrix );
  207. else
  208. glyphSize = GetGlyphOutlineA( hDC, glyphIndex, GGO_NATIVE,
  209. &glyphMetrics, 0, NULL, &matrix );
  210. if( glyphSize == GDI_ERROR ) {
  211. WARNING("GetGlyphOutline() failed\n");
  212. goto exit;
  213. }
  214. if (glyphSize > glyphBufSize)
  215. {
  216. FREE(glyphBuf);
  217. glyphBuf = (UCHAR*) ALLOC(glyphBufSize = glyphSize);
  218. if (!glyphBuf) {
  219. WARNING("Alloc of glyphBuf failed\n");
  220. goto exit;
  221. }
  222. }
  223. /*
  224. * Get the glyph's outlines.
  225. */
  226. if( bUnicode )
  227. error = GetGlyphOutlineW( hDC, glyphIndex, GGO_NATIVE,
  228. &glyphMetrics, glyphBufSize, glyphBuf, &matrix );
  229. else
  230. error = GetGlyphOutlineA( hDC, glyphIndex, GGO_NATIVE,
  231. &glyphMetrics, glyphBufSize, glyphBuf, &matrix );
  232. if( error == GDI_ERROR ) {
  233. WARNING("GetGlyphOutline() failed\n");
  234. goto exit;
  235. }
  236. /*
  237. * Turn the glyph into a display list:
  238. */
  239. ofc->glyphBuf = glyphBuf;
  240. ofc->glyphSize = glyphSize;
  241. if (!MakeDisplayListFromGlyph( ofc,
  242. listIndex,
  243. &glyphMetrics)) {
  244. WARNING("MakeDisplayListFromGlyph() failed\n");
  245. listIndex++; // so it will be deleted
  246. goto exit;
  247. }
  248. /*
  249. * Supply scaled glyphMetrics if requested
  250. */
  251. if( lpgmf ) {
  252. lpgmf->gmfBlackBoxX =
  253. ofc->scale * (FLOAT) glyphMetrics.gmBlackBoxX;
  254. lpgmf->gmfBlackBoxY =
  255. ofc->scale * (FLOAT) glyphMetrics.gmBlackBoxY;
  256. lpgmf->gmfptGlyphOrigin.x =
  257. ofc->scale * (FLOAT) glyphMetrics.gmptGlyphOrigin.x;
  258. lpgmf->gmfptGlyphOrigin.y =
  259. ofc->scale * (FLOAT) glyphMetrics.gmptGlyphOrigin.y;
  260. lpgmf->gmfCellIncX =
  261. ofc->scale * (FLOAT) glyphMetrics.gmCellIncX;
  262. lpgmf->gmfCellIncY =
  263. ofc->scale * (FLOAT) glyphMetrics.gmCellIncY;
  264. lpgmf++;
  265. }
  266. listIndex++;
  267. }
  268. // Set status to SUCCESS if we get this far
  269. status = WFO_SUCCESS;
  270. /*
  271. * Clean up temporary storage and return. If an error occurred,
  272. * set error flags and return FAILURE status;
  273. * otherwise just return SUCCESS.
  274. */
  275. exit:
  276. if( glyphBuf )
  277. FREE(glyphBuf);
  278. if( ofc )
  279. DestroyOFContext( hDC, ofc);
  280. if( !status )
  281. {
  282. // assume memory error
  283. WARNING("wglUseFontOutlines: not enough memory\n");
  284. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  285. // free up display lists
  286. glDeleteLists( listBase, listIndex-listBase );
  287. }
  288. return status;
  289. }
  290. /*****************************************************************************
  291. * MakeDisplayListFromGlyph
  292. *
  293. * Converts the outline of a glyph to an OpenGL display list.
  294. *
  295. * Return value is nonzero for success, zero for failure.
  296. *
  297. * Does not check for OpenGL errors, so if the caller needs to know about them,
  298. * it should call glGetError().
  299. *****************************************************************************/
  300. static BOOL
  301. MakeDisplayListFromGlyph( IN OFContext* ofc,
  302. IN DWORD listName,
  303. IN LPGLYPHMETRICS glyphMetrics )
  304. {
  305. BOOL status;
  306. glNewList(listName, GL_COMPILE);
  307. /*
  308. * Set normal and orientation for front face of glyph
  309. */
  310. glNormal3f( 0.0f, 0.0f, 1.0f );
  311. glFrontFace( GL_CCW );
  312. status = DrawGlyph( ofc );
  313. /*
  314. * Translate by gmCellIncX, gmCellIncY
  315. */
  316. glTranslatef( ofc->scale * (FLOAT) glyphMetrics->gmCellIncX,
  317. ofc->scale * (FLOAT) glyphMetrics->gmCellIncY,
  318. 0.0f );
  319. glEndList();
  320. // Check for GL errors occuring during processing of the glyph
  321. while( glGetError() != GL_NO_ERROR )
  322. status = WFO_FAILURE;
  323. return status;
  324. }
  325. /*****************************************************************************
  326. * DrawGlyph
  327. *
  328. * Converts the outline of a glyph to OpenGL drawing primitives, tessellating
  329. * as needed, and then draws the glyph. Tessellation of the quadratic splines
  330. * in the outline is controlled by "chordalDeviation", and the drawing
  331. * primitives (lines or polygons) are selected by "format".
  332. *
  333. * Return value is nonzero for success, zero for failure.
  334. *
  335. * Does not check for OpenGL errors, so if the caller needs to know about them,
  336. * it should call glGetError().
  337. * History:
  338. * 26-Sep-1995 -by- Marc Fortier [marcfo]
  339. * Use extrusioniser to draw polygonal faces with extrusion=0
  340. *****************************************************************************/
  341. static BOOL
  342. DrawGlyph( IN OFContext *ofc )
  343. {
  344. BOOL status = WFO_FAILURE;
  345. DWORD nLoops;
  346. DWORD point;
  347. DWORD nVerts;
  348. LOOP_LIST *pLoopList;
  349. LOOP *pLoop;
  350. POINT2D *p;
  351. MEM_POOL *mp = NULL;
  352. /*
  353. * Convert the glyph outlines to a set of polyline loops.
  354. * (See MakeLinesFromGlyph() for the format of the loop data
  355. * structure.)
  356. */
  357. if( !(pLoopList = MakeLinesFromGlyph(ofc)) )
  358. goto exit;
  359. /*
  360. * Filter out unnecessary vertices
  361. */
  362. ApplyVertexFilter( pLoopList );
  363. /*
  364. * Now draw the loops in the appropriate format:
  365. */
  366. if( ofc->format == WGL_FONT_LINES )
  367. {
  368. /*
  369. * This is the easy case. Just draw the outlines.
  370. */
  371. nLoops = pLoopList->nLoops;
  372. pLoop = pLoopList->LoopBuf;
  373. #ifndef FONT_DEBUG
  374. for( ; nLoops; nLoops--, pLoop++ )
  375. {
  376. glBegin(GL_LINE_LOOP);
  377. nVerts = pLoop->nVerts;
  378. p = pLoop->VertBuf;
  379. for( ; nVerts; nVerts--, p++ ) {
  380. glVertex2fv( (FLOAT*) p );
  381. }
  382. glEnd();
  383. }
  384. #else
  385. // color code the primitives
  386. for( ; nLoops; nLoops--, pLoop++ )
  387. {
  388. DrawColorCodedLineLoop( pLoop, 0.0f );
  389. }
  390. #endif
  391. if( ofc->ec )
  392. extr_DrawLines( ofc->ec, pLoopList );
  393. status = WFO_SUCCESS;
  394. }
  395. else if (ofc->format == WGL_FONT_POLYGONS)
  396. {
  397. GLdouble v[3];
  398. /*
  399. * This is the hard case. We have to set up a tessellator
  400. * to convert the outlines into a set of polygonal
  401. * primitives, which the tessellator passes to some
  402. * auxiliary routines for drawing.
  403. */
  404. /* Initialize polygon extrusion for the glyph.
  405. * This prepares for tracking of the tesselation in order to
  406. * build the Back-facing polygons.
  407. */
  408. mp = &ofc->combinePool;
  409. ofc->curCombinePool = mp;
  410. mp->index = 0;
  411. mp->next = NULL;
  412. if( ofc->ec ) {
  413. if( !extr_PolyInit( ofc->ec ) )
  414. goto exit;
  415. }
  416. ofc->TessErrorOccurred = 0;
  417. v[2] = 0.0;
  418. gluTessBeginPolygon( ofc->tess, ofc );
  419. /*
  420. * Each loop returned from MakeLinesFromGlyph is closed (first and
  421. * last points are the same). The old tesselator had trouble with
  422. * this. Since the tesselator automatically closes all loops,
  423. * we skip the last point to be on the safe side.
  424. */
  425. nLoops = pLoopList->nLoops;
  426. pLoop = pLoopList->LoopBuf;
  427. for( ; nLoops; nLoops--, pLoop++ )
  428. {
  429. gluTessBeginContour( ofc->tess );
  430. nVerts = pLoop->nVerts - 1; // skip last point
  431. p = pLoop->VertBuf;
  432. for( ; nVerts; nVerts--, p++ )
  433. {
  434. v[0] = p->x;
  435. v[1] = p->y;
  436. gluTessVertex(ofc->tess, v, p);
  437. }
  438. gluTessEndContour( ofc->tess );
  439. }
  440. gluTessEndPolygon( ofc->tess );
  441. if (ofc->TessErrorOccurred)
  442. goto exit;
  443. if( ofc->ec ) {
  444. /* check for OUT_OF_MEMORY_ERROR in extrusion lib, that might
  445. * have occured during tesselation tracking.
  446. */
  447. if( ofc->ec->TessErrorOccurred )
  448. goto exit;
  449. #ifdef VARRAY
  450. if( ofc->ec->zExtrusion == 0.0f )
  451. DrawFacePolygons( ofc->ec, 0.0f );
  452. else if( !extr_DrawPolygons( ofc->ec, pLoopList ) )
  453. goto exit;
  454. #else
  455. if( !extr_DrawPolygons( ofc->ec, pLoopList ) )
  456. goto exit;
  457. #endif
  458. }
  459. status = WFO_SUCCESS;
  460. }
  461. exit:
  462. /*
  463. * Putting PolyFinish here means PolyInit may not have been called.
  464. * This is ok.
  465. */
  466. if( mp )
  467. FreeCombinePool( mp );
  468. if( pLoopList )
  469. FreeLoopList( pLoopList );
  470. if( ofc->ec )
  471. extr_PolyFinish( ofc->ec );
  472. return status;
  473. }
  474. /*****************************************************************************
  475. * TessCombine
  476. *
  477. * Tesselation callback for loop intersection. We have to allocate a vertex
  478. * and return it to tesselator. Allocation is from the context's static pool.
  479. * If this runs dry, then a linked list of MEM_POOL blocks is used.
  480. *****************************************************************************/
  481. static void CALLBACK
  482. TessCombine( GLdouble coord[3], POINT2D *data[4], GLfloat w[4],
  483. POINT2D **dataOut, void *userData )
  484. {
  485. OFContext *ofc = (OFContext *) userData;
  486. MEM_POOL *mp = ofc->curCombinePool;
  487. POINT2D *p;
  488. // make sure there's room available in the current pool block
  489. if( mp->index >= POOL_SIZE )
  490. {
  491. // we need to allocate another MEM_POOL block
  492. MEM_POOL *newPool;
  493. newPool = (MEM_POOL *) ALLOC( sizeof(MEM_POOL) );
  494. if( !newPool )
  495. // tesselator will handle any problem with this
  496. return;
  497. newPool->index = 0;
  498. newPool->next = NULL;
  499. mp->next = newPool;
  500. mp = newPool;
  501. ofc->curCombinePool = mp; // new pool becomes the current pool
  502. }
  503. p = mp->pool + mp->index;
  504. p->x = (GLfloat) coord[0];
  505. p->y = (GLfloat) coord[1];
  506. mp->index ++;
  507. *dataOut = p;
  508. }
  509. /*****************************************************************************
  510. * FreeCombinePool
  511. *
  512. * Frees any pools of memory allocated by TessCombine callback
  513. *****************************************************************************/
  514. static void
  515. FreeCombinePool( MEM_POOL *memPool )
  516. {
  517. MEM_POOL *nextPool;
  518. memPool = memPool->next; // first pool in list is static part of context
  519. while( memPool ) {
  520. nextPool = memPool->next;
  521. FREE( memPool );
  522. memPool = nextPool;
  523. }
  524. }
  525. /*****************************************************************************
  526. * TessError
  527. *
  528. * Saves the last tessellator error code in ofc->TessErrorOccurred.
  529. *****************************************************************************/
  530. static void CALLBACK
  531. TessError(GLenum error, void *data)
  532. {
  533. OFContext *ofc = (OFContext *) data;
  534. // Only some of these errors are fatal:
  535. switch( error ) {
  536. case GLU_TESS_COORD_TOO_LARGE:
  537. case GLU_TESS_NEED_COMBINE_CALLBACK:
  538. ofc->TessErrorOccurred = error;
  539. break;
  540. default:
  541. break;
  542. }
  543. }
  544. /*****************************************************************************
  545. * MakeLinesFromGlyph
  546. *
  547. * Converts the outline of a glyph from the TTPOLYGON format into
  548. * structures of Loops, Primitives and Vertices.
  549. *
  550. * Line segments from the TTPOLYGON are transferred to the output array in
  551. * the obvious way. Quadratic splines in the TTPOLYGON are converted to
  552. * collections of line segments
  553. *****************************************************************************/
  554. static LOOP_LIST*
  555. MakeLinesFromGlyph( IN OFContext* ofc )
  556. {
  557. UCHAR* p;
  558. BOOL status = WFO_FAILURE;
  559. LOOP_LIST *pLoopList;
  560. /*
  561. * Initialize the buffer into which we place the loop data:
  562. */
  563. if( !(pLoopList = InitLoopBuf()) )
  564. return NULL;
  565. p = ofc->glyphBuf;
  566. while (p < ofc->glyphBuf + ofc->glyphSize)
  567. {
  568. if( !MakeLinesFromTTPolygon( ofc, pLoopList, &p) )
  569. goto exit;
  570. }
  571. status = WFO_SUCCESS;
  572. exit:
  573. if (!status) {
  574. FreeLoopList( pLoopList );
  575. pLoopList = (LOOP_LIST *) NULL;
  576. }
  577. return pLoopList;
  578. }
  579. /*****************************************************************************
  580. * MakeLinesFromTTPolygon
  581. *
  582. * Converts a TTPOLYGONHEADER and its associated curve structures into a
  583. * LOOP structure.
  584. *****************************************************************************/
  585. static BOOL
  586. MakeLinesFromTTPolygon( IN OFContext* ofc,
  587. IN LOOP_LIST* pLoopList,
  588. IN OUT UCHAR** pp)
  589. {
  590. DWORD polySize;
  591. UCHAR* polyStart;
  592. POINT2D *pFirstP, *pLastP, firstPoint;
  593. LOOP *pLoop;
  594. PRIM *pPrim;
  595. /*
  596. * Record where the polygon data begins.
  597. */
  598. polyStart = *pp;
  599. /*
  600. * Extract relevant data from the TTPOLYGONHEADER:
  601. */
  602. polySize = GetDWord(pp);
  603. if( GetDWord(pp) != TT_POLYGON_TYPE ) /* polygon type */
  604. return WFO_FAILURE;
  605. firstPoint.x = ofc->scale * GetFixed(pp); // 1st X coord
  606. firstPoint.y = ofc->scale * GetFixed(pp); // 1st Y coord
  607. /*
  608. * Initialize a new LOOP struct in the LoopBuf, with the first point
  609. */
  610. if( !(pLoop = NewLoop( pLoopList, &firstPoint )) )
  611. return WFO_FAILURE;
  612. /*
  613. * Process each of the TTPOLYCURVE structures in the polygon:
  614. */
  615. while (*pp < polyStart + polySize) {
  616. if( !MakeLinesFromTTPolycurve( ofc, pLoop, pp ) )
  617. return WFO_FAILURE;
  618. }
  619. /* Now have to fix up end of loop : after studying the chars, it
  620. * was determined that if a curve started with a line, and ended with
  621. * a qspline, AND the first and last point were not the same, then there
  622. * is an implied line joining the two.
  623. * In any case, we also make sure here that first and last points are
  624. * coincident.
  625. */
  626. pLastP = (POINT2D *) (pLoop->VertBuf+pLoop->nVerts-1);
  627. pFirstP = &firstPoint;
  628. if( !POINT2DEQUAL( pLastP, pFirstP ) ) {
  629. // add 1-vertex line prim at the end
  630. if( !(pPrim = NewPrim( pLoop, TT_PRIM_LINE)) )
  631. return WFO_FAILURE;
  632. if ( !AppendToVertBuf( pLoop, pPrim, pFirstP) )
  633. return WFO_FAILURE;
  634. }
  635. /* At end of each loop, calculate pVert for each PRIM from its
  636. * VertIndex value (for convenience later).
  637. */
  638. CalcVertPtrs( pLoop );
  639. return WFO_SUCCESS;
  640. }
  641. /*****************************************************************************
  642. * MakeLinesFromTTPolyCurve
  643. *
  644. * Converts the lines and splines in a single TTPOLYCURVE structure to points
  645. * in the Loop.
  646. *****************************************************************************/
  647. static BOOL
  648. MakeLinesFromTTPolycurve( IN OFContext* ofc,
  649. IN LOOP* pLoop,
  650. IN OUT UCHAR** pp )
  651. {
  652. WORD type;
  653. WORD pointCount;
  654. PRIM *pPrim;
  655. /*
  656. * Pick up the relevant fields of the TTPOLYCURVE structure:
  657. */
  658. type = GetWord(pp);
  659. pointCount = GetWord(pp);
  660. if( !(pPrim = NewPrim( pLoop, type )) )
  661. return WFO_FAILURE;
  662. /*
  663. * Convert the "curve" to line segments:
  664. */
  665. if (type == TT_PRIM_LINE) {
  666. return MakeLinesFromTTLine( ofc, pLoop, pPrim, pp, pointCount);
  667. } else if (type == TT_PRIM_QSPLINE) {
  668. return MakeLinesFromTTQSpline( ofc, pLoop, pPrim, pp, pointCount );
  669. } else
  670. return WFO_FAILURE;
  671. }
  672. /*****************************************************************************
  673. * MakeLinesFromTTLine
  674. *
  675. * Converts points from the polyline in a TT_PRIM_LINE structure to
  676. * equivalent points in the Loop.
  677. *****************************************************************************/
  678. static BOOL
  679. MakeLinesFromTTLine( IN OFContext* ofc,
  680. IN LOOP* pLoop,
  681. IN PRIM* pPrim,
  682. IN OUT UCHAR** pp,
  683. IN WORD pointCount)
  684. {
  685. POINT2D p;
  686. /*
  687. * Just copy the line segments into the vertex buffer (converting
  688. * type as we go):
  689. */
  690. while (pointCount--)
  691. {
  692. p.x = ofc->scale * GetFixed(pp); // X coord
  693. p.y = ofc->scale * GetFixed(pp); // Y coord
  694. if( !AppendToVertBuf( pLoop, pPrim, &p ) )
  695. return WFO_FAILURE;
  696. }
  697. return WFO_SUCCESS;
  698. }
  699. /*****************************************************************************
  700. * MakeLinesFromTTQSpline
  701. *
  702. * Converts points from the poly quadratic spline in a TT_PRIM_QSPLINE
  703. * structure to polyline points in the Loop.
  704. *****************************************************************************/
  705. static BOOL
  706. MakeLinesFromTTQSpline( IN OFContext* ofc,
  707. IN LOOP* pLoop,
  708. IN PRIM* pPrim,
  709. IN OUT UCHAR** pp,
  710. IN WORD pointCount )
  711. {
  712. POINT2D p0, p1, p2;
  713. WORD point;
  714. POINT2D p, *pLastP;
  715. /*
  716. * Process each of the non-interpolated points in the outline.
  717. * To do this, we need to generate two interpolated points (the
  718. * start and end of the arc) for each non-interpolated point.
  719. * The first interpolated point is always the one most recently
  720. * stored in VertBuf, so we just extract it from there. The
  721. * second interpolated point is either the average of the next
  722. * two points in the QSpline, or the last point in the QSpline
  723. * if only one remains.
  724. */
  725. // Start with last generated point in VertBuf
  726. p0 = *(pLoop->VertBuf + pLoop->nVerts - 1);
  727. // pointCount should be >=2, but in case it's not...
  728. p1 = p2 = p0;
  729. for (point = 0; point < pointCount - 1; ++point)
  730. {
  731. p1.x = ofc->scale * GetFixed(pp);
  732. p1.y = ofc->scale * GetFixed(pp);
  733. if (point == pointCount - 2)
  734. {
  735. /*
  736. * This is the last arc in the QSpline. The final
  737. * point is the end of the arc.
  738. */
  739. p2.x = ofc->scale * GetFixed(pp);
  740. p2.y = ofc->scale * GetFixed(pp);
  741. }
  742. else
  743. {
  744. /*
  745. * Peek at the next point in the input to compute
  746. * the end of the arc:
  747. */
  748. p.x = ofc->scale * GetFixed(pp);
  749. p.y = ofc->scale * GetFixed(pp);
  750. p2.x = 0.5f * (p1.x + p.x);
  751. p2.y = 0.5f * (p1.y + p.y);
  752. /*
  753. * Push the point back onto the input so it will
  754. * be reused as the next off-curve point:
  755. */
  756. *pp -= 2*sizeof(FIXED); // x and y
  757. }
  758. if( !MakeLinesFromArc( ofc,
  759. pLoop,
  760. pPrim,
  761. p0,
  762. p1,
  763. p2,
  764. ofc->chordalDeviation * ofc->chordalDeviation))
  765. return WFO_FAILURE;
  766. // p0 is now the last interpolated point (p2)
  767. p0 = p2;
  768. }
  769. // put in last point in arc
  770. if( !AppendToVertBuf( pLoop, pPrim, &p2 ) )
  771. return WFO_FAILURE;
  772. return WFO_SUCCESS;
  773. }
  774. /*****************************************************************************
  775. * MakeLinesFromArc
  776. *
  777. * Subdivides one arc of a quadratic spline until the chordal deviation
  778. * tolerance requirement is met, then places the resulting set of line
  779. * segments in the Loop.
  780. *****************************************************************************/
  781. static BOOL
  782. MakeLinesFromArc( IN OFContext *ofc,
  783. IN LOOP* pLoop,
  784. IN PRIM* pPrim,
  785. IN POINT2D p0,
  786. IN POINT2D p1,
  787. IN POINT2D p2,
  788. IN FLOAT chordalDeviationSquared)
  789. {
  790. POINT2D p01;
  791. POINT2D p12;
  792. POINT2D midPoint;
  793. FLOAT deltaX;
  794. FLOAT deltaY;
  795. /*
  796. * Calculate midpoint of the curve by de Casteljau:
  797. */
  798. p01.x = 0.5f * (p0.x + p1.x);
  799. p01.y = 0.5f * (p0.y + p1.y);
  800. p12.x = 0.5f * (p1.x + p2.x);
  801. p12.y = 0.5f * (p1.y + p2.y);
  802. midPoint.x = 0.5f * (p01.x + p12.x);
  803. midPoint.y = 0.5f * (p01.y + p12.y);
  804. /*
  805. * Estimate chordal deviation by the distance from the midpoint
  806. * of the curve to its non-interpolated control point. If this
  807. * distance is greater than the specified chordal deviation
  808. * constraint, then subdivide. Otherwise, generate polylines
  809. * from the three control points.
  810. */
  811. deltaX = midPoint.x - p1.x;
  812. deltaY = midPoint.y - p1.y;
  813. if (deltaX * deltaX + deltaY * deltaY > chordalDeviationSquared)
  814. {
  815. if( !MakeLinesFromArc( ofc, pLoop, pPrim,
  816. p0,
  817. p01,
  818. midPoint,
  819. chordalDeviationSquared) )
  820. return WFO_FAILURE;
  821. if( !MakeLinesFromArc( ofc, pLoop, pPrim,
  822. midPoint,
  823. p12,
  824. p2,
  825. chordalDeviationSquared) )
  826. return WFO_FAILURE;
  827. }
  828. else
  829. {
  830. /*
  831. * The "pen" is already at (x0, y0), so we don't need to
  832. * add that point to the LineBuf.
  833. */
  834. if( !AppendToVertBuf( pLoop, pPrim, &p1 ) )
  835. return WFO_FAILURE;
  836. }
  837. return WFO_SUCCESS;
  838. }
  839. /*****************************************************************************
  840. * ApplyVertexFilter
  841. *
  842. * Filter the vertex buffer to get rid of redundant vertices.
  843. * These can occur on Primitive boundaries.
  844. *****************************************************************************/
  845. static void ApplyVertexFilter( LOOP_LIST *pLoopList )
  846. {
  847. DWORD nLoops;
  848. LOOP *pLoop;
  849. nLoops = pLoopList->nLoops;
  850. pLoop = pLoopList->LoopBuf;
  851. for( ; nLoops; nLoops--, pLoop++ ) {
  852. CheckRedundantVertices( pLoop );
  853. }
  854. }
  855. /*****************************************************************************
  856. * CheckRedundantVertices
  857. *
  858. * Check for redundant vertices on Curve-Curve boundaries (including loop
  859. * closure), and get rid of them, using in-place algorithm.
  860. *****************************************************************************/
  861. static void CheckRedundantVertices( LOOP *pLoop )
  862. {
  863. PRIM *pPrim, *pNextPrim;
  864. DWORD primType, nextPrimType, nVerts;
  865. BOOL bEliminate, bLastEliminate;
  866. DWORD nEliminated=0, nPrims;
  867. POINT2D *pVert, *pVert2ndToLast;
  868. nPrims = pLoop->nPrims;
  869. if( nPrims < 2 )
  870. return;
  871. pPrim = pLoop->PrimBuf;
  872. pNextPrim = pPrim + 1;
  873. nPrims--; // the last prim is dealt with afterwards
  874. for( ; nPrims; nPrims--, pPrim = pNextPrim++ ) {
  875. bEliminate = FALSE;
  876. nVerts = pPrim->nVerts;
  877. // check spline<->* boundaries
  878. if( (pPrim->nVerts >= 2) &&
  879. ((pPrim->primType == PRIM_CURVE ) ||
  880. (pNextPrim->primType == PRIM_CURVE )) ) {
  881. /* get ptr to 2nd-to-last vertex in current prim
  882. * !! Note that last vertex in current prim and first vertex in
  883. * next prim are the same.
  884. */
  885. pVert2ndToLast = pPrim->pVert + pPrim->nVerts - 2;
  886. if( PointsColinear( pVert2ndToLast,
  887. pVert2ndToLast+1,
  888. pNextPrim->pVert+1 ) ) {
  889. // we eliminate last vertex in current prim
  890. bEliminate = TRUE;
  891. pPrim->nVerts--;
  892. nVerts--;
  893. }
  894. }
  895. /* move vertices up in vertBuf if necessary (if any vertices
  896. * were PREVIOUSLY eliminated)
  897. */
  898. if( nEliminated ) {
  899. pVert = pPrim->pVert - nEliminated; // new pVert
  900. memcpy( pVert+1, pPrim->pVert+1, (nVerts-1)*sizeof(POINT2D));
  901. pPrim->pVert = pVert;
  902. }
  903. if( bEliminate ) {
  904. nEliminated += 1;
  905. }
  906. }
  907. /* also check for redundancy at closure:
  908. * - replace firstPrim's first vertex with 2nd-to-last of last prim
  909. * - eliminate last vertex in last prim
  910. */
  911. bLastEliminate = bEliminate;
  912. bEliminate = FALSE;
  913. nVerts = pPrim->nVerts;
  914. pNextPrim = pLoop->PrimBuf; // first prim in loop
  915. if( (pPrim->nVerts >= 2) &&
  916. ((pPrim->primType == PRIM_CURVE ) ||
  917. (pNextPrim->primType == PRIM_CURVE )) ) {
  918. POINT2D *pVertLast;
  919. pVert2ndToLast = pPrim->pVert + pPrim->nVerts - 2; // always >=2 verts
  920. pVertLast = pVert2ndToLast + 1;
  921. if( (pPrim->nVerts == 2) && bLastEliminate )
  922. /* 2ndToLast vert (same as first vert) of this prim has
  923. * been eliminated. Deal with it by backing up the ptr.
  924. * This didn't matter in above loop, because there wasn't the
  925. * possibility of munging the first vertex in the loop
  926. */
  927. pVert2ndToLast--;
  928. // point to 2nd-to-last vertex in prim
  929. if( PointsColinear( pVert2ndToLast,
  930. pVertLast,
  931. pNextPrim->pVert+1 ) ) {
  932. bEliminate = TRUE;
  933. pPrim->nVerts--;
  934. // munge first prim's first vertex
  935. /* problem here if have 2 eliminations in a row, and pPrim was
  936. * a 2 vertex prim - then pVert2ndToLast is pointing to an
  937. * eliminated vertex
  938. */
  939. *(pNextPrim->pVert) = *(pVert2ndToLast);
  940. nVerts--;
  941. }
  942. }
  943. // move up last prim's vertices if necessary
  944. if( nEliminated ) {
  945. pVert = pPrim->pVert - nEliminated; // new pVert
  946. memcpy( pVert+1, pPrim->pVert+1, (nVerts-1)*sizeof(POINT2D) );
  947. // This misses copying one vertex
  948. pPrim->pVert = pVert;
  949. }
  950. if( bEliminate ) {
  951. nEliminated += 1;
  952. }
  953. // now update vertex count in Loop
  954. pLoop->nVerts -= nEliminated;
  955. // Check for prims with nVerts=1 (invalidated), and remove them
  956. nPrims = pLoop->nPrims;
  957. pPrim = pLoop->PrimBuf;
  958. nEliminated = 0;
  959. for( ; nPrims; nPrims--, pPrim++ ) {
  960. if( pPrim->nVerts == 1 ) {
  961. nEliminated++;
  962. continue;
  963. }
  964. *(pPrim-nEliminated) = *pPrim;
  965. }
  966. pLoop->nPrims -= nEliminated;
  967. }
  968. /*****************************************************************************
  969. * PointsColinear
  970. *
  971. * Returns TRUE if the 3 points are colinear enough.
  972. *****************************************************************************/
  973. static BOOL PointsColinear( POINT2D *p1,
  974. POINT2D *p2,
  975. POINT2D *p3 )
  976. {
  977. POINT2D v1, v2;
  978. // compare slopes of the 2 vectors? - optimize later
  979. if( POINT2DEQUAL( p1, p2 ) || POINT2DEQUAL( p2, p3 ) )
  980. // avoid sending 0 vector to CalcAngle (generates FPE)
  981. return TRUE;
  982. v1.x = p2->x - p1->x;
  983. v1.y = p2->y - p1->y;
  984. v2.x = p3->x - p2->x;
  985. v2.y = p3->y - p2->y;
  986. if( fabs(CalcAngle( &v1, &v2 )) < CoplanarThresholdAngle )
  987. return TRUE;
  988. return FALSE;
  989. }
  990. /*****************************************************************************
  991. * CreateOFContext
  992. *
  993. * Create and initialize the outline font context.
  994. *
  995. * History:
  996. * 26-Sep-1995 -by- Marc Fortier [marcfo]
  997. * Use extrusioniser to draw polygonal faces with extrusion=0
  998. *****************************************************************************/
  999. static OFContext* CreateOFContext( HDC hdc,
  1000. FLOAT chordalDeviation,
  1001. FLOAT extrusion,
  1002. INT format,
  1003. BOOL bUnicode )
  1004. {
  1005. OFContext *ofc = (OFContext *) NULL;
  1006. BOOL status = WFO_FAILURE;
  1007. // validate parameters
  1008. if( (format != WGL_FONT_LINES) && (format != WGL_FONT_POLYGONS) ) {
  1009. WARNING("wglUseFontOutlines: invalid format parameter\n");
  1010. SetLastError(ERROR_INVALID_PARAMETER);
  1011. return NULL;
  1012. }
  1013. if( chordalDeviation < 0.0f ) {
  1014. WARNING("wglUseFontOutlines: invalid deviation parameter\n");
  1015. SetLastError(ERROR_INVALID_PARAMETER);
  1016. return NULL;
  1017. }
  1018. if( extrusion < 0.0f ) {
  1019. WARNING("wglUseFontOutlines: invalid extrusion parameter\n");
  1020. SetLastError(ERROR_INVALID_PARAMETER);
  1021. return NULL;
  1022. }
  1023. ofc = (OFContext *) ALLOCZ( sizeof(OFContext) );
  1024. if( !ofc )
  1025. return NULL;
  1026. ofc->format = format;
  1027. ofc->chordalDeviation = chordalDeviation;
  1028. if( !ScaleFont( hdc, ofc, bUnicode ) )
  1029. goto exit;
  1030. // handle extrusion
  1031. #ifdef VARRAY
  1032. if( !((format == WGL_FONT_LINES) && (extrusion == 0.0f)) ) {
  1033. #else
  1034. if( extrusion != 0.0f ) {
  1035. #endif
  1036. ofc->ec = extr_Init( extrusion, format );
  1037. if( !ofc->ec ) {
  1038. goto exit;
  1039. }
  1040. } else {
  1041. ofc->ec = (EXTRContext *) NULL;
  1042. }
  1043. // init a tess obj
  1044. ofc->tess = NULL;
  1045. if( ofc->format == WGL_FONT_POLYGONS ) {
  1046. GLUtesselator *tess;
  1047. if (!(tess = gluNewTess()))
  1048. goto exit;
  1049. if( ofc->ec ) {
  1050. gluTessCallback(tess, GLU_TESS_BEGIN_DATA,
  1051. (void(CALLBACK*)()) extr_glBegin);
  1052. gluTessCallback(tess, GLU_TESS_END,
  1053. (void(CALLBACK*)()) extr_glEnd);
  1054. gluTessCallback(tess, GLU_TESS_VERTEX_DATA,
  1055. (void(CALLBACK*)()) extr_glVertex);
  1056. } else {
  1057. gluTessCallback(tess, GLU_BEGIN, (void(CALLBACK*)()) glBegin);
  1058. gluTessCallback(tess, GLU_END, (void(CALLBACK*)()) glEnd);
  1059. gluTessCallback(tess, GLU_VERTEX, (void(CALLBACK*)()) glVertex2fv);
  1060. }
  1061. gluTessCallback(tess, GLU_TESS_ERROR_DATA,
  1062. (void(CALLBACK*)()) TessError);
  1063. gluTessCallback(tess, GLU_TESS_COMBINE_DATA,
  1064. (void(CALLBACK*)()) TessCombine);
  1065. // set tesselator normal and winding rule
  1066. gluTessNormal( tess, 0.0, 0.0, 1.0 );
  1067. gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
  1068. ofc->tess = tess;
  1069. }
  1070. status = WFO_SUCCESS;
  1071. exit:
  1072. if( !status ) {
  1073. DestroyOFContext( hdc, ofc );
  1074. return NULL;
  1075. }
  1076. return ofc;
  1077. }
  1078. /*****************************************************************************
  1079. * ScaleFont
  1080. *
  1081. * To get the best representation of the font, we use its design height, or
  1082. * the emSquare size. We then scale emSquare to 1.0.
  1083. * A maxChordTolerance value is set, otherwise it was found that some
  1084. * glyphs displayed ugly loop intersections. The value .035f was chosen
  1085. * after cursory examination of the glyphs.
  1086. *
  1087. * History:
  1088. * 31-Jul-1995 -by- [marcfo]
  1089. * Get rid of unicode functions - since we're just accessing text metrics,
  1090. * the default 'string' functions should work on all platforms.
  1091. *****************************************************************************/
  1092. static BOOL
  1093. ScaleFont( HDC hdc, OFContext *ofc, BOOL bUnicode )
  1094. {
  1095. OUTLINETEXTMETRIC otm;
  1096. HFONT hfont;
  1097. LOGFONT lf;
  1098. DWORD textMetricsSize;
  1099. FLOAT scale, maxChordTolerance=0.035f;
  1100. UINT otmEMSquare;
  1101. // Query font metrics
  1102. if( GetOutlineTextMetrics( hdc, sizeof(otm), &otm) <= 0 )
  1103. // cmd failed, or buffer size=0
  1104. return WFO_FAILURE;
  1105. otmEMSquare = otm.otmEMSquare;
  1106. /*
  1107. * The font data is scaled, so that 1.0 maps to the font's em square
  1108. * size. Note that it is still possible for glyphs to extend beyond
  1109. * this square.
  1110. */
  1111. scale = 1.0f / (FLOAT) otmEMSquare;
  1112. // create new font object, using largest size
  1113. hfont = GetCurrentObject( hdc, OBJ_FONT );
  1114. GetObject( hfont, sizeof(LOGFONT), &lf );
  1115. lf.lfHeight = otmEMSquare;
  1116. lf.lfWidth = 0; // this will choose default width for the height
  1117. hfont = CreateFontIndirect(&lf);
  1118. // select new font into DC, and save current font
  1119. ofc->hfontOld = SelectObject( hdc, hfont );
  1120. // set ofc values
  1121. ofc->scale = scale;
  1122. /* check chord tolerance: in design space, minimum chord tolerance is
  1123. * ~1 logical unit, = ofc->scale.
  1124. */
  1125. if( ofc->chordalDeviation == 0.0f ) {
  1126. // select minimum tolerance in this case
  1127. ofc->chordalDeviation = ofc->scale;
  1128. }
  1129. /* also impose a maximum, or things can get ugly */
  1130. else if( ofc->chordalDeviation > maxChordTolerance ) {
  1131. // XXX might want to change maxChordTolerance based on scale ?
  1132. ofc->chordalDeviation = maxChordTolerance;
  1133. }
  1134. return WFO_SUCCESS;
  1135. }
  1136. /*****************************************************************************
  1137. * DestroyOFContext
  1138. *
  1139. *****************************************************************************/
  1140. static void
  1141. DestroyOFContext( HDC hdc, OFContext* ofc )
  1142. {
  1143. HFONT hfont;
  1144. if( ofc->ec ) {
  1145. extr_Finish( ofc->ec );
  1146. }
  1147. // put back original font object
  1148. if( ofc->hfontOld ) {
  1149. hfont = SelectObject( hdc, ofc->hfontOld );
  1150. DeleteObject( hfont );
  1151. }
  1152. if( ofc->format == WGL_FONT_POLYGONS ) {
  1153. if( ofc->tess )
  1154. gluDeleteTess( ofc->tess );
  1155. }
  1156. FREE( ofc );
  1157. }
  1158. /*****************************************************************************
  1159. * InitLoopBuf
  1160. *
  1161. * Initializes a LOOP_LIST structure for the Loops of each glyph.
  1162. *****************************************************************************/
  1163. static LOOP_LIST*
  1164. InitLoopBuf( void )
  1165. {
  1166. LOOP *pLoop;
  1167. LOOP_LIST *pLoopList;
  1168. DWORD initSize = 10;
  1169. pLoopList = (LOOP_LIST*) ALLOC( sizeof(LOOP_LIST) );
  1170. if( !pLoopList )
  1171. return( (LOOP_LIST *) NULL );
  1172. pLoop = (LOOP*) ALLOC( initSize * sizeof(LOOP) );
  1173. if( !pLoop ) {
  1174. FREE( pLoopList );
  1175. return( (LOOP_LIST *) NULL );
  1176. }
  1177. pLoopList->LoopBuf = pLoop;
  1178. pLoopList->nLoops = 0;
  1179. pLoopList->LoopBufSize = initSize;
  1180. return pLoopList;
  1181. }
  1182. /*****************************************************************************
  1183. * NewLoop
  1184. *
  1185. * Create a new LOOP structure. The first point in the loop is supplied.
  1186. *****************************************************************************/
  1187. static LOOP*
  1188. NewLoop( LOOP_LIST *pLoopList, POINT2D *pFirstPoint )
  1189. {
  1190. LOOP *pNewLoop;
  1191. PRIM *pPrim;
  1192. POINT2D *pVert;
  1193. DWORD size = 50;
  1194. if( pLoopList->nLoops >= pLoopList->LoopBufSize)
  1195. {
  1196. // need to increase size of LoopBuf
  1197. LOOP *pLoop;
  1198. pLoop = (LOOP*) REALLOC(pLoopList->LoopBuf,
  1199. (pLoopList->LoopBufSize += size) *
  1200. sizeof(LOOP));
  1201. if( !pLoop )
  1202. return (LOOP *) NULL;
  1203. pLoopList->LoopBuf = pLoop;
  1204. }
  1205. pNewLoop = pLoopList->LoopBuf + pLoopList->nLoops;
  1206. // give the loop a block of prims to work with
  1207. pPrim = (PRIM *) ALLOC( size * sizeof(PRIM) );
  1208. if( !pPrim )
  1209. return (LOOP *) NULL;
  1210. pNewLoop->PrimBuf = pPrim;
  1211. pNewLoop->nPrims = 0;
  1212. pNewLoop->PrimBufSize = size;
  1213. // give the loop a block of vertices to work with
  1214. pVert = (POINT2D*) ALLOC( size * sizeof(POINT2D) );
  1215. if( !pVert ) {
  1216. FREE( pPrim );
  1217. return (LOOP *) NULL;
  1218. }
  1219. pNewLoop->VertBuf = pVert;
  1220. pNewLoop->nVerts = 0;
  1221. pNewLoop->VertBufSize = size;
  1222. // stick that first point in
  1223. pVert->x = pFirstPoint->x;
  1224. pVert->y = pFirstPoint->y;
  1225. pNewLoop->nVerts++;
  1226. // normal buffers - used by extrusion
  1227. pNewLoop->FNormBuf = (POINT3D *) NULL;
  1228. pNewLoop->VNormBuf = (POINT3D *) NULL;
  1229. pLoopList->nLoops++; // increment loop count
  1230. return pNewLoop;
  1231. }
  1232. /*****************************************************************************
  1233. * NewPrim
  1234. *
  1235. * Create a new PRIM structure. The primType is supplied.
  1236. *****************************************************************************/
  1237. static PRIM*
  1238. NewPrim( LOOP *pLoop, DWORD primType )
  1239. {
  1240. PRIM *pNewPrim;
  1241. POINT2D *pVert;
  1242. DWORD size = 50;
  1243. if( pLoop->nPrims >= pLoop->PrimBufSize)
  1244. {
  1245. // need to increase size of PrimBuf
  1246. PRIM *pPrim;
  1247. pPrim = (PRIM *) REALLOC(pLoop->PrimBuf,
  1248. (pLoop->PrimBufSize += size) * sizeof(PRIM));
  1249. if( !pPrim )
  1250. return (PRIM *) NULL;
  1251. pLoop->PrimBuf = pPrim;
  1252. }
  1253. pNewPrim = pLoop->PrimBuf + pLoop->nPrims;
  1254. // translate primType to extrusion prim type
  1255. primType = (primType == TT_PRIM_LINE) ? PRIM_LINE : PRIM_CURVE;
  1256. pNewPrim->primType = primType;
  1257. pNewPrim->nVerts = 1; // since we include last point:
  1258. /*
  1259. * VertIndex must point to the last point of the previous prim
  1260. */
  1261. pNewPrim->VertIndex = pLoop->nVerts - 1;
  1262. // normal pointers - used by extrusion
  1263. pNewPrim->pFNorm = (POINT3D *) NULL;
  1264. pNewPrim->pVNorm = (POINT3D *) NULL;
  1265. pLoop->nPrims++; // increment prim count
  1266. return pNewPrim;
  1267. }
  1268. /*****************************************************************************
  1269. * FreeLoopList
  1270. *
  1271. * Free up all memory associated with processing a glyph.
  1272. *
  1273. *****************************************************************************/
  1274. static void
  1275. FreeLoopList( LOOP_LIST *pLoopList )
  1276. {
  1277. DWORD nLoops;
  1278. if( !pLoopList )
  1279. return;
  1280. if( pLoopList->LoopBuf ) {
  1281. // free up each loop
  1282. LOOP *pLoop = pLoopList->LoopBuf;
  1283. nLoops = pLoopList->nLoops;
  1284. for( ; nLoops; nLoops--, pLoop++ ) {
  1285. if( pLoop->PrimBuf )
  1286. FREE( pLoop->PrimBuf );
  1287. if( pLoop->VertBuf )
  1288. FREE( pLoop->VertBuf );
  1289. }
  1290. FREE( pLoopList->LoopBuf );
  1291. }
  1292. FREE( pLoopList );
  1293. }
  1294. /*****************************************************************************
  1295. * AppendToVertBuf
  1296. *
  1297. * Append a vertex to the Loop's VertBuf
  1298. *****************************************************************************/
  1299. static BOOL
  1300. AppendToVertBuf( LOOP *pLoop,
  1301. PRIM *pPrim,
  1302. POINT2D *p )
  1303. {
  1304. if( pLoop->nVerts >= pLoop->VertBufSize)
  1305. {
  1306. POINT2D *vertBuf;
  1307. DWORD size = 100;
  1308. vertBuf = (POINT2D *) REALLOC(pLoop->VertBuf,
  1309. (pLoop->VertBufSize += size) *
  1310. sizeof(POINT2D));
  1311. if( !vertBuf )
  1312. return WFO_FAILURE;
  1313. pLoop->VertBuf = vertBuf;
  1314. }
  1315. pLoop->VertBuf[pLoop->nVerts] = *p;
  1316. pLoop->nVerts++;
  1317. pPrim->nVerts++;
  1318. return WFO_SUCCESS;
  1319. }
  1320. /*****************************************************************************
  1321. * CalcVertPtrs
  1322. *
  1323. * Calculate vertex ptrs from index values for the prims in a loop.
  1324. *****************************************************************************/
  1325. static void
  1326. CalcVertPtrs( LOOP *pLoop )
  1327. {
  1328. DWORD nPrims;
  1329. PRIM *pPrim;
  1330. nPrims = pLoop->nPrims;
  1331. pPrim = pLoop->PrimBuf;
  1332. for( ; nPrims; pPrim++, nPrims-- ) {
  1333. pPrim->pVert = pLoop->VertBuf + pPrim->VertIndex;
  1334. }
  1335. }
  1336. /*****************************************************************************
  1337. * GetFixed
  1338. *
  1339. * Fetch the next 32-bit fixed-point value from a little-endian byte stream,
  1340. * convert it to floating-point, and increment the stream pointer to the next
  1341. * unscanned byte.
  1342. *****************************************************************************/
  1343. static FLOAT GetFixed(UCHAR** p)
  1344. {
  1345. FLOAT value;
  1346. FLOAT fraction;
  1347. fraction = ((FLOAT) (UINT) GetWord(p)) / 65536.0f;
  1348. value = (FLOAT) GetSignedWord(p);
  1349. return value+fraction;
  1350. }
  1351. #ifdef FONT_DEBUG
  1352. void
  1353. DrawColorCodedLineLoop( LOOP *pLoop, FLOAT zextrusion )
  1354. {
  1355. POINT2D *p;
  1356. DWORD nPrims;
  1357. DWORD nVerts;
  1358. PRIM *pPrim;
  1359. nPrims = pLoop->nPrims;
  1360. pPrim = pLoop->PrimBuf;
  1361. for( ; nPrims; nPrims--, pPrim++ ) {
  1362. if( pPrim->primType == PRIM_LINE ) {
  1363. if( nPrims == pLoop->nPrims ) // first prim
  1364. glColor3d( 0.5, 0.0, 0.0 );
  1365. else
  1366. glColor3d( 1.0, 0.0, 0.0 );
  1367. } else {
  1368. if( nPrims == pLoop->nPrims ) // first prim
  1369. glColor3d( 0.5, 0.5, 0.0 );
  1370. else
  1371. glColor3d( 1.0, 1.0, 0.0 );
  1372. }
  1373. nVerts = pPrim->nVerts;
  1374. p = pPrim->pVert;
  1375. glBegin(GL_LINE_STRIP);
  1376. for( ; nVerts; nVerts--, p++ ) {
  1377. glVertex3f( p->x, p->y, zextrusion );
  1378. }
  1379. glEnd();
  1380. #define DRAW_POINTS 1
  1381. #ifdef DRAW_POINTS
  1382. glColor3d( 0.0, 0.5, 0.0 );
  1383. nVerts = pPrim->nVerts;
  1384. p = pPrim->pVert;
  1385. glPointSize( 4.0f );
  1386. glBegin( GL_POINTS );
  1387. for( ; nVerts; nVerts--, p++ ) {
  1388. glVertex3f( p->x, p->y, zextrusion );
  1389. }
  1390. glEnd();
  1391. #endif
  1392. }
  1393. // Draw bright green point at start of loop
  1394. if( pLoop->nVerts ) {
  1395. glColor3d( 0.0, 1.0, 0.0 );
  1396. glPointSize( 4.0f );
  1397. glBegin( GL_POINTS );
  1398. p = pLoop->VertBuf;
  1399. glVertex3f( p->x, p->y, zextrusion );
  1400. glEnd();
  1401. glPointSize( 1.0f );
  1402. }
  1403. }
  1404. #endif