/* * libpipi Proper image processing implementation library * Copyright (c) 2004-2008 Sam Hocevar * 2008 Jean-Yves Lamoureux #include #include #undef __USE_MISC /* THAT sucks */ #undef __USE_XOPEN /* THAT sucks, too (avoid declaring y1 in math.h) */ #include #include "pipi.h" #include "pipi_internals.h" struct line { int x1, y1; int x2, y2; void (*draw) (pipi_image_t*, struct line*); union { uint32_t color32; float colorf[3]; }; union { uint32_t *buf_u32; float *buf_f; }; }; static void clip_line(pipi_image_t*, struct line*); 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 aa) { struct line s; s.x1 = x1; s.y1 = y1; s.x2 = x2; s.y2 = y2; /* 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 = 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[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 = aa==0?draw_aliased_line_float:draw_antialiased_line_float; } clip_line(img, &s); return 0; } int pipi_draw_polyline(pipi_image_t *img, int const x[], int const y[], int n, uint32_t c, int aa) { int i; struct line s; 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 = 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.buf_f = dstdata; s.draw = aa==0?draw_aliased_line_float:draw_antialiased_line_float; img->last_modified = PIPI_PIXELS_RGBA_F; } for(i = 0; i < n; i++) { s.x1 = x[i]; s.y1 = y[i]; s.x2 = x[i+1]; s.y2 = y[i+1]; clip_line(img, &s); } return 0; } /* * XXX: The following functions are local. */ /* Generic Cohen-Sutherland line clipping function. */ static void clip_line(pipi_image_t *img, struct line* s) { uint8_t bits1, bits2; bits1 = clip_bits(img, s->x1, s->y1); bits2 = clip_bits(img, s->x2, s->y2); if(bits1 & bits2) return; if(bits1 == 0) { if(bits2 == 0) s->draw(img, s); else { int tmp; tmp = s->x1; s->x1 = s->x2; s->x2 = tmp; tmp = s->y1; s->y1 = s->y2; s->y2 = tmp; clip_line(img, s); } return; } if(bits1 & (1<<0)) { s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1); s->x1 = 0; } else if(bits1 & (1<<1)) { int xmax = img->w - 1; s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1); s->x1 = xmax; } else if(bits1 & (1<<2)) { s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1); s->y1 = 0; } else if(bits1 & (1<<3)) { int ymax = img->h - 1; s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1); s->y1 = ymax; } clip_line(img, s); } /* Helper function for clip_line(). */ static uint8_t clip_bits(pipi_image_t *img, int x, int y) { uint8_t b = 0; if(x < 0) b |= (1<<0); else if(x >= (int)img->w) b |= (1<<1); if(y < 0) b |= (1<<2); else if(y >= (int)img->h) b |= (1<<3); return b; } /* Solid line drawing function, using Bresenham's mid-point line * 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.h" } 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]; \ 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.h" } 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.h" } /* Xiaolin Wu's line algorithm, as seen at http://portal.acm.org/citation.cfm?id=122734 */ /* math.h doesn't like y1 (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) \ { int qwer = (((int)(x)*4))+((int)(y))*(img->w*4);\ int qweg = (1+((int)(x)*4))+((int)(y))*(img->w*4); \ int qweb = (2+((int)(x)*4))+((int)(y))*(img->w*4); \ s->buf_f[qwer] = (c*s->colorf[0]) + (1-c) * s->buf_f[qwer]; \ s->buf_f[qweg] = (c*s->colorf[1]) + (1-c) * s->buf_f[qweg]; \ s->buf_f[qweb] = (c*s->colorf[2]) + (1-c) * s->buf_f[qweb]; \ if(s->buf_f[qwer] > 1.0f) s->buf_f[qwer] = 1.0f; \ if(s->buf_f[qwer] < 0.0f || isnan(s->buf_f[qwer])) s->buf_f[qwer] = 0.0f; \ if(s->buf_f[qweg] > 1.0f) s->buf_f[qweg] = 1.0f; \ if(s->buf_f[qweg] < 0.0f || isnan(s->buf_f[qweg])) s->buf_f[qweg] = 0.0f; \ if(s->buf_f[qweb] > 1.0f) s->buf_f[qweb] = 1.0f; \ if(s->buf_f[qweb] < 0.0f || isnan(s->buf_f[qweb])) s->buf_f[qweb] = 0.0f; } #include "aline_template.h" } 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]; \ if(s->buf_f[((int)(x))+((int)(y))*img->w] > 1.0f) s->buf_f[((int)(x))+((int)(y))*img->w] = 1.0f; \ if(s->buf_f[((int)(x))+((int)(y))*img->w] < 0.0f) s->buf_f[((int)(x))+((int)(y))*img->w] = 0.0f; \ if(isnan(s->buf_f[((int)(x))+((int)(y))*img->w])) s->buf_f[((int)(x))+((int)(y))*img->w] = 0.0f; #include "aline_template.h" }