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.
 
 
 
 
 
 

397 lines
11 KiB

  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright (c) 2002-2006 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://sam.zoy.org/wtfpl/COPYING 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. uint32_t savedattr;
  147. #define SWAP_F(a, b) {float c = a; a = b; b = c; }
  148. /* (very) Naive and (very) float-based affine and (very) non-clipped and
  149. (very) non-corrected triangle mapper Accepts arbitrary texture sizes
  150. Coordinates clamped to [0.0 - 1.0] (no repeat) */
  151. if (!cv || !tex)
  152. return -1;
  153. /* Bubble-sort y1 <= y2 <= y3 */
  154. if (y1 > y2)
  155. return caca_fill_triangle_textured_l(cv,
  156. x2, y2, x1, y1, x3, y3,
  157. tex, u2, v2, u1, v1, u3, v3);
  158. if (y2 > y3)
  159. return caca_fill_triangle_textured_l(cv,
  160. x1, y1, x3, y3, x2, y2,
  161. tex, u1, v1, u3, v3, u2, v2);
  162. savedattr = caca_get_attr(cv, -1, -1);
  163. /* Clip texture coordinates */
  164. if (u1 < 0.0f)
  165. u1 = 0.0f;
  166. if (v1 < 0.0f)
  167. v1 = 0.0f;
  168. if (u2 < 0.0f)
  169. u2 = 0.0f;
  170. if (v2 < 0.0f)
  171. v2 = 0.0f;
  172. if (u3 < 0.0f)
  173. u3 = 0.0f;
  174. if (v3 < 0.0f)
  175. v3 = 0.0f;
  176. if (u1 > 1.0f)
  177. u1 = 1.0f;
  178. if (v1 > 1.0f)
  179. v1 = 1.0f;
  180. if (u2 > 1.0f)
  181. u2 = 1.0f;
  182. if (v2 > 1.0f)
  183. v2 = 1.0f;
  184. if (u3 > 1.0f)
  185. u3 = 1.0f;
  186. if (v3 > 1.0f)
  187. v3 = 1.0f;
  188. /* Convert relative tex coordinates to absolute */
  189. int tw = caca_get_canvas_width(tex);
  190. int th = caca_get_canvas_height(tex);
  191. u1 *= (float)tw;
  192. u2 *= (float)tw;
  193. u3 *= (float)tw;
  194. v1 *= (float)th;
  195. v2 *= (float)th;
  196. v3 *= (float)th;
  197. int x, y;
  198. float y2y1 = y2 - y1;
  199. float y3y1 = y3 - y1;
  200. float y3y2 = y3 - y2;
  201. /* Compute slopes, making sure we don't divide by zero */
  202. /* (in this case, we don't need the value anyway) */
  203. /* FIXME : only compute needed slopes */
  204. float sl12 = ((float)x2 - x1) / (y2y1 == 0 ? 1 : y2y1);
  205. float sl13 = ((float)x3 - x1) / (y3y1 == 0 ? 1 : y3y1);
  206. float sl23 = ((float)x3 - x2) / (y3y2 == 0 ? 1 : y3y2);
  207. float usl12 = (u2 - u1) / (y2y1 == 0 ? 1 : y2y1);
  208. float usl13 = (u3 - u1) / (y3y1 == 0 ? 1 : y3y1);
  209. float usl23 = (u3 - u2) / (y3y2 == 0 ? 1 : y3y2);
  210. float vsl12 = (v2 - v1) / (y2y1 == 0 ? 1 : y2y1);
  211. float vsl13 = (v3 - v1) / (y3y1 == 0 ? 1 : y3y1);
  212. float vsl23 = (v3 - v2) / (y3y2 == 0 ? 1 : y3y2);
  213. float xa = (float)x1, xb = (float)x1;
  214. float ua = u1, ub = u1;
  215. float va = v1, vb = v1;
  216. float u, v;
  217. int s = 0;
  218. /* Top */
  219. for (y = y1; y < y2; y++)
  220. {
  221. if (xb < xa)
  222. {
  223. SWAP_F(xb, xa);
  224. SWAP_F(sl13, sl12);
  225. SWAP_F(ua, ub);
  226. SWAP_F(va, vb);
  227. SWAP_F(usl13, usl12);
  228. SWAP_F(vsl13, vsl12);
  229. s = 1;
  230. }
  231. float tus = (ub - ua) / (xb - xa);
  232. float tvs = (vb - va) / (xb - xa);
  233. v = va;
  234. u = ua;
  235. /* scanline */
  236. for (x = xa; x < xb; x++)
  237. {
  238. u += tus;
  239. v += tvs;
  240. /* FIXME: use caca_get_canvas_attrs / caca_get_canvas_chars */
  241. uint32_t attr = caca_get_attr(tex, u, v);
  242. uint32_t c = caca_get_char(tex, u, v);
  243. caca_set_attr(cv, attr);
  244. caca_put_char(cv, x, y, c);
  245. }
  246. xa += sl13;
  247. xb += sl12;
  248. ua += usl13;
  249. va += vsl13;
  250. ub += usl12;
  251. vb += vsl12;
  252. }
  253. if (s)
  254. {
  255. SWAP_F(xb, xa);
  256. SWAP_F(sl13, sl12);
  257. SWAP_F(ua, ub);
  258. SWAP_F(va, vb);
  259. SWAP_F(usl13, usl12);
  260. SWAP_F(vsl13, vsl12);
  261. }
  262. /* Bottom */
  263. xb = (float)x2;
  264. /* These variables are set by 'top' routine and are in an incorrect state
  265. if we only draw the bottom part */
  266. if (y1 == y2)
  267. {
  268. ua = u1;
  269. ub = u2;
  270. va = v1;
  271. vb = v2;
  272. }
  273. for (y = y2; y < y3; y++)
  274. {
  275. if (xb <= xa)
  276. {
  277. SWAP_F(xb, xa);
  278. SWAP_F(sl13, sl23);
  279. SWAP_F(ua, ub);
  280. SWAP_F(va, vb);
  281. SWAP_F(usl13, usl23);
  282. SWAP_F(vsl13, vsl23);
  283. }
  284. float tus = (ub - ua) / ((float)xb - xa);
  285. float tvs = (vb - va) / ((float)xb - xa);
  286. u = ua;
  287. v = va;
  288. /* scanline */
  289. for (x = xa; x < xb; x++)
  290. {
  291. u += tus;
  292. v += tvs;
  293. /* FIXME, can be heavily optimised */
  294. uint32_t attr = caca_get_attr(tex, u, v);
  295. uint32_t c = caca_get_char(tex, u, v);
  296. caca_set_attr(cv, attr);
  297. caca_put_char(cv, x, y, c);
  298. }
  299. xa += sl13;
  300. xb += sl23;
  301. ua += usl13;
  302. va += vsl13;
  303. ub += usl23;
  304. vb += vsl23;
  305. }
  306. caca_set_attr(cv, savedattr);
  307. return 0;
  308. }
  309. /** \brief Fill a triangle on the canvas using an arbitrary-sized texture.
  310. *
  311. * This function fails if one or both the canvas are missing
  312. *
  313. * \param cv The handle to the libcaca canvas.
  314. * \param coords The coordinates of the triangle (3{x,y})
  315. * \param tex The handle of the canvas texture.
  316. * \param uv The coordinates of the texture (3{u,v})
  317. * \return This function return 0 if ok, -1 if canvas or texture are missing.
  318. */
  319. int caca_fill_triangle_textured(caca_canvas_t * cv,
  320. int coords[6],
  321. caca_canvas_t * tex, float uv[6])
  322. {
  323. return caca_fill_triangle_textured_l(cv,
  324. coords[0], coords[1],
  325. coords[2], coords[3],
  326. coords[4], coords[5],
  327. tex,
  328. uv[0], uv[1],
  329. uv[2], uv[3], uv[4], uv[5]);
  330. }
  331. /*
  332. * XXX: The following functions are aliases.
  333. */
  334. int cucul_draw_triangle(cucul_canvas_t *, int, int, int, int, int,
  335. int, uint32_t) CACA_ALIAS(caca_draw_triangle);
  336. int cucul_draw_thin_triangle(cucul_canvas_t *, int, int, int, int,
  337. int,
  338. int) CACA_ALIAS(caca_draw_thin_triangle);
  339. int cucul_fill_triangle(cucul_canvas_t *, int, int, int, int, int, int,
  340. uint32_t) CACA_ALIAS(caca_fill_triangle);