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

Last change on this file since 2902 was 2902, checked in by Sam Hocevar, 11 years ago

Support C99 types on Win32 through the same hacks as in libcaca.

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
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#undef __USE_MISC  /* THAT sucks */
27#undef __USE_XOPEN /* THAT sucks, too (avoid declaring y1 in math.h) */
28#include <math.h>
29
30#include "pipi.h"
31#include "pipi_internals.h"
32
33/* math.h doesn't like y1 (sucker) */
34float floorf(float x);
35float truncf(float x);
36float fabsf(float x);
37
38#if !defined TEMPLATE_FILE /* This file uses the template system */
39
40static float fractf(float d) { return (d - floorf(d)); }
41static float fractinvf(float d) { return (1 - (d - floorf(d))); }
42
43struct line
44{
45    int x1, y1;
46    int x2, y2;
47    void (*draw) (pipi_image_t*, struct line*);
48    union {
49        uint32_t color32;
50        float    colorf[3];
51    };
52
53    union {
54        uint32_t *buf_u32;
55        float    *buf_f;
56    };
57
58};
59
60#define TEMPLATE_FLAGS SET_FLAG_GRAY | SET_FLAG_8BIT
61#define TEMPLATE_FILE "paint/line.c"
62#include "pipi_template.h"
63
64static void clip_line(pipi_image_t*, struct line*);
65static uint8_t clip_bits(pipi_image_t*, int, int);
66
67int pipi_draw_line(pipi_image_t *img , int x1, int y1, int x2, int y2, uint32_t c, int aa)
68{
69    struct line s;
70    s.x1 = x1;
71    s.y1 = y1;
72    s.x2 = x2;
73    s.y2 = y2;
74
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 T(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 T(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.