tess.c 17 KB

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