56 #ifdef FOR_TRITE_TEST_PROGRAM 
   57 extern void DebugEvent( GLUtesselator *tess );
 
   59 #define DebugEvent( tess ) 
   94 #define MAX(x,y)  ((x) >= (y) ? (x) : (y)) 
   95 #define MIN(x,y)  ((x) <= (y) ? (x) : (y)) 
  100 #define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \ 
  101                                  eDst->Sym->winding += eSrc->Sym->winding) 
  103 static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent );
 
  104 static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp );
 
  105 static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp );
 
  107 static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1,
 
  121   GLUvertex *
event = tess->event;
 
  122   GLUhalfEdge *e1, *e2;
 
  128   if( e1->Dst == event ) {
 
  129     if( e2->Dst == event ) {
 
  133       if( VertLeq( e1->Org, e2->Org )) {
 
  134    return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0;
 
  136       return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0;
 
  138     return EdgeSign( e2->Dst, event, e2->Org ) <= 0;
 
  140   if( e2->Dst == event ) {
 
  141     return EdgeSign( e1->Dst, event, e1->Org ) >= 0;
 
  145   t1 = EdgeEval( e1->Dst, event, e1->Org );
 
  146   t2 = EdgeEval( e2->Dst, event, e2->Org );
 
  151 static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg )
 
  153   if( reg->fixUpperEdge ) {
 
  158     assert( reg->eUp->winding == 0 );
 
  160   reg->eUp->activeRegion = NULL;
 
  161   dictDelete( tess->dict, reg->nodeUp ); 
 
  166 static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge )
 
  171   assert( reg->fixUpperEdge );
 
  172   if ( !__gl_meshDelete( reg->eUp ) ) 
return 0;
 
  173   reg->fixUpperEdge = FALSE;
 
  175   newEdge->activeRegion = reg;
 
  180 static ActiveRegion *TopLeftRegion( ActiveRegion *reg )
 
  182   GLUvertex *org = reg->eUp->Org;
 
  187     reg = RegionAbove( reg );
 
  188   } 
while( reg->eUp->Org == org );
 
  193   if( reg->fixUpperEdge ) {
 
  194     e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext );
 
  195     if (e == NULL) 
return NULL;
 
  196     if ( !FixUpperEdge( reg, e ) ) 
return NULL;
 
  197     reg = RegionAbove( reg );
 
  202 static ActiveRegion *TopRightRegion( ActiveRegion *reg )
 
  204   GLUvertex *dst = reg->eUp->Dst;
 
  208     reg = RegionAbove( reg );
 
  209   } 
while( reg->eUp->Dst == dst );
 
  213 static ActiveRegion *AddRegionBelow( GLUtesselator *tess,
 
  214                  ActiveRegion *regAbove,
 
  215                  GLUhalfEdge *eNewUp )
 
  223   ActiveRegion *regNew = (ActiveRegion *)memAlloc( 
sizeof( ActiveRegion ));
 
  224   if (regNew == NULL) longjmp(tess->env,1);
 
  226   regNew->eUp = eNewUp;
 
  228   regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew );
 
  229   if (regNew->nodeUp == NULL) longjmp(tess->env,1);
 
  230   regNew->fixUpperEdge = FALSE;
 
  231   regNew->sentinel = FALSE;
 
  232   regNew->dirty = FALSE;
 
  234   eNewUp->activeRegion = regNew;
 
  238 static GLboolean IsWindingInside( GLUtesselator *tess, 
int n )
 
  240   switch( tess->windingRule ) {
 
  241   case GLU_TESS_WINDING_ODD:
 
  243   case GLU_TESS_WINDING_NONZERO:
 
  245   case GLU_TESS_WINDING_POSITIVE:
 
  247   case GLU_TESS_WINDING_NEGATIVE:
 
  249   case GLU_TESS_WINDING_ABS_GEQ_TWO:
 
  250     return (n >= 2) || (n <= -2);
 
  259 static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg )
 
  261   reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding;
 
  262   reg->inside = IsWindingInside( tess, reg->windingNumber );
 
  266 static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg )
 
  275   GLUhalfEdge *e = reg->eUp;
 
  276   GLUface *f = e->Lface;
 
  278   f->inside = reg->inside;
 
  280   DeleteRegion( tess, reg );
 
  284 static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess,
 
  285           ActiveRegion *regFirst, ActiveRegion *regLast )
 
  299   ActiveRegion *reg, *regPrev;
 
  300   GLUhalfEdge *e, *ePrev;
 
  303   ePrev = regFirst->eUp;
 
  304   while( regPrev != regLast ) {
 
  305     regPrev->fixUpperEdge = FALSE;  
 
  306     reg = RegionBelow( regPrev );
 
  308     if( e->Org != ePrev->Org ) {
 
  309       if( ! reg->fixUpperEdge ) {
 
  316    FinishRegion( tess, regPrev );
 
  322       e = __gl_meshConnect( ePrev->Lprev, e->Sym );
 
  323       if (e == NULL) longjmp(tess->env,1);
 
  324       if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1);
 
  328     if( ePrev->Onext != e ) {
 
  329       if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
 
  330       if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1);
 
  332     FinishRegion( tess, regPrev );  
 
  340 static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp,
 
  341        GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft,
 
  354   ActiveRegion *reg, *regPrev;
 
  355   GLUhalfEdge *e, *ePrev;
 
  356   int firstTime = TRUE;
 
  361     assert( VertLeq( e->Org, e->Dst ));
 
  362     AddRegionBelow( tess, regUp, e->Sym );
 
  364   } 
while ( e != eLast );
 
  370   if( eTopLeft == NULL ) {
 
  371     eTopLeft = RegionBelow( regUp )->eUp->Rprev;
 
  376     reg = RegionBelow( regPrev );
 
  378     if( e->Org != ePrev->Org ) 
break;
 
  380     if( e->Onext != ePrev ) {
 
  382       if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
 
  383       if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1);
 
  386     reg->windingNumber = regPrev->windingNumber - e->winding;
 
  387     reg->inside = IsWindingInside( tess, reg->windingNumber );
 
  392     regPrev->dirty = TRUE;
 
  393     if( ! firstTime && CheckForRightSplice( tess, regPrev )) {
 
  394       AddWinding( e, ePrev );
 
  395       DeleteRegion( tess, regPrev );
 
  396       if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1);
 
  402   regPrev->dirty = TRUE;
 
  403   assert( regPrev->windingNumber - e->winding == reg->windingNumber );
 
  407     WalkDirtyRegions( tess, regPrev );
 
  412 static void CallCombine( GLUtesselator *tess, GLUvertex *isect,
 
  413           void *data[4], GLfloat weights[4], 
int needed )
 
  418   coords[0] = isect->coords[0];
 
  419   coords[1] = isect->coords[1];
 
  420   coords[2] = isect->coords[2];
 
  423   CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data );
 
  424   if( isect->data == NULL ) {
 
  426       isect->data = data[0];
 
  427     } 
else if( ! tess->fatalError ) {
 
  432       CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK );
 
  433       tess->fatalError = TRUE;
 
  438 static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1,
 
  445   void *data[4] = { NULL, NULL, NULL, NULL };
 
  446   GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 };
 
  448   data[0] = e1->Org->data;
 
  449   data[1] = e2->Org->data;
 
  450   CallCombine( tess, e1->Org, data, weights, FALSE );
 
  451   if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1);
 
  454 static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst,
 
  464   GLdouble t1 = VertL1dist( org, isect );
 
  465   GLdouble t2 = VertL1dist( dst, isect );
 
  467   weights[0] = 0.5 * t2 / (t1 + t2);
 
  468   weights[1] = 0.5 * t1 / (t1 + t2);
 
  469   isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0];
 
  470   isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1];
 
  471   isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2];
 
  475 static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect,
 
  476        GLUvertex *orgUp, GLUvertex *dstUp,
 
  477        GLUvertex *orgLo, GLUvertex *dstLo )
 
  487   data[0] = orgUp->data;
 
  488   data[1] = dstUp->data;
 
  489   data[2] = orgLo->data;
 
  490   data[3] = dstLo->data;
 
  492   isect->coords[0] = isect->coords[1] = isect->coords[2] = 0;
 
  493   VertexWeights( isect, orgUp, dstUp, &weights[0] );
 
  494   VertexWeights( isect, orgLo, dstLo, &weights[2] );
 
  496   CallCombine( tess, isect, data, weights, TRUE );
 
  499 static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp )
 
  526   ActiveRegion *regLo = RegionBelow(regUp);
 
  527   GLUhalfEdge *eUp = regUp->eUp;
 
  528   GLUhalfEdge *eLo = regLo->eUp;
 
  530   if( VertLeq( eUp->Org, eLo->Org )) {
 
  531     if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) 
