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

Last change on this file since 128 was 128, checked in by Sam Hocevar, 17 years ago
  • libee/line.c: + Added code comments.
  • 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 128 2003-11-10 15:16:38Z 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 * \brief Generic Cohen-Sutherland line clipping function.
87 *
88 * \param s a line structure
89 * \return nothing
90 */
91static void clip_line(struct line* s)
92{
93    uint8_t bits1, bits2;
94
95    bits1 = clip_bits(s->x1, s->y1);
96    bits2 = clip_bits(s->x2, s->y2);
97
98    if(bits1 & bits2)
99        return;
100
101    if(bits1 == 0)
102    {
103        if(bits2 == 0)
104            s->draw(s);
105        else
106        {
107            int tmp;
108            tmp = s->x1; s->x1 = s->x2; s->x2 = tmp;
109            tmp = s->y1; s->y1 = s->y2; s->y2 = tmp;
110            clip_line(s);
111        }
112
113        return;
114    }
115
116    if(bits1 & (1<<0))
117    {
118        s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1);
119        s->x1 = 0;
120    }
121    else if( bits1 & (1<<1) )
122    {
123        int xmax = ee_get_width() - 1;
124        s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1);
125        s->x1 = xmax;
126    }
127    else if( bits1 & (1<<2) )
128    {
129        s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1);
130        s->y1 = 0;
131    }
132    else if( bits1 & (1<<3) )
133    {
134        int ymax = ee_get_height() - 1;
135        s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1);
136        s->y1 = ymax;
137    }
138
139    clip_line(s);
140}
141
142/**
143 * \brief Helper function for clip_line().
144 *
145 * \param x X coordinate of the point.
146 * \param y Y coordinate of the point.
147 * \return b The clipping bits for the given point.
148 */
149static uint8_t clip_bits(int x, int y)
150{
151    uint8_t b = 0;
152
153    if(x < 0)
154        b |= (1<<0);
155    else if(x >= ee_get_width())
156        b |= (1<<1);
157
158    if(y < 0)
159        b |= (1<<2);
160    else if(y >= ee_get_height())
161        b |= (1<<3);
162
163    return b;
164}
165
166/**
167 * \brief Solid line drawing function, using Bresenham's mid-point line
168 *        scan-conversion algorithm.
169 *
170 * \param s a line structure
171 * \return nothing
172 */
173static void draw_solid_line(struct line* s)
174{
175    int x1, y1, x2, y2;
176    int dx, dy;
177    int xinc, yinc;
178
179    x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
180
181    dx = abs(x2 - x1);
182    dy = abs(y2 - y1);
183
184    xinc = (x1 > x2) ? -1 : 1;
185    yinc = (y1 > y2) ? -1 : 1;
186
187    if(dx >= dy)
188    {
189        int dpr = dy << 1;
190        int dpru = dpr - (dx << 1);
191        int delta = dpr - dx;
192
193        for(; dx>=0; dx--)
194        {
195            ee_goto(x1, y1);
196            ee_putchar(s->c);
197            if(delta > 0)
198            {
199                x1 += xinc;
200                y1 += yinc;
201                delta += dpru;
202            }
203            else
204            {
205                x1 += xinc;
206                delta += dpr;
207            }
208        }
209    }
210    else
211    {
212        int dpr = dx << 1;
213        int dpru = dpr - (dy << 1);
214        int delta = dpr - dy;
215
216        for(; dy >= 0; dy--)
217        {
218            ee_goto(x1, y1);
219            ee_putchar(s->c);
220            if(delta > 0)
221            {
222                x1 += xinc;
223                y1 += yinc;
224                delta += dpru;
225            }
226            else
227            {
228                y1 += yinc;
229                delta += dpr;
230            }
231        }
232    }
233}
234
235/**
236 * \brief Thin line drawing function, using Bresenham's mid-point line
237 *        scan-conversion algorithm and ASCII art graphics.
238 *
239 * \param s a line structure
240 * \return nothing
241 */
242static void draw_thin_line(struct line* s)
243{
244    char *charmapx, *charmapy;
245    int x1, y1, x2, y2;
246    int dx, dy;
247    int yinc;
248
249    if(s->x2 >= s->x1)
250    {
251        if(s->y1 > s->y2)
252            charmapx = ",'";
253        else
254            charmapx = "`.";
255        x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
256    }
257    else
258    {
259        if(s->y1 > s->y2)
260            charmapx = "`.";
261        else
262            charmapx = ",'";
263        x2 = s->x1; y2 = s->y1; x1 = s->x2; y1 = s->y2;
264    }
265
266    dx = abs(x2 - x1);
267    dy = abs(y2 - y1);
268
269    if(y1 > y2)
270    {
271        charmapy = ",'";
272        yinc = -1;
273    }
274    else
275    {
276        yinc = 1;
277        charmapy = "`.";
278    }
279
280    if(dx >= dy)
281    {
282        int dpr = dy << 1;
283        int dpru = dpr - (dx << 1);
284        int delta = dpr - dx;
285        int prev = 0;
286
287        for(; dx>=0; dx--)
288        {
289            ee_goto(x1, y1);
290            if(delta > 0)
291            {
292                ee_putchar(charmapy[1]);
293                x1++;
294                y1 += yinc;
295                delta += dpru;
296                prev = 1;
297            }
298            else
299            {
300                if(prev)
301                    ee_putchar(charmapy[0]);
302                else
303                    ee_putchar('-');
304                x1++;
305                delta += dpr;
306                prev = 0;
307            }
308        }
309    }
310    else
311    {
312        int dpr = dx << 1;
313        int dpru = dpr - (dy << 1);
314        int delta = dpr - dy;
315
316        for(; dy >= 0; dy--)
317        {
318            ee_goto(x1, y1);
319            if(delta > 0)
320            {
321                ee_putchar(charmapx[0]);
322                ee_putchar(charmapx[1]);
323                x1++;
324                y1 += yinc;
325                delta += dpru;
326            }
327            else
328            {
329                ee_putchar('|');
330                y1 += yinc;
331                delta += dpr;
332            }
333        }
334    }
335}
336
Note: See TracBrowser for help on using the repository browser.