tess.c 17 KB

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