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