您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

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