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.

преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /*
  2. * libcucul Unicode canvas library
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the Do What The Fuck You Want To
  8. * Public License, Version 2, as published by Sam Hocevar. See
  9. * http://sam.zoy.org/wtfpl/COPYING for more details.
  10. */
  11. /** \file line.c
  12. * \version \$Id$
  13. * \author Sam Hocevar <sam@zoy.org>
  14. * \brief Line drawing
  15. *
  16. * This file contains line and polyline drawing functions, with both thin
  17. * and thick styles.
  18. */
  19. #include "config.h"
  20. #if !defined(__KERNEL__)
  21. # include <stdlib.h>
  22. #endif
  23. #include "cucul.h"
  24. #include "cucul_internals.h"
  25. #if !defined(_DOXYGEN_SKIP_ME)
  26. struct line
  27. {
  28. int x1, y1;
  29. int x2, y2;
  30. char c;
  31. void (*draw) (cucul_t *, struct line*);
  32. };
  33. #endif
  34. static void clip_line(cucul_t*, struct line*);
  35. static uint8_t clip_bits(cucul_t*, int, int);
  36. static void draw_solid_line(cucul_t*, struct line*);
  37. static void draw_thin_line(cucul_t*, struct line*);
  38. /**
  39. * \brief Draw a line on the screen using the given character.
  40. *
  41. * \param x1 X coordinate of the first point.
  42. * \param y1 Y coordinate of the first point.
  43. * \param x2 X coordinate of the second point.
  44. * \param y2 Y coordinate of the second point.
  45. * \param c Character to draw the line with.
  46. * \return void
  47. */
  48. void cucul_draw_line(cucul_t *qq, int x1, int y1, int x2, int y2, char c)
  49. {
  50. struct line s;
  51. s.x1 = x1;
  52. s.y1 = y1;
  53. s.x2 = x2;
  54. s.y2 = y2;
  55. s.c = c;
  56. s.draw = draw_solid_line;
  57. clip_line(qq, &s);
  58. }
  59. /**
  60. * \brief Draw a polyline on the screen using the given character and
  61. * coordinate arrays. The first and last points are not connected,
  62. * so in order to draw a polygon you need to specify the starting
  63. * point at the end of the list as well.
  64. *
  65. * \param x Array of X coordinates. Must have \p n + 1 elements.
  66. * \param y Array of Y coordinates. Must have \p n + 1 elements.
  67. * \param n Number of lines to draw.
  68. * \param c Character to draw the lines with.
  69. * \return void
  70. */
  71. void cucul_draw_polyline(cucul_t *qq, int const x[], int const y[], int n, char c)
  72. {
  73. int i;
  74. struct line s;
  75. s.c = c;
  76. s.draw = draw_solid_line;
  77. for(i = 0; i < n; i++)
  78. {
  79. s.x1 = x[i];
  80. s.y1 = y[i];
  81. s.x2 = x[i+1];
  82. s.y2 = y[i+1];
  83. clip_line(qq, &s);
  84. }
  85. }
  86. /**
  87. * \brief Draw a thin line on the screen, using ASCII art.
  88. *
  89. * \param x1 X coordinate of the first point.
  90. * \param y1 Y coordinate of the first point.
  91. * \param x2 X coordinate of the second point.
  92. * \param y2 Y coordinate of the second point.
  93. * \return void
  94. */
  95. void cucul_draw_thin_line(cucul_t *qq, int x1, int y1, int x2, int y2)
  96. {
  97. struct line s;
  98. s.x1 = x1;
  99. s.y1 = y1;
  100. s.x2 = x2;
  101. s.y2 = y2;
  102. s.draw = draw_thin_line;
  103. clip_line(qq, &s);
  104. }
  105. /**
  106. * \brief Draw a thin polyline on the screen using the given coordinate
  107. * arrays and with ASCII art. The first and last points are not
  108. * connected, so in order to draw a polygon you need to specify the
  109. * starting point at the end of the list as well.
  110. *
  111. * \param x Array of X coordinates. Must have \p n + 1 elements.
  112. * \param y Array of Y coordinates. Must have \p n + 1 elements.
  113. * \param n Number of lines to draw.
  114. * \return void
  115. */
  116. void cucul_draw_thin_polyline(cucul_t *qq, int const x[], int const y[], int n)
  117. {
  118. int i;
  119. struct line s;
  120. s.draw = draw_thin_line;
  121. for(i = 0; i < n; i++)
  122. {
  123. s.x1 = x[i];
  124. s.y1 = y[i];
  125. s.x2 = x[i+1];
  126. s.y2 = y[i+1];
  127. clip_line(qq, &s);
  128. }
  129. }
  130. /*
  131. * XXX: The following functions are local.
  132. */
  133. /**
  134. * \brief Generic Cohen-Sutherland line clipping function.
  135. *
  136. * \param s a line structure
  137. * \return void
  138. */
  139. static void clip_line(cucul_t *qq, struct line* s)
  140. {
  141. uint8_t bits1, bits2;
  142. bits1 = clip_bits(qq, s->x1, s->y1);
  143. bits2 = clip_bits(qq, s->x2, s->y2);
  144. if(bits1 & bits2)
  145. return;
  146. if(bits1 == 0)
  147. {
  148. if(bits2 == 0)
  149. s->draw(qq, s);
  150. else
  151. {
  152. int tmp;
  153. tmp = s->x1; s->x1 = s->x2; s->x2 = tmp;
  154. tmp = s->y1; s->y1 = s->y2; s->y2 = tmp;
  155. clip_line(qq, s);
  156. }
  157. return;
  158. }
  159. if(bits1 & (1<<0))
  160. {
  161. s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1);
  162. s->x1 = 0;
  163. }
  164. else if(bits1 & (1<<1))
  165. {
  166. int xmax = qq->width - 1;
  167. s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1);
  168. s->x1 = xmax;
  169. }
  170. else if(bits1 & (1<<2))
  171. {
  172. s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1);
  173. s->y1 = 0;
  174. }
  175. else if(bits1 & (1<<3))
  176. {
  177. int ymax = qq->height - 1;
  178. s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1);
  179. s->y1 = ymax;
  180. }
  181. clip_line(qq, s);
  182. }
  183. /**
  184. * \brief Helper function for clip_line().
  185. *
  186. * \param x X coordinate of the point.
  187. * \param y Y coordinate of the point.
  188. * \return The clipping bits for the given point.
  189. */
  190. static uint8_t clip_bits(cucul_t *qq, int x, int y)
  191. {
  192. uint8_t b = 0;
  193. if(x < 0)
  194. b |= (1<<0);
  195. else if(x >= (int)qq->width)
  196. b |= (1<<1);
  197. if(y < 0)
  198. b |= (1<<2);
  199. else if(y >= (int)qq->height)
  200. b |= (1<<3);
  201. return b;
  202. }
  203. /**
  204. * \brief Solid line drawing function, using Bresenham's mid-point line
  205. * scan-conversion algorithm.
  206. *
  207. * \param s a line structure
  208. * \return void
  209. */
  210. static void draw_solid_line(cucul_t *qq, struct line* s)
  211. {
  212. int x1, y1, x2, y2;
  213. int dx, dy;
  214. int xinc, yinc;
  215. x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
  216. dx = abs(x2 - x1);
  217. dy = abs(y2 - y1);
  218. xinc = (x1 > x2) ? -1 : 1;
  219. yinc = (y1 > y2) ? -1 : 1;
  220. if(dx >= dy)
  221. {
  222. int dpr = dy << 1;
  223. int dpru = dpr - (dx << 1);
  224. int delta = dpr - dx;
  225. for(; dx>=0; dx--)
  226. {
  227. cucul_putchar(qq, x1, y1, s->c);
  228. if(delta > 0)
  229. {
  230. x1 += xinc;
  231. y1 += yinc;
  232. delta += dpru;
  233. }
  234. else
  235. {
  236. x1 += xinc;
  237. delta += dpr;
  238. }
  239. }
  240. }
  241. else
  242. {
  243. int dpr = dx << 1;
  244. int dpru = dpr - (dy << 1);
  245. int delta = dpr - dy;
  246. for(; dy >= 0; dy--)
  247. {
  248. cucul_putchar(qq, x1, y1, s->c);
  249. if(delta > 0)
  250. {
  251. x1 += xinc;
  252. y1 += yinc;
  253. delta += dpru;
  254. }
  255. else
  256. {
  257. y1 += yinc;
  258. delta += dpr;
  259. }
  260. }
  261. }
  262. }
  263. /**
  264. * \brief Thin line drawing function, using Bresenham's mid-point line
  265. * scan-conversion algorithm and ASCII art graphics.
  266. *
  267. * \param s a line structure
  268. * \return void
  269. */
  270. static void draw_thin_line(cucul_t *qq, struct line* s)
  271. {
  272. char *charmapx, *charmapy;
  273. int x1, y1, x2, y2;
  274. int dx, dy;
  275. int yinc;
  276. if(s->x2 >= s->x1)
  277. {
  278. if(s->y1 > s->y2)
  279. charmapx = ",'";
  280. else
  281. charmapx = "`.";
  282. x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
  283. }
  284. else
  285. {
  286. if(s->y1 > s->y2)
  287. charmapx = "`.";
  288. else
  289. charmapx = ",'";
  290. x2 = s->x1; y2 = s->y1; x1 = s->x2; y1 = s->y2;
  291. }
  292. dx = abs(x2 - x1);
  293. dy = abs(y2 - y1);
  294. if(y1 > y2)
  295. {
  296. charmapy = ",'";
  297. yinc = -1;
  298. }
  299. else
  300. {
  301. yinc = 1;
  302. charmapy = "`.";
  303. }
  304. if(dx >= dy)
  305. {
  306. int dpr = dy << 1;
  307. int dpru = dpr - (dx << 1);
  308. int delta = dpr - dx;
  309. int prev = 0;
  310. for(; dx>=0; dx--)
  311. {
  312. if(delta > 0)
  313. {
  314. cucul_putchar(qq, x1, y1, charmapy[1]);
  315. x1++;
  316. y1 += yinc;
  317. delta += dpru;
  318. prev = 1;
  319. }
  320. else
  321. {
  322. if(prev)
  323. cucul_putchar(qq, x1, y1, charmapy[0]);
  324. else
  325. cucul_putchar(qq, x1, y1, '-');
  326. x1++;
  327. delta += dpr;
  328. prev = 0;
  329. }
  330. }
  331. }
  332. else
  333. {
  334. int dpr = dx << 1;
  335. int dpru = dpr - (dy << 1);
  336. int delta = dpr - dy;
  337. for(; dy >= 0; dy--)
  338. {
  339. if(delta > 0)
  340. {
  341. cucul_putchar(qq, x1, y1, charmapx[0]);
  342. cucul_putchar(qq, x1 + 1, y1, charmapx[1]);
  343. x1++;
  344. y1 += yinc;
  345. delta += dpru;
  346. }
  347. else
  348. {
  349. cucul_putchar(qq, x1, y1, '|');
  350. y1 += yinc;
  351. delta += dpr;
  352. }
  353. }
  354. }
  355. }