/* * libpipi Pathetic image processing interface library * Copyright (c) 2004-2008 Sam Hocevar * 2008 Jean-Yves Lamoureux * All Rights Reserved * * $Id$ * * This library is free software. It comes without any warranty, to * the extent permitted by applicable law. You can redistribute it * and/or modify it under the terms of the Do What The Fuck You Want * To Public License, Version 2, as published by Sam Hocevar. See * http://sam.zoy.org/wtfpl/COPYING for more details. */ /* * line.c: line rendering functions */ #include "config.h" #include #include #include #include #include "pipi.h" #include "pipi_internals.h" #if !defined TEMPLATE_FILE /* This file uses the template system */ static float fractf(float d) { return (d - floorf(d)); } static float fractinvf(float d) { return (1 - (d - floorf(d))); } struct line { int xa, ya; int xb, yb; void (*draw) (pipi_image_t*, struct line*); union { uint32_t color32; float colorf[3]; }; union { uint32_t *buf_u32; float *buf_f; }; }; #define TEMPLATE_FLAGS SET_FLAG_GRAY | SET_FLAG_8BIT #define TEMPLATE_FILE "paint/line.c" #include "pipi_template.h" static void clip_line(pipi_image_t*, struct line*); static uint8_t clip_bits(pipi_image_t*, int, int); int pipi_draw_line(pipi_image_t *img , int xa, int ya, int xb, int yb, uint32_t c, int aa) { struct line s; s.xa = xa; s.ya = ya; s.xb = xb; s.yb = yb; /* 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_get_pixels(img, PIPI_PIXELS_RGBA_C)->pixels; s.color32 = c; s.buf_u32 = dstdata; s.draw = line_8bit; } else { float *dstdata; dstdata = (float *)pipi_get_pixels(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 = aaline; } } else if(img->last_modified == PIPI_PIXELS_Y_F) { float *dstdata; dstdata = (float *)pipi_get_pixels(img, PIPI_PIXELS_Y_F)->pixels; s.colorf[0] = (c & 0xff) / 255.0f; /* XXX FIXME */ s.buf_f = dstdata; s.draw = aa ? aaline_gray : line_gray; } else { float *dstdata; dstdata = (float *)pipi_get_pixels(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 ? aaline : line; } clip_line(img, &s); return 0; } int pipi_draw_rectangle(pipi_image_t *img , int xa, int ya, int xb, int yb, uint32_t c, int aa) { while(ya < yb) { pipi_draw_line(img, xa, ya, xb, ya, c, aa); ya++; } while(ya > yb) { pipi_draw_line(img, xa, ya, xb, ya, c, aa); ya--; } return pipi_draw_line(img, xa, yb, xb, yb, c, aa); } int pipi_draw_polyline(pipi_image_t *img, int const x[], int const y[], int n, uint32_t c, int aa) { int i; for(i = 0; i < n; i++) pipi_draw_line(img, x[i], y[i], x[i + 1], y[i + 1], c, aa); 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->xa, s->ya); bits2 = clip_bits(img, s->xb, s->yb); if(bits1 & bits2) return; if(bits1 == 0) { if(bits2 == 0) s->draw(img, s); else { int tmp; tmp = s->xa; s->xa = s->xb; s->xb = tmp; tmp = s->ya; s->ya = s->yb; s->yb = tmp; clip_line(img, s); } return; } if(bits1 & (1<<0)) { s->ya = s->yb - (s->xb - 0) * (s->yb - s->ya) / (s->xb - s->xa); s->xa = 0; } else if(bits1 & (1<<1)) { int xmax = img->w - 1; s->ya = s->yb - (s->xb - xmax) * (s->yb - s->ya) / (s->xb - s->xa); s->xa = xmax; } else if(bits1 & (1<<2)) { s->xa = s->xb - (s->yb - 0) * (s->xb - s->xa) / (s->yb - s->ya); s->ya = 0; } else if(bits1 & (1<<3)) { int ymax = img->h - 1; s->xa = s->xb - (s->yb - ymax) * (s->xb - s->xa) / (s->yb - s->ya); s->ya = 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; } #else /* XXX: the following functions use the template system */ /* Xiaolin Wu's line algorithm, as seen at http://portal.acm.org/citation.cfm?id=122734 */ #define PLOT(x, y, c) \ if(FLAG_8BIT) \ { \ /* TODO */ \ } \ else \ { \ if(FLAG_GRAY) \ { \ 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; \ } \ else \ { \ 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) 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) 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) s->buf_f[qweb] = 0.0f; \ } \ } static void T(aaline)(pipi_image_t *img, struct line* s) { float xa = s->xa, ya = s->ya, xb = s->xb, yb = s->yb; float g, xd, yd, xgap, xend, yend, xf, yf, val1, val2; int x, y, ixa, ixb, iya, iyb; xd = xb - xa; yd = yb - ya; /* "Horizontal" line (X greater than Y)*/ if (fabsf(xd) > fabsf(yd)) { if (xa > xb) { float tmp; tmp = xa; xa = xb; xb = tmp; tmp = ya; ya = yb; yb = tmp; xd = (xb-xa); yd = (yb-ya); } g = yd/xd; xend = (float)(int)(xa+0.5); yend = ya + g*(xend-xa); xgap = fractinvf(xa+0.5); ixa = (int)xend; iya = (int)yend; val1 = fractinvf(yend)*xgap; val2 = fractf(yend)*xgap; PLOT(ixa, iya, val1); PLOT(ixa, (iya+1) xb) { float tmp; tmp = xa; xa = xb; xb = tmp; tmp = ya; ya = yb; yb = tmp; xd = (xb-xa); yd = (yb-ya); } g = xd/yd; xend = (float)(int)(xa+0.5); yend = ya + g*(xend-xa); xgap = fractf(xa+0.5); ixa = (int)xend; iya = (int)yend; val1 = fractinvf(yend)*xgap; val2 = fractf(yend)*xgap; PLOT(ixa, iya, val1); PLOT(ixa, (iya+1)xa; ya = s->ya; xb = s->xb; yb = s->yb; dx = abs(xb - xa); dy = abs(yb - ya); xinc = (xa > xb) ? -1 : 1; yinc = (ya > yb) ? -1 : 1; if(dx >= dy) { int dpr = dy << 1; int dpru = dpr - (dx << 1); int delta = dpr - dx; for(; dx >= 0; dx--) { if(FLAG_GRAY) { if(FLAG_8BIT) /* TODO */; else s->buf_f[xa + ya * img->w] = s->colorf[0]; } else { if(FLAG_8BIT) s->buf_u32[xa + ya * img->w] = s->color32; else { s->buf_f[4 * (ya * img->w + xa)] = s->colorf[0]; s->buf_f[4 * (ya * img->w + xa) + 1] = s->colorf[1]; s->buf_f[4 * (ya * img->w + xa) + 2] = s->colorf[2]; } } if(delta > 0) { xa += xinc; ya += yinc; delta += dpru; } else { xa += xinc; delta += dpr; } } } else { int dpr = dx << 1; int dpru = dpr - (dy << 1); int delta = dpr - dy; for(; dy >= 0; dy--) { if(FLAG_GRAY) { if(FLAG_8BIT) /* TODO */; else s->buf_f[xa + ya * img->w] = s->colorf[0]; } else { if(FLAG_8BIT) s->buf_u32[xa + ya * img->w] = s->color32; else { s->buf_f[4 * (ya * img->w + xa)] = s->colorf[0]; s->buf_f[4 * (ya * img->w + xa) + 1] = s->colorf[1]; s->buf_f[4 * (ya * img->w + xa) + 2] = s->colorf[2]; } } if(delta > 0) { xa += xinc; ya += yinc; delta += dpru; } else { ya += yinc; delta += dpr; } } } } #endif