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.

преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 18 години
преди 19 години
преди 18 години
преди 19 години
преди 19 години
преди 19 години
преди 18 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 18 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 18 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 18 години
преди 19 години
преди 19 години
преди 18 години
преди 19 години
преди 19 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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. * $Id$
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the Do What The Fuck You Want To
  10. * Public License, Version 2, as published by Sam Hocevar. See
  11. * http://sam.zoy.org/wtfpl/COPYING for more details.
  12. */
  13. /*
  14. * This file contains the main functions used by \e libcucul applications
  15. * to initialise a drawing context.
  16. */
  17. #include "config.h"
  18. #include "common.h"
  19. #if !defined(__KERNEL__)
  20. # include <stdio.h>
  21. # include <stdlib.h>
  22. # include <string.h>
  23. # include <time.h>
  24. # if defined(HAVE_ERRNO_H)
  25. # include <errno.h>
  26. # endif
  27. # include <sys/types.h>
  28. # if defined(HAVE_UNISTD_H)
  29. # include <unistd.h>
  30. # endif
  31. #endif
  32. #include "cucul.h"
  33. #include "cucul_internals.h"
  34. /** \brief Initialise a \e libcucul canvas.
  35. *
  36. * This function initialises internal \e libcucul structures and the backend
  37. * that will be used for subsequent graphical operations. It must be the
  38. * first \e libcucul function to be called in a function. cucul_free_canvas()
  39. * should be called at the end of the program to free all allocated resources.
  40. *
  41. * If one of the desired canvas coordinates is zero, a default canvas size
  42. * of 80x32 is used instead.
  43. *
  44. * If an error occurs, NULL is returned and \b errno is set accordingly:
  45. * - \c ENOMEM Not enough memory for the requested canvas size.
  46. *
  47. * \param width The desired canvas width
  48. * \param height The desired canvas height
  49. * \return A libcucul canvas handle upon success, NULL if an error occurred.
  50. */
  51. cucul_canvas_t * cucul_create_canvas(unsigned int width, unsigned int height)
  52. {
  53. cucul_canvas_t *cv = malloc(sizeof(cucul_canvas_t));
  54. int ret;
  55. if(!cv)
  56. goto nomem;
  57. cv->refcount = 0;
  58. cv->fgcolor = CUCUL_COLOR_LIGHTGRAY;
  59. cv->bgcolor = CUCUL_COLOR_BLACK;
  60. cv->width = cv->height = 0;
  61. cv->chars = NULL;
  62. cv->attr = NULL;
  63. cv->frame = 0;
  64. cv->framecount = 1;
  65. cv->allchars = malloc(sizeof(uint32_t *));
  66. if(!cv->allchars)
  67. {
  68. free(cv);
  69. goto nomem;
  70. }
  71. cv->allattr = malloc(sizeof(uint32_t *));
  72. if(!cv->allattr)
  73. {
  74. free(cv->allchars);
  75. free(cv);
  76. goto nomem;
  77. }
  78. cv->allchars[0] = NULL;
  79. cv->allattr[0] = NULL;
  80. /* Initialise to a default size. 80x32 is arbitrary but matches AAlib's
  81. * default X11 window. When a graphic driver attaches to us, it can set
  82. * a different size. */
  83. if(width && height)
  84. ret = _cucul_set_canvas_size(cv, width, height);
  85. else
  86. ret = _cucul_set_canvas_size(cv, 80, 32);
  87. if(ret < 0)
  88. {
  89. #if defined(HAVE_ERRNO_H)
  90. int saved_errno = errno;
  91. #endif
  92. free(cv->allattr);
  93. free(cv->allchars);
  94. free(cv);
  95. #if defined(HAVE_ERRNO_H)
  96. errno = saved_errno;
  97. #endif
  98. return NULL;
  99. }
  100. /* FIXME: this shouldn't happen here */
  101. _cucul_init_dither();
  102. return cv;
  103. nomem:
  104. #if defined(HAVE_ERRNO_H)
  105. errno = ENOMEM;
  106. #endif
  107. return NULL;
  108. }
  109. /** \brief Resize a canvas.
  110. *
  111. * This function sets the canvas width and height, in character cells.
  112. *
  113. * The contents of the canvas are preserved to the extent of the new
  114. * canvas size. Newly allocated character cells at the right and/or at
  115. * the bottom of the canvas are filled with spaces.
  116. *
  117. * It is an error to try to resize the canvas if an output driver has
  118. * been attached to the canvas using caca_create_display(). You need to
  119. * remove the output driver using caca_free_display() before you can change
  120. * the canvas size again. However, the caca output driver can cause a
  121. * canvas resize through user interaction. See the caca_event() documentation
  122. * for more about this.
  123. *
  124. * If an error occurs, -1 is returned and \b errno is set accordingly:
  125. * - \c EBUSY The canvas is in use by a display driver and cannot be resized.
  126. * - \c ENOMEM Not enough memory for the requested canvas size. If this
  127. * happens, the canvas handle becomes invalid and should not be used.
  128. *
  129. * \param cv A libcucul canvas
  130. * \param width The desired canvas width
  131. * \param height The desired canvas height
  132. * \return 0 in case of success, -1 if an error occurred.
  133. */
  134. int cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
  135. unsigned int height)
  136. {
  137. if(cv->refcount)
  138. {
  139. #if defined(HAVE_ERRNO_H)
  140. errno = EBUSY;
  141. #endif
  142. return -1;
  143. }
  144. return _cucul_set_canvas_size(cv, width, height);
  145. }
  146. /** \brief Get the canvas width.
  147. *
  148. * This function returns the current canvas width, in character cells.
  149. *
  150. * This function never fails.
  151. *
  152. * \param cv A libcucul canvas
  153. * \return The canvas width.
  154. */
  155. unsigned int cucul_get_canvas_width(cucul_canvas_t *cv)
  156. {
  157. return cv->width;
  158. }
  159. /** \brief Get the canvas height.
  160. *
  161. * This function returns the current canvas height, in character cells.
  162. *
  163. * This function never fails.
  164. *
  165. * \param cv A libcucul canvas
  166. * \return The canvas height.
  167. */
  168. unsigned int cucul_get_canvas_height(cucul_canvas_t *cv)
  169. {
  170. return cv->height;
  171. }
  172. /** \brief Translate a colour index into the colour's name.
  173. *
  174. * This function translates a cucul_color enum into a human-readable
  175. * description string of the associated colour.
  176. *
  177. * This function never fails.
  178. *
  179. * \param color The colour value.
  180. * \return A static string containing the colour's name, or \c "unknown" if
  181. * the colour is unknown.
  182. */
  183. char const *cucul_get_color_name(unsigned int color)
  184. {
  185. static char const *color_names[] =
  186. {
  187. "black",
  188. "blue",
  189. "green",
  190. "cyan",
  191. "red",
  192. "magenta",
  193. "brown",
  194. "light gray",
  195. "dark gray",
  196. "light blue",
  197. "light green",
  198. "light cyan",
  199. "light red",
  200. "light magenta",
  201. "yellow",
  202. "white",
  203. };
  204. if(color < 0 || color > 15)
  205. return "unknown";
  206. return color_names[color];
  207. }
  208. /** \brief Uninitialise \e libcucul.
  209. *
  210. * This function frees all resources allocated by cucul_create_canvas(). After
  211. * cucul_free_canvas() has been called, no other \e libcucul functions may be
  212. * used unless a new call to cucul_create_canvas() is done.
  213. *
  214. * If an error occurs, -1 is returned and \b errno is set accordingly:
  215. * - \c EBUSY The canvas is in use by a display driver and cannot be freed.
  216. *
  217. * \param cv A libcucul canvas
  218. * \return 0 in case of success, -1 if an error occurred.
  219. */
  220. int cucul_free_canvas(cucul_canvas_t *cv)
  221. {
  222. unsigned int f;
  223. if(cv->refcount)
  224. {
  225. #if defined(HAVE_ERRNO_H)
  226. errno = EBUSY;
  227. #endif
  228. return -1;
  229. }
  230. /* FIXME: this shouldn't be here either (see above) */
  231. _cucul_end_dither();
  232. for(f = 0; f < cv->framecount; f++)
  233. {
  234. free(cv->allchars[f]);
  235. free(cv->allattr[f]);
  236. }
  237. free(cv);
  238. return 0;
  239. }
  240. /** \brief Generate a random integer within a range.
  241. *
  242. * This function never fails.
  243. *
  244. * \param min The lower bound of the integer range.
  245. * \param max The upper bound of the integer range.
  246. * \return A random integer comprised between \p min and \p max - 1
  247. * (inclusive).
  248. */
  249. int cucul_rand(int min, int max)
  250. {
  251. static int need_init = 1;
  252. if(need_init)
  253. {
  254. srand(getpid() + time(NULL));
  255. need_init = 0;
  256. }
  257. return min + (int)((1.0 * (max - min)) * rand() / (RAND_MAX + 1.0));
  258. }
  259. /*
  260. * XXX: The following functions are local.
  261. */
  262. int _cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
  263. unsigned int height)
  264. {
  265. unsigned int x, y, f, old_width, old_height, new_size, old_size;
  266. old_width = cv->width;
  267. old_height = cv->height;
  268. old_size = old_width * old_height;
  269. cv->width = width;
  270. cv->height = height;
  271. new_size = width * height;
  272. /* Step 1: if new area is bigger, resize the memory area now. */
  273. if(new_size > old_size)
  274. {
  275. for(f = 0; f < cv->framecount; f++)
  276. {
  277. cv->allchars[f] = realloc(cv->allchars[f],
  278. new_size * sizeof(uint32_t));
  279. cv->allattr[f] = realloc(cv->allattr[f],
  280. new_size * sizeof(uint32_t));
  281. if(!cv->allchars[f] || !cv->allattr[f])
  282. {
  283. #if defined(HAVE_ERRNO_H)
  284. errno = ENOMEM;
  285. #endif
  286. return -1;
  287. }
  288. }
  289. }
  290. /* Step 2: move line data if necessary. */
  291. if(width == old_width)
  292. {
  293. /* Width did not change, which means we do not need to move data. */
  294. ;
  295. }
  296. else if(width > old_width)
  297. {
  298. /* New width is bigger than old width, which means we need to
  299. * copy lines starting from the bottom of the screen otherwise
  300. * we will overwrite information. */
  301. for(f = 0; f < cv->framecount; f++)
  302. {
  303. uint32_t *chars = cv->allchars[f];
  304. uint32_t *attr = cv->allattr[f];
  305. for(y = height < old_height ? height : old_height; y--; )
  306. {
  307. for(x = old_width; x--; )
  308. {
  309. chars[y * width + x] = chars[y * old_width + x];
  310. attr[y * width + x] = attr[y * old_width + x];
  311. }
  312. /* Zero the end of the line */
  313. for(x = width - old_width; x--; )
  314. chars[y * width + old_width + x] = (uint32_t)' ';
  315. memset(attr + y * width + old_width, 0,
  316. (width - old_width) * 4);
  317. }
  318. }
  319. }
  320. else
  321. {
  322. /* New width is smaller. Copy as many lines as possible. Ignore
  323. * the first line, it is already in place. */
  324. unsigned int lines = height < old_height ? height : old_height;
  325. for(f = 0; f < cv->framecount; f++)
  326. {
  327. uint32_t *chars = cv->allchars[f];
  328. uint32_t *attr = cv->allattr[f];
  329. for(y = 1; y < lines; y++)
  330. {
  331. for(x = 0; x < width; x++)
  332. {
  333. chars[y * width + x] = chars[y * old_width + x];
  334. attr[y * width + x] = attr[y * old_width + x];
  335. }
  336. }
  337. }
  338. }
  339. /* Step 3: fill the bottom of the new screen if necessary. */
  340. if(height > old_height)
  341. {
  342. for(f = 0; f < cv->framecount; f++)
  343. {
  344. uint32_t *chars = cv->allchars[f];
  345. uint32_t *attr = cv->allattr[f];
  346. /* Zero the bottom of the screen */
  347. for(x = (height - old_height) * width; x--; )
  348. chars[old_height * width + x] = (uint32_t)' ';
  349. memset(attr + old_height * width, 0,
  350. (height - old_height) * width * 4);
  351. }
  352. }
  353. /* Step 4: if new area is smaller, resize memory area now. */
  354. if(new_size <= old_size)
  355. {
  356. for(f = 0; f < cv->framecount; f++)
  357. {
  358. cv->allchars[f] = realloc(cv->allchars[f],
  359. new_size * sizeof(uint32_t));
  360. cv->allattr[f] = realloc(cv->allattr[f],
  361. new_size * sizeof(uint32_t));
  362. if(!cv->allchars[f] || !cv->allattr[f])
  363. {
  364. #if defined(HAVE_ERRNO_H)
  365. errno = ENOMEM;
  366. #endif
  367. return -1;
  368. }
  369. }
  370. }
  371. /* Reset the current frame shortcut */
  372. cv->chars = cv->allchars[cv->frame];
  373. cv->attr = cv->allattr[cv->frame];
  374. return 0;
  375. }