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.

triangle.c 11 KiB

15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright © 2002—2018 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. }