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 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
15 jaren geleden
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);