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 );