|
- /*
- * libpipi Proper image processing implementation 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 "common.h"
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #undef __USE_MISC /* THAT sucks */
- #undef __USE_XOPEN /* THAT sucks, too (avoid declaring y1 in math.h) */
- #include <math.h>
-
-
- #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"
- }
|