Leaked source code of windows server 2003
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.

628 lines
17 KiB

  1. /*
  2. ** Copyright 1994, Silicon Graphics, Inc.
  3. ** All Rights Reserved.
  4. **
  5. ** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6. ** the contents of this file may not be disclosed to third parties, copied or
  7. ** duplicated in any form, in whole or in part, without the prior written
  8. ** permission of Silicon Graphics, Inc.
  9. **
  10. ** RESTRICTED RIGHTS LEGEND:
  11. ** Use, duplication or disclosure by the Government is subject to restrictions
  12. ** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13. ** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14. ** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15. ** rights reserved under the Copyright Laws of the United States.
  16. **
  17. ** Author: Eric Veach, July 1994.
  18. */
  19. #include <assert.h>
  20. #include "memalloc.h"
  21. #include "tess.h"
  22. #include "mesh.h"
  23. #include "normal.h"
  24. #include "sweep.h"
  25. #include "tessmono.h"
  26. #include "render.h"
  27. #define GLU_TESS_DEFAULT_TOLERANCE 0.0
  28. #ifndef NT
  29. #define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */
  30. #endif
  31. #define TRUE 1
  32. #define FALSE 0
  33. /*ARGSUSED*/ static void noBegin( GLenum type ) {}
  34. /*ARGSUSED*/ static void noEdgeFlag( GLboolean boundaryEdge ) {}
  35. /*ARGSUSED*/ static void noVertex( void *data ) {}
  36. /*ARGSUSED*/ static void noEnd( void ) {}
  37. /*ARGSUSED*/ static void noError( GLenum errno ) {}
  38. /*ARGSUSED*/ static void noCombine( GLdouble coords[3], void *data[4],
  39. GLfloat weight[4], void **dataOut ) {}
  40. /*ARGSUSED*/ static void noMesh( GLUmesh *mesh ) {}
  41. /*ARGSUSED*/ void __gl_noBeginData( GLenum type, void *polygonData ) {}
  42. /*ARGSUSED*/ void __gl_noEdgeFlagData( GLboolean boundaryEdge,
  43. void *polygonData ) {}
  44. /*ARGSUSED*/ void __gl_noVertexData( void *data, void *polygonData ) {}
  45. /*ARGSUSED*/ void __gl_noEndData( void *polygonData ) {}
  46. /*ARGSUSED*/ void __gl_noErrorData( GLenum errno, void *polygonData ) {}
  47. /*ARGSUSED*/ void __gl_noCombineData( GLdouble coords[3], void *data[4],
  48. GLfloat weight[4], void **outData,
  49. void *polygonData ) {}
  50. /* Half-edges are allocated in pairs (see mesh.c) */
  51. typedef struct { GLUhalfEdge e, eSym; } EdgePair;
  52. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  53. #define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
  54. MAX(sizeof(GLUvertex),sizeof(GLUface))))
  55. #ifdef NT
  56. GLUtesselator* APIENTRY gluNewTess( void )
  57. #else
  58. GLUtesselator *gluNewTess( void )
  59. #endif
  60. {
  61. GLUtesselator *tess;
  62. /* Only initialize fields which can be changed by the api. Other fields
  63. * are initialized where they are used.
  64. */
  65. if (memInit( MAX_FAST_ALLOC ) == 0) {
  66. return 0; /* out of memory */
  67. }
  68. tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
  69. if (tess == NULL) {
  70. return 0; /* out of memory */
  71. }
  72. tess->state = T_DORMANT;
  73. tess->normal[0] = 0;
  74. tess->normal[1] = 0;
  75. tess->normal[2] = 0;
  76. tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
  77. tess->windingRule = GLU_TESS_WINDING_ODD;
  78. tess->flagBoundary = FALSE;
  79. tess->boundaryOnly = FALSE;
  80. tess->callBegin = &noBegin;
  81. tess->callEdgeFlag = &noEdgeFlag;
  82. tess->callVertex = &noVertex;
  83. tess->callEnd = &noEnd;
  84. tess->callError = &noError;
  85. tess->callCombine = &noCombine;
  86. tess->callMesh = &noMesh;
  87. tess->callBeginData= &__gl_noBeginData;
  88. tess->callEdgeFlagData= &__gl_noEdgeFlagData;
  89. tess->callVertexData= &__gl_noVertexData;
  90. tess->callEndData= &__gl_noEndData;
  91. tess->callErrorData= &__gl_noErrorData;
  92. tess->callCombineData= &__gl_noCombineData;
  93. tess->polygonData= NULL;
  94. return tess;
  95. }
  96. static void MakeDormant( GLUtesselator *tess )
  97. {
  98. /* Return the tesselator to its original dormant state. */
  99. if( tess->mesh != NULL ) {
  100. __gl_meshDeleteMesh( tess->mesh );
  101. }
  102. tess->state = T_DORMANT;
  103. tess->lastEdge = NULL;
  104. tess->mesh = NULL;
  105. }
  106. #define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s)
  107. static void GotoState( GLUtesselator *tess, enum TessState newState )
  108. {
  109. #ifdef NT
  110. while( tess->state != (GLenum) newState ) {
  111. #else
  112. while( tess->state != newState ) {
  113. #endif
  114. /* We change the current state one level at a time, to get to
  115. * the desired state.
  116. */
  117. #ifdef NT
  118. if( tess->state < (GLenum) newState ) {
  119. #else
  120. if( tess->state < newState ) {
  121. #endif
  122. switch( tess->state ) {
  123. case T_DORMANT:
  124. CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
  125. gluTessBeginPolygon( tess, NULL );
  126. break;
  127. case T_IN_POLYGON:
  128. CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
  129. gluTessBeginContour( tess );
  130. break;
  131. }
  132. } else {
  133. switch( tess->state ) {
  134. case T_IN_CONTOUR:
  135. CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
  136. gluTessEndContour( tess );
  137. break;
  138. case T_IN_POLYGON:
  139. CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
  140. /* gluTessEndPolygon( tess ) is too much work! */
  141. MakeDormant( tess );
  142. break;
  143. }
  144. }
  145. }
  146. }
  147. #ifdef NT
  148. void APIENTRY gluDeleteTess( GLUtesselator *tess )
  149. #else
  150. void gluDeleteTess( GLUtesselator *tess )
  151. #endif
  152. {
  153. RequireState( tess, T_DORMANT );
  154. memFree( tess );
  155. }
  156. #ifdef NT
  157. void APIENTRY gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
  158. #else
  159. void gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
  160. #endif
  161. {
  162. GLenum windingRule;
  163. switch( which ) {
  164. case GLU_TESS_TOLERANCE:
  165. if( value < 0.0 || value > 1.0 ) break;
  166. tess->relTolerance = value;
  167. return;
  168. case GLU_TESS_WINDING_RULE:
  169. windingRule = (GLenum) value;
  170. if( windingRule != value ) break; /* not an integer */
  171. switch( windingRule ) {
  172. case GLU_TESS_WINDING_ODD:
  173. case GLU_TESS_WINDING_NONZERO:
  174. case GLU_TESS_WINDING_POSITIVE:
  175. case GLU_TESS_WINDING_NEGATIVE:
  176. case GLU_TESS_WINDING_ABS_GEQ_TWO:
  177. tess->windingRule = windingRule;
  178. return;
  179. default:
  180. break;
  181. }
  182. case GLU_TESS_BOUNDARY_ONLY:
  183. tess->boundaryOnly = (value != 0);
  184. return;
  185. default:
  186. CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
  187. return;
  188. }
  189. CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
  190. }
  191. /* Returns tesselator property */
  192. #ifdef NT
  193. void APIENTRY gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
  194. #else
  195. void gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
  196. #endif
  197. {
  198. switch (which) {
  199. case GLU_TESS_TOLERANCE:
  200. /* tolerance should be in range [0..1] */
  201. assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
  202. *value= tess->relTolerance;
  203. break;
  204. case GLU_TESS_WINDING_RULE:
  205. assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
  206. tess->windingRule == GLU_TESS_WINDING_NONZERO ||
  207. tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
  208. tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
  209. tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
  210. *value= tess->windingRule;
  211. break;
  212. case GLU_TESS_BOUNDARY_ONLY:
  213. assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
  214. *value= tess->boundaryOnly;
  215. break;
  216. default:
  217. *value= 0.0;
  218. CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
  219. break;
  220. }
  221. } /* gluGetTessProperty() */
  222. #ifdef NT
  223. void APIENTRY gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
  224. #else
  225. void gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
  226. #endif
  227. {
  228. tess->normal[0] = x;
  229. tess->normal[1] = y;
  230. tess->normal[2] = z;
  231. }
  232. #ifdef NT
  233. void APIENTRY gluTessCallback( GLUtesselator *tess, GLenum which, void (*fn)())
  234. #else
  235. void gluTessCallback( GLUtesselator *tess, GLenum which, void (*fn)())
  236. #endif
  237. {
  238. switch( which ) {
  239. case GLU_TESS_BEGIN:
  240. tess->callBegin = (fn == NULL) ? &noBegin : (void (*)(GLenum)) fn;
  241. return;
  242. case GLU_TESS_BEGIN_DATA:
  243. tess->callBeginData = (fn == NULL) ? &__gl_noBeginData :
  244. (void (*)(GLenum, void *)) fn;
  245. return;
  246. case GLU_TESS_EDGE_FLAG:
  247. tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag : (void (*)(GLboolean)) fn;
  248. /* If the client wants boundary edges to be flagged,
  249. * we render everything as separate triangles (no strips or fans).
  250. */
  251. tess->flagBoundary = (fn != NULL);
  252. return;
  253. case GLU_TESS_EDGE_FLAG_DATA:
  254. tess->callEdgeFlagData= (fn == NULL) ? &__gl_noEdgeFlagData :
  255. (void (*)(GLboolean, void *)) fn;
  256. /* If the client wants boundary edges to be flagged,
  257. * we render everything as separate triangles (no strips or fans).
  258. */
  259. tess->flagBoundary = (fn != NULL);
  260. return;
  261. case GLU_TESS_VERTEX:
  262. tess->callVertex = (fn == NULL) ? &noVertex : (void (*)(void *)) fn;
  263. return;
  264. case GLU_TESS_VERTEX_DATA:
  265. tess->callVertexData = (fn == NULL) ? &__gl_noVertexData :
  266. (void (*)(void *, void *)) fn;
  267. return;
  268. case GLU_TESS_END:
  269. tess->callEnd = (fn == NULL) ? &noEnd : (void (*)(void)) fn;
  270. return;
  271. case GLU_TESS_END_DATA:
  272. tess->callEndData = (fn == NULL) ? &__gl_noEndData :
  273. (void (*)(void *)) fn;
  274. return;
  275. case GLU_TESS_ERROR:
  276. tess->callError = (fn == NULL) ? &noError : (void (*)(GLenum)) fn;
  277. return;
  278. case GLU_TESS_ERROR_DATA:
  279. tess->callErrorData = (fn == NULL) ? &__gl_noErrorData :
  280. (void (*)(GLenum, void *)) fn;
  281. return;
  282. case GLU_TESS_COMBINE:
  283. tess->callCombine = (fn == NULL) ? &noCombine :
  284. (void (*)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn;
  285. return;
  286. case GLU_TESS_COMBINE_DATA:
  287. tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
  288. (void (*)(GLdouble [3],
  289. void *[4],
  290. GLfloat [4],
  291. void **,
  292. void *)) fn;
  293. return;
  294. #ifndef NT
  295. case GLU_TESS_MESH:
  296. tess->callMesh = (fn == NULL) ? &noMesh : (void (*)(GLUmesh *)) fn;
  297. return;
  298. #endif
  299. default:
  300. CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
  301. return;
  302. }
  303. }
  304. static void AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
  305. {
  306. GLUhalfEdge *e;
  307. e = tess->lastEdge;
  308. if( e == NULL ) {
  309. /* Make a self-loop (one vertex, one edge). */
  310. e = __gl_meshMakeEdge( tess->mesh );
  311. __gl_meshSplice( e, e->Sym );
  312. } else {
  313. /* Create a new vertex and edge which immediately follow e
  314. * in the ordering around the left face.
  315. */
  316. (void) __gl_meshSplitEdge( e );
  317. e = e->Lnext;
  318. }
  319. /* The new vertex is now e->Org. */
  320. e->Org->data = data;
  321. e->Org->coords[0] = coords[0];
  322. e->Org->coords[1] = coords[1];
  323. e->Org->coords[2] = coords[2];
  324. /* The winding of an edge says how the winding number changes as we
  325. * cross from the edge''s right face to its left face. We add the
  326. * vertices in such an order that a CCW contour will add +1 to
  327. * the winding number of the region inside the contour.
  328. */
  329. e->winding = 1;
  330. e->Sym->winding = -1;
  331. tess->lastEdge = e;
  332. }
  333. static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
  334. {
  335. CachedVertex *v = &tess->cache[tess->cacheCount];
  336. v->data = data;
  337. v->coords[0] = coords[0];
  338. v->coords[1] = coords[1];
  339. v->coords[2] = coords[2];
  340. ++tess->cacheCount;
  341. }
  342. static void EmptyCache( GLUtesselator *tess )
  343. {
  344. CachedVertex *v = tess->cache;
  345. CachedVertex *vLast;
  346. tess->mesh = __gl_meshNewMesh();
  347. for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
  348. AddVertex( tess, v->coords, v->data );
  349. }
  350. tess->cacheCount = 0;
  351. tess->emptyCache = FALSE;
  352. }
  353. #ifdef NT
  354. void APIENTRY gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
  355. #else
  356. void gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
  357. #endif
  358. {
  359. int i, tooLarge = FALSE;
  360. GLdouble x, clamped[3];
  361. RequireState( tess, T_IN_CONTOUR );
  362. if( tess->emptyCache ) {
  363. EmptyCache( tess );
  364. tess->lastEdge = NULL;
  365. }
  366. for( i = 0; i < 3; ++i ) {
  367. x = coords[i];
  368. if( x < - GLU_TESS_MAX_COORD ) {
  369. x = - GLU_TESS_MAX_COORD;
  370. tooLarge = TRUE;
  371. }
  372. if( x > GLU_TESS_MAX_COORD ) {
  373. x = GLU_TESS_MAX_COORD;
  374. tooLarge = TRUE;
  375. }
  376. clamped[i] = x;
  377. }
  378. if( tooLarge ) {
  379. CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
  380. }
  381. if( tess->mesh == NULL ) {
  382. if( tess->cacheCount < TESS_MAX_CACHE ) {
  383. CacheVertex( tess, clamped, data );
  384. return;
  385. }
  386. EmptyCache( tess );
  387. }
  388. AddVertex( tess, clamped, data );
  389. }
  390. #ifdef NT
  391. void APIENTRY gluTessBeginPolygon( GLUtesselator *tess, void *data )
  392. #else
  393. void gluTessBeginPolygon( GLUtesselator *tess, void *data )
  394. #endif
  395. {
  396. RequireState( tess, T_DORMANT );
  397. tess->state = T_IN_POLYGON;
  398. tess->cacheCount = 0;
  399. tess->emptyCache = FALSE;
  400. tess->mesh = NULL;
  401. tess->polygonData= data;
  402. }
  403. #ifdef NT
  404. void APIENTRY gluTessBeginContour( GLUtesselator *tess )
  405. #else
  406. void gluTessBeginContour( GLUtesselator *tess )
  407. #endif
  408. {
  409. RequireState( tess, T_IN_POLYGON );
  410. tess->state = T_IN_CONTOUR;
  411. tess->lastEdge = NULL;
  412. if( tess->cacheCount > 0 ) {
  413. /* Just set a flag so we don't get confused by empty contours
  414. * -- these can be generated accidentally with the obsolete
  415. * NextContour() interface.
  416. */
  417. tess->emptyCache = TRUE;
  418. }
  419. }
  420. #ifdef NT
  421. void APIENTRY gluTessEndContour( GLUtesselator *tess )
  422. #else
  423. void gluTessEndContour( GLUtesselator *tess )
  424. #endif
  425. {
  426. RequireState( tess, T_IN_CONTOUR );
  427. tess->state = T_IN_POLYGON;
  428. }
  429. #ifdef NT
  430. void APIENTRY gluTessEndPolygon( GLUtesselator *tess )
  431. #else
  432. void gluTessEndPolygon( GLUtesselator *tess )
  433. #endif
  434. {
  435. GLUmesh *mesh;
  436. RequireState( tess, T_IN_POLYGON );
  437. tess->state = T_DORMANT;
  438. if( tess->mesh == NULL ) {
  439. if( ! tess->flagBoundary && tess->callMesh == &noMesh ) {
  440. /* Try some special code to make the easy cases go quickly
  441. * (eg. convex polygons). This code does NOT handle multiple contours,
  442. * intersections, edge flags, and of course it does not generate
  443. * an explicit mesh either.
  444. */
  445. if( __gl_renderCache( tess )) {
  446. tess->polygonData= NULL;
  447. return;
  448. }
  449. }
  450. EmptyCache( tess );
  451. }
  452. /* Determine the polygon normal and project vertices onto the plane
  453. * of the polygon.
  454. */
  455. __gl_projectPolygon( tess );
  456. /* __gl_computeInterior( tess ) computes the planar arrangement specified
  457. * by the given contours, and further subdivides this arrangement
  458. * into regions. Each region is marked "inside" if it belongs
  459. * to the polygon, according to the rule given by tess->windingRule.
  460. * Each interior region is guaranteed be monotone.
  461. */
  462. __gl_computeInterior( tess );
  463. mesh = tess->mesh;
  464. if( ! tess->fatalError ) {
  465. /* If the user wants only the boundary contours, we throw away all edges
  466. * except those which separate the interior from the exterior.
  467. * Otherwise we tesselate all the regions marked "inside".
  468. */
  469. if( tess->boundaryOnly ) {
  470. __gl_meshSetWindingNumber( mesh, 1, TRUE );
  471. } else {
  472. __gl_meshTesselateInterior( mesh );
  473. }
  474. __gl_meshCheckMesh( mesh );
  475. if( tess->callBegin != &noBegin || tess->callEnd != &noEnd
  476. || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag
  477. || tess->callBeginData != &__gl_noBeginData
  478. || tess->callEndData != &__gl_noEndData
  479. || tess->callVertexData != &__gl_noVertexData
  480. || tess->callEdgeFlagData != &__gl_noEdgeFlagData )
  481. {
  482. if( tess->boundaryOnly ) {
  483. __gl_renderBoundary( tess, mesh ); /* output boundary contours */
  484. } else {
  485. __gl_renderMesh( tess, mesh ); /* output strips and fans */
  486. }
  487. }
  488. if( tess->callMesh != &noMesh ) {
  489. /* Throw away the exterior faces, so that all faces are interior.
  490. * This way the user doesn't have to check the "inside" flag,
  491. * and we don't need to even reveal its existence. It also leaves
  492. * the freedom for an implementation to not generate the exterior
  493. * faces in the first place.
  494. */
  495. __gl_meshDiscardExterior( mesh );
  496. (*tess->callMesh)( mesh ); /* user wants the mesh itself */
  497. tess->mesh = NULL;
  498. tess->polygonData= NULL;
  499. return;
  500. }
  501. }
  502. __gl_meshDeleteMesh( mesh );
  503. tess->polygonData= NULL;
  504. tess->mesh = NULL;
  505. }
  506. #ifndef NT
  507. void gluDeleteMesh( GLUmesh *mesh )
  508. {
  509. __gl_meshDeleteMesh( mesh );
  510. }
  511. #endif
  512. /*******************************************************/
  513. /* Obsolete calls -- for backward compatibility */
  514. #ifdef NT
  515. void APIENTRY gluBeginPolygon( GLUtesselator *tess )
  516. #else
  517. void gluBeginPolygon( GLUtesselator *tess )
  518. #endif
  519. {
  520. gluTessBeginPolygon( tess, NULL );
  521. gluTessBeginContour( tess );
  522. }
  523. /*ARGSUSED*/
  524. #ifdef NT
  525. void APIENTRY gluNextContour( GLUtesselator *tess, GLenum type )
  526. #else
  527. void gluNextContour( GLUtesselator *tess, GLenum type )
  528. #endif
  529. {
  530. gluTessEndContour( tess );
  531. gluTessBeginContour( tess );
  532. }
  533. #ifdef NT
  534. void APIENTRY gluEndPolygon( GLUtesselator *tess )
  535. #else
  536. void gluEndPolygon( GLUtesselator *tess )
  537. #endif
  538. {
  539. gluTessEndContour( tess );
  540. gluTessEndPolygon( tess );
  541. }