25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

triangle.c 11 KiB

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