Browse Source

* 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
remotes/tiles
jylam 16 years ago
parent
commit
b67fde0e94
5 changed files with 236 additions and 31 deletions
  1. +8
    -3
      examples/line.c
  2. +130
    -0
      pipi/paint/aline_template.c
  3. +81
    -27
      pipi/paint/line.c
  4. +4
    -1
      pipi/pipi.h
  5. +13
    -0
      pipi/pixels.c

+ 8
- 3
examples/line.c View File

@@ -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);


+ 130
- 0
pipi/paint/aline_template.c View File

@@ -0,0 +1,130 @@
/*
* 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.
*/

/*
* aline_template.c: antialiased (Wu) line rendering template
*/

float x1 = s->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;
}
}

+ 81
- 27
pipi/paint/line.c View File

@@ -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"
}

+ 4
- 1
pipi/pipi.h View File

@@ -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 *);


+ 13
- 0
pipi/pixels.c View File

@@ -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;
}

Loading…
Cancel
Save