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.
 
 
 
 
 
 

254 line
7.7 KiB

  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright (c) 2002-2009 Sam Hocevar <sam@hocevar.net>
  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 the dirty rectangle handling functions.
  16. *
  17. *
  18. * About dirty rectangles:
  19. *
  20. * * Dirty rectangles MUST NOT be larger than the canvas. If the user
  21. * provides a large rectangle through caca_add_dirty_rect(), or if the
  22. * canvas changes size to become smaller, all dirty rectangles MUST
  23. * immediately be clipped to the canvas size.
  24. */
  25. #include "config.h"
  26. #if !defined(__KERNEL__)
  27. # include <stdio.h>
  28. #endif
  29. #include "caca.h"
  30. #include "caca_internals.h"
  31. /** \brief Get the number of dirty rectangles in the canvas.
  32. *
  33. * Get the number of dirty rectangles in a canvas. Dirty rectangles are
  34. * areas that contain cells that have changed since the last reset.
  35. *
  36. * The dirty rectangles are used internally by display drivers to optimise
  37. * rendering by avoiding to redraw the whole screen. Once the display driver
  38. * has rendered the canvas, it resets the dirty rectangle list.
  39. *
  40. * Dirty rectangles are guaranteed not to overlap.
  41. *
  42. * This function never fails.
  43. *
  44. * \param cv A libcaca canvas.
  45. * \return The number of dirty rectangles in the given canvas.
  46. */
  47. int caca_get_dirty_rect_count(caca_canvas_t *cv)
  48. {
  49. return cv->ndirty;
  50. }
  51. /** \brief Get a canvas's dirty rectangle.
  52. *
  53. * Get the canvas's given dirty rectangle coordinates. The index must be
  54. * within the dirty rectangle count. See caca_get_dirty_rect_count()
  55. * for how to compute this count.
  56. *
  57. * If an error occurs, no coordinates are written in the pointer arguments,
  58. * -1 is returned and \b errno is set accordingly:
  59. * - \c EINVAL Specified rectangle index is out of bounds.
  60. *
  61. * \param cv A libcaca canvas.
  62. * \param r The requested rectangle index.
  63. * \param x A pointer to an integer where the leftmost edge of the
  64. * dirty rectangle will be stored.
  65. * \param y A pointer to an integer where the topmost edge of the
  66. * dirty rectangle will be stored.
  67. * \param width A pointer to an integer where the width of the
  68. * dirty rectangle will be stored.
  69. * \param height A pointer to an integer where the height of the
  70. * dirty rectangle will be stored.
  71. * \return 0 in case of success, -1 if an error occurred.
  72. */
  73. int caca_get_dirty_rect(caca_canvas_t *cv, int r,
  74. int *x, int *y, int *width, int *height)
  75. {
  76. if(r < 0 || r >= cv->ndirty)
  77. {
  78. seterrno(EINVAL);
  79. return -1;
  80. }
  81. *x = cv->dirty[r].xmin;
  82. *y = cv->dirty[r].ymin;
  83. *width = cv->dirty[r].xmax - cv->dirty[r].xmin + 1;
  84. *height = cv->dirty[r].ymax - cv->dirty[r].ymin + 1;
  85. debug("dirty #%i: %ix%i at (%i,%i)\n", r, *width, *height, *x, *y);
  86. return 0;
  87. }
  88. /** \brief Add an area to the canvas's dirty rectangle list.
  89. *
  90. * Add an invalidating zone to the canvas's dirty rectangle list. For more
  91. * information about the dirty rectangles, see caca_get_dirty_rect().
  92. *
  93. * This function may be useful to force refresh of a given zone of the
  94. * canvas even if the dirty rectangle tracking indicates that it is
  95. * unchanged. This may happen if the canvas contents were somewhat
  96. * directly modified.
  97. *
  98. * If an error occurs, -1 is returned and \b errno is set accordingly:
  99. * - \c EINVAL Specified rectangle coordinates are out of bounds.
  100. *
  101. * \param cv A libcaca canvas.
  102. * \param x The leftmost edge of the additional dirty rectangle.
  103. * \param y The topmost edge of the additional dirty rectangle.
  104. * \param width The width of the additional dirty rectangle.
  105. * \param height The height of the additional dirty rectangle.
  106. * \return 0 in case of success, -1 if an error occurred.
  107. */
  108. int caca_add_dirty_rect(caca_canvas_t *cv, int x, int y, int width, int height)
  109. {
  110. debug("new dirty: %ix%i at (%i,%i)\n", width, height, x, y);
  111. /* Clip arguments to canvas */
  112. if(x < 0) { width += x; x = 0; }
  113. if(x + width > cv->width)
  114. width = cv->width - x;
  115. if(y < 0) { height += y; y = 0; }
  116. if(y + height > cv->height)
  117. height = cv->height - y;
  118. /* Ignore empty and out-of-canvas rectangles */
  119. if(width <= 0 || height <= 0)
  120. {
  121. seterrno(EINVAL);
  122. return -1;
  123. }
  124. /* Add dirty rectangle to list. Current strategy: if there is room
  125. * for rectangles, just append it to the list. Otherwise, merge the
  126. * new rectangle with the first in the list. */
  127. if(cv->ndirty < MAX_DIRTY_COUNT)
  128. {
  129. cv->dirty[cv->ndirty].xmin = x;
  130. cv->dirty[cv->ndirty].xmax = x + width - 1;
  131. cv->dirty[cv->ndirty].ymin = y;
  132. cv->dirty[cv->ndirty].ymax = y + height - 1;
  133. cv->ndirty++;
  134. }
  135. else
  136. {
  137. /* FIXME We may get overlapping rectangles like this */
  138. if(x < cv->dirty[0].xmin)
  139. cv->dirty[0].xmin = x;
  140. if(x + width - 1 > cv->dirty[0].xmax)
  141. cv->dirty[0].xmax = x + width - 1;
  142. if(y < cv->dirty[0].ymin)
  143. cv->dirty[0].ymin = y;
  144. if(y + height - 1 > cv->dirty[0].ymax)
  145. cv->dirty[0].ymax = y + height - 1;
  146. }
  147. return 0;
  148. }
  149. /** \brief Remove an area from the dirty rectangle list.
  150. *
  151. * Mark a cell area in the canvas as not dirty. For more information about
  152. * the dirty rectangles, see caca_get_dirty_rect().
  153. *
  154. * Values such that \b xmin > \b xmax or \b ymin > \b ymax indicate that
  155. * the dirty rectangle is empty. They will be silently ignored.
  156. *
  157. * If an error occurs, -1 is returned and \b errno is set accordingly:
  158. * - \c EINVAL Specified rectangle coordinates are out of bounds.
  159. *
  160. * \param cv A libcaca canvas.
  161. * \param x The leftmost edge of the clean rectangle.
  162. * \param y The topmost edge of the clean rectangle.
  163. * \param width The width of the clean rectangle.
  164. * \param height The height of the clean rectangle.
  165. * \return 0 in case of success, -1 if an error occurred.
  166. */
  167. int caca_remove_dirty_rect(caca_canvas_t *cv, int x, int y,
  168. int width, int height)
  169. {
  170. /* Clip arguments to canvas size */
  171. if(x < 0) { width += x; x = 0; }
  172. if(x + width > cv->width)
  173. width = cv->width - x;
  174. if(y < 0) { height += y; y = 0; }
  175. if(y + height > cv->height)
  176. height = cv->height - y;
  177. /* Ignore empty and out-of-canvas rectangles */
  178. if(width <= 0 || height <= 0)
  179. {
  180. seterrno(EINVAL);
  181. return -1;
  182. }
  183. /* FIXME: implement this function. It's OK to have it do nothing,
  184. * since we take a conservative approach in dirty rectangle handling,
  185. * but we ought to help the rendering eventually. */
  186. return 0;
  187. }
  188. /** \brief Clear a canvas's dirty rectangle list.
  189. *
  190. * Empty the canvas's dirty rectangle list.
  191. *
  192. * This function never fails.
  193. *
  194. * \param cv A libcaca canvas.
  195. * \return This function always returns 0.
  196. */
  197. int caca_clear_dirty_rect_list(caca_canvas_t *cv)
  198. {
  199. cv->ndirty = 0;
  200. return 0;
  201. }
  202. /*
  203. * XXX: the following functions are local.
  204. */
  205. /* Clip all dirty rectangles in case they're larger than the canvas */
  206. void _caca_clip_dirty_rect_list(caca_canvas_t *cv)
  207. {
  208. int i;
  209. for(i = 0; i < cv->ndirty; i++)
  210. {
  211. if(cv->dirty[i].xmin < 0)
  212. cv->dirty[i].xmin = 0;
  213. if(cv->dirty[i].ymin < 0)
  214. cv->dirty[i].ymin = 0;
  215. if(cv->dirty[i].xmax >= cv->width)
  216. cv->dirty[i].xmax = cv->width - 1;
  217. if(cv->dirty[i].ymax >= cv->height)
  218. cv->dirty[i].ymax = cv->height - 1;
  219. }
  220. }