Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

line.c 7.2 KiB

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