From 222e1b5f320155985bc5cacd3cc63c272e901866 Mon Sep 17 00:00:00 2001 From: Tom Gilbert Date: Sun, 3 Sep 2000 18:04:00 +0000 Subject: [PATCH] Polygon filling. Right now only works for convex polygons. Works with a clipping rect, but highly suboptimally (I'm not doing proper polygon clipping here yet, just clipping slowly on each point drawn - really nasty). There are probably some rounding errors in here. I need to work more on this, but I have *so* little time for the next few weeks. Please don't kill me for this code. It's not finished, but I'm about to move house, and I have to get something working before I pack my PC away. SVN revision: 3303 --- src/rgbadraw.c | 285 ++++++++++++++++++++++++++++++++++++++++++++++++- src/rgbadraw.h | 8 ++ test/main.c | 7 +- 3 files changed, 296 insertions(+), 4 deletions(-) diff --git a/src/rgbadraw.c b/src/rgbadraw.c index 401c96a..a7b5bb0 100644 --- a/src/rgbadraw.c +++ b/src/rgbadraw.c @@ -12,6 +12,8 @@ #define XY_IN_RECT(x, y, rx, ry, rw, rh) \ (((x) >= (rx)) && ((y) >= (ry)) && ((x) <= ((rx) + (rw))) && ((y) <= ((ry) + (rh)))) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + void __imlib_FlipImageHoriz(ImlibImage * im) { @@ -1683,6 +1685,12 @@ __imlib_draw_polygon(ImlibImage * im, ImlibPoly poly, DATA8 r, DATA8 g, if (!poly || !poly->points || (poly->pointcount < 2)) return; + if (poly->filled) + { + __imlib_draw_polygon_filled(im, poly, r, g, b, a, op); + return; + } + for (i = 0; i < poly->pointcount; i++) { if (i < poly->pointcount - 1) @@ -1708,6 +1716,14 @@ __imlib_draw_polygon_clipped(ImlibImage * im, ImlibPoly poly, int clip_xmin, if (!poly || !poly->points || (poly->pointcount < 2)) return; + if (poly->filled) + { + __imlib_draw_polygon_filled_clipped(im, poly, clip_xmin, clip_xmax, + clip_ymin, clip_ymax, r, g, b, a, + op); + return; + } + for (i = 0; i < poly->pointcount; i++) { if (i < poly->pointcount - 1) @@ -1869,7 +1885,8 @@ __imlib_draw_set_point_clipped(ImlibImage * im, int x, int y, int clip_xmin, if ((x >= 0 && x < im->w) && (y >= 0 && y <= im->h)) { if (XY_IN_RECT - (x, y, clip_xmin, clip_ymin, clip_xmax - clip_xmin, clip_ymax - clip_ymin)) + (x, y, clip_xmin, clip_ymin, clip_xmax - clip_xmin, + clip_ymax - clip_ymin)) { p = &(im->data[(im->w * y) + x]); switch (op) @@ -1892,3 +1909,269 @@ __imlib_draw_set_point_clipped(ImlibImage * im, int x, int y, int clip_xmin, } } } + +#define exchange(type, a, b) \ +{ \ + type _t_; \ + _t_ = a; \ + a = b; \ + b = _t_; \ +} + +typedef struct +{ + int x; +} +edgeRec; + +static void +edge(edgeRec * table, ImlibPoint * pt1, ImlibPoint * pt2) +{ + long x, dx; + int idy, iy1, iy2; + + if (pt2->y < pt1->y) + { + exchange(ImlibPoint *, pt1, pt2)} + iy1 = pt1->y; + iy2 = pt2->y; + idy = iy2 - iy1; + if (idy == 0) + { + return; + } + idy = MAX(2, idy - 1); + x = pt1->x; + dx = (pt2->x - pt1->x) / idy; + do + { + table[iy1].x = x; + x += dx; + iy1++; + } + while (iy1 < iy2); +} + +static void +span(ImlibImage * im, int y, edgeRec * pt1, edgeRec * pt2, DATA8 r, DATA8 g, + DATA8 b, DATA8 a, ImlibOp op) +{ + int idx, ix1, ix2; + + if (pt2->x < pt1->x) + { + exchange(edgeRec *, pt1, pt2); + } + ix1 = pt1->x; + ix2 = pt2->x; + idx = ix2 - ix1; + if (idx == 0) + { + return; + } + do + { + __imlib_draw_set_point(im, ix1, y, r, g, b, a, op); + ix1++; + } + while (ix1 < ix2); +} + +static void +span_clipped(ImlibImage * im, int y, edgeRec * pt1, edgeRec * pt2, + int clip_xmin, int clip_xmax, int clip_ymin, int clip_ymax, + DATA8 r, DATA8 g, DATA8 b, DATA8 a, ImlibOp op) +{ + int idx, ix1, ix2; + + if (pt2->x < pt1->x) + { + exchange(edgeRec *, pt1, pt2); + } + ix1 = pt1->x; + ix2 = pt2->x; + idx = ix2 - ix1; + if (idx == 0) + { + return; + } + do + { + __imlib_draw_set_point_clipped(im, ix1, y, clip_xmin, clip_xmax, + clip_ymin, clip_ymax, r, g, b, a, op); + ix1++; + } + while (ix1 < ix2); +} + + +void +__imlib_draw_polygon_filled(ImlibImage * im, ImlibPoly poly, DATA8 r, DATA8 g, + DATA8 b, DATA8 a, ImlibOp op) +{ + long maxy, miny; + int iy1, iy2; + int imaxy, iminy; + int pnt1, pnt2; + int i; + edgeRec *table1, *table2; + + if (poly->pointcount < 3) + { + return; + } + + table1 = malloc(sizeof(edgeRec) * im->h); + table2 = malloc(sizeof(edgeRec) * im->h); + + maxy = miny = poly->points[0].y; + imaxy = iminy = 0; + for (i = 1; i < poly->pointcount; i++) + { + if (poly->points[i].y > maxy) + { + maxy = poly->points[i].y; + imaxy = i; + } + if (poly->points[i].y < miny) + { + miny = poly->points[i].y; + iminy = i; + } + } + iy1 = miny; + iy2 = maxy; + if (iy1 == iy2) + { + return; + } + pnt1 = iminy; + pnt2 = iminy + 1; + if (pnt2 >= poly->pointcount) + { + pnt2 = 0; + } + do + { + edge(table1, &poly->points[pnt1], &poly->points[pnt2]); + pnt1 = pnt2; + pnt2 = pnt2 + 1; + if (pnt2 >= poly->pointcount) + { + pnt2 = 0; + } + } + while (pnt1 != imaxy); + pnt1 = imaxy; + pnt2 = imaxy + 1; + if (pnt2 >= poly->pointcount) + { + pnt2 = 0; + } + do + { + edge(table2, &poly->points[pnt1], &poly->points[pnt2]); + pnt1 = pnt2; + pnt2 = pnt2 + 1; + if (pnt2 >= poly->pointcount) + { + pnt2 = 0; + } + } + while (pnt1 != iminy); + do + { + span(im, iy1, &table1[iy1], &table2[iy1], r, g, b, a, op); + iy1++; + } + while (iy1 < iy2); + free(table1); + free(table2); +} + +void +__imlib_draw_polygon_filled_clipped(ImlibImage * im, ImlibPoly poly, + int clip_xmin, int clip_xmax, + int clip_ymin, int clip_ymax, DATA8 r, + DATA8 g, DATA8 b, DATA8 a, ImlibOp op) +{ + long maxy, miny; + int iy1, iy2; + int imaxy, iminy; + int pnt1, pnt2; + int i; + edgeRec *table1, *table2; + + if (poly->pointcount < 3) + { + return; + } + + table1 = malloc(sizeof(edgeRec) * im->h); + table2 = malloc(sizeof(edgeRec) * im->h); + + maxy = miny = poly->points[0].y; + imaxy = iminy = 0; + for (i = 1; i < poly->pointcount; i++) + { + if (poly->points[i].y > maxy) + { + maxy = poly->points[i].y; + imaxy = i; + } + if (poly->points[i].y < miny) + { + miny = poly->points[i].y; + iminy = i; + } + } + iy1 = miny; + iy2 = maxy; + if (iy1 == iy2) + { + return; + } + pnt1 = iminy; + pnt2 = iminy + 1; + if (pnt2 >= poly->pointcount) + { + pnt2 = 0; + } + do + { + edge(table1, &poly->points[pnt1], &poly->points[pnt2]); + pnt1 = pnt2; + pnt2 = pnt2 + 1; + if (pnt2 >= poly->pointcount) + { + pnt2 = 0; + } + } + while (pnt1 != imaxy); + pnt1 = imaxy; + pnt2 = imaxy + 1; + if (pnt2 >= poly->pointcount) + { + pnt2 = 0; + } + do + { + edge(table2, &poly->points[pnt1], &poly->points[pnt2]); + pnt1 = pnt2; + pnt2 = pnt2 + 1; + if (pnt2 >= poly->pointcount) + { + pnt2 = 0; + } + } + while (pnt1 != iminy); + do + { + span_clipped(im, iy1, &table1[iy1], &table2[iy1], clip_xmin, clip_xmax, + clip_ymin, clip_ymax, r, g, b, a, op); + iy1++; + } + while (iy1 < iy2); + free(table1); + free(table2); +} diff --git a/src/rgbadraw.h b/src/rgbadraw.h index e59c9ae..a265e55 100644 --- a/src/rgbadraw.h +++ b/src/rgbadraw.h @@ -108,4 +108,12 @@ __imlib_draw_ellipse_clipped(ImlibImage * im, int xc, int yc, int aa, int bb, int clip_xmin, int clip_xmax, int clip_ymin, int clip_ymax, DATA8 r, DATA8 g, DATA8 b, DATA8 a, ImlibOp op); +void +__imlib_draw_polygon_filled(ImlibImage * im, ImlibPoly poly, DATA8 r, DATA8 g, + DATA8 b, DATA8 a, ImlibOp op); +void +__imlib_draw_polygon_filled_clipped(ImlibImage * im, ImlibPoly poly, + int clip_xmin, int clip_xmax, + int clip_ymin, int clip_ymax, DATA8 r, + DATA8 g, DATA8 b, DATA8 a, ImlibOp op); #endif diff --git a/test/main.c b/test/main.c index 11edc8f..2611904 100644 --- a/test/main.c +++ b/test/main.c @@ -295,7 +295,7 @@ int main (int argc, char **argv) sec1=(int)timev.tv_sec; /* and stores it so we can time outselves */ usec1=(int)timev.tv_usec; /* we will use this to vary speed of rot */ - poly = imlib_polygon_new(POLY_CLOSED); + poly = imlib_polygon_new(POLY_FILLED); imlib_polygon_add_point(poly, 400,50); imlib_polygon_add_point(poly, 450,100); imlib_polygon_add_point(poly, 350,100); @@ -309,7 +309,7 @@ int main (int argc, char **argv) imlib_polygon_add_point(poly3, 400,250); imlib_polygon_add_point(poly3, 450,300); imlib_polygon_add_point(poly3, 350,300); - + if (loop) { printf("loop\n"); @@ -848,8 +848,9 @@ int main (int argc, char **argv) imlib_context_set_cliprect(0,0,0,0); /* test polygons */ - imlib_context_set_color(255, 255, 255, 255); + imlib_context_set_color(255, 0, 0, 255); imlib_image_draw_polygon(poly); + imlib_context_set_color(255, 255, 255, 255); imlib_image_draw_polygon(poly2); imlib_image_draw_polygon(poly3); imlib_image_draw_rectangle(380,260,50,50);