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.
 
 
 
 
 

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