Browse Source

Change the dirty rectangle API so that it can handle several rectangles. The

inner implementation still only handles one dirty rectangle, but this way
we can prepare supporting applictions for the future.
tags/v0.99.beta17
Sam Hocevar sam 15 years ago
parent
commit
a6b98c2518
12 changed files with 395 additions and 274 deletions
  1. +1
    -0
      caca/Makefile.am
  2. +12
    -4
      caca/caca.h
  3. +0
    -127
      caca/canvas.c
  4. +215
    -0
      caca/dirty.c
  5. +45
    -43
      caca/driver/slang.c
  6. +44
    -41
      caca/driver/x11.c
  7. +2
    -2
      caca/frame.c
  8. +1
    -1
      caca/graphics.c
  9. +4
    -0
      caca/libcaca.vcproj
  10. +2
    -2
      caca/string.c
  11. +8
    -8
      caca/transform.c
  12. +61
    -46
      tests/dirty.cpp

+ 1
- 0
caca/Makefile.am View File

@@ -23,6 +23,7 @@ libcaca_la_SOURCES = \
caca0.c \
caca0.h \
canvas.c \
dirty.c \
string.c \
legacy.c \
transform.c \


+ 12
- 4
caca/caca.h View File

@@ -220,10 +220,6 @@ __extern char const * caca_get_version(void);
*
* @{ */
#define CACA_MAGIC_FULLWIDTH 0x000ffffe /**< Used to indicate that the previous character was a fullwidth glyph. */
__extern int caca_get_dirty_rectangle(caca_canvas_t *, int *, int *,
int *, int *);
__extern int caca_add_dirty_rectangle(caca_canvas_t *, int, int, int, int);
__extern int caca_set_dirty_rectangle(caca_canvas_t *, int, int, int, int);
__extern int caca_gotoxy(caca_canvas_t *, int, int);
__extern int caca_get_cursor_x(caca_canvas_t const *);
__extern int caca_get_cursor_y(caca_canvas_t const *);
@@ -240,6 +236,18 @@ __extern int caca_blit(caca_canvas_t *, int, int, caca_canvas_t const *,
__extern int caca_set_canvas_boundaries(caca_canvas_t *, int, int, int, int);
/* @} */

/** \defgroup caca_dirty libcaca dirty rectangle manipulation
*
* These functions manipulate dirty rectangles for optimised blitting.
* @{ */
__extern int caca_get_dirty_rectangle_count(caca_canvas_t *);
__extern int caca_get_dirty_rectangle(caca_canvas_t *, int, int *, int *,
int *, int *);
__extern int caca_add_dirty_rectangle(caca_canvas_t *, int, int, int, int);
__extern int caca_remove_dirty_rectangle(caca_canvas_t *, int, int, int, int);
__extern int caca_clear_dirty_rectangle_list(caca_canvas_t *);
/* @} */

/** \defgroup caca_transform libcaca canvas transformation
*
* These functions perform horizontal and vertical canvas flipping.


+ 0
- 127
caca/canvas.c View File

@@ -298,133 +298,6 @@ uint8_t const * caca_get_canvas_attrs(caca_canvas_t const *cv)
return (uint8_t const *)cv->attrs;
}

/** \brief Get a canvas's dirty rectangle.
*
* Get the canvas's dirty rectangle coordinates. The dirty rectangle is
* the smallest area containing all the cells that have changed since it
* was last reset.
*
* The dirty rectangle is used internally by display drivers to optimise
* rendering by avoiding to redraw the whole screen. Once the display driver
* has rendered the canvas, it resets the dirty rectangle.
*
* Values such that \b xmin > \b xmax or \b ymin > \b ymax indicate that
* the dirty rectangle is empty. It means that the canvas's contents have
* not changed since the dirty rectangle was last reset.
*
* FIXME: having only one dirty rectangle instead of a list of rectangles
* is a severe limitation, but the potential gain does not yet look to be
* worth the implementation complexity of a multiple-rectangle scheme.
*
* This function never fails.
*
* \param cv A libcaca canvas.
* \param xmin A pointer to an integer where the leftmost edge of the
* dirty rectangle will be stored.
* \param ymin A pointer to an integer where the topmost edge of the
* dirty rectangle will be stored.
* \param xmax A pointer to an integer where the rightmost edge of the
* dirty rectangle will be stored.
* \param ymax A pointer to an integer where the bottommost edge of the
* dirty rectangle will be stored.
* \return This function always returns 0.
*/
int caca_get_dirty_rectangle(caca_canvas_t *cv, int *xmin, int *ymin,
int *xmax, int *ymax)
{
*xmin = cv->dirty_xmin;
*xmax = cv->dirty_xmax;
*ymin = cv->dirty_ymin;
*ymax = cv->dirty_ymax;

return 0;
}

/** \brief Add a dirty rectangle to the canvas's dirty rectangle.
*
* Add an invalidating zone to the canvas's dirty rectangle. For more
* information about the dirty rectangle, see caca_get_dirty_rectangle().
*
* This function may be useful to force refresh of a given zone of the
* canvas even if the dirty rectangle tracking indicates that it is
* unchanged.
*
* Values such that \b xmin > \b xmax or \b ymin > \b ymax indicate that
* the dirty rectangle is empty. They will be silently ignored.
*
* This function never fails.
*
* \param cv A libcaca canvas.
* \param xmin The leftmost edge of the additional dirty rectangle.
* \param ymin The topmost edge of the additional dirty rectangle.
* \param xmax The rightmost edge of the additional dirty rectangle.
* \param ymax The bottommost edge of the additional dirty rectangle.
* \return This function always returns 0.
*/
int caca_add_dirty_rectangle(caca_canvas_t *cv, int xmin, int ymin,
int xmax, int ymax)
{
/* Ignore empty rectangles. */
if(xmin > xmax || ymin > ymax)
return 0;

/* Ignore out-of-bounds rectangles. */
if(xmax < 0 || xmin >= cv->width || ymax < 0 || ymin >= cv->height)
return 0;

if(xmin < cv->dirty_xmin)
cv->dirty_xmin = xmin;

if(xmax > cv->dirty_xmax)
cv->dirty_xmax = xmax;

if(ymin < cv->dirty_ymin)
cv->dirty_ymin = ymin;

if(ymax > cv->dirty_ymax)
cv->dirty_ymax = ymax;

return 0;
}

/** \brief Set a canvas's dirty rectangle.
*
* Set the canvas's dirty rectangle coordinates. For more information
* about the dirty rectangle, see caca_get_dirty_rectangle().
*
* Values such that \b xmin > \b xmax or \b ymin > \b ymax indicate that
* the dirty rectangle is empty.
*
* This function never fails.
*
* \param cv A libcaca canvas.
* \param xmin The leftmost edge of the desired dirty rectangle.
* \param ymin The topmost edge of the desired dirty rectangle.
* \param xmax The rightmost edge of the desired dirty rectangle.
* \param ymax The bottommost edge of the desired dirty rectangle.
* \return This function always returns 0.
*/
int caca_set_dirty_rectangle(caca_canvas_t *cv, int xmin, int ymin,
int xmax, int ymax)
{
/* Normalise values indicating an empty or out-of-bounds rectangle. */
if(xmin > xmax || ymin > ymax ||
xmax < 0 || xmin >= cv->width || ymax < 0 || ymin >= cv->height)
{
xmin = cv->width;
xmax = -1;
ymin = cv->height;
ymax = -1;
}

cv->dirty_xmin = xmin;
cv->dirty_xmax = xmax;
cv->dirty_ymin = ymin;
cv->dirty_ymax = ymax;

return 0;
}

/** \brief Free a \e libcaca canvas.
*
* Free all resources allocated by caca_create_canvas(). The canvas


+ 215
- 0
caca/dirty.c View File

@@ -0,0 +1,215 @@
/*
* libcaca Colour ASCII-Art library
* Copyright (c) 2002-2009 Sam Hocevar <sam@hocevar.net>
* All Rights Reserved
*
* $Id$
*
* This library is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/

/*
* This file contains the dirty rectangle handling functions.
*/

#include "config.h"

#if !defined(__KERNEL__)
# include <stdio.h>
#endif

#include "caca.h"
#include "caca_internals.h"

/** \brief Get the number of dirty rectangles in the canvas.
*
* Get the number of dirty rectangles in a canvas. Dirty rectangles are
* areas that contain cells that have changed since the last reset.
*
* The dirty rectangles are used internally by display drivers to optimise
* rendering by avoiding to redraw the whole screen. Once the display driver
* has rendered the canvas, it resets the dirty rectangle list.
*
* Dirty rectangles are guaranteed not to overlap.
*
* This function never fails.
*
* \param cv A libcaca canvas.
* \return The number of dirty rectangles in the given canvas.
*/
int caca_get_dirty_rectangle_count(caca_canvas_t *cv)
{
/* Ignore empty rectangles. */
if(cv->dirty_xmin > cv->dirty_xmax || cv->dirty_ymin > cv->dirty_ymax)
return 0;

/* Ignore out-of-bounds rectangles. */
if(cv->dirty_xmax < 0 || cv->dirty_xmin >= cv->width
|| cv->dirty_ymax < 0 || cv->dirty_ymin >= cv->height)
return 0;

return 1;
}

/** \brief Get a canvas's dirty rectangle.
*
* Get the canvas's given dirty rectangle coordinates. The index must be
* within the dirty rectangle count. See caca_get_dirty_rectangle_count()
* for how to compute this count.
*
* If an error occurs, no coordinates are written in the pointer arguments,
* -1 is returned and \b errno is set accordingly:
* - \c EINVAL Specified rectangle index is out of bounds.
*
* \param cv A libcaca canvas.
* \param index The requested rectangle index.
* \param xmin A pointer to an integer where the leftmost edge of the
* dirty rectangle will be stored.
* \param ymin A pointer to an integer where the topmost edge of the
* dirty rectangle will be stored.
* \param xmax A pointer to an integer where the rightmost edge of the
* dirty rectangle will be stored.
* \param ymax A pointer to an integer where the bottommost edge of the
* dirty rectangle will be stored.
* \return 0 in case of success, -1 if an error occurred.
*/
int caca_get_dirty_rectangle(caca_canvas_t *cv, int index,
int *xmin, int *ymin, int *xmax, int *ymax)
{
/* For now, index can only be zero, and if the dirty rectangle is
* empty, we don't return anything. */
if(index < 0 || index > 0
|| cv->dirty_xmin > cv->dirty_xmax || cv->dirty_ymin > cv->dirty_ymax
|| cv->dirty_xmax < 0 || cv->dirty_xmin >= cv->width
|| cv->dirty_ymax < 0 || cv->dirty_ymin >= cv->height)
{
seterrno(EINVAL);
return -1;
}

/* Normalise dirty rectangle so that the values can be directly used. */
if(cv->dirty_xmin < 0)
cv->dirty_xmin = 0;

if(cv->dirty_xmax > cv->width - 1)
cv->dirty_xmax = cv->width - 1;

if(cv->dirty_ymin < 0)
cv->dirty_ymin = 0;

if(cv->dirty_ymax > cv->height - 1)
cv->dirty_ymax = cv->height - 1;

*xmin = cv->dirty_xmin;
*xmax = cv->dirty_xmax;
*ymin = cv->dirty_ymin;
*ymax = cv->dirty_ymax;

return 0;
}

/** \brief Add an area to the canvas's dirty rectangle list.
*
* Add an invalidating zone to the canvas's dirty rectangle list. For more
* information about the dirty rectangles, see caca_get_dirty_rectangle().
*
* This function may be useful to force refresh of a given zone of the
* canvas even if the dirty rectangle tracking indicates that it is
* unchanged. This may happen if the canvas contents were somewhat
* directly modified.
*
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Specified rectangle coordinates are out of bounds.
*
* \param cv A libcaca canvas.
* \param xmin The leftmost edge of the additional dirty rectangle.
* \param ymin The topmost edge of the additional dirty rectangle.
* \param xmax The rightmost edge of the additional dirty rectangle.
* \param ymax The bottommost edge of the additional dirty rectangle.
* \return 0 in case of success, -1 if an error occurred.
*/
int caca_add_dirty_rectangle(caca_canvas_t *cv, int xmin, int ymin,
int xmax, int ymax)
{
/* Ignore empty and out-of-bounds rectangles */
if(xmin > xmax || ymin > ymax
|| xmax < 0 || xmin >= cv->width || ymax < 0 || ymin >= cv->height)
{
seterrno(EINVAL);
return -1;
}

if(xmin < cv->dirty_xmin)
cv->dirty_xmin = xmin;

if(xmax > cv->dirty_xmax)
cv->dirty_xmax = xmax;

if(ymin < cv->dirty_ymin)
cv->dirty_ymin = ymin;

if(ymax > cv->dirty_ymax)
cv->dirty_ymax = ymax;

return 0;
}

/** \brief Remove an area from the dirty rectangle list.
*
* Mark a cell area in the canvas as not dirty. For more information about
* the dirty rectangles, see caca_get_dirty_rectangle().
*
* Values such that \b xmin > \b xmax or \b ymin > \b ymax indicate that
* the dirty rectangle is empty. They will be silently ignored.
*
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Specified rectangle coordinates are out of bounds.
*
* \param cv A libcaca canvas.
* \param xmin The leftmost edge of the clean rectangle.
* \param ymin The topmost edge of the clean rectangle.
* \param xmax The rightmost edge of the clean rectangle.
* \param ymax The bottommost edge of the clean rectangle.
* \return 0 in case of success, -1 if an error occurred.
*/
int caca_remove_dirty_rectangle(caca_canvas_t *cv, int xmin, int ymin,
int xmax, int ymax)
{
/* Ignore empty and out-of-bounds rectangles */
if(xmin > xmax || ymin > ymax
|| xmax < 0 || xmin >= cv->width || ymax < 0 || ymin >= cv->height)
{
seterrno(EINVAL);
return -1;
}

/* FIXME: implement this function. It's OK to have it do nothing,
* since we take a conservative approach in dirty rectangle handling,
* but we ought to help the rendering eventually. */

return 0;
}

/** \brief Clear a canvas's dirty rectangle list.
*
* Empty the canvas's dirty rectangle list.
*
* This function never fails.
*
* \param cv A libcaca canvas.
* \return This function always returns 0.
*/
int caca_clear_dirty_rectangle_list(caca_canvas_t *cv)
{
cv->dirty_xmin = cv->width;
cv->dirty_xmax = -1;
cv->dirty_ymin = cv->height;
cv->dirty_ymax = -1;

return 0;
}


+ 45
- 43
caca/driver/slang.c View File

@@ -222,59 +222,61 @@ static void slang_display(caca_display_t *dp)
{
uint32_t const *cvchars = (uint32_t const *)caca_get_canvas_chars(dp->cv);
uint32_t const *cvattrs = (uint32_t const *)caca_get_canvas_attrs(dp->cv);
int x, y;
int xmin, ymin, xmax, ymax;
int x, y, i;

caca_get_dirty_rectangle(dp->cv, &xmin, &ymin, &xmax, &ymax);
if(xmin > xmax || ymin > ymax)
return;

for(y = ymin; y <= ymax; y++)
for(i = 0; i < caca_get_dirty_rectangle_count(dp->cv); i++)
{
SLsmg_gotorc(y, 0);
for(x = xmax; x >= xmin; x--)
int xmin, ymin, xmax, ymax;

caca_get_dirty_rectangle(dp->cv, i, &xmin, &ymin, &xmax, &ymax);

for(y = ymin; y <= ymax; y++)
{
uint32_t ch = *cvchars++;
SLsmg_gotorc(y, 0);
for(x = xmax; x >= xmin; x--)
{
uint32_t ch = *cvchars++;

#if defined(OPTIMISE_SLANG_PALETTE)
/* If foreground == background, just don't use this colour
* pair, and print a space instead of the real character.
* XXX: disabled, because I can't remember what it was
* here for, and in cases where SLang does not render
* bright backgrounds, it's just fucked up. */
/* If foreground == background, just don't use this colour
* pair, and print a space instead of the real character. */
/* XXX: disabled, because I can't remember what it was
* here for, and in cases where SLang does not render
* bright backgrounds, it's just fucked up. */
#if 0
uint8_t fgcolor = caca_attr_to_ansi_fg(*cvattrs);
uint8_t bgcolor = caca_attr_to_ansi_bg(*cvattrs);

if(fgcolor >= 0x10)
fgcolor = CACA_LIGHTGRAY;

if(bgcolor >= 0x10)
bgcolor = CACA_BLACK; /* FIXME: handle transparency */

if(fgcolor == bgcolor)
{
if(fgcolor == CACA_BLACK)
fgcolor = CACA_WHITE;
else if(fgcolor == CACA_WHITE
|| fgcolor <= CACA_LIGHTGRAY)
fgcolor = CACA_BLACK;
uint8_t fgcolor = caca_attr_to_ansi_fg(*cvattrs);
uint8_t bgcolor = caca_attr_to_ansi_bg(*cvattrs);

if(fgcolor >= 0x10)
fgcolor = CACA_LIGHTGRAY;

if(bgcolor >= 0x10)
bgcolor = CACA_BLACK; /* FIXME: handle transparency */

if(fgcolor == bgcolor)
{
if(fgcolor == CACA_BLACK)
fgcolor = CACA_WHITE;
else if(fgcolor == CACA_WHITE
|| fgcolor <= CACA_LIGHTGRAY)
fgcolor = CACA_BLACK;
else
fgcolor = CACA_WHITE;
SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]);
SLsmg_write_char(' ');
cvattrs++;
}
else
fgcolor = CACA_WHITE;
SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]);
SLsmg_write_char(' ');
cvattrs++;
}
else
#endif
{
SLsmg_set_color(slang_assoc[caca_attr_to_ansi(*cvattrs++)]);
slang_write_utf32(ch);
}
{
SLsmg_set_color(slang_assoc[caca_attr_to_ansi(*cvattrs++)]);
slang_write_utf32(ch);
}
#else
SLsmg_set_color(caca_attr_to_ansi(*cvattrs++));
slang_write_utf32(ch);
SLsmg_set_color(caca_attr_to_ansi(*cvattrs++));
slang_write_utf32(ch);
#endif
}
}
}
SLsmg_gotorc(caca_get_cursor_y(dp->cv), caca_get_cursor_x(dp->cv));


