source: libcaca/trunk/src/line.c @ 205

Last change on this file since 205 was 205, checked in by Sam Hocevar, 18 years ago
  • src/: + Doxygenated a few things.
  • Property svn:keywords set to Id
File size: 8.1 KB
Line 
1/*
2 *   libcaca       ASCII-Art library
3 *   Copyright (c) 2002, 2003 Sam Hocevar <sam@zoy.org>
4 *                 All Rights Reserved
5 *
6 *   This library is free software; you can redistribute it and/or
7 *   modify it under the terms of the GNU Lesser General Public
8 *   License as published by the Free Software Foundation; either
9 *   version 2 of the License, or (at your option) any later version.
10 *
11 *   This library is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 *   Lesser General Public License for more details.
15 *
16 *   You should have received a copy of the GNU Lesser General Public
17 *   License along with this library; if not, write to the Free Software
18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 *   02111-1307  USA
20 */
21
22/**  \file line.c
23 *   \version \$Id: line.c 205 2003-11-22 12:45:25Z sam $
24 *   \author Sam Hocevar <sam@zoy.org>
25 *   \brief Line drawing functions
26 *
27 *   This file contains line and polyline drawing functions, with both thin
28 *   and thick styles.
29 */
30
31#include "config.h"
32
33#ifdef HAVE_INTTYPES_H
34#   include <inttypes.h>
35#else
36typedef unsigned char uint8_t;
37#endif
38
39#include <stdlib.h>
40
41#include "caca.h"
42#include "caca_internals.h"
43
44struct line
45{
46    int x1, y1;
47    int x2, y2;
48    char c;
49    void (*draw) (struct line*);
50};
51
52static void clip_line(struct line*);
53static uint8_t clip_bits(int, int);
54static void draw_solid_line(struct line*);
55static void draw_thin_line(struct line*);
56
57/**
58 * \brief Draw a line on the screen using the given character.
59 *
60 * \param x1 X coordinate of the first point.
61 * \param y1 Y coordinate of the first point.
62 * \param x2 X coordinate of the second point.
63 * \param y2 Y coordinate of the second point.
64 * \param c Character to draw the line with.
65 * \return void
66 */
67void caca_draw_line(int x1, int y1, int x2, int y2, char c)
68{
69    struct line s;
70    s.x1 = x1;
71    s.y1 = y1;
72    s.x2 = x2;
73    s.y2 = y2;
74    s.c = c;
75    s.draw = draw_solid_line;
76    clip_line(&s);
77}
78
79void caca_draw_polyline(const int x[], const int y[], int n, char c)
80{
81    int i;
82    struct line s;
83    s.c = c;
84    s.draw = draw_solid_line;
85
86    for(i = 0; i < n; i++)
87    {
88        s.x1 = x[i];
89        s.y1 = y[i];
90        s.x2 = x[i+1];
91        s.y2 = y[i+1];
92        clip_line(&s);
93    }
94}
95
96/**
97 * \brief Draw a thin line on the screen, using ASCII art.
98 *
99 * \param x1 X coordinate of the first point.
100 * \param y1 Y coordinate of the first point.
101 * \param x2 X coordinate of the second point.
102 * \param y2 Y coordinate of the second point.
103 * \return void
104 */
105void caca_draw_thin_line(int x1, int y1, int x2, int y2)
106{
107    struct line s;
108    s.x1 = x1;
109    s.y1 = y1;
110    s.x2 = x2;
111    s.y2 = y2;
112    s.draw = draw_thin_line;
113    clip_line(&s);
114}
115
116void caca_draw_thin_polyline(const int x[], const int y[], int n)
117{
118    int i;
119    struct line s;
120    s.draw = draw_thin_line;
121
122    for(i = 0; i < n; i++)
123    {
124        s.x1 = x[i];
125        s.y1 = y[i];
126        s.x2 = x[i+1];
127        s.y2 = y[i+1];
128        clip_line(&s);
129    }
130}
131
132/*
133 * XXX: The following functions are local.
134 */
135
136/**
137 * \brief Generic Cohen-Sutherland line clipping function.
138 *
139 * \param s a line structure
140 * \return void
141 */
142static void clip_line(struct line* s)
143{
144    uint8_t bits1, bits2;
145
146    bits1 = clip_bits(s->x1, s->y1);
147    bits2 = clip_bits(s->x2, s->y2);
148
149    if(bits1 & bits2)
150        return;
151
152    if(bits1 == 0)
153    {
154        if(bits2 == 0)
155            s->draw(s);
156        else
157        {
158            int tmp;
159            tmp = s->x1; s->x1 = s->x2; s->x2 = tmp;
160            tmp = s->y1; s->y1 = s->y2; s->y2 = tmp;
161            clip_line(s);
162        }
163
164        return;
165    }
166
167    if(bits1 & (1<<0))
168    {
169        s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1);
170        s->x1 = 0;
171    }
172    else if(bits1 & (1<<1))
173    {
174        int xmax = caca_get_width() - 1;
175        s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1);
176        s->x1 = xmax;
177    }
178    else if(bits1 & (1<<2))
179    {
180        s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1);
181        s->y1 = 0;
182    }
183    else if(bits1 & (1<<3))
184    {
185        int ymax = caca_get_height() - 1;
186        s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1);
187        s->y1 = ymax;
188    }
189
190    clip_line(s);
191}
192
193/**
194 * \brief Helper function for clip_line().
195 *
196 * \param x X coordinate of the point.
197 * \param y Y coordinate of the point.
198 * \return b The clipping bits for the given point.
199 */
200static uint8_t clip_bits(int x, int y)
201{
202    uint8_t b = 0;
203
204    if(x < 0)
205        b |= (1<<0);
206    else if(x >= (int)caca_get_width())
207        b |= (1<<1);
208
209    if(y < 0)
210        b |= (1<<2);
211    else if(y >= (int)caca_get_height())
212        b |= (1<<3);
213
214    return b;
215}
216
217/**
218 * \brief Solid line drawing function, using Bresenham's mid-point line
219 *        scan-conversion algorithm.
220 *
221 * \param s a line structure
222 * \return void
223 */
224static void draw_solid_line(struct line* s)
225{
226    int x1, y1, x2, y2;
227    int dx, dy;
228    int xinc, yinc;
229
230    x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
231
232    dx = abs(x2 - x1);
233    dy = abs(y2 - y1);
234
235    xinc = (x1 > x2) ? -1 : 1;
236    yinc = (y1 > y2) ? -1 : 1;
237
238    if(dx >= dy)
239    {
240        int dpr = dy << 1;
241        int dpru = dpr - (dx << 1);
242        int delta = dpr - dx;
243
244        for(; dx>=0; dx--)
245        {
246            caca_putchar(x1, y1, s->c);
247            if(delta > 0)
248            {
249                x1 += xinc;
250                y1 += yinc;
251                delta += dpru;
252            }
253            else
254            {
255                x1 += xinc;
256                delta += dpr;
257            }
258        }
259    }
260    else
261    {
262        int dpr = dx << 1;
263        int dpru = dpr - (dy << 1);
264        int delta = dpr - dy;
265
266        for(; dy >= 0; dy--)
267        {
268            caca_putchar(x1, y1, s->c);
269            if(delta > 0)
270            {
271                x1 += xinc;
272                y1 += yinc;
273                delta += dpru;
274            }
275            else
276            {
277                y1 += yinc;
278                delta += dpr;
279            }
280        }
281    }
282}
283
284/**
285 * \brief Thin line drawing function, using Bresenham's mid-point line
286 *        scan-conversion algorithm and ASCII art graphics.
287 *
288 * \param s a line structure
289 * \return void
290 */
291static void draw_thin_line(struct line* s)
292{
293    char *charmapx, *charmapy;
294    int x1, y1, x2, y2;
295    int dx, dy;
296    int yinc;
297
298    if(s->x2 >= s->x1)
299    {
300        if(s->y1 > s->y2)
301            charmapx = ",'";
302        else
303            charmapx = "`.";
304        x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
305    }
306    else
307    {
308        if(s->y1 > s->y2)
309            charmapx = "`.";
310        else
311            charmapx = ",'";
312        x2 = s->x1; y2 = s->y1; x1 = s->x2; y1 = s->y2;
313    }
314
315    dx = abs(x2 - x1);
316    dy = abs(y2 - y1);
317
318    if(y1 > y2)
319    {
320        charmapy = ",'";
321        yinc = -1;
322    }
323    else
324    {
325        yinc = 1;
326        charmapy = "`.";
327    }
328
329    if(dx >= dy)
330    {
331        int dpr = dy << 1;
332        int dpru = dpr - (dx << 1);
333        int delta = dpr - dx;
334        int prev = 0;
335
336        for(; dx>=0; dx--)
337        {
338            if(delta > 0)
339            {
340                caca_putchar(x1, y1, charmapy[1]);
341                x1++;
342                y1 += yinc;
343                delta += dpru;
344                prev = 1;
345            }
346            else
347            {
348                if(prev)
349                    caca_putchar(x1, y1, charmapy[0]);
350                else
351                    caca_putchar(x1, y1, '-');
352                x1++;
353                delta += dpr;
354                prev = 0;
355            }
356        }
357    }
358    else
359    {
360        int dpr = dx << 1;
361        int dpru = dpr - (dy << 1);
362        int delta = dpr - dy;
363
364        for(; dy >= 0; dy--)
365        {
366            if(delta > 0)
367            {
368                caca_putchar(x1, y1, charmapx[0]);
369                caca_putchar(x1 + 1, y1, charmapx[1]);
370                x1++;
371                y1 += yinc;
372                delta += dpru;
373            }
374            else
375            {
376                caca_putchar(x1, y1, '|');
377                y1 += yinc;
378                delta += dpr;
379            }
380        }
381    }
382}
383
Note: See TracBrowser for help on using the repository browser.