From b67fde0e945ab1b74d1eb665637498b21c4ba7b9 Mon Sep 17 00:00:00 2001 From: jylam Date: Wed, 27 Aug 2008 11:17:26 +0000 Subject: [PATCH] * Added Wu-Xaolin antialiased lines (Still lacks RGBA32 transparency code, with a fallback to float for now) git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@2777 92316355-f0b4-4df1-b90c-862c8a59935f --- examples/line.c | 11 ++- pipi/paint/aline_template.c | 130 ++++++++++++++++++++++++++++++++++++ pipi/paint/line.c | 108 ++++++++++++++++++++++-------- pipi/pipi.h | 5 +- pipi/pixels.c | 13 ++++ 5 files changed, 236 insertions(+), 31 deletions(-) create mode 100644 pipi/paint/aline_template.c diff --git a/examples/line.c b/examples/line.c index 1de2282..5d63201 100644 --- a/examples/line.c +++ b/examples/line.c @@ -32,12 +32,17 @@ int main(int argc, char *argv[]) newimg = pipi_copy(img); pipi_free(img); + int w = pipi_get_image_width(newimg); + int h = pipi_get_image_height(newimg); + while(count--) { pipi_draw_line(newimg, - rand() % 500, rand() % 500, - rand() % 500, rand() % 500, - rand()); + rand() % w, rand() % h, + rand() % w, rand() % h, + rand(), + 1); } + pipi_save(newimg, dstname); pipi_free(newimg); diff --git a/pipi/paint/aline_template.c b/pipi/paint/aline_template.c new file mode 100644 index 0000000..fc267aa --- /dev/null +++ b/pipi/paint/aline_template.c @@ -0,0 +1,130 @@ +/* + * libpipi Proper image processing implementation library + * Copyright (c) 2004-2008 Sam Hocevar + * 2008 Jean-Yves Lamoureux x1, y1 = s->y1, x2 = s->x2, y2 = s->y2; +float g, xd, yd, xgap, xend, yend, xf, yf, val1, val2; +int x, y, ix1, ix2, iy1, iy2; + +xd = x2 - x1; +yd = y2 - y1; + +/* "Horizontal" line (X greater than Y)*/ +if (fabsf(xd) > fabsf(yd)) { + if (x1 > x2) + { + float tmp; + tmp = x1; x1 = x2; x2 = tmp; + tmp = y1; y1 = y2; y2 = tmp; + xd = (x2-x1); + yd = (y2-y1); + } + g = yd/xd; + + xend = truncf(x1+0.5); + yend = y1 + g*(xend-x1); + xgap = fractinvf(x1+0.5); + ix1 = (int)xend; + iy1 = (int)yend; + val1 = fractinvf(yend)*xgap; + val2 = fractf(yend)*xgap; + + PLOT(ix1, iy1, val1); + PLOT(ix1, iy1+1, val2); + + yf = yend+g; + xend = truncf(x2+0.5); + yend = y2 + g*(xend-x2); + xgap = fractinvf(x2-0.5); + ix2 = (int)xend; + iy2 = (int)yend; + val1 = fractinvf(yend)*xgap; + val2 = fractf(yend)*xgap; + + PLOT(ix2, iy2, val1); + PLOT(ix2, iy2+1, val2); + + for (x = (ix1+1); x < ix2; x++) + { + float focus; + + val1 = fractinvf(yf); + val2 = fractf(yf); + focus = (1.0 - fabsf(val1-val2)); + val1 += 0.3*focus; + val2 += 0.3*focus; + + PLOT(x, yf, val1); + PLOT(x, yf+1, val2); + + yf = yf + g; + } +} +/* "Vertical" line (Y greater than X)*/ +else { + if (x1 > x2) + { + float tmp; + tmp = x1; x1 = x2; x2 = tmp; + tmp = y1; y1 = y2; y2 = tmp; + xd = (x2-x1); + yd = (y2-y1); + } + + g = xd/yd; + + xend = truncf(x1+0.5); + yend = y1 + g*(xend-x1); + xgap = fractf(x1+0.5); + ix1 = (int)xend; + iy1 = (int)yend; + val1 = fractinvf(yend)*xgap; + val2 = fractf(yend)*xgap; + + PLOT(ix1, iy1, val1); + PLOT(ix1, iy1+1, val2); + + xf = xend + g; + + xend = truncf(x2+0.5); + yend = y2 + g*(xend-x2); + xgap = fractinvf(x2-0.5); + ix2 = (int)xend; + iy2 = (int)yend; + val1 = fractinvf(yend)*xgap; + val2 = fractf(yend)*xgap; + + PLOT(ix2, iy2, val1); + PLOT(ix2, iy2+1, val2); + + + for (y = (iy1+1); y < iy2; y++) + { + float focus; + int vx = xf; + val1 = fractinvf(xf); + val2 = fractf(xf); + focus = (1.0 - fabsf(val1-val2)); + val1 += 0.3*focus; + val2 += 0.3*focus; + PLOT(vx, y, val1); + vx++; + PLOT(vx, y, val2); + xf = xf + g; + } +} diff --git a/pipi/paint/line.c b/pipi/paint/line.c index d4e7a28..97d3cd2 100644 --- a/pipi/paint/line.c +++ b/pipi/paint/line.c @@ -48,10 +48,12 @@ static uint8_t clip_bits(pipi_image_t*, int, int); static void draw_aliased_line_u32(pipi_image_t*, struct line*); static void draw_aliased_line_gray(pipi_image_t *img, struct line* s); static void draw_aliased_line_float(pipi_image_t *img, struct line* s); +static void draw_antialiased_line_float(pipi_image_t *img, struct line* s); +static void draw_antialiased_line_gray(pipi_image_t *img, struct line* s); -int pipi_draw_line(pipi_image_t *img , int x1, int y1, int x2, int y2, uint32_t c) +int pipi_draw_line(pipi_image_t *img , int x1, int y1, int x2, int y2, uint32_t c, int aa) { struct line s; s.x1 = x1; @@ -59,28 +61,45 @@ int pipi_draw_line(pipi_image_t *img , int x1, int y1, int x2, int y2, uint32_t s.x2 = x2; s.y2 = y2; - if(img->last_modified == PIPI_PIXELS_RGBA_C) { - uint32_t *dstdata; - dstdata = (uint32_t *)pipi_getpixels(img, PIPI_PIXELS_RGBA_C)->pixels; - s.color32 = c; - s.buf_u32 = dstdata; - s.draw = draw_aliased_line_u32; - } else if(img->last_modified == PIPI_PIXELS_Y_F) { + /* No Transparency routine for u32 yet, fallback to float version */ + if(img->last_modified == PIPI_PIXELS_RGBA_C) + { + if(!aa) + { + uint32_t *dstdata; + dstdata = (uint32_t *)pipi_getpixels(img, PIPI_PIXELS_RGBA_C)->pixels; + s.color32 = c; + s.buf_u32 = dstdata; + s.draw = draw_aliased_line_u32; + } + else + { + float *dstdata; + dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels; + s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */ + s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f; /* XXX FIXME */ + s.colorf[0] = (c&0x000000FF)/255.0f; /* XXX FIXME */ + s.buf_f = dstdata; + s.draw = draw_antialiased_line_float; + } + } + else if(img->last_modified == PIPI_PIXELS_Y_F) + { float *dstdata; dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_Y_F)->pixels; s.colorf[0] = c/255.0f; /* XXX FIXME */ s.buf_f = dstdata; - s.draw = draw_aliased_line_gray; - - - } else { + s.draw = aa==0?draw_aliased_line_gray:draw_antialiased_line_gray; + } + else + { float *dstdata; dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels; - s.colorf[0] = (c&0x00FF0000)/255.0f; /* XXX FIXME */ - s.colorf[1] = (c&0x0000FF00)/255.0f; /* XXX FIXME */ - s.colorf[2] = (c&0x000000FF)/255.0f; /* XXX FIXME */ + s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */ + s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f; /* XXX FIXME */ + s.colorf[0] = (c&0x000000FF)/255.0f; /* XXX FIXME */ s.buf_f = dstdata; - s.draw = draw_aliased_line_float; + s.draw = aa==0?draw_aliased_line_float:draw_antialiased_line_float; } clip_line(img, &s); @@ -94,13 +113,16 @@ int pipi_draw_polyline(pipi_image_t *img, int const x[], int const y[], int i; struct line s; - if(img->last_modified == PIPI_PIXELS_RGBA_C) { + if(img->last_modified == PIPI_PIXELS_RGBA_C) + { uint32_t *dstdata; dstdata = (uint32_t *)pipi_getpixels(img, PIPI_PIXELS_RGBA_C)->pixels; s.color32 = c; s.buf_u32 = dstdata; s.draw = draw_aliased_line_u32; - } else { + } + else + { float *dstdata; dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels; s.colorf[0] = (c&0x00FF0000)/255.0f; /* XXX FIXME */ @@ -204,21 +226,53 @@ static uint8_t clip_bits(pipi_image_t *img, int x, int y) * scan-conversion algorithm. */ static void draw_aliased_line_u32(pipi_image_t *img, struct line* s) { - #undef ASSIGN - #define ASSIGN(x, y, w) s->buf_u32[x+y*w] = s->color32; - #include "line_template.c" +#undef ASSIGN +#define ASSIGN(x, y, w) s->buf_u32[x+y*w] = s->color32; +#include "line_template.c" } static void draw_aliased_line_float(pipi_image_t *img, struct line* s) { - #undef ASSIGN - #define ASSIGN(x, y, w) s->buf_f[(x*4)+y*(w*4)] = s->colorf[0]; \ +#undef ASSIGN +#define ASSIGN(x, y, w) s->buf_f[(x*4)+y*(w*4)] = s->colorf[0]; \ s->buf_f[1 + (x*4)+y*(w*4)] = s->colorf[1]; \ s->buf_f[2 + (x*4)+y*(w*4)] = s->colorf[2]; - #include "line_template.c" +#include "line_template.c" } static void draw_aliased_line_gray(pipi_image_t *img, struct line* s) { - #undef ASSIGN - #define ASSIGN(x, y, w) s->buf_f[x+y*w] = s->colorf[0]; - #include "line_template.c" +#undef ASSIGN +#define ASSIGN(x, y, w) s->buf_f[x+y*w] = s->colorf[0]; +#include "line_template.c" +} + +/* Xiaolin Wu's line algorithm, as seen at http://portal.acm.org/citation.cfm?id=122734 */ + +/* math.h doesn't like y0 (sucker) */ +float floorf(float x); +float truncf(float x); +float fabsf(float x); +static float fractf(float d) { return (d - floorf(d)); } +static float fractinvf(float d) { return (1 - (d - floorf(d))); } + +static void draw_antialiased_line_float(pipi_image_t *img, struct line* s) +{ +/* Is that an horrible mess ? Yes, it is. */ +#undef PLOT +#define PLOT(x, y, c) \ + s->buf_f[(((int)(x)*4))+((int)(y))*(img->w*4)] = \ + (c*s->colorf[0]) + (1-c) * s->buf_f[(((int)(x)*4))+((int)(y))*(img->w*4)]; \ + s->buf_f[(1+((int)(x)*4))+((int)(y))*(img->w*4)] = \ + (c*s->colorf[1]) + (1-c) * s->buf_f[(1+((int)(x)*4))+((int)(y))*(img->w*4)]; \ + s->buf_f[(2+((int)(x)*4))+((int)(y))*(img->w*4)] = \ + (c*s->colorf[2]) + (1-c) * s->buf_f[(2+((int)(x)*4))+((int)(y))*(img->w*4)]; +#include "aline_template.c" +} + + +static void draw_antialiased_line_gray(pipi_image_t *img, struct line* s) +{ +#undef PLOT +#define PLOT(x, y, c) s->buf_f[((int)(x))+((int)(y))*img->w] = \ + (c*s->colorf[0]) + (1-c) * s->buf_f[((int)(x))+((int)(y))*img->w]; +#include "aline_template.c" } diff --git a/pipi/pipi.h b/pipi/pipi.h index 74d89ab..4dc9ca5 100644 --- a/pipi/pipi.h +++ b/pipi/pipi.h @@ -101,6 +101,9 @@ extern void pipi_free(pipi_image_t *); extern void pipi_save(pipi_image_t *, const char *); extern pipi_pixels_t *pipi_getpixels(pipi_image_t *, pipi_format_t); +extern int pipi_get_image_width(pipi_image_t *img); +extern int pipi_get_image_height(pipi_image_t *img); +extern int pipi_get_image_pitch(pipi_image_t *img); extern double pipi_measure_msd(pipi_image_t *, pipi_image_t *); extern double pipi_measure_rmsd(pipi_image_t *, pipi_image_t *); @@ -150,7 +153,7 @@ extern pipi_image_t *pipi_erode(pipi_image_t *); extern pipi_image_t *pipi_tile(pipi_image_t *, int, int); extern int pipi_flood_fill(pipi_image_t *, int, int, float, float, float, float); -extern int pipi_draw_line(pipi_image_t *, int, int, int, int, uint32_t); +extern int pipi_draw_line(pipi_image_t *, int, int, int, int, uint32_t, int); extern int pipi_draw_polyline(pipi_image_t *, int const[], int const[], int , uint32_t); extern pipi_image_t *pipi_reduce(pipi_image_t *, int, double const *); diff --git a/pipi/pixels.c b/pipi/pixels.c index 13e6b2e..233ae24 100644 --- a/pipi/pixels.c +++ b/pipi/pixels.c @@ -266,3 +266,16 @@ static void init_tables(void) done = 1; } +/* Accessors */ +int pipi_get_image_width(pipi_image_t *img) +{ + return img->w; +} +int pipi_get_image_height(pipi_image_t *img) +{ + return img->h; +} +int pipi_get_image_pitch(pipi_image_t *img) +{ + return img->pitch; +}