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

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

Quick and dirty implementation of pipi_draw_rectangle() to save zMoo.

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