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

Last change on this file since 2799 was 2799, checked in by Sam Hocevar, 12 years ago
  • line.c: minor refactoring.
File size: 11.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 = 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 = aaline;
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 ? aaline_gray : 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 ? aaline : line;
115    }
116
117    clip_line(img, &s);
118    return 0;
119}
120
121int pipi_draw_polyline(pipi_image_t *img, int const x[], int const y[],
122                       int n, uint32_t c, int aa)
123{
124    int i;
125
126    for(i = 0; i < n; i++)
127        pipi_draw_line(img, x[i], y[i], x[i + 1], y[i + 1], c, aa);
128
129    return 0;
130}
131
132/*
133 * XXX: The following functions are local.
134 */
135
136/* Generic Cohen-Sutherland line clipping function. */
137static void clip_line(pipi_image_t *img, struct line* s)
138{
139    uint8_t bits1, bits2;
140
141    bits1 = clip_bits(img, s->x1, s->y1);
142    bits2 = clip_bits(img, s->x2, s->y2);
143
144    if(bits1 & bits2)
145        return;
146
147    if(bits1 == 0)
148    {
149        if(bits2 == 0)
150            s->draw(img, s);
151        else
152        {
153            int tmp;
154            tmp = s->x1; s->x1 = s->x2; s->x2 = tmp;
155            tmp = s->y1; s->y1 = s->y2; s->y2 = tmp;
156            clip_line(img, s);
157        }
158        return;
159    }
160
161    if(bits1 & (1<<0))
162    {
163        s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1);
164        s->x1 = 0;
165    }
166    else if(bits1 & (1<<1))
167    {
168        int xmax = img->w - 1;
169        s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1);
170        s->x1 = xmax;
171    }
172    else if(bits1 & (1<<2))
173    {
174        s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1);
175        s->y1 = 0;
176    }
177    else if(bits1 & (1<<3))
178    {
179        int ymax = img->h - 1;
180        s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1);
181        s->y1 = ymax;
182    }
183
184    clip_line(img, s);
185}
186
187/* Helper function for clip_line(). */
188static uint8_t clip_bits(pipi_image_t *img, int x, int y)
189{
190    uint8_t b = 0;
191
192    if(x < 0)
193        b |= (1<<0);
194    else if(x >= (int)img->w)
195        b |= (1<<1);
196
197    if(y < 0)
198        b |= (1<<2);
199    else if(y >= (int)img->h)
200        b |= (1<<3);
201
202    return b;
203}
204
205#else /* XXX: the following functions use the template system */
206
207/* Xiaolin Wu's line algorithm, as seen at http://portal.acm.org/citation.cfm?id=122734 */
208
209#define PLOT(x, y, c) \
210    if(FLAG_8BIT) \
211    { \
212        /* TODO */ \
213    } \
214    else \
215    { \
216        if(FLAG_GRAY) \
217        { \
218            s->buf_f[((int)(x))+((int)(y))*img->w] =  \
219            (c*s->colorf[0]) + (1-c) * s->buf_f[((int)(x))+((int)(y))*img->w]; \
220            if(s->buf_f[((int)(x))+((int)(y))*img->w] > 1.0f) \
221                s->buf_f[((int)(x))+((int)(y))*img->w] = 1.0f; \
222            if(s->buf_f[((int)(x))+((int)(y))*img->w] < 0.0f) \
223                s->buf_f[((int)(x))+((int)(y))*img->w] = 0.0f; \
224        } \
225        else \
226        { \
227            int qwer = (((int)(x)*4))+((int)(y))*(img->w*4);\
228            int qweg = (1+((int)(x)*4))+((int)(y))*(img->w*4); \
229            int qweb = (2+((int)(x)*4))+((int)(y))*(img->w*4); \
230            s->buf_f[qwer] = (c*s->colorf[0]) + (1-c) * s->buf_f[qwer]; \
231            s->buf_f[qweg] = (c*s->colorf[1]) + (1-c) * s->buf_f[qweg]; \
232            s->buf_f[qweb] = (c*s->colorf[2]) + (1-c) * s->buf_f[qweb]; \
233            if(s->buf_f[qwer] > 1.0f) s->buf_f[qwer] = 1.0f; \
234            if(s->buf_f[qwer] < 0.0f) s->buf_f[qwer] = 0.0f; \
235            if(s->buf_f[qweg] > 1.0f) s->buf_f[qweg] = 1.0f; \
236            if(s->buf_f[qweg] < 0.0f) s->buf_f[qweg] = 0.0f; \
237            if(s->buf_f[qweb] > 1.0f) s->buf_f[qweb] = 1.0f; \
238            if(s->buf_f[qweb] < 0.0f) s->buf_f[qweb] = 0.0f; \
239        } \
240    }
241
242static void SUFFIX(aaline)(pipi_image_t *img, struct line* s)
243{
244    float x1 = s->x1, y1 = s->y1, x2 = s->x2, y2 = s->y2;
245    float g, xd, yd, xgap, xend, yend, xf, yf, val1, val2;
246    int x, y, ix1, ix2, iy1, iy2;
247
248    xd = x2 - x1;
249    yd = y2 - y1;
250
251    /* "Horizontal" line (X greater than Y)*/
252    if (fabsf(xd) > fabsf(yd))
253    {
254        if (x1 > x2)
255        {
256            float tmp;
257            tmp = x1; x1 = x2; x2 = tmp;
258            tmp = y1; y1 = y2; y2 = tmp;
259            xd = (x2-x1);
260            yd = (y2-y1);
261        }
262        g = yd/xd;
263
264        xend = truncf(x1+0.5);
265        yend = y1 + g*(xend-x1);
266        xgap = fractinvf(x1+0.5);
267        ix1 = (int)xend;
268        iy1 = (int)yend;
269        val1 = fractinvf(yend)*xgap;
270        val2 = fractf(yend)*xgap;
271
272        PLOT(ix1, iy1,   val1);
273        PLOT(ix1, (iy1+1)<y1?(iy1+1):iy1, val2);
274
275        yf = yend+g;
276        xend = truncf(x2+0.5);
277        yend = y2 + g*(xend-x2);
278        xgap = fractinvf(x2-0.5);
279        ix2 = (int)xend;
280        iy2 = (int)yend;
281        val1 = fractinvf(yend)*xgap;
282        val2 = fractf(yend)*xgap;
283
284        PLOT(ix2, iy2,   val1);
285        PLOT(ix2, iy2+1<y2?iy2+1:iy2, val2);
286
287        for (x = (ix1+1); x < ix2; x++)
288        {
289            float focus;
290
291            val1 = fractinvf(yf);
292            val2 = fractf(yf);
293            focus = (1.0 - fabsf(val1-val2));
294            val1 += 0.3*focus;
295            val2 += 0.3*focus;
296
297            PLOT(x, yf, val1);
298            PLOT(x, (yf+1)<y1?(yf+1):yf, val2);
299
300            yf = yf + g;
301        }
302    }
303    /* "Vertical" line (Y greater than X)*/
304    else
305    {
306        if (x1 > x2)
307        {
308            float tmp;
309            tmp = x1; x1 = x2; x2 = tmp;
310            tmp = y1; y1 = y2; y2 = tmp;
311            xd = (x2-x1);
312            yd = (y2-y1);
313        }
314
315        g = xd/yd;
316
317        xend = truncf(x1+0.5);
318        yend = y1 + g*(xend-x1);
319        xgap = fractf(x1+0.5);
320        ix1 = (int)xend;
321        iy1 = (int)yend;
322        val1 = fractinvf(yend)*xgap;
323        val2 = fractf(yend)*xgap;
324
325        PLOT(ix1, iy1, val1);
326        PLOT(ix1, (iy1+1)<y1?(iy1+1):iy1, val2);
327
328        xf = xend + g;
329
330        xend = truncf(x2+0.5);
331        yend = y2 + g*(xend-x2);
332        xgap = fractinvf(x2-0.5);
333        ix2 = (int)xend;
334        iy2 = (int)yend;
335        val1 = fractinvf(yend)*xgap;
336        val2 = fractf(yend)*xgap;
337
338        PLOT(ix2, iy2,   val1);
339        PLOT(ix2, (iy2+1)<y2?(iy2+1):iy2, val2);
340
341
342        for (y = (iy1+1); y < iy2; y++)
343        {
344            float focus;
345            int   vx = xf;
346            val1 = fractinvf(xf);
347            val2 = fractf(xf);
348            focus = (1.0 - fabsf(val1-val2));
349            val1 += 0.3*focus;
350            val2 += 0.3*focus;
351            PLOT(vx, y, val1);
352            vx++;
353            PLOT(vx, y, val2);
354            xf = xf + g;
355        }
356    }
357}
358
359#undef PLOT
360
361/* Solid line drawing function, using Bresenham's mid-point line
362 * scan-conversion algorithm. */
363static void SUFFIX(line)(pipi_image_t *img, struct line* s)
364{
365    int x1, y1, x2, y2;
366    int dx, dy;
367    int xinc, yinc;
368
369    x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
370
371    dx = abs(x2 - x1);
372    dy = abs(y2 - y1);
373
374    xinc = (x1 > x2) ? -1 : 1;
375    yinc = (y1 > y2) ? -1 : 1;
376
377    if(dx >= dy)
378    {
379        int dpr = dy << 1;
380        int dpru = dpr - (dx << 1);
381        int delta = dpr - dx;
382
383        for(; dx >= 0; dx--)
384        {
385            if(FLAG_GRAY)
386            {
387                if(FLAG_8BIT)
388                    /* TODO */;
389                else
390                    s->buf_f[x1 + y1 * img->w] = s->colorf[0];
391            }
392            else
393            {
394                if(FLAG_8BIT)
395                    s->buf_u32[x1 + y1 * img->w] = s->color32;
396                else
397                {
398                    s->buf_f[4 * (y1 * img->w + x1)] = s->colorf[0];
399                    s->buf_f[4 * (y1 * img->w + x1) + 1] = s->colorf[1];
400                    s->buf_f[4 * (y1 * img->w + x1) + 2] = s->colorf[2];
401                }
402            }
403
404            if(delta > 0)
405            {
406                x1 += xinc;
407                y1 += yinc;
408                delta += dpru;
409            }
410            else
411            {
412                x1 += xinc;
413                delta += dpr;
414            }
415        }
416    }
417    else
418    {
419        int dpr = dx << 1;
420        int dpru = dpr - (dy << 1);
421        int delta = dpr - dy;
422
423        for(; dy >= 0; dy--)
424        {
425            if(FLAG_GRAY)
426            {
427                if(FLAG_8BIT)
428                    /* TODO */;
429                else
430                    s->buf_f[x1 + y1 * img->w] = s->colorf[0];
431            }
432            else
433            {
434                if(FLAG_8BIT)
435                    s->buf_u32[x1 + y1 * img->w] = s->color32;
436                else
437                {
438                    s->buf_f[4 * (y1 * img->w + x1)] = s->colorf[0];
439                    s->buf_f[4 * (y1 * img->w + x1) + 1] = s->colorf[1];
440                    s->buf_f[4 * (y1 * img->w + x1) + 2] = s->colorf[2];
441                }
442            }
443
444            if(delta > 0)
445            {
446                x1 += xinc;
447                y1 += yinc;
448                delta += dpru;
449            }
450            else
451            {
452                y1 += yinc;
453                delta += dpr;
454            }
455        }
456    }
457}
458
459#endif
460
Note: See TracBrowser for help on using the repository browser.