-static void add_horizontals(gfxpoly_t*poly, windrule_t*windrule, windcontext_t*context)
-{
- /*
- |..| |...........| | |
- |..| |...........| | |
- |..+ + +..| +--+ +--+
- |...........| |..| | |
- |...........| |..| | |
- */
-
-#ifdef DEBUG
- fprintf(stderr, "========================================================================\n");
-#endif
- hqueue_t hqueue;
- hqueue_init(&hqueue);
- gfxpoly_enqueue(poly, 0, &hqueue, 0);
-
- actlist_t* actlist = actlist_new();
-
- event_t*e = hqueue_get(&hqueue);
- while(e) {
- int32_t y = e->p.y;
- int32_t x = 0;
- windstate_t w = windrule->start(context);
-#ifdef DEBUG
- fprintf(stderr, "HORIZONTALS ----------------------------------- %d\n", y);
- actlist_dump(actlist, y-1);
-#endif
-#ifdef CHECKS
- actlist_verify(actlist, y-1);
-#endif
- edgestyle_t*fill = 0;
- edgestyle_t*fill2 = 0;
-
- do {
- assert(e->s1->fs_orig);
- if(fill && x != e->p.x) {
-#ifdef DEBUG
- fprintf(stderr, "%d) draw horizontal line from %d to %d\n", y, x, e->p.x);
-#endif
- assert(x<e->p.x);
-
- gfxpolystroke_t*stroke = rfx_calloc(sizeof(gfxpolystroke_t));
- stroke->next = poly->strokes;
- poly->strokes = stroke;
-
- stroke->num_points = 2;
- stroke->points = malloc(sizeof(point_t)*2);
- stroke->dir = DIR_UP; // FIXME
- stroke->fs = fill;
- point_t a,b;
- a.y = b.y = y;
- /* 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)
- */
- a.x = e->p.x;
- b.x = x;
- stroke->points[0] = a;
- stroke->points[1] = b;
-#ifdef CHECKS
- /* the output should always be intersection free polygons, so check this horizontal
- line isn't puncturing any segments in the active list */
- segment_t* start = actlist_find(actlist, b, b);
- segment_t* s = actlist_find(actlist, a, a);
- while(s!=start) {
- assert(s->a.y == y || s->b.y == y);
- s = s->left;
- }
-#endif
- }
-
- /*
- before1 / after1
- -----+-----------
- before2 / after2
- /
- */
-
- edgestyle_t*old_fill = fill;
- windstate_t before1 = w;
- windstate_t after1;
- /* the current horizontal line is between before1 and before2: */
- windstate_t before2 = fill?windrule->add(context, before1, fill, DIR_UNKNOWN, -1):before1;
- windstate_t after2;
-
- segment_t*s = e->s1;
- assert(!e->s2);
-
- switch(e->type) {
- case EVENT_START: {
- after1 = before1;
- after2 = windrule->add(context, before2, s->fs_orig, DIR_UNKNOWN, s->polygon_nr);
- break;
- }
- case EVENT_END: {
- after1 = windrule->add(context, before1, s->fs_orig, DIR_UNKNOWN, s->polygon_nr);
- after2 = before2;
- break;
- }
- default: assert(0);
- }
- fill2 = windrule->diff(&after1, &after2);
-
- segment_t*left = 0;
- switch(e->type) {
- case EVENT_START: {
- assert(e->p.x == s->a.x && e->p.y == s->a.y);
- actlist_insert(actlist, s->a, s->b, s);
- event_t* e = event_new();
- e->type = EVENT_END;
- e->p = s->b;
- e->s1 = s;
- e->s2 = 0;
- hqueue_put(&hqueue, e);
- left = actlist_left(actlist, s);
- break;
- }
- case EVENT_END: {
- left = actlist_left(actlist, s);
- actlist_delete(actlist, s);
- advance_stroke(0, &hqueue, s->stroke, s->polygon_nr, s->stroke_pos);
- break;
- }
- default: assert(0);
- }
-
- x = e->p.x;
-#ifdef CHECKS
- if(windrule==&windrule_evenodd) {
- fill = fill?0:&edgestyle_default;
- if(!!fill != !!fill2) {
- segment_dump(s);
- event_dump(e);
- printf("at y=%d x=%d (hline:%p)\n", e->p.y, x, old_fill);
- if(e->type==EVENT_END) {
- printf(" %9p\n", s->fs_orig);
- printf(" |\n");
- }
- printf(" %3d %c%2d \n", before1.is_filled, e->type==EVENT_END?'|':' ', after1.is_filled);
- printf("%12p -----+----- %p\n", old_fill, fill2);
- printf(" %3d %c%2d \n", before2.is_filled, e->type==EVENT_START?'|':' ', after2.is_filled);
- if(e->type==EVENT_START) {
- printf(" |\n");
- printf(" %9p\n", s->fs_orig);
- }
- }
- assert(!!fill == !!fill2);
- }
-#endif
-
-#ifdef DEBUG
- 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);
-#endif
-
- if(e->type == EVENT_END)
- segment_destroy(s);
-
- event_free(e);
- e = hqueue_get(&hqueue);
- } while(e && y == e->p.y);
-
-#ifdef CHECKS
- edgestyle_t*bleeding = fill;
- assert(!bleeding);
-#endif
- }
-
- actlist_destroy(actlist);
- hqueue_destroy(&hqueue);
-}
-