47 #define GLU_TESS_DEFAULT_TOLERANCE 0.0
48 #define GLU_TESS_MESH 100112
57 #if defined(__GNUC__) || defined(__clang__)
58 #pragma GCC diagnostic push
60 #pragma GCC diagnostic ignored "-Wunused-parameter"
63 static void GLAPIENTRY noBegin( GLenum type ) {}
64 static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {}
65 static void GLAPIENTRY noVertex(
void *data ) {}
66 static void GLAPIENTRY noEnd(
void ) {}
67 static void GLAPIENTRY noError( GLenum errnum ) {}
68 static void GLAPIENTRY noCombine( GLdouble coords[3],
void *data[4],
69 GLfloat weight[4],
void **dataOut ) {}
70 static void GLAPIENTRY noMesh( GLUmesh *mesh ) {}
73 void GLAPIENTRY __gl_noBeginData( GLenum type,
74 void *polygonData ) {}
75 void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge,
76 void *polygonData ) {}
77 void GLAPIENTRY __gl_noVertexData(
void *data,
78 void *polygonData ) {}
79 void GLAPIENTRY __gl_noEndData(
void *polygonData ) {}
80 void GLAPIENTRY __gl_noErrorData( GLenum errnum,
81 void *polygonData ) {}
82 void GLAPIENTRY __gl_noCombineData( GLdouble coords[3],
86 void *polygonData ) {}
88 #if defined(__GNUC__) || defined(__clang__)
89 #pragma GCC diagnostic pop
96 #define MAX(a,b) ((a) > (b) ? (a) : (b))
97 #define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
98 MAX(sizeof(GLUvertex),sizeof(GLUface))))
101 GLUtesselator * GLAPIENTRY
110 if (memInit( MAX_FAST_ALLOC ) == 0) {
113 tess = (GLUtesselator *)memAlloc(
sizeof( GLUtesselator ));
118 tess->state = T_DORMANT;
124 tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
125 tess->windingRule = GLU_TESS_WINDING_ODD;
126 tess->flagBoundary = FALSE;
127 tess->boundaryOnly = FALSE;
129 tess->callBegin = &noBegin;
130 tess->callEdgeFlag = &noEdgeFlag;
131 tess->callVertex = &noVertex;
132 tess->callEnd = &noEnd;
134 tess->callError = &noError;
135 tess->callCombine = &noCombine;
136 tess->callMesh = &noMesh;
138 tess->callBeginData= &__gl_noBeginData;
139 tess->callEdgeFlagData= &__gl_noEdgeFlagData;
140 tess->callVertexData= &__gl_noVertexData;
141 tess->callEndData= &__gl_noEndData;
142 tess->callErrorData= &__gl_noErrorData;
143 tess->callCombineData= &__gl_noCombineData;
145 tess->polygonData= NULL;
150 static void MakeDormant( GLUtesselator *tess )
154 if( tess->mesh != NULL ) {
155 __gl_meshDeleteMesh( tess->mesh );
157 tess->state = T_DORMANT;
158 tess->lastEdge = NULL;
162 #define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s)
164 static void GotoState( GLUtesselator *tess,
enum TessState newState )
166 while( tess->state != newState ) {
170 if( tess->state < newState ) {
171 switch( tess->state ) {
173 CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
174 gluTessBeginPolygon( tess, NULL );
177 CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
178 gluTessBeginContour( tess );
184 switch( tess->state ) {
186 CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
187 gluTessEndContour( tess );
190 CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
203 gluDeleteTess( GLUtesselator *tess )
205 RequireState( tess, T_DORMANT );
211 gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
216 case GLU_TESS_TOLERANCE:
217 if( value < 0.0 || value > 1.0 )
break;
218 tess->relTolerance = value;
221 case GLU_TESS_WINDING_RULE:
222 windingRule = (GLenum) value;
223 if( windingRule != value )
break;
225 switch( windingRule ) {
226 case GLU_TESS_WINDING_ODD:
227 case GLU_TESS_WINDING_NONZERO:
228 case GLU_TESS_WINDING_POSITIVE:
229 case GLU_TESS_WINDING_NEGATIVE:
230 case GLU_TESS_WINDING_ABS_GEQ_TWO:
231 tess->windingRule = windingRule;
237 case GLU_TESS_BOUNDARY_ONLY:
238 tess->boundaryOnly = (value != 0);
242 CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
245 CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
250 gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
253 case GLU_TESS_TOLERANCE:
255 assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
256 *value= tess->relTolerance;
258 case GLU_TESS_WINDING_RULE:
259 assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
260 tess->windingRule == GLU_TESS_WINDING_NONZERO ||
261 tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
262 tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
263 tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
264 *value= tess->windingRule;
266 case GLU_TESS_BOUNDARY_ONLY:
267 assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
268 *value= tess->boundaryOnly;
272 CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
278 gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
286 gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn)
290 tess->callBegin = (fn == NULL) ? &noBegin : (
void (GLAPIENTRY *)(GLenum)) fn;
292 case GLU_TESS_BEGIN_DATA:
293 tess->callBeginData = (fn == NULL) ?
294 &__gl_noBeginData : (
void (GLAPIENTRY *)(GLenum,
void *)) fn;
296 case GLU_TESS_EDGE_FLAG:
297 tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag :
298 (
void (GLAPIENTRY *)(GLboolean)) fn;
302 tess->flagBoundary = (fn != NULL);
304 case GLU_TESS_EDGE_FLAG_DATA:
305 tess->callEdgeFlagData= (fn == NULL) ?
306 &__gl_noEdgeFlagData : (
void (GLAPIENTRY *)(GLboolean,
void *)) fn;
310 tess->flagBoundary = (fn != NULL);
312 case GLU_TESS_VERTEX:
313 tess->callVertex = (fn == NULL) ? &noVertex :
314 (
void (GLAPIENTRY *)(
void *)) fn;
316 case GLU_TESS_VERTEX_DATA:
317 tess->callVertexData = (fn == NULL) ?
318 &__gl_noVertexData : (
void (GLAPIENTRY *)(
void *,
void *)) fn;
321 tess->callEnd = (fn == NULL) ? &noEnd : (
void (GLAPIENTRY *)(void)) fn;
323 case GLU_TESS_END_DATA:
324 tess->callEndData = (fn == NULL) ? &__gl_noEndData :
325 (
void (GLAPIENTRY *)(
void *)) fn;
328 tess->callError = (fn == NULL) ? &noError : (
void (GLAPIENTRY *)(GLenum)) fn;
330 case GLU_TESS_ERROR_DATA:
331 tess->callErrorData = (fn == NULL) ?
332 &__gl_noErrorData : (
void (GLAPIENTRY *)(GLenum,
void *)) fn;
334 case GLU_TESS_COMBINE:
335 tess->callCombine = (fn == NULL) ? &noCombine :
336 (
void (GLAPIENTRY *)(GLdouble [3],
void *[4], GLfloat [4],
void ** )) fn;
338 case GLU_TESS_COMBINE_DATA:
339 tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
340 (
void (GLAPIENTRY *)(GLdouble [3],
347 tess->callMesh = (fn == NULL) ? &noMesh : (
void (GLAPIENTRY *)(GLUmesh *)) fn;
350 CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
355 static int AddVertex( GLUtesselator *tess, GLdouble coords[3],
void *data )
363 e = __gl_meshMakeEdge( tess->mesh );
364 if (e == NULL)
return 0;
365 if ( !__gl_meshSplice( e, e->Sym ) )
return 0;
370 if (__gl_meshSplitEdge( e ) == NULL)
return 0;
376 e->Org->coords[0] = coords[0];
377 e->Org->coords[1] = coords[1];
378 e->Org->coords[2] = coords[2];
386 e->Sym->winding = -1;
394 static void CacheVertex( GLUtesselator *tess, GLdouble coords[3],
void *data )
396 CachedVertex *v = &tess->cache[tess->cacheCount];
399 v->coords[0] = coords[0];
400 v->coords[1] = coords[1];
401 v->coords[2] = coords[2];
406 static int EmptyCache( GLUtesselator *tess )
408 CachedVertex *v = tess->cache;
411 tess->mesh = __gl_meshNewMesh();
412 if (tess->mesh == NULL)
return 0;
414 for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
415 if ( !AddVertex( tess, v->coords, v->data ) )
return 0;
417 tess->cacheCount = 0;
418 tess->emptyCache = FALSE;
425 gluTessVertex( GLUtesselator *tess, GLdouble coords[3],
void *data )
427 int i, tooLarge = FALSE;
428 GLdouble x, clamped[3];
430 RequireState( tess, T_IN_CONTOUR );
432 if( tess->emptyCache ) {
433 if ( !EmptyCache( tess ) ) {
434 CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
437 tess->lastEdge = NULL;
439 for( i = 0; i < 3; ++i ) {
441 if( x < - GLU_TESS_MAX_COORD ) {
442 x = - GLU_TESS_MAX_COORD;
445 if( x > GLU_TESS_MAX_COORD ) {
446 x = GLU_TESS_MAX_COORD;
452 CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
455 if( tess->mesh == NULL ) {
456 if( tess->cacheCount < TESS_MAX_CACHE ) {
457 CacheVertex( tess, clamped, data );
460 if ( !EmptyCache( tess ) ) {
461 CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
465 if ( !AddVertex( tess, clamped, data ) ) {
466 CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
472 gluTessBeginPolygon( GLUtesselator *tess,
void *data )
474 RequireState( tess, T_DORMANT );
476 tess->state = T_IN_POLYGON;
477 tess->cacheCount = 0;
478 tess->emptyCache = FALSE;
481 tess->polygonData= data;
486 gluTessBeginContour( GLUtesselator *tess )
488 RequireState( tess, T_IN_POLYGON );
490 tess->state = T_IN_CONTOUR;
491 tess->lastEdge = NULL;
492 if( tess->cacheCount > 0 ) {
497 tess->emptyCache = TRUE;
503 gluTessEndContour( GLUtesselator *tess )
505 RequireState( tess, T_IN_CONTOUR );
506 tess->state = T_IN_POLYGON;
510 gluTessEndPolygon( GLUtesselator *tess )
514 if (setjmp(tess->env) != 0) {
516 CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
520 RequireState( tess, T_IN_POLYGON );
521 tess->state = T_DORMANT;
523 if( tess->mesh == NULL ) {
524 if( ! tess->flagBoundary && tess->callMesh == &noMesh ) {
531 if( __gl_renderCache( tess )) {
532 tess->polygonData= NULL;
536 if ( !EmptyCache( tess ) ) longjmp(tess->env,1);
542 __gl_projectPolygon( tess );
550 if ( !__gl_computeInterior( tess ) ) {
551 longjmp(tess->env,1);
555 if( ! tess->fatalError ) {
562 if( tess->boundaryOnly ) {
563 rc = __gl_meshSetWindingNumber( mesh, 1, TRUE );
565 rc = __gl_meshTessellateInterior( mesh );
567 if (rc == 0) longjmp(tess->env,1);
569 __gl_meshCheckMesh( mesh );
571 if( tess->callBegin != &noBegin || tess->callEnd != &noEnd
572 || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag
573 || tess->callBeginData != &__gl_noBeginData
574 || tess->callEndData != &__gl_noEndData
575 || tess->callVertexData != &__gl_noVertexData
576 || tess->callEdgeFlagData != &__gl_noEdgeFlagData )
578 if( tess->boundaryOnly ) {
579 __gl_renderBoundary( tess, mesh );
581 __gl_renderMesh( tess, mesh );
584 if( tess->callMesh != &noMesh ) {
592 __gl_meshDiscardExterior( mesh );
593 (*tess->callMesh)( mesh );
595 tess->polygonData= NULL;
599 __gl_meshDeleteMesh( mesh );
600 tess->polygonData= NULL;
608 gluDeleteMesh( GLUmesh *mesh )
610 __gl_meshDeleteMesh( mesh );
621 gluBeginPolygon( GLUtesselator *tess )
623 gluTessBeginPolygon( tess, NULL );
624 gluTessBeginContour( tess );
630 gluNextContour( GLUtesselator *tess, GLenum type)
632 gluTessEndContour( tess );
633 gluTessBeginContour( tess );
639 gluEndPolygon( GLUtesselator *tess )
641 gluTessEndContour( tess );
642 gluTessEndPolygon( tess );