source: ttyvaders/trunk/libee/line.c @ 156

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