1 /*
2 * libcaca Colour ASCII-Art library
3 * Copyright (c) 2002-2012 Sam Hocevar <sam@hocevar.net>
4 * All Rights Reserved
5 *
6 * This library is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What the Fuck You Want
9 * to Public License, Version 2, as published by Sam Hocevar. See
10 * http://www.wtfpl.net/ for more details.
11 */
12
13 /*
14 * This file contains ellipse and circle drawing functions, both filled
15 * and outline.
16 */
17
18 #include "config.h"
19
20 #if !defined(__KERNEL__)
21 # include <stdlib.h>
22 #endif
23
24 #include "caca.h"
25 #include "caca_internals.h"
26
27 static void ellipsepoints(caca_canvas_t *, int, int, int, int, uint32_t, int);
28
29 /** \brief Draw a circle on the canvas using the given character.
30 *
31 * This function never fails.
32 *
33 * \param cv The handle to the libcaca canvas.
34 * \param x Center X coordinate.
35 * \param y Center Y coordinate.
36 * \param r Circle radius.
37 * \param ch UTF-32 character to be used to draw the circle outline.
38 * \return This function always returns 0.
39 */
caca_draw_circle(caca_canvas_t * cv,int x,int y,int r,uint32_t ch)40 int caca_draw_circle(caca_canvas_t *cv, int x, int y, int r, uint32_t ch)
41 {
42 int test, dx, dy;
43
44 /* Optimized Bresenham. Kick ass. */
45 for(test = 0, dx = 0, dy = r ; dx <= dy ; dx++)
46 {
47 ellipsepoints(cv, x, y, dx, dy, ch, 1);
48 ellipsepoints(cv, x, y, dy, dx, ch, 1);
49
50 test += test > 0 ? dx - dy-- : dx;
51 }
52
53 return 0;
54 }
55
56 /** \brief Fill an ellipse on the canvas using the given character.
57 *
58 * This function never fails.
59 *
60 * \param cv The handle to the libcaca canvas.
61 * \param xo Center X coordinate.
62 * \param yo Center Y coordinate.
63 * \param a Ellipse X radius.
64 * \param b Ellipse Y radius.
65 * \param ch UTF-32 character to be used to fill the ellipse.
66 * \return This function always returns 0.
67 */
caca_fill_ellipse(caca_canvas_t * cv,int xo,int yo,int a,int b,uint32_t ch)68 int caca_fill_ellipse(caca_canvas_t *cv, int xo, int yo, int a, int b,
69 uint32_t ch)
70 {
71 int d2;
72 int x = 0;
73 int y = b;
74 int d1 = b*b - (a*a*b) + (a*a/4);
75
76 while(a*a*y - a*a/2 > b*b*(x+1))
77 {
78 if(d1 < 0)
79 {
80 d1 += b*b*(2*x+1); /* XXX: "Computer Graphics" has + 3 here. */
81 }
82 else
83 {
84 d1 += b*b*(2*x*1) + a*a*(-2*y+2);
85 caca_draw_line(cv, xo - x, yo - y, xo + x, yo - y, ch);
86 caca_draw_line(cv, xo - x, yo + y, xo + x, yo + y, ch);
87 y--;
88 }
89 x++;
90 }
91
92 caca_draw_line(cv, xo - x, yo - y, xo + x, yo - y, ch);
93 caca_draw_line(cv, xo - x, yo + y, xo + x, yo + y, ch);
94
95 d2 = b*b*(x+0.5)*(x+0.5) + a*a*(y-1)*(y-1) - a*a*b*b;
96 while(y > 0)
97 {
98 if(d2 < 0)
99 {
100 d2 += b*b*(2*x+2) + a*a*(-2*y+3);
101 x++;
102 }
103 else
104 {
105 d2 += a*a*(-2*y+3);
106 }
107
108 y--;
109 caca_draw_line(cv, xo - x, yo - y, xo + x, yo - y, ch);
110 caca_draw_line(cv, xo - x, yo + y, xo + x, yo + y, ch);
111 }
112
113 return 0;
114 }
115
116 /** \brief Draw an ellipse on the canvas using the given character.
117 *
118 * This function never fails.
119 *
120 * \param cv The handle to the libcaca canvas.
121 * \param xo Center X coordinate.
122 * \param yo Center Y coordinate.
123 * \param a Ellipse X radius.
124 * \param b Ellipse Y radius.
125 * \param ch UTF-32 character to be used to draw the ellipse outline.
126 * \return This function always returns 0.
127 */
caca_draw_ellipse(caca_canvas_t * cv,int xo,int yo,int a,int b,uint32_t ch)128 int caca_draw_ellipse(caca_canvas_t *cv, int xo, int yo, int a, int b,
129 uint32_t ch)
130 {
131 int d2;
132 int x = 0;
133 int y = b;
134 int d1 = b*b - (a*a*b) + (a*a/4);
135
136 ellipsepoints(cv, xo, yo, x, y, ch, 0);
137
138 while(a*a*y - a*a/2 > b*b*(x+1))
139 {
140 if(d1 < 0)
141 {
142 d1 += b*b*(2*x+1); /* XXX: "Computer Graphics" has + 3 here. */
143 }
144 else
145 {
146 d1 += b*b*(2*x*1) + a*a*(-2*y+2);
147 y--;
148 }
149 x++;
150 ellipsepoints(cv, xo, yo, x, y, ch, 0);
151 }
152
153 d2 = b*b*(x+0.5)*(x+0.5) + a*a*(y-1)*(y-1) - a*a*b*b;
154 while(y > 0)
155 {
156 if(d2 < 0)
157 {
158 d2 += b*b*(2*x+2) + a*a*(-2*y+3);
159 x++;
160 }
161 else
162 {
163 d2 += a*a*(-2*y+3);
164 }
165
166 y--;
167 ellipsepoints(cv, xo, yo, x, y, ch, 0);
168 }
169
170 return 0;
171 }
172
173 /** \brief Draw a thin ellipse on the canvas.
174 *
175 * This function never fails.
176 *
177 * \param cv The handle to the libcaca canvas.
178 * \param xo Center X coordinate.
179 * \param yo Center Y coordinate.
180 * \param a Ellipse X radius.
181 * \param b Ellipse Y radius.
182 * \return This function always returns 0.
183 */
caca_draw_thin_ellipse(caca_canvas_t * cv,int xo,int yo,int a,int b)184 int caca_draw_thin_ellipse(caca_canvas_t *cv, int xo, int yo, int a, int b)
185 {
186 /* FIXME: this is not correct */
187 int d2;
188 int x = 0;
189 int y = b;
190 int d1 = b*b - (a*a*b) + (a*a/4);
191
192 ellipsepoints(cv, xo, yo, x, y, '-', 1);
193
194 while(a*a*y - a*a/2 > b*b*(x+1))
195 {
196 if(d1 < 0)
197 {
198 d1 += b*b*(2*x+1); /* XXX: "Computer Graphics" has + 3 here. */
199 ellipsepoints(cv, xo, yo, x + 1, y, '0', 1);
200 }
201 else
202 {
203 d1 += b*b*(2*x*1) + a*a*(-2*y+2);
204 y--;
205 ellipsepoints(cv, xo, yo, x + 1, y, '1', 1);
206 }
207 x++;
208
209
210 }
211
212 d2 = b*b*(x+0.5)*(x+0.5) + a*a*(y-1)*(y-1) - a*a*b*b;
213 while(y > 0)
214 {
215 if(d2 < 0)
216 {
217 d2 += b*b*(2*x+2) + a*a*(-2*y+3);
218 x++;
219 ellipsepoints(cv, xo, yo, x , y - 1, '2', 1);
220 }
221 else
222 {
223 d2 += a*a*(-2*y+3);
224 ellipsepoints(cv, xo, yo, x , y - 1, '3', 1);
225 }
226
227 y--;
228
229
230 }
231
232 return 0;
233 }
234
ellipsepoints(caca_canvas_t * cv,int xo,int yo,int x,int y,uint32_t ch,int thin)235 static void ellipsepoints(caca_canvas_t *cv, int xo, int yo, int x, int y,
236 uint32_t ch, int thin)
237 {
238 uint8_t b = 0;
239
240 if(xo + x >= 0 && xo + x < (int)cv->width)
241 b |= 0x1;
242 if(xo - x >= 0 && xo - x < (int)cv->width)
243 b |= 0x2;
244 if(yo + y >= 0 && yo + y < (int)cv->height)
245 b |= 0x4;
246 if(yo - y >= 0 && yo - y < (int)cv->height)
247 b |= 0x8;
248
249 if((b & (0x1|0x4)) == (0x1|0x4)) {
250 uint32_t c = ch;
251
252 if(thin) {
253 switch(c) {
254 case '0':
255 c = '-';
256 break;
257 case '1':
258 c = ',';
259 break;
260 case '2':
261 c = '/';
262 break;
263 case '3':
264 c = '|';
265 break;
266 }
267
268 }
269 caca_put_char(cv, xo + x, yo + y, c);
270 }
271 if((b & (0x2|0x4)) == (0x2|0x4)) {
272 uint32_t c = ch;
273
274 if(thin) {
275 switch(c) {
276 case '0':
277 c = '-';
278 break;
279 case '1':
280 c = '.';
281 break;
282 case '2':
283 c = '\\';
284 break;
285 case '3':
286 c = '|';
287 break;
288 }
289
290 }
291 caca_put_char(cv, xo - x, yo + y, c);
292 }
293
294
295 if((b & (0x1|0x8)) == (0x1|0x8)) {
296 uint32_t c = ch;
297
298 if(thin) {
299 switch(c) {
300 case '0':
301 c = '-';
302 break;
303 case '1':
304 c = '`';
305 break;
306 case '2':
307 c = '\\';
308 break;
309 case '3':
310 c = '|';
311 break;
312 }
313
314 }
315 caca_put_char(cv, xo + x, yo - y, c);
316 }
317
318 if((b & (0x2|0x8)) == (0x2|0x8)) {
319 uint32_t c = ch;
320
321 if(thin) {
322 switch(c) {
323 case '0':
324 c = '-';
325 break;
326 case '1':
327 c = '\'';
328 break;
329 case '2':
330 c = '/';
331 break;
332 case '3':
333 c = '|';
334 break;
335 }
336
337 }
338 caca_put_char(cv, xo - x, yo - y, c);
339 }
340 }
341
342 /*
343 * XXX: The following functions are aliases.
344 */
345
346 int cucul_draw_circle(cucul_canvas_t *, int, int, int, uint32_t)
347 CACA_ALIAS(caca_draw_circle);
348 int cucul_draw_ellipse(cucul_canvas_t *, int, int, int, int, uint32_t)
349 CACA_ALIAS(caca_draw_ellipse);
350 int cucul_draw_thin_ellipse(cucul_canvas_t *, int, int, int, int)
351 CACA_ALIAS(caca_draw_thin_ellipse);
352 int cucul_fill_ellipse(cucul_canvas_t *, int, int, int, int, uint32_t)
353 CACA_ALIAS(caca_fill_ellipse);
354
355