+ 44
- 41
caca/driver/x11.c View File

@@ -293,58 +293,61 @@ static void x11_display(caca_display_t *dp)
uint32_t const *cvattrs = (uint32_t const *)caca_get_canvas_attrs(dp->cv);
int width = caca_get_canvas_width(dp->cv);
int height = caca_get_canvas_height(dp->cv);
int x, y, len;
int xmin, ymin, xmax, ymax;
int x, y, i, len;

caca_get_dirty_rectangle(dp->cv, &xmin, &ymin, &xmax, &ymax);
if(xmin > xmax || ymin > ymax)
return;

/* First draw the background colours. Splitting the process in two
* loops like this is actually slightly faster. */
for(y = ymin; y <= ymax; y++)
for(i = 0; i < caca_get_dirty_rectangle_count(dp->cv); i++)
{
for(x = xmin; x <= xmax; x += len)
int xmin, ymin, xmax, ymax;

caca_get_dirty_rectangle(dp->cv, i, &xmin, &ymin, &xmax, &ymax);

/* First draw the background colours. Splitting the process in two
* loops like this is actually slightly faster. */
for(y = ymin; y <= ymax; y++)
{
uint32_t const *attrs = cvattrs + x + y * width;
uint16_t bg = caca_attr_to_rgb12_bg(*attrs);

len = 1;
while(x + len < width
&& caca_attr_to_rgb12_bg(attrs[len]) == bg)
len++;

XSetForeground(dp->drv.p->dpy, dp->drv.p->gc,
dp->drv.p->colors[bg]);
XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap, dp->drv.p->gc,
x * dp->drv.p->font_width,
y * dp->drv.p->font_height,
len * dp->drv.p->font_width,
dp->drv.p->font_height);
for(x = xmin; x <= xmax; x += len)
{
uint32_t const *attrs = cvattrs + x + y * width;
uint16_t bg = caca_attr_to_rgb12_bg(*attrs);

len = 1;
while(x + len < width
&& caca_attr_to_rgb12_bg(attrs[len]) == bg)
len++;

XSetForeground(dp->drv.p->dpy, dp->drv.p->gc,
dp->drv.p->colors[bg]);
XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
dp->drv.p->gc,
x * dp->drv.p->font_width,
y * dp->drv.p->font_height,
len * dp->drv.p->font_width,
dp->drv.p->font_height);
}
}
}

