You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

341 lines
7.2 KiB

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