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.
 
 
 
 
 
 

337 lines
9.8 KiB

  1. /*
  2. * libcucul Canvas for ultrafast compositing of Unicode letters
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the Do What The Fuck You Want To
  8. * Public License, Version 2, as published by Sam Hocevar. See
  9. * http://sam.zoy.org/wtfpl/COPYING for more details.
  10. */
  11. /** \file transform.c
  12. * \version \$Id$
  13. * \author Sam Hocevar <sam@zoy.org>
  14. * \brief Canvas transformation
  15. *
  16. * This file contains horizontal and vertical flipping routines.
  17. */
  18. #include "config.h"
  19. #if !defined(__KERNEL__)
  20. #endif
  21. #include "cucul.h"
  22. #include "cucul_internals.h"
  23. static uint32_t flipchar(uint32_t ch);
  24. static uint32_t flopchar(uint32_t ch);
  25. static uint32_t rotatechar(uint32_t ch);
  26. /** \brief Invert a canvas' colours.
  27. *
  28. * This function inverts a canvas' colours (black becomes white, red
  29. * becomes cyan, etc.) without changing the characters in it.
  30. *
  31. * \param qq The canvas to invert.
  32. */
  33. void cucul_invert(cucul_t *qq)
  34. {
  35. uint32_t *attr = qq->attr;
  36. unsigned int i;
  37. for(i = qq->height * qq->width; i--; )
  38. {
  39. *attr = *attr ^ 0x000f000f;
  40. attr++;
  41. }
  42. }
  43. /** \brief Flip a canvas horizontally.
  44. *
  45. * This function flips a canvas horizontally, choosing characters that
  46. * look like the mirrored version wherever possible.
  47. *
  48. * \param qq The canvas to flip.
  49. */
  50. void cucul_flip(cucul_t *qq)
  51. {
  52. unsigned int y;
  53. for(y = 0; y < qq->height; y++)
  54. {
  55. uint32_t *cleft = qq->chars + y * qq->width;
  56. uint32_t *cright = cleft + qq->width - 1;
  57. uint32_t *aleft = qq->attr + y * qq->width;
  58. uint32_t *aright = aleft + qq->width - 1;
  59. while(cleft < cright)
  60. {
  61. uint32_t ch;
  62. uint32_t attr;
  63. /* Swap attributes */
  64. attr = *aright; *aright = *aleft; *aleft = attr;
  65. /* Swap characters */
  66. ch = *cright; *cright = flipchar(*cleft); *cleft = flipchar(ch);
  67. cleft++; cright--; aleft++; aright--;
  68. }
  69. if(cleft == cright)
  70. *cleft = flipchar(*cleft);
  71. }
  72. }
  73. /** \brief Flip a canvas vertically.
  74. *
  75. * This function flips a canvas vertically, choosing characters that
  76. * look like the mirrored version wherever possible.
  77. *
  78. * \param qq The canvas to flop.
  79. */
  80. void cucul_flop(cucul_t *qq)
  81. {
  82. unsigned int x;
  83. for(x = 0; x < qq->width; x++)
  84. {
  85. uint32_t *ctop = qq->chars + x;
  86. uint32_t *cbottom = ctop + qq->width * (qq->height - 1);
  87. uint32_t *atop = qq->attr + x;
  88. uint32_t *abottom = atop + qq->width * (qq->height - 1);
  89. while(ctop < cbottom)
  90. {
  91. uint32_t ch;
  92. uint32_t attr;
  93. /* Swap attributes */
  94. attr = *abottom; *abottom = *atop; *atop = attr;
  95. /* Swap characters */
  96. ch = *cbottom; *cbottom = flopchar(*ctop); *ctop = flopchar(ch);
  97. ctop += qq->width; cbottom -= qq->width;
  98. atop += qq->width; abottom -= qq->width;
  99. }
  100. if(ctop == cbottom)
  101. *ctop = flopchar(*ctop);
  102. }
  103. }
  104. /** \brief Rotate a canvas.
  105. *
  106. * This function applies a 180 degrees transformation to a canvas,
  107. * choosing characters that look like the mirrored version wherever
  108. * possible.
  109. *
  110. * \param qq The canvas to rotate.
  111. */
  112. void cucul_rotate(cucul_t *qq)
  113. {
  114. uint32_t *cbegin = qq->chars;
  115. uint32_t *cend = cbegin + qq->width * qq->height - 1;
  116. uint32_t *abegin = qq->attr;
  117. uint32_t *aend = abegin + qq->width * qq->height - 1;
  118. while(cbegin < cend)
  119. {
  120. uint32_t ch;
  121. uint32_t attr;
  122. /* Swap attributes */
  123. attr = *aend; *aend = *abegin; *abegin = attr;
  124. /* Swap characters */
  125. ch = *cend; *cend = rotatechar(*cbegin); *cbegin = rotatechar(ch);
  126. cbegin++; cend--; abegin++; aend--;
  127. }
  128. if(cbegin == cend)
  129. *cbegin = rotatechar(*cbegin);
  130. }
  131. static uint32_t flipchar(uint32_t ch)
  132. {
  133. int i;
  134. static uint32_t const noflip[] =
  135. {
  136. /* ASCII */
  137. (uint32_t)' ', (uint32_t)'"', (uint32_t)'#', (uint32_t)'\'',
  138. (uint32_t)'-', (uint32_t)'.', (uint32_t)'*', (uint32_t)'+',
  139. (uint32_t)':', (uint32_t)'=',
  140. (uint32_t)'0', (uint32_t)'8', (uint32_t)'A', (uint32_t)'H',
  141. (uint32_t)'I', (uint32_t)'M', (uint32_t)'O', (uint32_t)'T',
  142. (uint32_t)'U', (uint32_t)'V', (uint32_t)'W', (uint32_t)'X',
  143. (uint32_t)'Y', (uint32_t)'^', (uint32_t)'_', (uint32_t)'i',
  144. (uint32_t)'o', (uint32_t)'v', (uint32_t)'w', (uint32_t)'x',
  145. (uint32_t)'|',
  146. /* Unicode */
  147. 0x2591, 0x2592, 0x2593, 0x2588, 0x2584, 0x2580, /* ░ ▒ ▓ █ ▄ ▀ */
  148. 0
  149. };
  150. static uint32_t const pairs[] =
  151. {
  152. /* ASCII */
  153. (uint32_t)'(', (uint32_t)')', (uint32_t)'/', (uint32_t)'\\',
  154. (uint32_t)'<', (uint32_t)'>', (uint32_t)'[', (uint32_t)']',
  155. (uint32_t)'b', (uint32_t)'d', (uint32_t)'p', (uint32_t)'q',
  156. (uint32_t)'{', (uint32_t)'}',
  157. /* ASCII-Unicode */
  158. (uint32_t)';', 0x204f, /* ; ⁏ */
  159. (uint32_t)'`', 0x00b4, /* ` ´ */
  160. (uint32_t)'E', 0x018e, /* E Ǝ */
  161. (uint32_t)'N', 0x0418, /* N И */
  162. (uint32_t)'R', 0x042f, /* R Я */
  163. (uint32_t)'S', 0x01a7, /* S Ƨ */
  164. (uint32_t)'c', 0x0254, /* c ɔ */
  165. (uint32_t)'e', 0x0258, /* e ɘ */
  166. /* Unicode only */
  167. 0x258c, 0x2590, /* ▌ ▐ */
  168. 0x2596, 0x2597, /* ▖ ▗ */
  169. 0x2598, 0x259d, /* ▘ ▝ */
  170. 0x2599, 0x259f, /* ▙ ▟ */
  171. 0x259a, 0x259e, /* ▚ ▞ */
  172. 0x259b, 0x259c, /* ▛ ▜ */
  173. 0
  174. };
  175. for(i = 0; noflip[i]; i++)
  176. if(ch == noflip[i])
  177. return ch;
  178. for(i = 0; pairs[i]; i++)
  179. if(ch == pairs[i])
  180. return pairs[i ^ 1];
  181. return ch;
  182. }
  183. static uint32_t flopchar(uint32_t ch)
  184. {
  185. int i;
  186. static uint32_t const noflop[] =
  187. {
  188. /* ASCII */
  189. (uint32_t)' ', (uint32_t)'(', (uint32_t)')', (uint32_t)'*',
  190. (uint32_t)'+', (uint32_t)'-',
  191. (uint32_t)'0', (uint32_t)'3', (uint32_t)'8', (uint32_t)':',
  192. (uint32_t)'<', (uint32_t)'=', (uint32_t)'>', (uint32_t)'B',
  193. (uint32_t)'C', (uint32_t)'D', (uint32_t)'E', (uint32_t)'H',
  194. (uint32_t)'I', (uint32_t)'K', (uint32_t)'O', (uint32_t)'X',
  195. (uint32_t)'[', (uint32_t)']', (uint32_t)'c', (uint32_t)'o',
  196. (uint32_t)'{', (uint32_t)'|', (uint32_t)'}',
  197. /* Unicode */
  198. 0x2591, 0x2592, 0x2593, 0x2588, 0x258c, 0x2590, /* ░ ▒ ▓ █ ▌ ▐ */
  199. 0
  200. };
  201. static uint32_t const pairs[] =
  202. {
  203. /* ASCII */
  204. (uint32_t)'/', (uint32_t)'\\', (uint32_t)'M', (uint32_t)'W',
  205. (uint32_t)',', (uint32_t)'`', (uint32_t)'b', (uint32_t)'p',
  206. (uint32_t)'d', (uint32_t)'q', (uint32_t)'p', (uint32_t)'q',
  207. (uint32_t)'f', (uint32_t)'t', (uint32_t)'.', (uint32_t)'\'',
  208. /* ASCII-Unicode */
  209. (uint32_t)'_', 0x2594, /* _ ▔ */
  210. (uint32_t)'`', 0x201a, /* ` ‚ */
  211. (uint32_t)'!', 0x00a1, /* ! ¡ */
  212. (uint32_t)'N', 0x0418, /* N И */
  213. (uint32_t)'P', 0x042c, /* P Ь */
  214. (uint32_t)'S', 0x01a7, /* S Ƨ */
  215. (uint32_t)'v', 0x028c, /* v ʌ */
  216. (uint32_t)'w', 0x028d, /* w ʍ */
  217. /* Unicode only */
  218. 0x2584, 0x2580, /* ▄ ▀ */
  219. 0x2596, 0x2598, /* ▖ ▘ */
  220. 0x2597, 0x259d, /* ▗ ▝ */
  221. 0x2599, 0x259b, /* ▙ ▛ */
  222. 0x259f, 0x259c, /* ▟ ▜ */
  223. 0x259a, 0x259e, /* ▚ ▞ */
  224. 0
  225. };
  226. for(i = 0; noflop[i]; i++)
  227. if(ch == noflop[i])
  228. return ch;
  229. for(i = 0; pairs[i]; i++)
  230. if(ch == pairs[i])
  231. return pairs[i ^ 1];
  232. return ch;
  233. }
  234. static uint32_t rotatechar(uint32_t ch)
  235. {
  236. int i;
  237. static uint32_t const norotate[] =
  238. {
  239. /* ASCII - FIXME: a lot are missing */
  240. (uint32_t)' ', (uint32_t)'*', (uint32_t)'+', (uint32_t)'-',
  241. (uint32_t)'0', (uint32_t)'8', (uint32_t)':', (uint32_t)'=',
  242. /* Unicode */
  243. 0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
  244. 0
  245. };
  246. static uint32_t const pairs[] =
  247. {
  248. /* ASCII */
  249. (uint32_t)'(', (uint32_t)')', (uint32_t)'<', (uint32_t)'>',
  250. (uint32_t)'[', (uint32_t)']', (uint32_t)'{', (uint32_t)'}',
  251. (uint32_t)'.', (uint32_t)'\'',
  252. (uint32_t)'6', (uint32_t)'9',
  253. (uint32_t)'M', (uint32_t)'W', (uint32_t)'b', (uint32_t)'q',
  254. (uint32_t)'d', (uint32_t)'p', (uint32_t)'n', (uint32_t)'u',
  255. /* ASCII-Unicode */
  256. (uint32_t)'_', 0x2594, /* _ ▔ */
  257. (uint32_t)',', 0x02bb, /* , ʻ */
  258. (uint32_t)'!', 0x00a1, /* ! ¡ */
  259. (uint32_t)'?', 0x00bf, /* ? ¿ */
  260. (uint32_t)'E', 0x018e, /* E Ǝ */
  261. (uint32_t)'F', 0x2132, /* F Ⅎ */
  262. (uint32_t)'a', 0x0250, /* a ɐ */
  263. (uint32_t)'c', 0x0254, /* c ɔ */
  264. (uint32_t)'e', 0x0259, /* e ə */
  265. (uint32_t)'f', 0x025f, /* f ɟ */
  266. (uint32_t)'h', 0x0265, /* h ɥ */
  267. (uint32_t)'k', 0x029e, /* k ʞ */
  268. (uint32_t)'m', 0x026f, /* m ɯ */
  269. (uint32_t)'r', 0x0279, /* r ɹ */
  270. (uint32_t)'t', 0x0287, /* t ʇ */
  271. (uint32_t)'v', 0x028c, /* v ʌ */
  272. (uint32_t)'w', 0x028d, /* w ʍ */
  273. (uint32_t)'y', 0x028e, /* y ʎ */
  274. /* Unicode only */
  275. 0x258c, 0x2590, /* ▌ ▐ */
  276. 0x2584, 0x2580, /* ▄ ▀ */
  277. 0x2596, 0x259d, /* ▖ ▝ */
  278. 0x2597, 0x2598, /* ▗ ▘ */
  279. 0x2599, 0x259c, /* ▙ ▜ */
  280. 0x259f, 0x259b, /* ▟ ▛ */
  281. 0
  282. };
  283. for(i = 0; norotate[i]; i++)
  284. if(ch == norotate[i])
  285. return ch;
  286. for(i = 0; pairs[i]; i++)
  287. if(ch == pairs[i])
  288. return pairs[i ^ 1];
  289. return ch;
  290. }