return FALSE;
 
  534     if( ! VertEq( eUp->Org, eLo->Org )) {
 
  536       if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
 
  537       if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1);
 
  538       regUp->dirty = regLo->dirty = TRUE;
 
  540     } 
else if( eUp->Org != eLo->Org ) {
 
  542       pqDelete( tess->pq, eUp->Org->pqHandle ); 
 
  543       SpliceMergeVertices( tess, eLo->Oprev, eUp );
 
  546     if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) 
return FALSE;
 
  549     RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
 
  550     if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
 
  551     if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
 
  556 static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp )
 
  576   ActiveRegion *regLo = RegionBelow(regUp);
 
  577   GLUhalfEdge *eUp = regUp->eUp;
 
  578   GLUhalfEdge *eLo = regLo->eUp;
 
  581   assert( ! VertEq( eUp->Dst, eLo->Dst ));
 
  583   if( VertLeq( eUp->Dst, eLo->Dst )) {
 
  584     if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) 
return FALSE;
 
  587     RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
 
  588     e = __gl_meshSplitEdge( eUp );
 
  589     if (e == NULL) longjmp(tess->env,1);
 
  590     if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1);
 
  591     e->Lface->inside = regUp->inside;
 
  593     if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) 
return FALSE;
 
  596     regUp->dirty = regLo->dirty = TRUE;
 
  597     e = __gl_meshSplitEdge( eLo );
 
  598     if (e == NULL) longjmp(tess->env,1);
 
  599     if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1);
 
  600     e->Rface->inside = regUp->inside;
 
  606 static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp )
 
  617   ActiveRegion *regLo = RegionBelow(regUp);
 
  618   GLUhalfEdge *eUp = regUp->eUp;
 
  619   GLUhalfEdge *eLo = regLo->eUp;
 
  620   GLUvertex *orgUp = eUp->Org;
 
  621   GLUvertex *orgLo = eLo->Org;
 
  622   GLUvertex *dstUp = eUp->Dst;
 
  623   GLUvertex *dstLo = eLo->Dst;
 
  624   GLdouble tMinUp, tMaxLo;
 
  625   GLUvertex isect, *orgMin;
 
  628   assert( ! VertEq( dstLo, dstUp ));
 
  629   assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 );
 
  630   assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 );
 
  631   assert( orgUp != tess->event && orgLo != tess->event );
 
  632   assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge );
 
  634   if( orgUp == orgLo ) 
