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

Last change on this file since 2798 was 2798, checked in by Sam Hocevar, 12 years ago
  • line.c: merge the antialiased line template back into line.c.
File size: 13.7 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#include "pipi.h"
32#include "pipi_internals.h"
33
34/* math.h doesn't like y1 (sucker) */
35float floorf(float x);
36float truncf(float x);
37float fabsf(float x);
38
39#if !defined TEMPLATE_FILE /* This file uses the template system */
40
41static float fractf(float d) { return (d - floorf(d)); }
42static float fractinvf(float d) { return (1 - (d - floorf(d))); }
43
44struct line
45{
46    int x1, y1;
47    int x2, y2;
48    void (*draw) (pipi_image_t*, struct line*);
49    union {
50        uint32_t color32;
51        float    colorf[3];
52    };
53
54    union {
55        uint32_t *buf_u32;
56        float    *buf_f;
57    };
58
59};
60
61#define TEMPLATE_FLAGS SET_FLAG_GRAY | SET_FLAG_8BIT
62#define TEMPLATE_FILE "paint/line.c"
63#include "pipi_template.h"
64
65static void clip_line(pipi_image_t*, struct line*);
66static uint8_t clip_bits(pipi_image_t*, int, int);
67
68int pipi_draw_line(pipi_image_t *img , int x1, int y1, int x2, int y2, uint32_t c, int aa)
69{
70    struct line s;
71    s.x1 = x1;
72    s.y1 = y1;
73    s.x2 = x2;
74    s.y2 = y2;
75
76    /* No Transparency routine for u32 yet, fallback to float version */
77    if(img->last_modified == PIPI_PIXELS_RGBA_C)
78    {
79        if(!aa)
80        {
81            uint32_t  *dstdata;
82            dstdata = (uint32_t *)pipi_getpixels(img, PIPI_PIXELS_RGBA_C)->pixels;
83            s.color32 = c;
84            s.buf_u32 = dstdata;
85            s.draw = aliased_line_8bit;
86        }
87        else
88        {
89            float  *dstdata;
90            dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
91            s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
92            s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f;  /* XXX FIXME */
93            s.colorf[0] = (c&0x000000FF)/255.0f;       /* XXX FIXME */
94            s.buf_f = dstdata;
95            s.draw = antialiased_line;
96        }
97    }
98    else if(img->last_modified == PIPI_PIXELS_Y_F)
99    {
100        float  *dstdata;
101        dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_Y_F)->pixels;
102        s.colorf[0] = (c & 0xff) / 255.0f; /* XXX FIXME */
103        s.buf_f = dstdata;
104        s.draw = aa == 0 ? aliased_line_gray : antialiased_line_gray;
105    }
106    else
107    {
108        float  *dstdata;
109        dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
110        s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
111        s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f;  /* XXX FIXME */
112        s.colorf[0] = (c&0x000000FF)/255.0f;       /* XXX FIXME */
113        s.buf_f = dstdata;
114        s.draw = aa == 0 ? aliased_line : antialiased_line;
115    }
116
117    clip_line(img, &s);
118    return 0;
119}
120
121
122int pipi_draw_polyline(pipi_image_t *img, int const x[], int const y[],
123                       int n, uint32_t c, int aa)
124{
125    int i;
126    struct line s;
127
128    if(img->last_modified == PIPI_PIXELS_RGBA_C)
129    {
130        if(!aa)
131        {
132            uint32_t  *dstdata;
133            dstdata = (uint32_t *)pipi_getpixels(img, PIPI_PIXELS_RGBA_C)->pixels;
134            s.color32 = c;
135            s.buf_u32 = dstdata;
136            s.draw = aliased_line_8bit;
137        }
138        else
139        {
140            float  *dstdata;
141            dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
142            s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
143            s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f;  /* XXX FIXME */
144            s.colorf[0] = (c&0x000000FF)/255.0f;       /* XXX FIXME */
145            s.buf_f = dstdata;
146            s.draw = antialiased_line;
147        }
148    }
149    else if(img->last_modified == PIPI_PIXELS_Y_F)
150    {
151        float  *dstdata;
152        dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_Y_F)->pixels;
153        s.colorf[0] = (c & 0xff) / 255.0f; /* XXX FIXME */
154        s.buf_f = dstdata;
155        s.draw = aa == 0 ? aliased_line_gray : antialiased_line_gray;
156    }
157    else
158    {
159        float  *dstdata;
160        dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
161        s.colorf[0] = (c&0x00FF0000)/255.0f; /* XXX FIXME */
162        s.colorf[1] = (c&0x0000FF00)/255.0f; /* XXX FIXME */
163        s.colorf[2] = (c&0x000000FF)/255.0f; /* XXX FIXME */
164        s.buf_f = dstdata;
165        s.draw = aa == 0 ? aliased_line : antialiased_line;
166        img->last_modified = PIPI_PIXELS_RGBA_F;
167    }
168
169    for(i = 0; i < n; i++)
170    {
171        s.x1 = x[i];
172        s.y1 = y[i];
173        s.x2 = x[i+1];
174        s.y2 = y[i+1];
175        clip_line(img, &s);
176    }
177    return 0;
178}
179
180/*
181 * XXX: The following functions are local.
182 */
183
184/* Generic Cohen-Sutherland line clipping function. */
185static void clip_line(pipi_image_t *img, struct line* s)
186{
187    uint8_t bits1, bits2;
188
189    bits1 = clip_bits(img, s->x1, s->y1);
190    bits2 = clip_bits(img, s->x2, s->y2);
191
192    if(bits1 & bits2)
193        return;
194
195    if(bits1 == 0)
196    {
197        if(bits2 == 0)
198            s->draw(img, s);
199        else
200        {
201            int tmp;
202            tmp = s->x1; s->x1 = s->x2; s->x2 = tmp;
203            tmp = s->y1; s->y1 = s->y2; s->y2 = tmp;
204            clip_line(img, s);
205        }
206        return;
207    }
208
209    if(bits1 & (1<<0))
210    {
211        s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1);
212        s->x1 = 0;
213    }
214    else if(bits1 & (1<<1))
215    {
216        int xmax = img->w - 1;
217        s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1);
218        s->x1 = xmax;
219    }
220    else if(bits1 & (1<<2))
221    {
222        s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1);
223        s->y1 = 0;
224    }
225    else if(bits1 & (1<<3))
226    {
227        int ymax = img->h - 1;
228        s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1);
229        s->y1 = ymax;
230    }
231
232    clip_line(img, s);
233}
234
235/* Helper function for clip_line(). */
236static uint8_t clip_bits(pipi_image_t *img, int x, int y)
237{
238    uint8_t b = 0;
239
240    if(x < 0)
241        b |= (1<<0);
242    else if(x >= (int)img->w)
243        b |= (1<<1);
244
245    if(y < 0)
246        b |= (1<<2);
247    else if(y >= (int)img->h)
248        b |= (1<<3);
249
250    return b;
251}
252
253#else /* XXX: the following functions use the template system */
254
255/* Xiaolin Wu's line algorithm, as seen at http://portal.acm.org/citation.cfm?id=122734 */
256
257#define PLOT(x, y, c) \
258    if(FLAG_GRAY) \
259    { \
260        if(FLAG_8BIT) \
261        { \
262            /* TODO */ \
263        } \
264        else \
265        { \
266            s->buf_f[((int)(x))+((int)(y))*img->w] =  \
267            (c*s->colorf[0]) + (1-c) * s->buf_f[((int)(x))+((int)(y))*img->w]; \
268            if(s->buf_f[((int)(x))+((int)(y))*img->w] > 1.0f) \
269                s->buf_f[((int)(x))+((int)(y))*img->w] = 1.0f; \
270            if(s->buf_f[((int)(x))+((int)(y))*img->w] < 0.0f) \
271                s->buf_f[((int)(x))+((int)(y))*img->w] = 0.0f; \
272            if(isnan(s->buf_f[((int)(x))+((int)(y))*img->w])) \
273                s->buf_f[((int)(x))+((int)(y))*img->w] = 0.0f; \
274        } \
275    } \
276    else \
277    { \
278        if(FLAG_8BIT) \
279        { \
280            /* TODO */ \
281        } \
282        else \
283        { \
284            int qwer = (((int)(x)*4))+((int)(y))*(img->w*4);\
285            int qweg = (1+((int)(x)*4))+((int)(y))*(img->w*4); \
286            int qweb = (2+((int)(x)*4))+((int)(y))*(img->w*4); \
287            s->buf_f[qwer] = (c*s->colorf[0]) + (1-c) * s->buf_f[qwer]; \
288            s->buf_f[qweg] = (c*s->colorf[1]) + (1-c) * s->buf_f[qweg]; \
289            s->buf_f[qweb] = (c*s->colorf[2]) + (1-c) * s->buf_f[qweb]; \
290            if(s->buf_f[qwer] > 1.0f) \
291                s->buf_f[qwer] = 1.0f; \
292            if(s->buf_f[qwer] < 0.0f || isnan(s->buf_f[qwer])) \
293                s->buf_f[qwer] = 0.0f; \
294            if(s->buf_f[qweg] > 1.0f) \
295                s->buf_f[qweg] = 1.0f; \
296            if(s->buf_f[qweg] < 0.0f || isnan(s->buf_f[qweg])) \
297                s->buf_f[qweg] = 0.0f; \
298            if(s->buf_f[qweb] > 1.0f) \
299                s->buf_f[qweb] = 1.0f; \
300            if(s->buf_f[qweb] < 0.0f || isnan(s->buf_f[qweb])) \
301                s->buf_f[qweb] = 0.0f; \
302        } \
303    }
304
305static void SUFFIX(antialiased_line)(pipi_image_t *img, struct line* s)
306{
307    float x1 = s->x1, y1 = s->y1, x2 = s->x2, y2 = s->y2;
308    float g, xd, yd, xgap, xend, yend, xf, yf, val1, val2;
309    int x, y, ix1, ix2, iy1, iy2;
310
311    xd = x2 - x1;
312    yd = y2 - y1;
313
314    /* "Horizontal" line (X greater than Y)*/
315    if (fabsf(xd) > fabsf(yd))
316    {
317        if (x1 > x2)
318        {
319            float tmp;
320            tmp = x1; x1 = x2; x2 = tmp;
321            tmp = y1; y1 = y2; y2 = tmp;
322            xd = (x2-x1);
323            yd = (y2-y1);
324        }
325        g = yd/xd;
326
327        xend = truncf(x1+0.5);
328        yend = y1 + g*(xend-x1);
329        xgap = fractinvf(x1+0.5);
330        ix1 = (int)xend;
331        iy1 = (int)yend;
332        val1 = fractinvf(yend)*xgap;
333        val2 = fractf(yend)*xgap;
334
335        PLOT(ix1, iy1,   val1);
336        PLOT(ix1, (iy1+1)<y1?(iy1+1):iy1, val2);
337
338        yf = yend+g;
339        xend = truncf(x2+0.5);
340        yend = y2 + g*(xend-x2);
341        xgap = fractinvf(x2-0.5);
342        ix2 = (int)xend;
343        iy2 = (int)yend;
344        val1 = fractinvf(yend)*xgap;
345        val2 = fractf(yend)*xgap;
346
347        PLOT(ix2, iy2,   val1);
348        PLOT(ix2, iy2+1<y2?iy2+1:iy2, val2);
349
350        for (x = (ix1+1); x < ix2; x++)
351        {
352            float focus;
353
354            val1 = fractinvf(yf);
355            val2 = fractf(yf);
356            focus = (1.0 - fabsf(val1-val2));
357            val1 += 0.3*focus;
358            val2 += 0.3*focus;
359
360            PLOT(x, yf, val1);
361            PLOT(x, (yf+1)<y1?(yf+1):yf, val2);
362
363            yf = yf + g;
364        }
365    }
366    /* "Vertical" line (Y greater than X)*/
367    else
368    {
369        if (x1 > x2)
370        {
371            float tmp;
372            tmp = x1; x1 = x2; x2 = tmp;
373            tmp = y1; y1 = y2; y2 = tmp;
374            xd = (x2-x1);
375            yd = (y2-y1);
376        }
377
378        g = xd/yd;
379
380        xend = truncf(x1+0.5);
381        yend = y1 + g*(xend-x1);
382        xgap = fractf(x1+0.5);
383        ix1 = (int)xend;
384        iy1 = (int)yend;
385        val1 = fractinvf(yend)*xgap;
386        val2 = fractf(yend)*xgap;
387
388        PLOT(ix1, iy1, val1);
389        PLOT(ix1, (iy1+1)<y1?(iy1+1):iy1, val2);
390
391        xf = xend + g;
392
393        xend = truncf(x2+0.5);
394        yend = y2 + g*(xend-x2);
395        xgap = fractinvf(x2-0.5);
396        ix2 = (int)xend;
397        iy2 = (int)yend;
398        val1 = fractinvf(yend)*xgap;
399        val2 = fractf(yend)*xgap;
400
401        PLOT(ix2, iy2,   val1);
402        PLOT(ix2, (iy2+1)<y2?(iy2+1):iy2, val2);
403
404
405        for (y = (iy1+1); y < iy2; y++)
406        {
407            float focus;
408            int   vx = xf;
409            val1 = fractinvf(xf);
410            val2 = fractf(xf);
411            focus = (1.0 - fabsf(val1-val2));
412            val1 += 0.3*focus;
413            val2 += 0.3*focus;
414            PLOT(vx, y, val1);
415            vx++;
416            PLOT(vx, y, val2);
417            xf = xf + g;
418        }
419    }
420}
421
422#undef PLOT
423
424/* Solid line drawing function, using Bresenham's mid-point line
425 * scan-conversion algorithm. */
426static void SUFFIX(aliased_line)(pipi_image_t *img, struct line* s)
427{
428    int x1, y1, x2, y2;
429    int dx, dy;
430    int xinc, yinc;
431
432    x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
433
434    dx = abs(x2 - x1);
435    dy = abs(y2 - y1);
436
437    xinc = (x1 > x2) ? -1 : 1;
438    yinc = (y1 > y2) ? -1 : 1;
439
440    if(dx >= dy)
441    {
442        int dpr = dy << 1;
443        int dpru = dpr - (dx << 1);
444        int delta = dpr - dx;
445
446        for(; dx >= 0; dx--)
447        {
448            if(FLAG_GRAY)
449            {
450                if(FLAG_8BIT)
451                    /* TODO */;
452                else
453                    s->buf_f[x1 + y1 * img->w] = s->colorf[0];
454            }
455            else
456            {
457                if(FLAG_8BIT)
458                    s->buf_u32[x1 + y1 * img->w] = s->color32;
459                else
460                {
461                    s->buf_f[4 * (y1 * img->w + x1)] = s->colorf[0];
462                    s->buf_f[4 * (y1 * img->w + x1) + 1] = s->colorf[1];
463                    s->buf_f[4 * (y1 * img->w + x1) + 2] = s->colorf[2];
464                }
465            }
466
467            if(delta > 0)
468            {
469                x1 += xinc;
470                y1 += yinc;
471                delta += dpru;
472            }
473            else
474            {
475                x1 += xinc;
476                delta += dpr;
477            }
478        }
479    }
480    else
481    {
482        int dpr = dx << 1;
483        int dpru = dpr - (dy << 1);
484        int delta = dpr - dy;
485
486        for(; dy >= 0; dy--)
487        {
488            if(FLAG_GRAY)
489            {
490                if(FLAG_8BIT)
491                    /* TODO */;
492                else
493                    s->buf_f[x1 + y1 * img->w] = s->colorf[0];
494            }
495            else
496            {
497                if(FLAG_8BIT)
498                    s->buf_u32[x1 + y1 * img->w] = s->color32;
499                else
500                {
501                    s->buf_f[4 * (y1 * img->w + x1)] = s->colorf[0];
502                    s->buf_f[4 * (y1 * img->w + x1) + 1] = s->colorf[1];
503                    s->buf_f[4 * (y1 * img->w + x1) + 2] = s->colorf[2];
504                }
505            }
506
507            if(delta > 0)
508            {
509                x1 += xinc;
510                y1 += yinc;
511                delta += dpru;
512            }
513            else
514            {
515                y1 += yinc;
516                delta += dpr;
517            }
518        }
519    }
520}
521
522#endif
523
Note: See TracBrowser for help on using the repository browser.