/* Then print the foreground characters */
for(y = ymin; y <= ymax; y++)
{
int yoff = (y + 1) * dp->drv.p->font_height
- dp->drv.p->font_offset;
uint32_t const *chars = cvchars + y * width;
uint32_t const *attrs = cvattrs + y * width;

for(x = xmin; x <= xmax; x++, chars++, attrs++)
/* Then print the foreground characters */
for(y = ymin; y <= ymax; y++)
{
XSetForeground(dp->drv.p->dpy, dp->drv.p->gc,
int yoff = (y + 1) * dp->drv.p->font_height
- dp->drv.p->font_offset;
uint32_t const *chars = cvchars + y * width;
uint32_t const *attrs = cvattrs + y * width;

for(x = xmin; x <= xmax; x++, chars++, attrs++)
{
XSetForeground(dp->drv.p->dpy, dp->drv.p->gc,
dp->drv.p->colors[caca_attr_to_rgb12_fg(*attrs)]);

x11_put_glyph(dp, x * dp->drv.p->font_width,
y * dp->drv.p->font_height, yoff,
dp->drv.p->font_width, dp->drv.p->font_height,
*attrs, *chars);
x11_put_glyph(dp, x * dp->drv.p->font_width,
y * dp->drv.p->font_height, yoff,
dp->drv.p->font_width, dp->drv.p->font_height,
*attrs, *chars);
}
}
}

/* Print the cursor if necessary */
/* Print the cursor if necessary. FIXME: handle dirty rectangles! */
if(dp->drv.p->cursor_flags)
{
XSetForeground(dp->drv.p->dpy, dp->drv.p->gc,


+ 2
- 2
caca/frame.c View File

@@ -72,7 +72,7 @@ int caca_set_frame(caca_canvas_t *cv, int id)
cv->frame = id;
_caca_load_frame_info(cv);

caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);

return 0;
}
@@ -236,7 +236,7 @@ int caca_free_frame(caca_canvas_t *cv, int id)
{
cv->frame = 0;
_caca_load_frame_info(cv);
caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
}

return 0;


+ 1
- 1
caca/graphics.c View File

@@ -155,7 +155,7 @@ int caca_refresh_display(caca_display_t *dp)
dp->drv.display(dp);

/* Invalidate the dirty rectangle */
caca_set_dirty_rectangle(dp->cv, -1, -1, -1, -1);
caca_clear_dirty_rectangle_list(dp->cv);

/* Once the display is finished, we can ack resizes */
if(dp->resize.resized)


+ 4
- 0
caca/libcaca.vcproj View File

@@ -416,6 +416,10 @@
RelativePath=".\driver\conio.c"
>
</File>
<File
RelativePath=".\dirty.c"
>
</File>
<File
RelativePath=".\dither.c"
>


+ 2
- 2
caca/string.c View File

@@ -322,7 +322,7 @@ int caca_clear_canvas(caca_canvas_t *cv)
cv->attrs[n] = attr;
}

caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);

return 0;
}
@@ -528,7 +528,7 @@ int caca_set_canvas_boundaries(caca_canvas_t *cv, int x, int y, int w, int h)
_caca_load_frame_info(cv);

/* FIXME: this may be optimised somewhat */
caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);

return 0;
}


+ 8
- 8
caca/transform.c View File

@@ -54,7 +54,7 @@ int caca_invert(caca_canvas_t *cv)
attrs++;
}

caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);

return 0;
}
@@ -115,7 +115,7 @@ int caca_flip(caca_canvas_t *cv)
}
}

caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);

return 0;
}
@@ -162,7 +162,7 @@ int caca_flop(caca_canvas_t *cv)
*ctop = flopchar(*ctop);
}

caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);

return 0;
}
@@ -221,7 +221,7 @@ int caca_rotate_180(caca_canvas_t *cv)
}
}

caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);

return 0;
}
@@ -340,7 +340,7 @@ int caca_rotate_left(caca_canvas_t *cv)
/* Reset the current frame shortcuts */
_caca_load_frame_info(cv);

caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);

return 0;
}
@@ -459,7 +459,7 @@ int caca_rotate_right(caca_canvas_t *cv)
/* Reset the current frame shortcuts */
_caca_load_frame_info(cv);

caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);

return 0;
}
@@ -552,7 +552,7 @@ int caca_stretch_left(caca_canvas_t *cv)
/* Reset the current frame shortcuts */
_caca_load_frame_info(cv);

caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);

return 0;
}
@@ -645,7 +645,7 @@ int caca_stretch_right(caca_canvas_t *cv)
/* Reset the current frame shortcuts */
_caca_load_frame_info(cv);

caca_set_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);

return 0;
}


+ 61
- 46
tests/dirty.cpp View File

@@ -38,21 +38,24 @@ public:
void test_create()
{
caca_canvas_t *cv;
int xmin, xmax, ymin, ymax;
int i, xmin, xmax, ymin, ymax;

/* Check that the dirty rectangle contains the whole canvas
* upon creation. */
cv = caca_create_canvas(WIDTH, HEIGHT);
caca_get_dirty_rectangle(cv, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT(xmin <= 0);
CPPUNIT_ASSERT(ymin <= 0);
CPPUNIT_ASSERT(xmax >= caca_get_canvas_width(cv) - 1);
CPPUNIT_ASSERT(ymax >= caca_get_canvas_height(cv) - 1);
i = caca_get_dirty_rectangle_count(cv);
CPPUNIT_ASSERT_EQUAL(i, 1);

caca_get_dirty_rectangle(cv, 0, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT_EQUAL(xmin, 0);
CPPUNIT_ASSERT_EQUAL(ymin, 0);
CPPUNIT_ASSERT_EQUAL(xmax, caca_get_canvas_width(cv) - 1);
CPPUNIT_ASSERT_EQUAL(ymax, caca_get_canvas_height(cv) - 1);

/* Invalidate the dirty rectangle and check that it stays so. */
caca_set_dirty_rectangle(cv, -1, -1, -1, -1);
caca_get_dirty_rectangle(cv, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT(xmin > xmax || ymin > ymax);
caca_clear_dirty_rectangle_list(cv);
i = caca_get_dirty_rectangle_count(cv);
CPPUNIT_ASSERT_EQUAL(i, 0);

caca_free_canvas(cv);
}
@@ -60,66 +63,78 @@ public:
void test_put_char()
{
caca_canvas_t *cv;
int xmin, xmax, ymin, ymax;
int i, xmin, xmax, ymin, ymax;

cv = caca_create_canvas(WIDTH, HEIGHT);

caca_set_dirty_rectangle(cv, -1, -1, -1, -1);
caca_clear_dirty_rectangle_list(cv);
caca_put_char(cv, 7, 3, 'x');
caca_get_dirty_rectangle(cv, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT(xmin <= 7);
CPPUNIT_ASSERT(ymin <= 3);
CPPUNIT_ASSERT(xmax >= 7);
CPPUNIT_ASSERT(ymax >= 3);
i = caca_get_dirty_rectangle_count(cv);
CPPUNIT_ASSERT_EQUAL(i, 1);
caca_get_dirty_rectangle(cv, 0, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT_EQUAL(xmin, 7);
CPPUNIT_ASSERT_EQUAL(ymin, 3);
CPPUNIT_ASSERT_EQUAL(xmax, 7);
CPPUNIT_ASSERT_EQUAL(ymax, 3);

caca_clear_canvas(cv);
caca_set_dirty_rectangle(cv, -1, -1, -1, -1);
caca_clear_dirty_rectangle_list(cv);
caca_put_char(cv, 7, 3, 0x2f06 /* ⼆ */);
caca_get_dirty_rectangle(cv, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT(xmin <= 7);
CPPUNIT_ASSERT(ymin <= 3);
CPPUNIT_ASSERT(xmax >= 8);
CPPUNIT_ASSERT(ymax >= 3);
i = caca_get_dirty_rectangle_count(cv);
CPPUNIT_ASSERT_EQUAL(i, 1);
caca_get_dirty_rectangle(cv, 0, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT_EQUAL(xmin, 7);
CPPUNIT_ASSERT_EQUAL(ymin, 3);
CPPUNIT_ASSERT_EQUAL(xmax, 8);
CPPUNIT_ASSERT_EQUAL(ymax, 3);

caca_clear_canvas(cv);
caca_put_char(cv, 7, 3, 0x2f06 /* ⼆ */);
caca_set_dirty_rectangle(cv, -1, -1, -1, -1);
caca_clear_dirty_rectangle_list(cv);
caca_put_char(cv, 7, 3, 'x');
caca_get_dirty_rectangle(cv, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT(xmin <= 7);
CPPUNIT_ASSERT(ymin <= 3);
CPPUNIT_ASSERT(xmax >= 8);
CPPUNIT_ASSERT(ymax >= 3);
i = caca_get_dirty_rectangle_count(cv);
CPPUNIT_ASSERT_EQUAL(i, 1);
caca_get_dirty_rectangle(cv, 0, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT_EQUAL(xmin, 7);
CPPUNIT_ASSERT_EQUAL(ymin, 3);
CPPUNIT_ASSERT_EQUAL(xmax, 8);
CPPUNIT_ASSERT_EQUAL(ymax, 3);

caca_clear_canvas(cv);
caca_put_char(cv, 7, 3, 0x2f06 /* ⼆ */);
caca_set_dirty_rectangle(cv, -1, -1, -1, -1);
caca_clear_dirty_rectangle_list(cv);
caca_put_char(cv, 8, 3, 'x');
caca_get_dirty_rectangle(cv, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT(xmin <= 7);
CPPUNIT_ASSERT(ymin <= 3);
CPPUNIT_ASSERT(xmax >= 8);
CPPUNIT_ASSERT(ymax >= 3);
i = caca_get_dirty_rectangle_count(cv);
CPPUNIT_ASSERT_EQUAL(i, 1);
caca_get_dirty_rectangle(cv, 0, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT_EQUAL(xmin, 7);
CPPUNIT_ASSERT_EQUAL(ymin, 3);
CPPUNIT_ASSERT_EQUAL(xmax, 8);
CPPUNIT_ASSERT_EQUAL(ymax, 3);

caca_clear_canvas(cv);
caca_put_char(cv, 7, 3, 0x2f06 /* ⼆ */);
caca_set_dirty_rectangle(cv, -1, -1, -1, -1);
caca_clear_dirty_rectangle_list(cv);
caca_put_char(cv, 6, 3, 0x2f06 /* ⼆ */);
caca_get_dirty_rectangle(cv, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT(xmin <= 6);
CPPUNIT_ASSERT(ymin <= 3);
CPPUNIT_ASSERT(xmax >= 8);
CPPUNIT_ASSERT(ymax >= 3);
i = caca_get_dirty_rectangle_count(cv);
CPPUNIT_ASSERT_EQUAL(i, 1);
caca_get_dirty_rectangle(cv, 0, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT_EQUAL(xmin, 6);
CPPUNIT_ASSERT_EQUAL(ymin, 3);
CPPUNIT_ASSERT_EQUAL(xmax, 8);
CPPUNIT_ASSERT_EQUAL(ymax, 3);

caca_clear_canvas(cv);
caca_put_char(cv, 7, 3, 0x2f06 /* ⼆ */);
caca_set_dirty_rectangle(cv, -1, -1, -1, -1);
caca_clear_dirty_rectangle_list(cv);
caca_put_char(cv, 8, 3, 0x2f06 /* ⼆ */);
caca_get_dirty_rectangle(cv, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT(xmin <= 7);
CPPUNIT_ASSERT(ymin <= 3);
CPPUNIT_ASSERT(xmax >= 9);
CPPUNIT_ASSERT(ymax >= 3);
i = caca_get_dirty_rectangle_count(cv);
CPPUNIT_ASSERT_EQUAL(i, 1);
caca_get_dirty_rectangle(cv, 0, &xmin, &ymin, &xmax, &ymax);
CPPUNIT_ASSERT_EQUAL(xmin, 7);
CPPUNIT_ASSERT_EQUAL(ymin, 3);
CPPUNIT_ASSERT_EQUAL(xmax, 9);
CPPUNIT_ASSERT_EQUAL(ymax, 3);
}

private:


Loading…
Cancel
Save