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

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