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.
 
 
 
 
 
 

378 lines
11 KiB

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