Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright (c) 2002-2012 Sam Hocevar <sam@hocevar.net>
  4. * All Rights Reserved
  5. *
  6. * This library is free software. It comes without any warranty, to
  7. * the extent permitted by applicable law. You can redistribute it
  8. * and/or modify it under the terms of the Do What the Fuck You Want
  9. * to Public License, Version 2, as published by Sam Hocevar. See
  10. * http://www.wtfpl.net/ for more details.
  11. */
  12. /*
  13. * This file contains triangle drawing functions, both filled and outline.
  14. */
  15. #include "config.h"
  16. #if !defined(__KERNEL__)
  17. # include <stdlib.h>
  18. #endif
  19. #include "caca.h"
  20. #include "caca_internals.h"
  21. /** \brief Draw a triangle on the canvas using the given character.
  22. *
  23. * This function never fails.
  24. *
  25. * \param cv The handle to the libcaca canvas.
  26. * \param x1 X coordinate of the first point.
  27. * \param y1 Y coordinate of the first point.
  28. * \param x2 X coordinate of the second point.
  29. * \param y2 Y coordinate of the second point.
  30. * \param x3 X coordinate of the third point.
  31. * \param y3 Y coordinate of the third point.
  32. * \param ch UTF-32 character to be used to draw the triangle outline.
  33. * \return This function always returns 0.
  34. */
  35. int caca_draw_triangle(caca_canvas_t * cv, int x1, int y1, int x2, int y2,
  36. int x3, int y3, uint32_t ch)
  37. {
  38. caca_draw_line(cv, x1, y1, x2, y2, ch);
  39. caca_draw_line(cv, x2, y2, x3, y3, ch);
  40. caca_draw_line(cv, x3, y3, x1, y1, ch);
  41. return 0;
  42. }
  43. /** \brief Draw a thin triangle on the canvas.
  44. *
  45. * This function never fails.
  46. *
  47. * \param cv The handle to the libcaca canvas.
  48. * \param x1 X coordinate of the first point.
  49. * \param y1 Y coordinate of the first point.
  50. * \param x2 X coordinate of the second point.
  51. * \param y2 Y coordinate of the second point.
  52. * \param x3 X coordinate of the third point.
  53. * \param y3 Y coordinate of the third point.
  54. * \return This function always returns 0.
  55. */
  56. int caca_draw_thin_triangle(caca_canvas_t * cv, int x1, int y1,
  57. int x2, int y2, int x3, int y3)
  58. {
  59. caca_draw_thin_line(cv, x1, y1, x2, y2);
  60. caca_draw_thin_line(cv, x2, y2, x3, y3);
  61. caca_draw_thin_line(cv, x3, y3, x1, y1);
  62. return 0;
  63. }
  64. /** \brief Fill a triangle on the canvas using the given character.
  65. *
  66. * This function never fails.
  67. *
  68. * \param cv The handle to the libcaca canvas.
  69. * \param x1 X coordinate of the first point.
  70. * \param y1 Y coordinate of the first point.
  71. * \param x2 X coordinate of the second point.
  72. * \param y2 Y coordinate of the second point.
  73. * \param x3 X coordinate of the third point.
  74. * \param y3 Y coordinate of the third point.
  75. * \param ch UTF-32 character to be used to fill the triangle.
  76. * \return This function always returns 0.
  77. */
  78. int caca_fill_triangle(caca_canvas_t * cv, int x1, int y1, int x2, int y2,
  79. int x3, int y3, uint32_t ch)
  80. {
  81. int x, y, xmin, xmax, ymin, ymax;
  82. int xx1, xx2, xa, xb, sl21, sl31, sl32;
  83. /* Bubble-sort y1 <= y2 <= y3 */
  84. if (y1 > y2)
  85. return caca_fill_triangle(cv, x2, y2, x1, y1, x3, y3, ch);
  86. if (y2 > y3)
  87. return caca_fill_triangle(cv, x1, y1, x3, y3, x2, y2, ch);
  88. /* Compute slopes and promote precision */
  89. sl21 = (y2 == y1) ? 0 : (x2 - x1) * 0x10000 / (y2 - y1);
  90. sl31 = (y3 == y1) ? 0 : (x3 - x1) * 0x10000 / (y3 - y1);
  91. sl32 = (y3 == y2) ? 0 : (x3 - x2) * 0x10000 / (y3 - y2);
  92. x1 *= 0x10000;
  93. x2 *= 0x10000;
  94. x3 *= 0x10000;
  95. ymin = y1 < 0 ? 0 : y1;
  96. ymax = y3 + 1 < cv->height ? y3 + 1 : cv->height;
  97. if (ymin < y2)
  98. {
  99. xa = x1 + sl21 * (ymin - y1);
  100. xb = x1 + sl31 * (ymin - y1);
  101. }
  102. else if (ymin == y2)
  103. {
  104. xa = x2;
  105. xb = (y1 == y3) ? x3 : x1 + sl31 * (ymin - y1);
  106. }
  107. else /* (ymin > y2) */
  108. {
  109. xa = x3 + sl32 * (ymin - y3);
  110. xb = x3 + sl31 * (ymin - y3);
  111. }
  112. /* Rasterize our triangle */
  113. for (y = ymin; y < ymax; y++)
  114. {
  115. /* Rescale xa and xb, recentering the division */
  116. if (xa < xb)
  117. {
  118. xx1 = (xa + 0x800) / 0x10000;
  119. xx2 = (xb + 0x801) / 0x10000;
  120. }
  121. else
  122. {
  123. xx1 = (xb + 0x800) / 0x10000;
  124. xx2 = (xa + 0x801) / 0x10000;
  125. }
  126. xmin = xx1 < 0 ? 0 : xx1;
  127. xmax = xx2 + 1 < cv->width ? xx2 + 1 : cv->width;
  128. for (x = xmin; x < xmax; x++)
  129. caca_put_char(cv, x, y, ch);
  130. xa += y < y2 ? sl21 : sl32;
  131. xb += sl31;
  132. }
  133. return 0;
  134. }
  135. /* This function actually renders the triangle, but is not exported due to
  136. sam's pedantic will. */
  137. static int caca_fill_triangle_textured_l(caca_canvas_t * cv,
  138. int x1, int y1,
  139. int x2, int y2,
  140. int x3, int y3,
  141. caca_canvas_t * tex,
  142. float u1, float v1,
  143. float u2, float v2,
  144. float u3, float v3)
  145. {
  146. float y2y1, y3y1, y3y2;
  147. float sl12, sl13, sl23;
  148. float usl12, usl13, usl23, vsl12, vsl13, vsl23;
  149. float xa, xb, ua, va, ub, vb, u, v;
  150. uint32_t savedattr;
  151. int tw, th, x, y, s;
  152. #define SWAP_F(a, b) {float c = a; a = b; b = c; }
  153. /* (very) Naive and (very) float-based affine and (very) non-clipped and
  154. (very) non-corrected triangle mapper Accepts arbitrary texture sizes
  155. Coordinates clamped to [0.0 - 1.0] (no repeat) */
  156. if (!cv || !tex)
  157. return -1;
  158. /* Bubble-sort y1 <= y2 <= y3 */
  159. if (y1 > y2)
  160. return caca_fill_triangle_textured_l(cv,
  161. x2, y2, x1, y1, x3, y3,
  162. tex, u2, v2, u1, v1, u3, v3);
  163. if (y2 > y3)
  164. return caca_fill_triangle_textured_l(cv,
  165. x1, y1, x3, y3, x2, y2,
  166. tex, u1, v1, u3, v3, u2, v2);
  167. savedattr = caca_get_attr(cv, -1, -1);
  168. /* Clip texture coordinates */
  169. if (u1 < 0.0f) u1 = 0.0f; else if (u1 > 1.0f) u1 = 1.0f;
  170. if (u2 < 0.0f) u2 = 0.0f; else if (u2 > 1.0f) u2 = 1.0f;
  171. if (u3 < 0.0f) u3 = 0.0f; else if (u3 > 1.0f) u3 = 1.0f;
  172. if (v1 < 0.0f) v1 = 0.0f; else if (v1 > 1.0f) v1 = 1.0f;
  173. if (v2 < 0.0f) v2 = 0.0f; else if (v2 > 1.0f) v2 = 1.0f;
  174. if (v3 < 0.0f) v3 = 0.0f; else if (v3 > 1.0f) v3 = 1.0f;
  175. /* Convert relative tex coordinates to absolute */
  176. tw = caca_get_canvas_width(tex);
  177. th = caca_get_canvas_height(tex);
  178. u1 *= (float)tw;
  179. u2 *= (float)tw;
  180. u3 *= (float)tw;
  181. v1 *= (float)th;
  182. v2 *= (float)th;
  183. v3 *= (float)th;
  184. y2y1 = (float)(y2 - y1);
  185. y3y1 = (float)(y3 - y1);
  186. y3y2 = (float)(y3 - y2);
  187. /* Compute slopes, making sure we don't divide by zero */
  188. /* (in this case, we don't need the value anyway) */
  189. /* FIXME : only compute needed slopes */
  190. sl12 = ((float)x2 - x1) / (y2y1 == 0 ? 1 : y2y1);
  191. sl13 = ((float)x3 - x1) / (y3y1 == 0 ? 1 : y3y1);
  192. sl23 = ((float)x3 - x2) / (y3y2 == 0 ? 1 : y3y2);
  193. usl12 = (u2 - u1) / (y2y1 == 0 ? 1 : y2y1);
  194. usl13 = (u3 - u1) / (y3y1 == 0 ? 1 : y3y1);
  195. usl23 = (u3 - u2) / (y3y2 == 0 ? 1 : y3y2);
  196. vsl12 = (v2 - v1) / (y2y1 == 0 ? 1 : y2y1);
  197. vsl13 = (v3 - v1) / (y3y1 == 0 ? 1 : y3y1);
  198. vsl23 = (v3 - v2) / (y3y2 == 0 ? 1 : y3y2);
  199. xa = (float)x1;
  200. xb = (float)x1;
  201. ua = u1; ub = u1;
  202. va = v1; vb = v1;
  203. s = 0;
  204. /* Top */
  205. for (y = y1; y < y2; y++)
  206. {
  207. float tus, tvs;
  208. if (xb < xa)
  209. {
  210. SWAP_F(xb, xa);
  211. SWAP_F(sl13, sl12);
  212. SWAP_F(ua, ub);
  213. SWAP_F(va, vb);
  214. SWAP_F(usl13, usl12);
  215. SWAP_F(vsl13, vsl12);
  216. s = 1;
  217. }
  218. tus = (ub - ua) / (xb - xa);
  219. tvs = (vb - va) / (xb - xa);
  220. v = va;
  221. u = ua;
  222. /* scanline */
  223. for (x = xa; x < xb; x++)
  224. {
  225. uint32_t attr, c;
  226. u += tus;
  227. v += tvs;
  228. /* FIXME: use caca_get_canvas_attrs / caca_get_canvas_chars */
  229. attr = caca_get_attr(tex, u, v);
  230. c = caca_get_char(tex, u, v);
  231. caca_set_attr(cv, attr);
  232. caca_put_char(cv, x, y, c);
  233. }
  234. xa += sl13;
  235. xb += sl12;
  236. ua += usl13;
  237. va += vsl13;
  238. ub += usl12;
  239. vb += vsl12;
  240. }
  241. if (s)
  242. {
  243. SWAP_F(xb, xa);
  244. SWAP_F(sl13, sl12);
  245. SWAP_F(ua, ub);
  246. SWAP_F(va, vb);
  247. SWAP_F(usl13, usl12);
  248. SWAP_F(vsl13, vsl12);
  249. }
  250. /* Bottom */
  251. xb = (float)x2;
  252. /* These variables are set by 'top' routine and are in an incorrect state
  253. if we only draw the bottom part */
  254. if (y1 == y2)
  255. {
  256. ua = u1;
  257. ub = u2;
  258. va = v1;
  259. vb = v2;
  260. }
  261. for (y = y2; y < y3; y++)
  262. {
  263. float tus, tvs;
  264. if (xb <= xa)
  265. {
  266. SWAP_F(xb, xa);
  267. SWAP_F(sl13, sl23);
  268. SWAP_F(ua, ub);
  269. SWAP_F(va, vb);
  270. SWAP_F(usl13, usl23);
  271. SWAP_F(vsl13, vsl23);
  272. }
  273. tus = (ub - ua) / ((float)xb - xa);
  274. tvs = (vb - va) / ((float)xb - xa);
  275. u = ua;
  276. v = va;
  277. /* scanline */
  278. for (x = xa; x < xb; x++)
  279. {
  280. uint32_t attr, c;
  281. u += tus;
  282. v += tvs;
  283. /* FIXME, can be heavily optimised */
  284. attr = caca_get_attr(tex, u, v);
  285. c = caca_get_char(tex, u, v);
  286. caca_set_attr(cv, attr);
  287. caca_put_char(cv, x, y, c);
  288. }
  289. xa += sl13;
  290. xb += sl23;
  291. ua += usl13;
  292. va += vsl13;
  293. ub += usl23;
  294. vb += vsl23;
  295. }
  296. caca_set_attr(cv, savedattr);
  297. return 0;
  298. }
  299. /** \brief Fill a triangle on the canvas using an arbitrary-sized texture.
  300. *
  301. * This function fails if one or both the canvas are missing
  302. *
  303. * \param cv The handle to the libcaca canvas.
  304. * \param coords The coordinates of the triangle (3{x,y})
  305. * \param tex The handle of the canvas texture.
  306. * \param uv The coordinates of the texture (3{u,v})
  307. * \return This function return 0 if ok, -1 if canvas or texture are missing.
  308. */
  309. int caca_fill_triangle_textured(caca_canvas_t * cv,
  310. int coords[6],
  311. caca_canvas_t * tex, float uv[6])
  312. {
  313. return caca_fill_triangle_textured_l(cv,
  314. coords[0], coords[1],
  315. coords[2], coords[3],
  316. coords[4], coords[5],
  317. tex,
  318. uv[0], uv[1],
  319. uv[2], uv[3], uv[4], uv[5]);
  320. }
  321. /*
  322. * XXX: The following functions are aliases.
  323. */
  324. int cucul_draw_triangle(cucul_canvas_t *, int, int, int, int, int,
  325. int, uint32_t) CACA_ALIAS(caca_draw_triangle);
  326. int cucul_draw_thin_triangle(cucul_canvas_t *, int, int, int, int,
  327. int,
  328. int) CACA_ALIAS(caca_draw_thin_triangle);
  329. int cucul_fill_triangle(cucul_canvas_t *, int, int, int, int, int, int,
  330. uint32_t) CACA_ALIAS(caca_fill_triangle);