|
- /*
- * libpipi Pathetic image processing interface library
- * Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
- * 2008 Jean-Yves Lamoureux <jylam@lnxscene.org>
- * 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 <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include <math.h>
-
- #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_U8)
- {
- if(!aa)
- {
- uint32_t *dstdata;
- dstdata = (uint32_t *)pipi_get_pixels(img, PIPI_PIXELS_RGBA_U8)->pixels;
- s.color32 = c;
- s.buf_u32 = dstdata;
- s.draw = line_8bit;
- }
- else
- {
- float *dstdata;
- dstdata = (float *)pipi_get_pixels(img, PIPI_PIXELS_RGBA_F32)->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_F32)
- {
- float *dstdata;
- dstdata = (float *)pipi_get_pixels(img, PIPI_PIXELS_Y_F32)->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_F32)->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)<ya?(iya+1):iya, val2);
-
- yf = yend+g;
- xend = (float)(int)(xb+0.5);
- yend = yb + g*(xend-xb);
- xgap = fractinvf(xb-0.5);
- ixb = (int)xend;
- iyb = (int)yend;
- val1 = fractinvf(yend)*xgap;
- val2 = fractf(yend)*xgap;
-
- PLOT(ixb, iyb, val1);
- PLOT(ixb, iyb+1<yb?iyb+1:iyb, val2);
-
- for (x = (ixa+1); x < ixb; 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)<ya?(yf+1):yf, val2);
-
- yf = yf + g;
- }
- }
- /* "Vertical" line (Y greater than X)*/
- else
- {
- if (xa > 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)<ya?(iya+1):iya, val2);
-
- xf = xend + g;
-
- xend = (float)(int)(xb+0.5);
- yend = yb + g*(xend-xb);
- xgap = fractinvf(xb-0.5);
- ixb = (int)xend;
- iyb = (int)yend;
- val1 = fractinvf(yend)*xgap;
- val2 = fractf(yend)*xgap;
-
- PLOT(ixb, iyb, val1);
- PLOT(ixb, (iyb+1)<yb?(iyb+1):iyb, val2);
-
-
- for (y = (iya+1); y < iyb; 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;
- }
- }
- }
-
- #undef PLOT
-
- /* Solid line drawing function, using Bresenham's mid-point line
- * scan-conversion algorithm. */
- static void T(line)(pipi_image_t *img, struct line* s)
- {
- int xa, ya, xb, yb;
- int dx, dy;
- int xinc, yinc;
-
- xa = s->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
|