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

Last change on this file since 2844 was 2844, checked in by Sam Hocevar, 12 years ago

Fix headers.

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