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

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