several small fixes in polygon code
[swftools.git] / lib / gfxpoly / poly.c
index 7036a61..ca81be1 100644 (file)
 static gfxpoly_t*current_polygon = 0;
 void gfxpoly_fail(char*expr, char*file, int line, const char*function)
 {
-    if(!current_polygon) {fprintf(stderr, "error outside polygon\n");exit(1);}
+    if(!current_polygon) {
+       fprintf(stderr, "assert(%s) failed in %s in line %d: %s\n", expr, file, line, function);
+       exit(1);
+    }
 
     void*md5 = init_md5();
     
@@ -110,15 +113,21 @@ static int compare_events(const void*_a,const void*_b)
     /* we need to schedule end after intersect (so that a segment about
        to end has a chance to tear up a few other segs first) and start
        events after end (in order not to confuse the intersection check, which
-       assumes there's an actual y overlap between active segments)). 
+       assumes there's an actual y overlap between active segments, and 
+       because ending segments in the active list make it difficult to insert
+       starting segments at the right position)). 
        Horizontal lines come last, because the only purpose
        they have is to create snapping coordinates for the segments (still)
        existing in this scanline.
     */
     d = b->type - a->type;
     if(d) return d;
-    d = b->p.x - a->p.x;
-    return d;
+    return 0;
+
+    /* I don't see any reason why we would need to order by x- at least as long
+       as we do horizontal lines in a seperate pass */
+    //d = b->p.x - a->p.x;
+    //return d;
 }
 
 gfxpoly_t* gfxpoly_new(double gridsize)
@@ -186,6 +195,7 @@ void gfxpoly_dump(gfxpoly_t*poly)
 {
     edge_t* s = poly->edges;
     double g = poly->gridsize;
+    fprintf(stderr, "polyon %08x (gridsize: %f)\n", poly, poly->gridsize);
     while(s) {
         fprintf(stderr, "(%f,%f) -> (%f,%f)\n", s->a.x*g, s->a.y*g, s->b.x*g, s->b.y*g);
         s = s->next;
@@ -358,7 +368,6 @@ static void schedule_crossing(status_t*status, segment_t*s1, segment_t*s2)
     /* the code that's required (and the checks you can perform) before
        it can be said with 100% certainty that we indeed have a valid crossing
        amazes me every time. -mk */
-
 #ifdef CHECKS
     assert(s1!=s2);
     assert(s1->right == s2);
@@ -596,7 +605,6 @@ static void segrange_test_segment_min(segrange_t*range, segment_t*seg, int32_t y
     /* we need to calculate the xpos anew (and can't use start coordinate or
        intersection coordinate), because we need the xpos exactly at the end of
        this scanline.
-       TODO: might be faster to use XPOS_COMPARE here (see also _max)
      */
     double x = XPOS(seg, y);
     if(!range->segmin || x<range->xmin) {
@@ -652,7 +660,7 @@ static void add_points_to_positively_sloped_segments(status_t*status, int32_t y,
                     //break;
                 }
             }
-            seg = actlist_right(status->actlist, seg);
+            seg = seg->right;
         }
     }
     segrange_test_segment_min(range, first, y);
@@ -691,7 +699,7 @@ static void add_points_to_negatively_sloped_segments(status_t*status, int32_t y,
                     //break;
                 }
             }
-            seg = actlist_left(status->actlist, seg);
+            seg = seg->left;
         }
     }
     segrange_test_segment_min(range, last, y);
