source: libpipi/trunk/pipi/paint/line.c @ 2788

Last change on this file since 2788 was 2788, checked in by jylam, 6 years ago
  • Added a bezier curve primitive (2 control points).
  • Fixed a float overflow in antialiased lines (this algorithm is a mess, and I need to rewrite it)
  • Wrote a bunch of craderies degueulasses to avoid having y1 already defined in math.h
  • Did I say this antialiased line implementation sucks ?
File size: 9.2 KB
Line 
1/*
2 *  libpipi       Proper image processing implementation library
3 *  Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
4 *                2008 Jean-Yves Lamoureux <jylam@lnxscene.org
5 *                All Rights Reserved
6 *
7 *  $Id$
8 *
9 *  This library is free software. It comes without any warranty, to
10 *  the extent permitted by applicable law. You can redistribute it
11 *  and/or modify it under the terms of the Do What The Fuck You Want
12 *  To Public License, Version 2, as published by Sam Hocevar. See
13 *  http://sam.zoy.org/wtfpl/COPYING for more details.
14 */
15
16/*
17 * line.c: line rendering functions
18 */
19
20#include "config.h"
21#include "common.h"
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#undef __USE_MISC  /* THAT sucks */
28#undef __USE_XOPEN /* THAT sucks, too (avoid declaring y1 in math.h) */
29#include <math.h>
30
31
32#include "pipi.h"
33#include "pipi_internals.h"
34
35struct line
36{
37    int x1, y1;
38    int x2, y2;
39    void (*draw) (pipi_image_t*, struct line*);
40    union {
41        uint32_t color32;
42        float    colorf[3];
43    };
44
45    union {
46        uint32_t *buf_u32;
47        float    *buf_f;
48    };
49
50};
51static void clip_line(pipi_image_t*, struct line*);
52static uint8_t clip_bits(pipi_image_t*, int, int);
53static void draw_aliased_line_u32(pipi_image_t*, struct line*);
54static void draw_aliased_line_gray(pipi_image_t *img, struct line* s);
55static void draw_aliased_line_float(pipi_image_t *img, struct line* s);
56static void draw_antialiased_line_float(pipi_image_t *img, struct line* s);
57static void draw_antialiased_line_gray(pipi_image_t *img, struct line* s);
58
59
60
61int pipi_draw_line(pipi_image_t *img , int x1, int y1, int x2, int y2, uint32_t c, int aa)
62{
63    struct line s;
64    s.x1 = x1;
65    s.y1 = y1;
66    s.x2 = x2;
67    s.y2 = y2;
68
69    /* No Transparency routine for u32 yet, fallback to float version */
70    if(img->last_modified == PIPI_PIXELS_RGBA_C)
71    {
72        if(!aa)
73        {
74            uint32_t  *dstdata;
75            dstdata = (uint32_t *)pipi_getpixels(img, PIPI_PIXELS_RGBA_C)->pixels;
76            s.color32 = c;
77            s.buf_u32 = dstdata;
78            s.draw = draw_aliased_line_u32;
79        }
80        else
81        {
82            float  *dstdata;
83            dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
84            s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
85            s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f;  /* XXX FIXME */
86            s.colorf[0] = (c&0x000000FF)/255.0f;       /* XXX FIXME */
87            s.buf_f = dstdata;
88            s.draw = draw_antialiased_line_float;
89        }
90    }
91    else if(img->last_modified == PIPI_PIXELS_Y_F)
92    {
93        float  *dstdata;
94        dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_Y_F)->pixels;
95        s.colorf[0] = c/255.0f; /* XXX FIXME */
96        s.buf_f = dstdata;
97        s.draw = aa==0?draw_aliased_line_gray:draw_antialiased_line_gray;
98    }
99    else
100    {
101        float  *dstdata;
102        dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
103        s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
104        s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f;  /* XXX FIXME */
105        s.colorf[0] = (c&0x000000FF)/255.0f;       /* XXX FIXME */
106        s.buf_f = dstdata;
107        s.draw = aa==0?draw_aliased_line_float:draw_antialiased_line_float;
108    }
109
110    clip_line(img, &s);
111    return 0;
112}
113
114
115int pipi_draw_polyline(pipi_image_t *img, int const x[], int const y[],
116                       int n, uint32_t c, int aa)
117{
118    int i;
119    struct line s;
120
121    if(img->last_modified == PIPI_PIXELS_RGBA_C)
122    {
123        if(!aa)
124        {
125            uint32_t  *dstdata;
126            dstdata = (uint32_t *)pipi_getpixels(img, PIPI_PIXELS_RGBA_C)->pixels;
127            s.color32 = c;
128            s.buf_u32 = dstdata;
129            s.draw = draw_aliased_line_u32;
130        }
131        else
132        {
133            float  *dstdata;
134            dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
135            s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
136            s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f;  /* XXX FIXME */
137            s.colorf[0] = (c&0x000000FF)/255.0f;       /* XXX FIXME */
138            s.buf_f = dstdata;
139            s.draw = draw_antialiased_line_float;
140        }
141    }
142    else if(img->last_modified == PIPI_PIXELS_Y_F)
143    {
144        float  *dstdata;
145        dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_Y_F)->pixels;
146        s.colorf[0] = c/255.0f; /* XXX FIXME */
147        s.buf_f = dstdata;
148        s.draw = aa==0?draw_aliased_line_gray:draw_antialiased_line_gray;
149    }
150    else
151    {
152        float  *dstdata;
153        dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
154        s.colorf[0] = (c&0x00FF0000)/255.0f; /* XXX FIXME */
155        s.colorf[1] = (c&0x0000FF00)/255.0f; /* XXX FIXME */
156        s.colorf[2] = (c&0x000000FF)/255.0f; /* XXX FIXME */
157        s.buf_f = dstdata;
158        s.draw = aa==0?draw_aliased_line_float:draw_antialiased_line_float;
159        img->last_modified = PIPI_PIXELS_RGBA_F;
160    }
161
162    for(i = 0; i < n; i++)
163    {
164        s.x1 = x[i];
165        s.y1 = y[i];
166        s.x2 = x[i+1];
167        s.y2 = y[i+1];
168        clip_line(img, &s);
169    }
170    return 0;
171}
172
173
174
175
176
177/*
178 * XXX: The following functions are local.
179 */
180/* Generic Cohen-Sutherland line clipping function. */
181static void clip_line(pipi_image_t *img, struct line* s)
182{
183    uint8_t bits1, bits2;
184
185    bits1 = clip_bits(img, s->x1, s->y1);
186    bits2 = clip_bits(img, s->x2, s->y2);
187
188    if(bits1 & bits2)
189        return;
190
191    if(bits1 == 0)
192    {
193        if(bits2 == 0)
194            s->draw(img, s);
195        else
196        {
197            int tmp;
198            tmp = s->x1; s->x1 = s->x2; s->x2 = tmp;
199            tmp = s->y1; s->y1 = s->y2; s->y2 = tmp;
200            clip_line(img, s);
201        }
202        return;
203    }
204
205    if(bits1 & (1<<0))
206    {
207        s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1);
208        s->x1 = 0;
209    }
210    else if(bits1 & (1<<1))
211    {
212        int xmax = img->w - 1;
213        s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1);
214        s->x1 = xmax;
215    }
216    else if(bits1 & (1<<2))
217    {
218        s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1);
219        s->y1 = 0;
220    }
221    else if(bits1 & (1<<3))
222    {
223        int ymax = img->h - 1;
224        s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1);
225        s->y1 = ymax;
226    }
227
228    clip_line(img, s);
229}
230
231/* Helper function for clip_line(). */
232static uint8_t clip_bits(pipi_image_t *img, int x, int y)
233{
234    uint8_t b = 0;
235
236    if(x < 0)
237        b |= (1<<0);
238    else if(x >= (int)img->w)
239        b |= (1<<1);
240
241    if(y < 0)
242        b |= (1<<2);
243    else if(y >= (int)img->h)
244        b |= (1<<3);
245
246    return b;
247}
248
249
250
251/* Solid line drawing function, using Bresenham's mid-point line
252 * scan-conversion algorithm. */
253static void draw_aliased_line_u32(pipi_image_t *img, struct line* s)
254{
255#undef  ASSIGN
256#define ASSIGN(x, y, w) s->buf_u32[x+y*w] = s->color32;
257#include "line_template.h"
258}
259static void draw_aliased_line_float(pipi_image_t *img, struct line* s)
260{
261#undef  ASSIGN
262#define ASSIGN(x, y, w) s->buf_f[(x*4)+y*(w*4)]     = s->colorf[0]; \
263                         s->buf_f[1 + (x*4)+y*(w*4)] = s->colorf[1]; \
264                         s->buf_f[2 + (x*4)+y*(w*4)] = s->colorf[2];
265#include "line_template.h"
266}
267static void draw_aliased_line_gray(pipi_image_t *img, struct line* s)
268{
269#undef  ASSIGN
270#define ASSIGN(x, y, w) s->buf_f[x+y*w]     = s->colorf[0];
271#include "line_template.h"
272}
273
274/* Xiaolin Wu's line algorithm, as seen at http://portal.acm.org/citation.cfm?id=122734 */
275
276/* math.h doesn't like y1 (sucker) */
277float floorf(float x);
278float truncf(float x);
279float fabsf(float x);
280
281static float fractf(float d) { return (d - floorf(d)); }
282static float fractinvf(float d) { return (1 - (d - floorf(d))); }
283
284static void draw_antialiased_line_float(pipi_image_t *img, struct line* s)
285{
286/* Is that an horrible mess ? Yes, it is. */
287#undef  PLOT
288#define PLOT(x, y, c)  \
289    { int qwer = (((int)(x)*4))+((int)(y))*(img->w*4);\
290      int qweg = (1+((int)(x)*4))+((int)(y))*(img->w*4); \
291      int qweb = (2+((int)(x)*4))+((int)(y))*(img->w*4); \
292    s->buf_f[qwer] = (c*s->colorf[0]) + (1-c) * s->buf_f[qwer]; \
293    s->buf_f[qweg] = (c*s->colorf[1]) + (1-c) * s->buf_f[qweg]; \
294    s->buf_f[qweb] = (c*s->colorf[2]) + (1-c) * s->buf_f[qweb]; \
295    if(s->buf_f[qwer] > 1.0f) s->buf_f[qwer] = 1.0f; \
296    if(s->buf_f[qwer] < 0.0f || isnan(s->buf_f[qwer])) s->buf_f[qwer] = 0.0f; \
297    if(s->buf_f[qweg] > 1.0f) s->buf_f[qweg] = 1.0f; \
298    if(s->buf_f[qweg] < 0.0f || isnan(s->buf_f[qweg])) s->buf_f[qweg] = 0.0f; \
299    if(s->buf_f[qweb] > 1.0f) s->buf_f[qweb] = 1.0f; \
300    if(s->buf_f[qweb] < 0.0f || isnan(s->buf_f[qweb])) s->buf_f[qweb] = 0.0f;  }
301
302#include "aline_template.h"
303}
304
305
306static void draw_antialiased_line_gray(pipi_image_t *img, struct line* s)
307{
308#undef  PLOT
309#define PLOT(x, y, c) s->buf_f[((int)(x))+((int)(y))*img->w] =  \
310    (c*s->colorf[0]) + (1-c) * s->buf_f[((int)(x))+((int)(y))*img->w]; \
311    if(s->buf_f[((int)(x))+((int)(y))*img->w] > 1.0f) s->buf_f[((int)(x))+((int)(y))*img->w] = 1.0f; \
312    if(s->buf_f[((int)(x))+((int)(y))*img->w] < 0.0f) s->buf_f[((int)(x))+((int)(y))*img->w] = 0.0f; \
313    if(isnan(s->buf_f[((int)(x))+((int)(y))*img->w])) s->buf_f[((int)(x))+((int)(y))*img->w] = 0.0f;
314
315#include "aline_template.h"
316}
Note: See TracBrowser for help on using the repository browser.