source: libcaca/trunk/libee/line.c @ 165

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