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.

преди 19 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /*
  2. * libcucul Canvas for ultrafast compositing of Unicode letters
  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. uint32_t 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 str UTF-8 string containing the character to use to draw the line.
  46. * \return void
  47. */
  48. void cucul_draw_line(cucul_t *qq, int x1, int y1, int x2, int y2,
  49. char const *str)
  50. {
  51. struct line s;
  52. s.x1 = x1;
  53. s.y1 = y1;
  54. s.x2 = x2;
  55. s.y2 = y2;
  56. s.c = _cucul_utf8_to_utf32(str);
  57. s.draw = draw_solid_line;
  58. clip_line(qq, &s);
  59. }
  60. /**
  61. * \brief Draw a polyline on the screen using the given character and
  62. * coordinate arrays. The first and last points are not connected,
  63. * so in order to draw a polygon you need to specify the starting
  64. * point at the end of the list as well.
  65. *
  66. * \param x Array of X coordinates. Must have \p n + 1 elements.
  67. * \param y Array of Y coordinates. Must have \p n + 1 elements.
  68. * \param n Number of lines to draw.
  69. * \param str UTF-8 string containing the character to use to draw the lines.
  70. * \return void
  71. */
  72. void cucul_draw_polyline(cucul_t *qq, int const x[], int const y[], int n,
  73. char const *str)
  74. {
  75. int i;
  76. struct line s;
  77. s.c = _cucul_utf8_to_utf32(str);
  78. s.draw = draw_solid_line;
  79. for(i = 0; i < n; i++)
  80. {
  81. s.x1 = x[i];
  82. s.y1 = y[i];
  83. s.x2 = x[i+1];
  84. s.y2 = y[i+1];
  85. clip_line(qq, &s);
  86. }
  87. }
  88. /**
  89. * \brief Draw a thin line on the screen, using ASCII art.
  90. *
  91. * \param x1 X coordinate of the first point.
  92. * \param y1 Y coordinate of the first point.
  93. * \param x2 X coordinate of the second point.
  94. * \param y2 Y coordinate of the second point.
  95. * \return void
  96. */
  97. void cucul_draw_thin_line(cucul_t *qq, int x1, int y1, int x2, int y2)
  98. {
  99. struct line s;
  100. s.x1 = x1;
  101. s.y1 = y1;
  102. s.x2 = x2;
  103. s.y2 = y2;
  104. s.draw = draw_thin_line;
  105. clip_line(qq, &s);
  106. }
  107. /**
  108. * \brief Draw a thin polyline on the screen using the given coordinate
  109. * arrays and with ASCII art. The first and last points are not
  110. * connected, so in order to draw a polygon you need to specify the
  111. * starting point at the end of the list as well.
  112. *
  113. * \param x Array of X coordinates. Must have \p n + 1 elements.
  114. * \param y Array of Y coordinates. Must have \p n + 1 elements.
  115. * \param n Number of lines to draw.
  116. * \return void
  117. */
  118. void cucul_draw_thin_polyline(cucul_t *qq, int const x[], int const y[], int n)
  119. {
  120. int i;
  121. struct line s;
  122. s.draw = draw_thin_line;
  123. for(i = 0; i < n; i++)
  124. {
  125. s.x1 = x[i];
  126. s.y1 = y[i];
  127. s.x2 = x[i+1];
  128. s.y2 = y[i+1];
  129. clip_line(qq, &s);
  130. }
  131. }
  132. /*
  133. * XXX: The following functions are local.
  134. */
  135. /**
  136. * \brief Generic Cohen-Sutherland line clipping function.
  137. *
  138. * \param s a line structure
  139. * \return void
  140. */
  141. static void clip_line(cucul_t *qq, struct line* s)
  142. {
  143. uint8_t bits1, bits2;
  144. bits1 = clip_bits(qq, s->x1, s->y1);
  145. bits2 = clip_bits(qq, s->x2, s->y2);
  146. if(bits1 & bits2)
  147. return;
  148. if(bits1 == 0)
  149. {
  150. if(bits2 == 0)
  151. s->draw(qq, s);
  152. else
  153. {
  154. int tmp;
  155. tmp = s->x1; s->x1 = s->x2; s->x2 = tmp;
  156. tmp = s->y1; s->y1 = s->y2; s->y2 = tmp;
  157. clip_line(qq, s);
  158. }
  159. return;
  160. }
  161. if(bits1 & (1<<0))
  162. {
  163. s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1);
  164. s->x1 = 0;
  165. }
  166. else if(bits1 & (1<<1))
  167. {
  168. int xmax = qq->width - 1;
  169. s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1);
  170. s->x1 = xmax;
  171. }
  172. else if(bits1 & (1<<2))
  173. {
  174. s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1);
  175. s->y1 = 0;
  176. }
  177. else if(bits1 & (1<<3))
  178. {
  179. int ymax = qq->height - 1;
  180. s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1);
  181. s->y1 = ymax;
  182. }
  183. clip_line(qq, s);
  184. }
  185. /**
  186. * \brief Helper function for clip_line().
  187. *
  188. * \param x X coordinate of the point.
  189. * \param y Y coordinate of the point.
  190. * \return The clipping bits for the given point.
  191. */
  192. static uint8_t clip_bits(cucul_t *qq, int x, int y)
  193. {
  194. uint8_t b = 0;
  195. if(x < 0)
  196. b |= (1<<0);
  197. else if(x >= (int)qq->width)
  198. b |= (1<<1);
  199. if(y < 0)
  200. b |= (1<<2);
  201. else if(y >= (int)qq->height)
  202. b |= (1<<3);
  203. return b;
  204. }
  205. /**
  206. * \brief Solid line drawing function, using Bresenham's mid-point line
  207. * scan-conversion algorithm.
  208. *
  209. * \param s a line structure
  210. * \return void
  211. */
  212. static void draw_solid_line(cucul_t *qq, struct line* s)
  213. {
  214. int x1, y1, x2, y2;
  215. int dx, dy;
  216. int xinc, yinc;
  217. x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
  218. dx = abs(x2 - x1);
  219. dy = abs(y2 - y1);
  220. xinc = (x1 > x2) ? -1 : 1;
  221. yinc = (y1 > y2) ? -1 : 1;
  222. if(dx >= dy)
  223. {
  224. int dpr = dy << 1;
  225. int dpru = dpr - (dx << 1);
  226. int delta = dpr - dx;
  227. for(; dx>=0; dx--)
  228. {
  229. _cucul_putchar32(qq, x1, y1, s->c);
  230. if(delta > 0)
  231. {
  232. x1 += xinc;
  233. y1 += yinc;
  234. delta += dpru;
  235. }
  236. else
  237. {
  238. x1 += xinc;
  239. delta += dpr;
  240. }
  241. }
  242. }
  243. else
  244. {
  245. int dpr = dx << 1;
  246. int dpru = dpr - (dy << 1);
  247. int delta = dpr - dy;
  248. for(; dy >= 0; dy--)
  249. {
  250. _cucul_putchar32(qq, x1, y1, s->c);
  251. if(delta > 0)
  252. {
  253. x1 += xinc;
  254. y1 += yinc;
  255. delta += dpru;
  256. }
  257. else
  258. {
  259. y1 += yinc;
  260. delta += dpr;
  261. }
  262. }
  263. }
  264. }
  265. /**
  266. * \brief Thin line drawing function, using Bresenham's mid-point line
  267. * scan-conversion algorithm and ASCII art graphics.
  268. *
  269. * \param s a line structure
  270. * \return void
  271. */
  272. static void draw_thin_line(cucul_t *qq, struct line* s)
  273. {
  274. uint32_t charmapx[2], charmapy[2];
  275. int x1, y1, x2, y2;
  276. int dx, dy;
  277. int yinc;
  278. if(s->x2 >= s->x1)
  279. {
  280. charmapx[0] = (s->y1 > s->y2) ? (uint32_t)',' : (uint32_t)'`';
  281. charmapx[1] = (s->y1 > s->y2) ? (uint32_t)'\'' : (uint32_t)'.';
  282. x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
  283. }
  284. else
  285. {
  286. charmapx[0] = (s->y1 > s->y2) ? (uint32_t)'`' : (uint32_t)'.';
  287. charmapx[1] = (s->y1 > s->y2) ? (uint32_t)',' : (uint32_t)'\'';
  288. x2 = s->x1; y2 = s->y1; x1 = s->x2; y1 = s->y2;
  289. }
  290. dx = abs(x2 - x1);
  291. dy = abs(y2 - y1);
  292. if(y1 > y2)
  293. {
  294. charmapy[0] = (uint32_t)',';
  295. charmapy[1] = (uint32_t)'\'';
  296. yinc = -1;
  297. }
  298. else
  299. {
  300. yinc = 1;
  301. charmapy[0] = (uint32_t)'`';
  302. charmapy[1] = (uint32_t)'.';
  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_putchar32(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_putchar32(qq, x1, y1, charmapy[0]);
  324. else
  325. _cucul_putchar32(qq, x1, y1, (uint32_t)'-');
  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_putchar32(qq, x1, y1, charmapx[0]);
  342. _cucul_putchar32(qq, x1 + 1, y1, charmapx[1]);
  343. x1++;
  344. y1 += yinc;
  345. delta += dpru;
  346. }
  347. else
  348. {
  349. _cucul_putchar32(qq, x1, y1, (uint32_t)'|');
  350. y1 += yinc;
  351. delta += dpr;
  352. }
  353. }
  354. }
  355. }