📄 tess.c
字号:
case GLU_TESS_ERROR_DATA: tess->callErrorData = (fn == NULL) ? &__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn; return; case GLU_TESS_COMBINE: tess->callCombine = (fn == NULL) ? &noCombine : (void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn; return; case GLU_TESS_COMBINE_DATA: tess->callCombineData = (fn == NULL) ? &__gl_noCombineData : (void (GLAPIENTRY *)(GLdouble [3], void *[4], GLfloat [4], void **, void *)) fn; return; case GLU_TESS_MESH: tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn; return; default: CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); return; }}static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data ){ GLUhalfEdge *e; e = tess->lastEdge; if( e == NULL ) { /* Make a self-loop (one vertex, one edge). */ e = __gl_meshMakeEdge( tess->mesh ); if (e == NULL) return 0; if ( !__gl_meshSplice( e, e->Sym ) ) return 0; } else { /* Create a new vertex and edge which immediately follow e * in the ordering around the left face. */ if (__gl_meshSplitEdge( e ) == NULL) return 0; e = e->Lnext; } /* The new vertex is now e->Org. */ e->Org->data = data; e->Org->coords[0] = coords[0]; e->Org->coords[1] = coords[1]; e->Org->coords[2] = coords[2]; /* The winding of an edge says how the winding number changes as we * cross from the edge''s right face to its left face. We add the * vertices in such an order that a CCW contour will add +1 to * the winding number of the region inside the contour. */ e->winding = 1; e->Sym->winding = -1; tess->lastEdge = e; return 1;}static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data ){ CachedVertex *v = &tess->cache[tess->cacheCount]; v->data = data; v->coords[0] = coords[0]; v->coords[1] = coords[1]; v->coords[2] = coords[2]; ++tess->cacheCount;}static int EmptyCache( GLUtesselator *tess ){ CachedVertex *v = tess->cache; CachedVertex *vLast; tess->mesh = __gl_meshNewMesh(); if (tess->mesh == NULL) return 0; for( vLast = v + tess->cacheCount; v < vLast; ++v ) { if ( !AddVertex( tess, v->coords, v->data ) ) return 0; } tess->cacheCount = 0; tess->emptyCache = FALSE; return 1;}void GLAPIENTRYgluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data ){ int i, tooLarge = FALSE; GLdouble x, clamped[3]; RequireState( tess, T_IN_CONTOUR ); if( tess->emptyCache ) { if ( !EmptyCache( tess ) ) { CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); return; } tess->lastEdge = NULL; } for( i = 0; i < 3; ++i ) { x = coords[i]; if( x < - GLU_TESS_MAX_COORD ) { x = - GLU_TESS_MAX_COORD; tooLarge = TRUE; } if( x > GLU_TESS_MAX_COORD ) { x = GLU_TESS_MAX_COORD; tooLarge = TRUE; } clamped[i] = x; } if( tooLarge ) { CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE ); } if( tess->mesh == NULL ) { if( tess->cacheCount < TESS_MAX_CACHE ) { CacheVertex( tess, clamped, data ); return; } if ( !EmptyCache( tess ) ) { CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); return; } } if ( !AddVertex( tess, clamped, data ) ) { CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); }}void GLAPIENTRYgluTessBeginPolygon( GLUtesselator *tess, void *data ){ RequireState( tess, T_DORMANT ); tess->state = T_IN_POLYGON; tess->cacheCount = 0; tess->emptyCache = FALSE; tess->mesh = NULL; tess->polygonData= data;}void GLAPIENTRYgluTessBeginContour( GLUtesselator *tess ){ RequireState( tess, T_IN_POLYGON ); tess->state = T_IN_CONTOUR; tess->lastEdge = NULL; if( tess->cacheCount > 0 ) { /* Just set a flag so we don't get confused by empty contours * -- these can be generated accidentally with the obsolete * NextContour() interface. */ tess->emptyCache = TRUE; }}void GLAPIENTRYgluTessEndContour( GLUtesselator *tess ){ RequireState( tess, T_IN_CONTOUR ); tess->state = T_IN_POLYGON;}void GLAPIENTRYgluTessEndPolygon( GLUtesselator *tess ){ GLUmesh *mesh; if (setjmp(tess->env) != 0) { /* come back here if out of memory */ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); return; } RequireState( tess, T_IN_POLYGON ); tess->state = T_DORMANT; if( tess->mesh == NULL ) { if( ! tess->flagBoundary && tess->callMesh == &noMesh ) { /* Try some special code to make the easy cases go quickly * (eg. convex polygons). This code does NOT handle multiple contours, * intersections, edge flags, and of course it does not generate * an explicit mesh either. */ if( __gl_renderCache( tess )) { tess->polygonData= NULL; return; } } if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/ } /* Determine the polygon normal and project vertices onto the plane * of the polygon. */ __gl_projectPolygon( tess ); /* __gl_computeInterior( tess ) computes the planar arrangement specified * by the given contours, and further subdivides this arrangement * into regions. Each region is marked "inside" if it belongs * to the polygon, according to the rule given by tess->windingRule. * Each interior region is guaranteed be monotone. */ if ( !__gl_computeInterior( tess ) ) { longjmp(tess->env,1); /* could've used a label */ } mesh = tess->mesh; if( ! tess->fatalError ) { int rc = 1; /* If the user wants only the boundary contours, we throw away all edges * except those which separate the interior from the exterior. * Otherwise we tessellate all the regions marked "inside". */ if( tess->boundaryOnly ) { rc = __gl_meshSetWindingNumber( mesh, 1, TRUE ); } else { rc = __gl_meshTessellateInterior( mesh ); } if (rc == 0) longjmp(tess->env,1); /* could've used a label */ __gl_meshCheckMesh( mesh ); if( tess->callBegin != &noBegin || tess->callEnd != &noEnd || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag || tess->callBeginData != &__gl_noBeginData || tess->callEndData != &__gl_noEndData || tess->callVertexData != &__gl_noVertexData || tess->callEdgeFlagData != &__gl_noEdgeFlagData ) { if( tess->boundaryOnly ) { __gl_renderBoundary( tess, mesh ); /* output boundary contours */ } else { __gl_renderMesh( tess, mesh ); /* output strips and fans */ } } if( tess->callMesh != &noMesh ) { /* Throw away the exterior faces, so that all faces are interior. * This way the user doesn't have to check the "inside" flag, * and we don't need to even reveal its existence. It also leaves * the freedom for an implementation to not generate the exterior * faces in the first place. */ __gl_meshDiscardExterior( mesh ); (*tess->callMesh)( mesh ); /* user wants the mesh itself */ tess->mesh = NULL; tess->polygonData= NULL; return; } } __gl_meshDeleteMesh( mesh ); tess->polygonData= NULL; tess->mesh = NULL;}/*XXXblythe unused function*/#if 0void GLAPIENTRYgluDeleteMesh( GLUmesh *mesh ){ __gl_meshDeleteMesh( mesh );}#endif/*******************************************************//* Obsolete calls -- for backward compatibility */void GLAPIENTRYgluBeginPolygon( GLUtesselator *tess ){ gluTessBeginPolygon( tess, NULL ); gluTessBeginContour( tess );}/*ARGSUSED*/void GLAPIENTRYgluNextContour( GLUtesselator *tess, GLenum type ){ gluTessEndContour( tess ); gluTessBeginContour( tess );}void GLAPIENTRYgluEndPolygon( GLUtesselator *tess ){ gluTessEndContour( tess ); gluTessEndPolygon( tess );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -