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.

1321 lines
35 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include <commdlg.h>
  4. #include <ptypes32.h>
  5. #include <pwin32.h>
  6. #include <math.h>
  7. #include <GL\gl.h>
  8. #include <GL\glu.h>
  9. #include <imports.h>
  10. #include <types.h>
  11. #include "fontoutl.h"
  12. // Extrusion types
  13. #define EXTR_LINES 0
  14. #define EXTR_POLYGONS 1
  15. // Prim to prim transitions
  16. #define EXTR_LINE_LINE 0
  17. #define EXTR_LINE_CURVE 1
  18. #define EXTR_CURVE_LINE 2
  19. #define EXTR_CURVE_CURVE 3
  20. static const double CurveCurveCutoffAngle = PI/2.0;
  21. static const double LineCurveCutoffAngle = PI/4.0;
  22. static BOOL InitFaceBuf( EXTRContext *ec );
  23. #ifndef VARRAY
  24. static void DrawFacePolygons( EXTRContext *ec,
  25. FLOAT z );
  26. #endif
  27. static BOOL DrawSidePolygons( EXTRContext *ec,
  28. LOOP_LIST *pLoopList );
  29. static void DrawPrims( EXTRContext *ec,
  30. LOOP *pLoop );
  31. static void DrawQuads( PRIM *pPrim,
  32. FLOAT zExtrusion );
  33. static void DrawQuadStrip( EXTRContext *ec,
  34. PRIM *pPrim );
  35. static BOOL AppendToFaceBuf( EXTRContext *ec,
  36. FLOAT value );
  37. static BOOL ReallocFaceBuf( EXTRContext *ec );
  38. static BOOL CalculateFaceNormals( LOOP *pLoop,
  39. GLenum orientation );
  40. static BOOL CalculateVertexNormals( LOOP *pLoop );
  41. static void ConsolidatePrims( LOOP *pLoop );
  42. static double PrimNormAngle( PRIM *pPrimA,
  43. PRIM *pPrimB );
  44. static int PrimTransition( PRIM *pPrevPrim,
  45. PRIM *pPrim );
  46. static GLenum LoopOrientation( LOOP_LIST *pLoopList );
  47. static LOOP* GetMaxExtentLoop( LOOP_LIST *pLoopList );
  48. double CalcAngle( POINT2D *v1,
  49. POINT2D *v2 );
  50. static void CalcNormal2d( POINT2D *p,
  51. POINT2D *n,
  52. GLenum orientation );
  53. static void Normalize2d( POINT2D *n );
  54. static void AddVectors3d( POINT3D *v1,
  55. POINT3D *v2,
  56. POINT3D *n );
  57. static void FreeLoopMem( LOOP *pLoop );
  58. #ifdef VARRAY
  59. static PFNGLVERTEXPOINTEREXTPROC glWFOVertexPointerEXT ;
  60. static PFNGLNORMALPOINTEREXTPROC glWFONormalPointerEXT ;
  61. static PFNGLDRAWARRAYSEXTPROC glWFODrawArraysEXT ;
  62. static BOOL InitVArray( EXTRContext *ec );
  63. static BOOL VArrayBufSize( EXTRContext *ec, DWORD size );
  64. #endif
  65. /*****************************************************************************
  66. * exported functions
  67. *****************************************************************************/
  68. /*****************************************************************************
  69. * extr_Init
  70. *
  71. * Initialises extrusion for a wglUseFontOutline call
  72. *****************************************************************************/
  73. EXTRContext *
  74. extr_Init( FLOAT extrusion, INT format )
  75. {
  76. EXTRContext *ec;
  77. ec = (EXTRContext *) ALLOCZ(sizeof(EXTRContext) );
  78. if( !ec )
  79. return NULL;
  80. ec->zExtrusion = -extrusion;
  81. switch( format ) {
  82. case WGL_FONT_LINES :
  83. ec->extrType = EXTR_LINES;
  84. #ifdef FONT_DEBUG
  85. ec->bSidePolys = FALSE;
  86. ec->bFacePolys = FALSE;
  87. #endif
  88. break;
  89. case WGL_FONT_POLYGONS :
  90. ec->extrType = EXTR_POLYGONS;
  91. #ifdef FONT_DEBUG
  92. ec->bSidePolys = TRUE;
  93. ec->bFacePolys = TRUE;
  94. #endif
  95. #ifdef VARRAY
  96. if( ! InitVArray( ec ) ) {
  97. FREE( ec );
  98. return NULL;
  99. }
  100. #endif
  101. break;
  102. default:
  103. ASSERTOPENGL( FALSE, "extr_Init(): invalid format\n" );
  104. }
  105. return ec;
  106. }
  107. /*****************************************************************************
  108. * extr_Finish
  109. *
  110. * Finishes extrusion for a wglUseFontOutline call
  111. *****************************************************************************/
  112. void
  113. extr_Finish( EXTRContext *ec )
  114. {
  115. #ifdef VARRAY
  116. if( ec->extrType == EXTR_POLYGONS )
  117. FREE( ec->vaBuf );
  118. #endif
  119. FREE( ec );
  120. }
  121. /*****************************************************************************
  122. * extr_PolyInit
  123. *
  124. * Initializes the extrusion of a single glyph.
  125. * If the extrusion is polygonal, it sets up FaceBuf, which holds a buffer
  126. * of primitives for drawing the faces of the extruded glyphs.
  127. *
  128. *****************************************************************************/
  129. BOOL extr_PolyInit( EXTRContext *ec )
  130. {
  131. if( ec->extrType == EXTR_LINES )
  132. return WFO_SUCCESS;
  133. ec->FaceBuf = (FLOAT *) NULL;
  134. if( !InitFaceBuf( ec ) ||
  135. !AppendToFaceBuf( ec, 0.0f) ) // primitive count at FaceBuf[0]
  136. return WFO_FAILURE;
  137. // initialize error flag
  138. ec->TessErrorOccurred = 0;
  139. return WFO_SUCCESS;
  140. }
  141. /*****************************************************************************
  142. * extr_PolyFinish
  143. *
  144. * Cleans up stuff from processing a single glyph
  145. *****************************************************************************/
  146. void extr_PolyFinish( EXTRContext *ec )
  147. {
  148. if( ec->extrType == EXTR_LINES )
  149. return;
  150. if( ec->FaceBuf ) {
  151. FREE( ec->FaceBuf );
  152. ec->FaceBuf = (FLOAT *) NULL;
  153. }
  154. }
  155. /*****************************************************************************
  156. * extr_DrawLines
  157. *
  158. * Draws the lines in a glyph loop for Line extrusion
  159. *****************************************************************************/
  160. void extr_DrawLines( EXTRContext *ec, LOOP_LIST *pLoopList )
  161. {
  162. DWORD nLoops, nVerts;
  163. POINT2D *p;
  164. LOOP *pLoop;
  165. nLoops = pLoopList->nLoops;
  166. pLoop = pLoopList->LoopBuf;
  167. for( ; nLoops; nLoops--, pLoop++ ) {
  168. // Draw the back face loop
  169. #ifdef FONT_DEBUG
  170. DrawColorCodedLineLoop( pLoop, ec->zExtrusion );
  171. #else
  172. glBegin(GL_LINE_LOOP);
  173. nVerts = pLoop->nVerts - 1; // skip last point
  174. p = pLoop->VertBuf;
  175. for ( ; nVerts; nVerts--, p++ ) {
  176. glVertex3f( p->x, p->y, ec->zExtrusion );
  177. }
  178. glEnd();
  179. #endif
  180. // Draw the lines along the sides
  181. #ifdef FONT_DEBUG
  182. glColor3d( 0.0, 0.0, 1.0 );
  183. #endif
  184. glBegin(GL_LINES);
  185. nVerts = pLoop->nVerts - 1; // skip last point
  186. p = pLoop->VertBuf;
  187. for( ; nVerts; nVerts--, p++ ) {
  188. glVertex2fv( (GLfloat *) p);
  189. glVertex3f( p->x, p->y, ec->zExtrusion );
  190. }
  191. glEnd();
  192. }
  193. }
  194. /*****************************************************************************
  195. * extr_glBegin
  196. *
  197. * Tesselation callback for glBegin.
  198. * Buffers data into FaceBuf
  199. *
  200. *****************************************************************************/
  201. void CALLBACK
  202. extr_glBegin( GLenum primType, void *data )
  203. {
  204. EXTRContext *ec = ((OFContext *)data)->ec;
  205. // buffer face data
  206. ec->FaceBuf[0] += 1.0f; // increment prim counter
  207. ec->FaceVertexCountIndex = ec->FaceBufIndex+1; // mark vertex count index
  208. if( !AppendToFaceBuf( ec, (FLOAT) primType ) || // enter prim type
  209. !AppendToFaceBuf( ec, 0.0f ) ) // vertex count
  210. ec->TessErrorOccurred = GLU_OUT_OF_MEMORY;
  211. }
  212. /*****************************************************************************
  213. * extr_glEnd
  214. *
  215. * Tesselation callback for glEnd.
  216. * Noop, since we are just tracking the tesselation at this point.
  217. *
  218. *****************************************************************************/
  219. void CALLBACK
  220. extr_glEnd( void )
  221. {
  222. }
  223. /*****************************************************************************
  224. * extr_glVertex
  225. *
  226. * Tesselation callback for glVertex.
  227. * Buffers data into FaceBuf
  228. *
  229. *****************************************************************************/
  230. void CALLBACK
  231. extr_glVertex( GLfloat *v, void *data )
  232. {
  233. EXTRContext *ec = ((OFContext *)data)->ec;
  234. // put vertex in face buffer
  235. if( !AppendToFaceBuf( ec, v[0]) || !AppendToFaceBuf( ec, v[1]) )
  236. ec->TessErrorOccurred = GLU_OUT_OF_MEMORY;
  237. // increment vertex counter
  238. ec->FaceBuf[ec->FaceVertexCountIndex] += 1.0f;
  239. }
  240. /*****************************************************************************
  241. * extr_DrawPolygons
  242. *
  243. * Draws the side and face polygons of a glyph for polygonal extrusion
  244. * Gets polygon information from LineBuf, which was created during
  245. * MakeLinesFromGlyph().
  246. *****************************************************************************/
  247. BOOL
  248. extr_DrawPolygons( EXTRContext *ec, LOOP_LIST *pLoopList )
  249. {
  250. #ifdef FONT_DEBUG
  251. if( ec->bSidePolys )
  252. if( !DrawSidePolygons( ec, pLoopList ) ) {
  253. return WFO_FAILURE;
  254. }
  255. if( ec->bFacePolys ) {
  256. DrawFacePolygons( ec, 0.0f ); // front face
  257. DrawFacePolygons( ec, ec->zExtrusion ); // back face
  258. }
  259. #else
  260. if( !DrawSidePolygons( ec, pLoopList ) )
  261. return WFO_FAILURE;
  262. DrawFacePolygons( ec, 0.0f ); // front face
  263. DrawFacePolygons( ec, ec->zExtrusion ); // back face
  264. #endif
  265. return WFO_SUCCESS;
  266. }
  267. /*****************************************************************************
  268. * internal functions
  269. *****************************************************************************/
  270. /*****************************************************************************
  271. * DrawSidePolygons
  272. *
  273. * Draw the side prims, using several passes on each prim loop:
  274. * 1) Calculate face normals for all the prims
  275. * 2) Consolidate prims if possible
  276. * 3) Calculate vertex normals for curve prims
  277. * 4) Draw the prims
  278. * Side effects: sets glFrontFace
  279. *****************************************************************************/
  280. static BOOL
  281. DrawSidePolygons( EXTRContext *ec,
  282. LOOP_LIST *pLoopList )
  283. {
  284. DWORD nLoops;
  285. LOOP *pLoop;
  286. GLenum orientation;
  287. nLoops = pLoopList->nLoops;
  288. if( !nLoops )
  289. return WFO_SUCCESS;
  290. /*
  291. * Determine orientation of loop
  292. */
  293. orientation = LoopOrientation( pLoopList );
  294. glFrontFace( orientation );
  295. pLoop = pLoopList->LoopBuf;
  296. for( ; nLoops; nLoops--, pLoop++ ) {
  297. // Calculate face normals
  298. if( !CalculateFaceNormals( pLoop, orientation ) )
  299. return WFO_FAILURE;
  300. // Consolidate list of prims
  301. ConsolidatePrims( pLoop );
  302. // Calculate vertex normals
  303. if( !CalculateVertexNormals( pLoop ) ) {
  304. FreeLoopMem( pLoop ); // free mem alloc'd by CalculateFaceNormals
  305. return WFO_FAILURE;
  306. }
  307. DrawPrims( ec, pLoop );
  308. // Free memory allocated during loop processing
  309. FreeLoopMem( pLoop );
  310. }
  311. return WFO_SUCCESS;
  312. }
  313. /*****************************************************************************
  314. * FreeLoopMem
  315. *
  316. * Frees up memory associated with each prim loop
  317. *****************************************************************************/
  318. static void
  319. FreeLoopMem( LOOP *pLoop )
  320. {
  321. PRIM *pPrim;
  322. if( !pLoop )
  323. return;
  324. if( pLoop->FNormBuf )
  325. FREE( pLoop->FNormBuf );
  326. if( pLoop->VNormBuf )
  327. FREE( pLoop->VNormBuf );
  328. }
  329. /*****************************************************************************
  330. * DrawPrims
  331. *
  332. * Draws a loop of Prims
  333. *****************************************************************************/
  334. static void
  335. DrawPrims( EXTRContext *ec, LOOP *pLoop )
  336. {
  337. PRIM *pPrim;
  338. DWORD nPrims;
  339. nPrims = pLoop->nPrims;
  340. pPrim = pLoop->PrimBuf;
  341. for( ; nPrims; nPrims--, pPrim++ ) {
  342. switch( pPrim->primType ) {
  343. case PRIM_LINE:
  344. DrawQuads( pPrim, ec->zExtrusion );
  345. break;
  346. case PRIM_CURVE:
  347. DrawQuadStrip( ec, pPrim );
  348. break;
  349. }
  350. }
  351. }
  352. //#define EXTRANORMAL 1
  353. /*****************************************************************************
  354. * DrawQuads
  355. *
  356. * Draws independent quads of a PRIM.
  357. *****************************************************************************/
  358. static void
  359. DrawQuads( PRIM *pPrim, FLOAT zExtrusion )
  360. {
  361. POINT2D *p;
  362. POINT3D *pNorm;
  363. ULONG quadCount;
  364. quadCount = pPrim->nVerts - 1;
  365. glBegin( GL_QUADS );
  366. p = pPrim->pVert;
  367. pNorm = pPrim->pFNorm;
  368. while( quadCount-- ) {
  369. Normalize2d( (POINT2D *) pNorm ); // normalize
  370. glNormal3fv( (GLfloat *) pNorm );
  371. glVertex3f( p->x, p->y, 0.0f );
  372. glVertex3f( p->x, p->y, zExtrusion );
  373. p++;
  374. #ifdef EXTRANORMAL
  375. glNormal3fv( (GLfloat *) pNorm );
  376. #endif
  377. glVertex3f( p->x, p->y, zExtrusion );
  378. glVertex3f( p->x, p->y, 0.0f );
  379. pNorm++;
  380. }
  381. glEnd();
  382. }
  383. /*****************************************************************************
  384. * DrawQuadStrip
  385. *
  386. * Draws a quadstrip from a PRIM
  387. *****************************************************************************/
  388. static void
  389. DrawQuadStrip( EXTRContext *ec, PRIM *pPrim )
  390. {
  391. #ifndef VARRAY
  392. POINT3D *pNorm;
  393. POINT2D *p;
  394. ULONG nVerts;
  395. glBegin( GL_QUAD_STRIP );
  396. // initialize pointers, setup
  397. nVerts = pPrim->nVerts;
  398. p = pPrim->pVert;
  399. pNorm = pPrim->pVNorm;
  400. while( nVerts-- ) {
  401. glNormal3fv( (GLfloat *) pNorm );
  402. glVertex3f( p->x, p->y, 0.0f );
  403. #ifdef EXTRANORMAL
  404. glNormal3fv( (GLfloat *) pNorm );
  405. #endif
  406. glVertex3f( p->x, p->y, ec->zExtrusion );
  407. // reset pointers
  408. p++; // next point
  409. pNorm++; // next vertex normal
  410. }
  411. glEnd();
  412. #else
  413. POINT3D *n;
  414. POINT2D *p;
  415. ULONG nVerts;
  416. ULONG i;
  417. FLOAT *pDst, *pVert, *pNorm;
  418. nVerts = pPrim->nVerts;
  419. // For every vertex in prim, need in varray buf: 2 verts, 2 normals
  420. if( !VArrayBufSize( ec, nVerts * 2 * 2 * 3) )
  421. return; // nothing drawn
  422. // setup vertices
  423. p = pPrim->pVert;
  424. pVert = pDst = ec->vaBuf;
  425. for( i = 0; i < nVerts; i++, p++ ) {
  426. *pDst++ = p->x;
  427. *pDst++ = p->y;
  428. *pDst++ = 0.0f;
  429. *pDst++ = p->x;
  430. *pDst++ = p->y;
  431. *pDst++ = ec->zExtrusion;
  432. }
  433. // setup normals
  434. n = pPrim->pVNorm;
  435. pNorm = pDst;
  436. for( i = 0; i < nVerts; i++, n++ ) {
  437. *( ((POINT3D *) pDst)++ ) = *n;
  438. *( ((POINT3D *) pDst)++ ) = *n;
  439. }
  440. // send it
  441. glEnable(GL_NORMAL_ARRAY_EXT);
  442. glWFOVertexPointerEXT(3, GL_FLOAT, 0, nVerts*2, pVert );
  443. glWFONormalPointerEXT( GL_FLOAT, 0, nVerts*2, pNorm );
  444. glWFODrawArraysEXT( GL_QUAD_STRIP, 0, nVerts*2);
  445. glDisable(GL_NORMAL_ARRAY_EXT);
  446. #endif
  447. }
  448. /*****************************************************************************
  449. * DrawFacePolygons
  450. *
  451. * Draws the front or back facing polygons of a glyph.
  452. * If z is 0.0, the front face of the glyph is drawn, otherwise the back
  453. * face is drawn.
  454. *****************************************************************************/
  455. #ifdef VARRAY
  456. void
  457. #else
  458. static void
  459. #endif
  460. DrawFacePolygons( EXTRContext *ec, FLOAT z )
  461. {
  462. ULONG primCount, vertexCount;
  463. GLenum primType;
  464. FLOAT *FaceBuf = ec->FaceBuf;
  465. FLOAT *p;
  466. #ifdef VARRAY
  467. POINT3D normal = {0.0f, 0.0f, 0.0f};
  468. FLOAT *pVert, *pNorm, *pDst;
  469. ULONG i;
  470. #endif
  471. if( z == 0.0f ) {
  472. glNormal3f( 0.0f, 0.0f, 1.0f );
  473. glFrontFace( GL_CCW );
  474. } else {
  475. glNormal3f( 0.0f, 0.0f, -1.0f );
  476. glFrontFace( GL_CW );
  477. }
  478. primCount = (ULONG) FaceBuf[0];
  479. p = &FaceBuf[1];
  480. #ifndef VARRAY
  481. while( primCount-- ) {
  482. primType = (GLenum) *p++;
  483. vertexCount = (ULONG) *p++;
  484. glBegin( primType );
  485. for( ; vertexCount; vertexCount--, p+=2 )
  486. glVertex3f( p[0], p[1], z );
  487. glEnd();
  488. }
  489. #else
  490. if( z == 0.0f )
  491. normal.z = 1.0f;
  492. else
  493. normal.z = -1.0f;
  494. while( primCount-- ) {
  495. primType = (GLenum) *p++;
  496. vertexCount = (ULONG) *p++;
  497. if( !VArrayBufSize( ec, vertexCount * 3 ) )
  498. return; // nothing drawn
  499. pVert = pDst = ec->vaBuf;
  500. // put vertices into varray buf
  501. for( i = 0; i < vertexCount; i++, p+=2 ) {
  502. *pDst++ = p[0];
  503. *pDst++ = p[1];
  504. *pDst++ = z;
  505. }
  506. glWFOVertexPointerEXT(3, GL_FLOAT, 0, vertexCount, pVert );
  507. glWFODrawArraysEXT( primType, 0, vertexCount );
  508. }
  509. #endif
  510. }
  511. /*****************************************************************************
  512. * ConsolidatePrims
  513. *
  514. * Consolidate a loop of prims.
  515. * Go through list of prims, consolidating consecutive Curve and Line prims
  516. * When 2 prims are consolidated into one, the first prim is set to
  517. * null by setting it's nVerts=0. The second prim get's the first's stuff.
  518. * If joining occured, the array of prims is compacted at the end.
  519. *
  520. *****************************************************************************/
  521. static void
  522. ConsolidatePrims( LOOP *pLoop )
  523. {
  524. DWORD nPrims, nJoined = 0;
  525. BOOL bJoined;
  526. PRIM *pPrim, *pPrevPrim;
  527. int trans;
  528. double angle;
  529. nPrims = pLoop->nPrims;
  530. if( nPrims < 2 )
  531. return;
  532. pPrim = pLoop->PrimBuf;
  533. pPrevPrim = pPrim++;
  534. nPrims--; // nPrim-1 comparisons
  535. for( ; nPrims; nPrims--, pPrevPrim = pPrim++ ) {
  536. bJoined = FALSE;
  537. trans = PrimTransition( pPrevPrim, pPrim );
  538. switch( trans ) {
  539. case EXTR_LINE_LINE:
  540. // always consolidate 2 lines
  541. bJoined = TRUE;
  542. break;
  543. case EXTR_LINE_CURVE:
  544. break;
  545. case EXTR_CURVE_LINE:
  546. break;
  547. case EXTR_CURVE_CURVE:
  548. /*
  549. * Join the prims if angle_between_norms < cutoff_angle
  550. */
  551. angle = PrimNormAngle( pPrevPrim, pPrim );
  552. if( angle < CurveCurveCutoffAngle ) {
  553. bJoined = TRUE;
  554. }
  555. break;
  556. }
  557. if( bJoined ) {
  558. // nullify the prev prim - move all data to current prim
  559. pPrim->nVerts += (pPrevPrim->nVerts - 1);
  560. pPrim->pVert = pPrevPrim->pVert;
  561. pPrim->pFNorm = pPrevPrim->pFNorm;
  562. pPrevPrim->nVerts = 0;
  563. nJoined++;
  564. }
  565. }
  566. if( nJoined ) {
  567. // one or more prims eliminated - compact the list
  568. nPrims = pLoop->nPrims;
  569. pPrim = pLoop->PrimBuf;
  570. // set new nPrims value
  571. pLoop->nPrims = nPrims - nJoined;
  572. nJoined = 0; // nJoined now used as counter
  573. for( ; nPrims; nPrims--, pPrim++ ) {
  574. if( pPrim->nVerts == 0 ) {
  575. nJoined++;
  576. continue;
  577. }
  578. *(pPrim-nJoined) = *pPrim;
  579. }
  580. }
  581. }
  582. /*****************************************************************************
  583. * PrimTransition
  584. *
  585. * Given two adjacent prims, returns a code based on prim-type transition.
  586. *
  587. *****************************************************************************/
  588. static int
  589. PrimTransition( PRIM *pPrevPrim, PRIM *pPrim )
  590. {
  591. int trans;
  592. if( pPrevPrim->primType == PRIM_LINE ) {
  593. if( pPrim->primType == PRIM_LINE )
  594. trans = EXTR_LINE_LINE;
  595. else
  596. trans = EXTR_LINE_CURVE;
  597. } else {
  598. if( pPrim->primType == PRIM_LINE )
  599. trans = EXTR_CURVE_LINE;
  600. else
  601. trans = EXTR_CURVE_CURVE;
  602. }
  603. return trans;
  604. }
  605. /*****************************************************************************
  606. * LoopOrientation
  607. *
  608. * Check for glyphs that have incorrectly specified the contour direction (for
  609. * example, many of the Wingding glyphs). We do this by first determining
  610. * the loop in the glyph that has the largest extent. We then make the
  611. * assumption that this loop is external, and check it's orientation. If
  612. * the orientation is CCW (non-default), we have to set the orientation to
  613. * GL_CCW in the extrusion context, so that normals will be generated
  614. * correctly.
  615. * The method used here may fail for any loops that intersect themselves.
  616. * This will happen if the loops created by the intersections are in the opposite
  617. * direction to the main loop (if 1 such extra loop exists, then the sum of
  618. * angles around the entire contour will be 0 - we put in a check for this,
  619. * and always default to CW in this case)
  620. *
  621. * Note that this method *always* works for properly designed TruyType glyphs.
  622. * From the TrueType font spec "The direction of the curves has to be such that,
  623. * if the curve is followed in the direction of increasing point numbers, the
  624. * black space (the filled area) will always be to the right." So this means
  625. * that the outer loop should always be CW.
  626. *
  627. *****************************************************************************/
  628. // These macros handle the rare case of a self-intersecting, polarity-reversing
  629. // loop as explained above. (Observed in animals1.ttf) Note that will only
  630. // catch some cases.
  631. #define INTERSECTING_LOOP_WORKAROUND 1
  632. #define NEAR_ZERO( fAngle ) \
  633. ( fabs(fAngle) < 0.00001 )
  634. static GLenum
  635. LoopOrientation( LOOP_LIST *pLoopList )
  636. {
  637. DWORD nLoops, nVerts;
  638. double angle = 0;
  639. POINT2D *p1, *p2, v1, v2;
  640. LOOP *pMaxLoop;
  641. nLoops = pLoopList->nLoops;
  642. if( !nLoops )
  643. return GL_CW; // default value
  644. // determine which loop has the maximum extent
  645. pMaxLoop = GetMaxExtentLoop( pLoopList );
  646. nVerts = pMaxLoop->nVerts;
  647. if( nVerts < 3 )
  648. return GL_CW; // can't determine angle
  649. p1 = pMaxLoop->VertBuf + nVerts - 2; // 2nd to last point
  650. p2 = pMaxLoop->VertBuf; // first point
  651. /*
  652. * Accumulate relative angle between consecutive line segments along
  653. * the loop - this will tell us the loop's orientation.
  654. */
  655. v1.x = p2->x - p1->x;
  656. v1.y = p2->y - p1->y;
  657. nVerts--; // n-1 comparisons
  658. for( ; nVerts; nVerts-- ) {
  659. // calc next vector
  660. p1 = p2++;
  661. v2.x = p2->x - p1->x;
  662. v2.y = p2->y - p1->y;
  663. angle += CalcAngle( &v1, &v2 );
  664. v1 = v2;
  665. }
  666. #ifdef INTERSECTING_LOOP_WORKAROUND
  667. if( NEAR_ZERO( angle ) ) {
  668. DBGPRINT( "wglUseFontOutlines:LoopOrientation : Total loop angle is zero, assuming CW orientation\n" );
  669. return GL_CW;
  670. }
  671. #endif
  672. if( angle > 0.0 )
  673. return GL_CCW;
  674. else
  675. return GL_CW;
  676. }
  677. /*****************************************************************************
  678. * GetMaxExtentLoop
  679. *
  680. * Determine which of the loops in a glyph description has the maximum
  681. * extent, and return a ptr to it. We check extents in the x direction.
  682. *****************************************************************************/
  683. LOOP *
  684. GetMaxExtentLoop( LOOP_LIST *pLoopList )
  685. {
  686. DWORD nLoops, nVerts;
  687. FLOAT curxExtent, xExtent=0.0f, x, xMin, xMax;
  688. LOOP *pMaxLoop, *pLoop;
  689. POINT2D *p;
  690. pMaxLoop = pLoop = pLoopList->LoopBuf;
  691. nLoops = pLoopList->nLoops;
  692. if( nLoops == 1 )
  693. // just one loop - no comparison required
  694. return pMaxLoop;
  695. for( ; nLoops; nLoops--, pLoop++ ) {
  696. nVerts = pLoop->nVerts;
  697. p = pLoop->VertBuf;
  698. // use x value of first point as reference
  699. x = p->x;
  700. xMin = xMax = x;
  701. // compare x's of rest of points
  702. for( ; nVerts; nVerts--, p++ ) {
  703. x = p->x;
  704. if( x < xMin )
  705. xMin = x;
  706. else if( x > xMax )
  707. xMax = x;
  708. }
  709. curxExtent = xMax - xMin;
  710. if( curxExtent > xExtent ) {
  711. xExtent = curxExtent;
  712. pMaxLoop = pLoop;
  713. }
  714. }
  715. return pMaxLoop;
  716. }
  717. /*****************************************************************************
  718. * CalcAngle
  719. *
  720. * Determine the signed angle between 2 vectors. The angle is measured CCW
  721. * from vector 1 to vector 2.
  722. *****************************************************************************/
  723. double
  724. CalcAngle( POINT2D *v1, POINT2D *v2 )
  725. {
  726. double angle1, angle2, angle;
  727. // Calculate absolute angle of each vector
  728. /* Check for (0,0) vectors - this shouldn't happen unless 2 consecutive
  729. * vertices in the VertBuf are equal.
  730. */
  731. if( (v1->y == 0.0f) && (v1->x == 0.0f) )
  732. angle1 = 0.0f;
  733. else
  734. angle1 = __GL_ATAN2F( v1->y, v1->x ); // range: -PI to PI
  735. if( (v2->y == 0.0f) && (v2->x == 0.0f) )
  736. angle1 = 0.0f;
  737. else
  738. angle2 = __GL_ATAN2F( v2->y, v2->x ); // range: -PI to PI
  739. // Calculate relative angle between vectors
  740. angle = angle2 - angle1; // range: -2*PI to 2*PI
  741. // force angle to be in range -PI to PI
  742. if( angle < -PI )
  743. angle += TWO_PI;
  744. else if( angle > PI )
  745. angle -= TWO_PI;
  746. return angle;
  747. }
  748. /*****************************************************************************
  749. * CalculateFaceNormals
  750. *
  751. * Calculate face normals for a prim loop.
  752. * The normals are NOT normalized.
  753. *
  754. *****************************************************************************/
  755. static BOOL
  756. CalculateFaceNormals( LOOP *pLoop,
  757. GLenum orientation )
  758. {
  759. DWORD nPrims;
  760. ULONG nQuads = 0;
  761. POINT2D *p;
  762. POINT3D *pNorm;
  763. PRIM *pPrim;
  764. // Need 1 normal per vertex
  765. pNorm = (POINT3D*) ALLOC(pLoop->nVerts*sizeof(POINT3D));
  766. pLoop->FNormBuf = pNorm;
  767. if( !pNorm )
  768. return WFO_FAILURE;
  769. // Calculate the face normals
  770. nPrims = pLoop->nPrims;
  771. pPrim = pLoop->PrimBuf;
  772. for( ; nPrims; nPrims--, pPrim++ ) {
  773. pPrim->pFNorm = pNorm; // ptr to each prims norms
  774. nQuads = pPrim->nVerts - 1;
  775. p = pPrim->pVert;
  776. for( ; nQuads; nQuads--, p++, pNorm++ ) {
  777. CalcNormal2d( p, (POINT2D *) pNorm, orientation );
  778. pNorm->z = 0.0f; // normals in xy plane
  779. }
  780. }
  781. return WFO_SUCCESS;
  782. }
  783. /*****************************************************************************
  784. * CalculateVertexNormals
  785. *
  786. * Calculate vertex normals for a prim loop, only for those prims that
  787. * are of type 'CURVE'.
  788. * Uses previously calculated face normals to generate the vertex normals.
  789. * Allocates memory for the normals by calculating memory requirements on
  790. * the fly.
  791. * The normals are normalized.
  792. * Handles closing of loops properly.
  793. *
  794. *****************************************************************************/
  795. static BOOL
  796. CalculateVertexNormals( LOOP *pLoop )
  797. {
  798. ULONG nPrims, nVerts = 0;
  799. POINT3D *pVNorm, *pFNorm, *pDstNorm;
  800. PRIM *pPrim, *pPrevPrim;
  801. double angle;
  802. GLenum trans;
  803. // How much memory we need for the normals?
  804. nPrims = pLoop->nPrims;
  805. pPrim = pLoop->PrimBuf;
  806. for( ; nPrims; nPrims--, pPrim++ ) {
  807. if( pPrim->primType == PRIM_CURVE )
  808. nVerts += pPrim->nVerts;
  809. }
  810. if( !nVerts )
  811. return WFO_SUCCESS;
  812. // XXX: could just allocate 2*nVerts of mem for the normals
  813. pVNorm = (POINT3D*) ALLOC( nVerts*sizeof(POINT3D) );
  814. pLoop->VNormBuf = pVNorm;
  815. if( !pVNorm )
  816. return WFO_FAILURE;
  817. // First pass: calculate normals for all vertices of Curve prims
  818. nPrims = pLoop->nPrims;
  819. pPrim = pLoop->PrimBuf;
  820. for( ; nPrims; nPrims--, pPrim++ ) {
  821. if( pPrim->primType == PRIM_LINE )
  822. continue;
  823. nVerts = pPrim->nVerts;
  824. pPrim->pVNorm = pVNorm; // ptr to each prims norms
  825. pFNorm = pPrim->pFNorm; // ptr to face norms already calculated
  826. // set the first vnorm to the fnorm
  827. *pVNorm = *pFNorm;
  828. Normalize2d( (POINT2D *) pVNorm ); // normalize it
  829. nVerts--; // one less vertex to worry about
  830. pVNorm++; // advance ptrs
  831. pFNorm++;
  832. nVerts--; // do last vertex after this loop
  833. for( ; nVerts; nVerts--, pFNorm++, pVNorm++ ) {
  834. // use neighbouring face normals to get vertex normal
  835. AddVectors3d( pFNorm, pFNorm-1, pVNorm );
  836. Normalize2d( (POINT2D *) pVNorm ); // normalize it
  837. }
  838. // last vnorm is same as fnorm of *previous* vertex
  839. *pVNorm = *(pFNorm-1);
  840. Normalize2d( (POINT2D *) pVNorm ); // normalize it
  841. pVNorm++; // next available space in vnorm buffer
  842. }
  843. // Second pass: calculate normals on prim boundaries
  844. nPrims = pLoop->nPrims;
  845. pPrim = pLoop->PrimBuf;
  846. // set pPrevPrim to last prim in loop
  847. pPrevPrim = pLoop->PrimBuf + pLoop->nPrims - 1;
  848. for( ; nPrims; nPrims--, pPrevPrim = pPrim++ ) {
  849. trans = PrimTransition( pPrevPrim, pPrim );
  850. angle = PrimNormAngle( pPrevPrim, pPrim );
  851. switch( trans ) {
  852. case EXTR_LINE_CURVE:
  853. if( angle < LineCurveCutoffAngle ) {
  854. // set curve's first vnorm to line's last fnorm
  855. *(pPrim->pVNorm) =
  856. *(pPrevPrim->pFNorm + pPrevPrim->nVerts -2);
  857. Normalize2d( (POINT2D *) pPrim->pVNorm );
  858. }
  859. break;
  860. case EXTR_CURVE_LINE:
  861. if( angle < LineCurveCutoffAngle ) {
  862. // set curve's last vnorm to line's first fnorm
  863. pDstNorm = pPrevPrim->pVNorm + pPrevPrim->nVerts - 1;
  864. *pDstNorm = *(pPrim->pFNorm);
  865. Normalize2d( (POINT2D *) pDstNorm );
  866. }
  867. break;
  868. case EXTR_CURVE_CURVE:
  869. if( angle < CurveCurveCutoffAngle ) {
  870. // average normals of adjoining faces, and
  871. // set last curve's first vnorm to averaged normal
  872. AddVectors3d( pPrevPrim->pFNorm + pPrevPrim->nVerts - 2,
  873. pPrim->pFNorm,
  874. pPrim->pVNorm );
  875. Normalize2d( (POINT2D *) pPrim->pVNorm );
  876. // set first curve's last vnorm to averaged normal
  877. *(pPrevPrim->pVNorm + pPrevPrim->nVerts - 1) =
  878. *(pPrim->pVNorm);
  879. }
  880. break;
  881. case EXTR_LINE_LINE:
  882. // nothing to do
  883. break;
  884. }
  885. }
  886. return WFO_SUCCESS;
  887. }
  888. /*****************************************************************************
  889. * PrimNormAngle
  890. *
  891. * Determine angle between the last face's normal of primA, and the first
  892. * face's normal of primB.
  893. *
  894. * The result should be an angle between -PI and PI.
  895. * For now, we only care about the relative angle, so we return the
  896. * absolute value of the signed angle between the faces.
  897. *
  898. *****************************************************************************/
  899. static double
  900. PrimNormAngle( PRIM *pPrimA, PRIM *pPrimB )
  901. {
  902. double angle;
  903. // last face norm at index (nvert-2)
  904. POINT3D *normA = pPrimA->pFNorm + pPrimA->nVerts - 2;
  905. POINT3D *normB = pPrimB->pFNorm;
  906. angle = CalcAngle( (POINT2D *) normA, (POINT2D *) normB );
  907. return fabs(angle); // don't care about sign of angle for now
  908. }
  909. /*****************************************************************************
  910. * InitFaceBuf
  911. *
  912. * Initializes FaceBuf and its associated size and current-element
  913. * counters.
  914. *
  915. *****************************************************************************/
  916. static BOOL
  917. InitFaceBuf( EXTRContext *ec )
  918. {
  919. DWORD initSize = 1000;
  920. if( !(ec->FaceBuf =
  921. (FLOAT*) ALLOC(initSize*sizeof(FLOAT))) )
  922. return WFO_FAILURE;
  923. ec->FaceBufSize = initSize;
  924. ec->FaceBufIndex = 0;
  925. return WFO_SUCCESS;
  926. }
  927. /*****************************************************************************
  928. * AppendToFaceBuf
  929. *
  930. * Appends one floating-point value to the FaceBuf array.
  931. *****************************************************************************/
  932. static BOOL
  933. AppendToFaceBuf(EXTRContext *ec, FLOAT value)
  934. {
  935. if (ec->FaceBufIndex >= ec->FaceBufSize)
  936. {
  937. if( !ReallocFaceBuf( ec ) )
  938. return WFO_FAILURE;
  939. }
  940. ec->FaceBuf[ec->FaceBufIndex++] = value;
  941. return WFO_SUCCESS;
  942. }
  943. /*****************************************************************************
  944. * ReallocBuf
  945. *
  946. * Increases size of FaceBuf by a constant value.
  947. *
  948. *****************************************************************************/
  949. static BOOL
  950. ReallocFaceBuf( EXTRContext *ec )
  951. {
  952. FLOAT* f;
  953. DWORD increase = 1000; // in floats
  954. f = (FLOAT*) REALLOC(ec->FaceBuf,
  955. (ec->FaceBufSize += increase)*sizeof(FLOAT));
  956. if (!f)
  957. return WFO_FAILURE;
  958. ec->FaceBuf = f;
  959. return WFO_SUCCESS;
  960. }
  961. /*****************************************************************************
  962. * CalcNormal2d
  963. *
  964. * Calculates the 2d normal of a 2d vector, by rotating the vector:
  965. * - CCW 90 degrees for CW contours.
  966. * - CW 90 degrees for CCW contours.
  967. * Does not normalize.
  968. *
  969. *****************************************************************************/
  970. static void
  971. CalcNormal2d( POINT2D *p, POINT2D *n, GLenum orientation )
  972. {
  973. static POINT2D v;
  974. v.x = (p+1)->x - p->x;
  975. v.y = (p+1)->y - p->y;
  976. if( orientation == GL_CW ) {
  977. n->x = -v.y;
  978. n->y = v.x;
  979. } else {
  980. n->x = v.y;
  981. n->y = -v.x;
  982. }
  983. }
  984. /*****************************************************************************
  985. * Normalize2d
  986. *
  987. * Normalizes a 2d vector
  988. *
  989. *****************************************************************************/
  990. static void
  991. Normalize2d( POINT2D *n )
  992. {
  993. float len;
  994. len = (n->x * n->x) + (n->y * n->y);
  995. if (len > ZERO_EPS)
  996. len = 1.0f / __GL_SQRTF(len);
  997. else
  998. len = 1.0f;
  999. n->x *= len;
  1000. n->y *= len;
  1001. }
  1002. /*****************************************************************************
  1003. * AddVectors3d
  1004. *
  1005. * Adds two 3d vectors.
  1006. *
  1007. *****************************************************************************/
  1008. static void
  1009. AddVectors3d( POINT3D *v1, POINT3D *v2, POINT3D *n )
  1010. {
  1011. n->x = v1->x + v2->x;
  1012. n->y = v1->y + v2->y;
  1013. n->z = v1->z + v2->z;
  1014. }
  1015. #ifdef VARRAY
  1016. static BOOL
  1017. InitVArray( EXTRContext *ec )
  1018. {
  1019. int size = 500;
  1020. // set up global buffer
  1021. ec->vaBufSize = size;
  1022. ec->vaBuf = (FLOAT*) ALLOC( size*sizeof(FLOAT) );
  1023. if( !ec->vaBuf ) {
  1024. return WFO_FAILURE;
  1025. }
  1026. // set up and enable ptrs
  1027. glWFOVertexPointerEXT = (PFNGLVERTEXPOINTEREXTPROC )wglGetProcAddress("glVertexPointerEXT");
  1028. glWFONormalPointerEXT = (PFNGLNORMALPOINTEREXTPROC )wglGetProcAddress("glNormalPointerEXT");
  1029. glWFODrawArraysEXT = (PFNGLDRAWARRAYSEXTPROC )wglGetProcAddress("glDrawArraysEXT");
  1030. if( (glWFOVertexPointerEXT == NULL)
  1031. || (glWFONormalPointerEXT == NULL)
  1032. || (glWFODrawArraysEXT == NULL) ) {
  1033. FREE( ec->vaBuf );
  1034. return WFO_FAILURE;
  1035. }
  1036. glEnable(GL_VERTEX_ARRAY_EXT);
  1037. return WFO_SUCCESS;
  1038. }
  1039. /*****************************************************************************
  1040. *
  1041. * Size is in floats
  1042. *
  1043. *****************************************************************************/
  1044. static BOOL
  1045. VArrayBufSize( EXTRContext *ec, DWORD size )
  1046. {
  1047. if( size > ec->vaBufSize )
  1048. {
  1049. FLOAT *f;
  1050. f = (FLOAT*) REALLOC( ec->vaBuf, size*sizeof(FLOAT));
  1051. if( !f )
  1052. return WFO_FAILURE;
  1053. ec->vaBuf = f;
  1054. ec->vaBufSize = size;
  1055. }
  1056. return WFO_SUCCESS;
  1057. }
  1058. #endif