@@ -721,6 +729,7 @@ static void add_points_to_ending_segments(status_t*status, int32_t y)
 
         if(status->xrow->num == 1) {
             // shortcut
+           assert(seg->b.x == status->xrow->x[0]);
             point_t p = {status->xrow->x[0], y};
             insert_point_into_segment(status, seg, p);
         } else {
@@ -798,7 +807,7 @@ static void recalculate_windings(status_t*status, segrange_t*range)
 #endif
 
     if(end)
-        end = actlist_right(status->actlist, end);
+        end = end->right;
     while(s!=end) {
 #ifndef CHECKS
         if(s->changed)
@@ -888,12 +897,13 @@ static void event_apply(status_t*status, event_t*e)
             assert(!dict_contains(status->intersecting_segs, s));
             assert(!dict_contains(status->segs_with_point, s));
 #endif
-            segment_t*left = actlist_left(status->actlist, s);
-            segment_t*right = actlist_right(status->actlist, s);
+            segment_t*left = s->left;
+            segment_t*right = s->right;
             actlist_delete(status->actlist, s);
             if(left && right)
                 schedule_crossing(status, left, right);
 
+           /* schedule segment for xrow handling */
             s->left = 0; s->right = status->ending_segments;
             status->ending_segments = s;
             break;
@@ -906,8 +916,8 @@ static void event_apply(status_t*status, event_t*e)
             segment_t*s = e->s1;
            assert(e->p.x == s->a.x && e->p.y == s->a.y);
             actlist_insert(status->actlist, s->a, s->b, s);
-            segment_t*left = actlist_left(status->actlist, s);
-            segment_t*right = actlist_right(status->actlist, s);
+            segment_t*left = s->left;
+            segment_t*right = s->right;
             if(left)
                 schedule_crossing(status, left, s);
             if(right)
@@ -920,10 +930,11 @@ static void event_apply(status_t*status, event_t*e)
 #ifdef DEBUG
             event_dump(e);
 #endif
-            if(actlist_right(status->actlist, e->s1) == e->s2 &&
-               actlist_left(status->actlist, e->s2) == e->s1) {
+            if(e->s1->right == e->s2) {
+               assert(e->s2->left == e->s1);
                 exchange_two(status, e);
             } else {
+               assert(e->s2->left != e->s1);
 #ifdef DEBUG
                fprintf(stderr, "Ignore this crossing ([%d] not next to [%d])\n", e->s1->nr, e->s2->nr);
 #endif
@@ -999,18 +1010,18 @@ static void add_horizontals(gfxpoly_t*poly, windrule_t*windrule, windcontext_t*c
                assert(x<e->p.x);
                 edge_t*l= malloc(sizeof(edge_t));
                 l->a.y = l->b.y = y;
-               /* TODO: strictly speaking we need to draw from low x to high x so that left/right fillstyles add up
-                        (because the horizontal line's fill style controls the area *below* the line)
+               /* we draw from low x to high x so that left/right fillstyles add up
+                   (because the horizontal line's fill style controls the area *below* the line)
                 */
-                l->a.x = x;
-                l->b.x = e->p.x;
+                l->a.x = e->p.x;
+                l->b.x = x;
                 l->next = poly->edges;
                 poly->edges = l;
 #ifdef CHECKS
                /* the output should always be intersection free polygons, so check this horizontal
                   line isn't hacking through any segments in the active list */
-               segment_t* start = actlist_find(actlist, l->a, l->a);
-               segment_t* s = actlist_find(actlist, l->b, l->b);
+               segment_t* start = actlist_find(actlist, l->b, l->b);
+               segment_t* s = actlist_find(actlist, l->a, l->a);
                while(s!=start) {
                    assert(s->a.y == y || s->b.y == y);
                    s = s->left;
@@ -1020,7 +1031,6 @@ static void add_horizontals(gfxpoly_t*poly, windrule_t*windrule, windcontext_t*c
             segment_t*left = 0;
             segment_t*s = e->s1;
 
-            windstate_t before,after;
             switch(e->type) {
                 case EVENT_START: {
                    assert(e->p.x == s->a.x && e->p.y == s->a.y);
@@ -1032,17 +1042,11 @@ static void add_horizontals(gfxpoly_t*poly, windrule_t*windrule, windcontext_t*c
                     e.s2 = 0;
                     heap_put(queue, &e);
                     left = actlist_left(actlist, s);
-
-                    before = left?left->wind:windrule->start(context);
-                    after = s->wind = windrule->add(context, before, s->fs, s->dir, s->polygon_nr);
                     break;
                 }
                 case EVENT_END: {
                     left = actlist_left(actlist, s);
                     actlist_delete(actlist, s);
-
-                    before = s->wind;
-                    after = left?left->wind:windrule->start(context);
                     break;
                 }
                 default: assert(0);
@@ -1051,12 +1055,11 @@ static void add_horizontals(gfxpoly_t*poly, windrule_t*windrule, windcontext_t*c
             x = e->p.x;
             fill ^= 1;//(before.is_filled != after.is_filled);
 #ifdef DEBUG
-            fprintf(stderr, "%d) event=%s[%d] left:[%d] x:%d before:%d after:%d\n",
+            fprintf(stderr, "%d) event=%s[%d] left:[%d] x:%d\n",
                     y, e->type==EVENT_START?"start":"end",
                     s->nr,
                     left?left->nr:-1,
-                    x,
-                    before.is_filled, after.is_filled);
+                    x);
 #endif
 
             if(e->type == EVENT_END)