return FALSE;   
 
  636   tMinUp = MIN( orgUp->t, dstUp->t );
 
  637   tMaxLo = MAX( orgLo->t, dstLo->t );
 
  638   if( tMinUp > tMaxLo ) 
return FALSE;  
 
  640   if( VertLeq( orgUp, orgLo )) {
 
  641     if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) 
return FALSE;
 
  643     if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) 
return FALSE;
 
  649   __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect );
 
  651   assert( MIN( orgUp->t, dstUp->t ) <= isect.t );
 
  652   assert( isect.t <= MAX( orgLo->t, dstLo->t ));
 
  653   assert( MIN( dstLo->s, dstUp->s ) <= isect.s );
 
  654   assert( isect.s <= MAX( orgLo->s, orgUp->s ));
 
  656   if( VertLeq( &isect, tess->event )) {
 
  663     isect.s = tess->event->s;
 
  664     isect.t = tess->event->t;
 
  672   orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo;
 
  673   if( VertLeq( orgMin, &isect )) {
 
  678   if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) {
 
  680     (void) CheckForRightSplice( tess, regUp );
 
  684   if(  (! VertEq( dstUp, tess->event )
 
  685      && EdgeSign( dstUp, tess->event, &isect ) >= 0)
 
  686       || (! VertEq( dstLo, tess->event )
 
  687      && EdgeSign( dstLo, tess->event, &isect ) <= 0 ))
 
  693     if( dstLo == tess->event ) {
 
  695       if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
 
  696       if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1);
 
  697       regUp = TopLeftRegion( regUp );
 
  698       if (regUp == NULL) longjmp(tess->env,1);
 
  699       eUp = RegionBelow(regUp)->eUp;
 
  700       FinishLeftRegions( tess, RegionBelow(regUp), regLo );
 
  701       AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE );
 
  704     if( dstUp == tess->event ) {
 
  706       if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
 
  707       if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1);
 
  709       regUp = TopRightRegion( regUp );
 
  710       e = RegionBelow(regUp)->eUp->Rprev;
 
  711       regLo->eUp = eLo->Oprev;
 
  712       eLo = FinishLeftRegions( tess, regLo, NULL );
 
  713       AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE );
 
  720     if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) {
 
  721       RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
 
  722       if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
 
  723       eUp->Org->s = tess->event->s;
 
  724       eUp->Org->t = tess->event->t;
 
  726     if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) {
 
  727       regUp->dirty = regLo->dirty = TRUE;
 
  728       if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
 
  729       eLo->Org->s = tess->event->s;
 
  730       eLo->Org->t = tess->event->t;
 
  744   if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
 
  745   if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
 
  746   if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
 
  747   eUp->Org->s = isect.s;
 
  748   eUp->Org->t = isect.t;
 
  749   eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org ); 
 
  750   if (eUp->Org->pqHandle == LONG_MAX) {
 
  751      pqDeletePriorityQ(tess->pq);   
 
  753      longjmp(tess->env,1);
 
  755   GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo );
 
  756   RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE;
 
  760 static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp )
 
  770   ActiveRegion *regLo = RegionBelow(regUp);
 
  771   GLUhalfEdge *eUp, *eLo;
 
  775     while( regLo->dirty ) {
 
  777       regLo = RegionBelow(regLo);
 
  779     if( ! regUp->dirty ) {
 
  781       regUp = RegionAbove( regUp );
 
  782       if( regUp == NULL || ! regUp->dirty ) {
 
  787     regUp->dirty = FALSE;
 
  791     if( eUp->Dst != eLo->Dst ) {
 
  793       if( CheckForLeftSplice( tess, regUp )) {
 
  799    if( regLo->fixUpperEdge ) {
 
  800      DeleteRegion( tess, regLo );
 
  801      if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1);
 
  802      regLo = RegionBelow( regUp );
 
  804    } 
else if( regUp->fixUpperEdge ) {
 
  805      DeleteRegion( tess, regUp );
 
  806      if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
 
  807      regUp = RegionAbove( regLo );
 
  812     if( eUp->Org != eLo->Org ) {
 
  813       if(    eUp->Dst != eLo->Dst
 
  814      && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge
 
  815      && (eUp->Dst == tess->event || eLo->Dst == tess->event) )
 
  825    if( CheckForIntersect( tess, regUp )) {
 
  833    (void) CheckForRightSplice( tess, regUp );
 
  836     if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) {
 
  838       AddWinding( eLo, eUp );
 
  839       DeleteRegion( tess, regUp );
 
  840       if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
 
  841       regUp = RegionAbove( regLo );
 
  847 static void ConnectRightVertex( GLUtesselator *tess, ActiveRegion *regUp,
 
  848             GLUhalfEdge *eBottomLeft )
 
  882   GLUhalfEdge *eTopLeft = eBottomLeft->Onext;
 
  883   ActiveRegion *regLo = RegionBelow(regUp);
 
  884   GLUhalfEdge *eUp = regUp->eUp;
 
  885   GLUhalfEdge *eLo = regLo->eUp;
 
  886   int degenerate = FALSE;
 
  888   if( eUp->Dst != eLo->Dst ) {
 
  889     (void) CheckForIntersect( tess, regUp );
 
  895   if( VertEq( eUp->Org, tess->event )) {
 
  896     if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1);
 
  897     regUp = TopLeftRegion( regUp );
 
  898     if (regUp == NULL) longjmp(tess->env,1);
 
  899     eTopLeft = RegionBelow( regUp )->eUp;
 
  900     FinishLeftRegions( tess, RegionBelow(regUp), regLo );
 
  903   if( VertEq( eLo->Org, tess->event )) {
 
  904     if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1);
 
  905     eBottomLeft = FinishLeftRegions( tess, regLo, NULL );
 
  909     AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
 
  916   if( VertLeq( eLo->Org, eUp->Org )) {
 
  921   eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew );
 
  922   if (eNew == NULL) longjmp(tess->env,1);
 
  927   AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE );
 
  928   eNew->Sym->activeRegion->fixUpperEdge = TRUE;
 
  929   WalkDirtyRegions( tess, regUp );
 
  939 #define TOLERANCE_NONZERO  FALSE 
  941 static void ConnectLeftDegenerate( GLUtesselator *tess,
 
  942                ActiveRegion *regUp, GLUvertex *vEvent )
 
  949   GLUhalfEdge *e, *eTopLeft, *eTopRight, *eLast;
 
  953   if( VertEq( e->Org, vEvent )) {
 
  957     assert( TOLERANCE_NONZERO );
 
  958     SpliceMergeVertices( tess, e, vEvent->anEdge );
 
  962   if( ! VertEq( e->Dst, vEvent )) {
 
  964     if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1);
 
  965     if( regUp->fixUpperEdge ) {
 
  967       if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1);
 
  968       regUp->fixUpperEdge = FALSE;
 
  970     if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1);
 
  971     SweepEvent( tess, vEvent ); 
 
  978   assert( TOLERANCE_NONZERO );
 
  979   regUp = TopRightRegion( regUp );
 
  980   reg = RegionBelow( regUp );
 
  981   eTopRight = reg->eUp->Sym;
 
  982   eTopLeft = eLast = eTopRight->Onext;
 
  983   if( reg->fixUpperEdge ) {
 
  987     assert( eTopLeft != eTopRight );   
 
  988     DeleteRegion( tess, reg );
 
  989     if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1);
 
  990     eTopRight = eTopLeft->Oprev;
 
  992   if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1);
 
  993   if( ! EdgeGoesLeft( eTopLeft )) {
 
  997   AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE );
 
 1001 static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent )
 
 1018   ActiveRegion *regUp, *regLo, *reg;
 
 1019   GLUhalfEdge *eUp, *eLo, *eNew;
 
 1025   tmp.eUp = vEvent->anEdge->Sym;
 
 1027   regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp ));
 
 1028   regLo = RegionBelow( regUp );
 
 1033   if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) {
 
 1034     ConnectLeftDegenerate( tess, regUp, vEvent );
 
 1041   reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo;
 
 1043   if( regUp->inside || reg->fixUpperEdge) {
 
 1044     if( reg == regUp ) {
 
 1045       eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext );
 
 1046       if (eNew == NULL) longjmp(tess->env,1);
 
 1048       GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge);
 
 1049       if (tempHalfEdge == NULL) longjmp(tess->env,1);
 
 1051       eNew = tempHalfEdge->Sym;
 
 1053     if( reg->fixUpperEdge ) {
 
 1054       if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1);
 
 1056       ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew ));
 
 1058     SweepEvent( tess, vEvent );
 
 1063     AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE );
 
 1068 static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent )
 
 1074   ActiveRegion *regUp, *reg;
 
 1075   GLUhalfEdge *e, *eTopLeft, *eBottomLeft;
 
 1077   tess->event = vEvent;    
 
 1085   while( e->activeRegion == NULL ) {
 
 1087     if( e == vEvent->anEdge ) {
 
 1089       ConnectLeftVertex( tess, vEvent );
 
 1101   regUp = TopLeftRegion( e->activeRegion );
 
 1102   if (regUp == NULL) longjmp(tess->env,1);
 
 1103   reg = RegionBelow( regUp );
 
 1104   eTopLeft = reg->eUp;
 
 1105   eBottomLeft = FinishLeftRegions( tess, reg, NULL );
 
 1112   if( eBottomLeft->Onext == eTopLeft ) {
 
 1114     ConnectRightVertex( tess, regUp, eBottomLeft );
 
 1116     AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
 
 1126 #define SENTINEL_COORD  (4 * GLU_TESS_MAX_COORD) 
 1128 static void AddSentinel( GLUtesselator *tess, GLdouble t )
 
 1135   ActiveRegion *reg = (ActiveRegion *)memAlloc( 
sizeof( ActiveRegion ));
 
 1136   if (reg == NULL) longjmp(tess->env,1);
 
 1138   e = __gl_meshMakeEdge( tess->mesh );
 
 1139   if (e == NULL) longjmp(tess->env,1);
 
 1141   e->Org->s = SENTINEL_COORD;
 
 1143   e->Dst->s = -SENTINEL_COORD;
 
 1145   tess->event = e->Dst;    
 
 1148   reg->windingNumber = 0;
 
 1149   reg->inside = FALSE;
 
 1150   reg->fixUpperEdge = FALSE;
 
 1151   reg->sentinel = TRUE;
 
 1153   reg->nodeUp = dictInsert( tess->dict, reg ); 
 
 1154   if (reg->nodeUp == NULL) longjmp(tess->env,1);
 
 1158 static void InitEdgeDict( GLUtesselator *tess )
 
 1165   tess->dict = dictNewDict( tess, (
int (*)(
void *, DictKey, DictKey)) EdgeLeq );
 
 1166   if (tess->dict == NULL) longjmp(tess->env,1);
 
 1168   AddSentinel( tess, -SENTINEL_COORD );
 
 1169   AddSentinel( tess, SENTINEL_COORD );
 
 1173 static void DoneEdgeDict( GLUtesselator *tess )
 
 1181   while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) {
 
 1187     if( ! reg->sentinel ) {
 
 1188       assert( reg->fixUpperEdge );
 
 1189       assert( ++fixedEdges == 1 );
 
 1191     assert( reg->windingNumber == 0 );
 
 1192     DeleteRegion( tess, reg );
 
 1195   dictDeleteDict( tess->dict ); 
 
 1199 static void RemoveDegenerateEdges( GLUtesselator *tess )
 
 1204   GLUhalfEdge *e, *eNext, *eLnext;
 
 1205   GLUhalfEdge *eHead = &tess->mesh->eHead;
 
 1208   for( e = eHead->next; e != eHead; e = eNext ) {
 
 1212     if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) {
 
 1215       SpliceMergeVertices( tess, eLnext, e );   
 
 1216       if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); 
 
 1220     if( eLnext->Lnext == e ) {
 
 1224    if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; }
 
 1225    if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1);
 
 1227       if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; }
 
 1228       if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1);
 
 1233 static int InitPriorityQ( GLUtesselator *tess )
 
 1240   GLUvertex *v, *vHead;
 
 1243   pq = tess->pq = pqNewPriorityQ( (
int (*)(PQkey, PQkey)) __gl_vertLeq );
 
 1244   if (pq == NULL) 
return 0;
 
 1246   vHead = &tess->mesh->vHead;
 
 1247   for( v = vHead->next; v != vHead; v = v->next ) {
 
 1248     v->pqHandle = pqInsert( pq, v ); 
 
 1249     if (v->pqHandle == LONG_MAX) 
break;
 
 1251   if (v != vHead || !pqInit( pq ) ) { 
 
 1252     pqDeletePriorityQ(tess->pq); 
 
 1261 static void DonePriorityQ( GLUtesselator *tess )
 
 1263   pqDeletePriorityQ( tess->pq ); 
 
 1267 static int RemoveDegenerateFaces( GLUmesh *mesh )
 
 1287   for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
 
 1290     assert( e->Lnext != e );
 
 1292     if( e->Lnext->Lnext == e ) {
 
 1294       AddWinding( e->Onext, e );
 
 1295       if ( !__gl_meshDelete( e ) ) 
return 0;
 
 1301 int __gl_computeInterior( GLUtesselator *tess )
 
 1310   GLUvertex *v, *vNext;
 
 1312   tess->fatalError = FALSE;
 
 1320   RemoveDegenerateEdges( tess );
 
 1321   if ( !InitPriorityQ( tess ) ) 
return 0; 
 
 1322   InitEdgeDict( tess );
 
 1325   while( (v = (GLUvertex *)pqExtractMin( tess->pq )) != NULL ) {
 
 1327       vNext = (GLUvertex *)pqMinimum( tess->pq ); 
 
 1328       if( vNext == NULL || ! VertEq( vNext, v )) 
break;
 
 1344       vNext = (GLUvertex *)pqExtractMin( tess->pq ); 
 
 1345       SpliceMergeVertices( tess, v->anEdge, vNext->anEdge );
 
 1347     SweepEvent( tess, v );
 
 1352   tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org;
 
 1354   DoneEdgeDict( tess );
 
 1355   DonePriorityQ( tess );
 
 1357   if ( !RemoveDegenerateFaces( tess->mesh ) ) 
return 0;
 
 1358   __gl_meshCheckMesh( tess->mesh );