mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-29 12:32:52 +00:00
Convert Dirty to a class.
Remove all deprecated code of Dirty class that was not being used because the new ASE 0.8 tools implementation. Remove pointers to an Image/Mask from Dirty class.
This commit is contained in:
parent
9f58d0378a
commit
4c5a0177cc
@ -18,548 +18,141 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "gui/jbase.h" // TODO remove this reference
|
||||
|
||||
#include "raster/algo.h"
|
||||
#include "raster/pen.h"
|
||||
#include "raster/dirty.h"
|
||||
#include "raster/image.h"
|
||||
#include "raster/mask.h"
|
||||
|
||||
#define ADD_COLUMN(row, col, u) \
|
||||
++row->cols; \
|
||||
row->col = (DirtyCol*)jrealloc(row->col, \
|
||||
sizeof(DirtyCol) * row->cols); \
|
||||
col = row->col+u; \
|
||||
if (u < row->cols-1) \
|
||||
memmove(col+1, \
|
||||
col, \
|
||||
sizeof(DirtyCol) * (row->cols-1-u));
|
||||
|
||||
#define ADD_ROW(dirty, row, v) \
|
||||
++dirty->rows; \
|
||||
dirty->row = (DirtyRow*)jrealloc(dirty->row, \
|
||||
sizeof(DirtyRow) * dirty->rows); \
|
||||
row = dirty->row+v; \
|
||||
if (v < dirty->rows-1) \
|
||||
memmove(row+1, \
|
||||
row, \
|
||||
sizeof(DirtyRow) * (dirty->rows-1-v));
|
||||
|
||||
#define RESTORE_IMAGE(col) \
|
||||
if ((col)->flags & DIRTY_VALID_COLUMN) { \
|
||||
(col)->flags ^= DIRTY_VALID_COLUMN; \
|
||||
\
|
||||
memcpy((col)->ptr, \
|
||||
(col)->data, \
|
||||
dirty_line_size(dirty, (col)->w)); \
|
||||
}
|
||||
|
||||
#define JOIN_WITH_NEXT(row, col, u) \
|
||||
{ \
|
||||
RESTORE_IMAGE(col+1); \
|
||||
\
|
||||
col->w += (col+1)->w; \
|
||||
\
|
||||
if ((col+1)->data) \
|
||||
jfree((col+1)->data); \
|
||||
\
|
||||
if (u+1 < row->cols-1) \
|
||||
memmove(row->col+u+1, \
|
||||
row->col+u+2, \
|
||||
sizeof(DirtyCol) * (row->cols-2-u)); \
|
||||
\
|
||||
row->cols--; \
|
||||
row->col = (DirtyCol*)jrealloc(row->col, \
|
||||
sizeof(DirtyCol) * row->cols); \
|
||||
col = row->col+u; \
|
||||
}
|
||||
|
||||
#define EAT_COLUMNS() \
|
||||
to_x2 = x2; \
|
||||
\
|
||||
/* "eat" columns in range */ \
|
||||
for (u2=u+1; u2<row->cols; ++u2) { \
|
||||
/* done (next column too far) */ \
|
||||
if (x2 < row->col[u2].x-1) \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
u2--; \
|
||||
\
|
||||
/* "eat" columns */ \
|
||||
if (u2 > u) { \
|
||||
for (u3=u+1; u3<=u2; ++u3) { \
|
||||
RESTORE_IMAGE(row->col+u3); \
|
||||
if (row->col[u3].data) \
|
||||
jfree(row->col[u3].data); \
|
||||
} \
|
||||
\
|
||||
to_x2 = MAX(to_x2, row->col[u2].x+row->col[u2].w-1); \
|
||||
\
|
||||
if (u2 < row->cols-1) \
|
||||
memmove(row->col+u+1, \
|
||||
row->col+u2+1, \
|
||||
sizeof(DirtyCol) * (row->cols-u2-1)); \
|
||||
\
|
||||
row->cols -= u2 - u; \
|
||||
row->col = (DirtyCol*)jrealloc(row->col, \
|
||||
sizeof(DirtyCol) * row->cols); \
|
||||
col = row->col+u; \
|
||||
} \
|
||||
\
|
||||
row->col[u].w = to_x2 - row->col[u].x + 1; \
|
||||
row->col[u].data = jrealloc(row->col[u].data, \
|
||||
dirty_line_size(dirty, row->col[u].w));
|
||||
|
||||
typedef void (*HLineSwapper)(void*,void*,int,int);
|
||||
|
||||
static HLineSwapper swap_hline(Image* image);
|
||||
static void swap_hline32(void* image, void* data, int x1, int x2);
|
||||
static void swap_hline16(void* image, void* data, int x1, int x2);
|
||||
static void swap_hline8(void* image, void* data, int x1, int x2);
|
||||
|
||||
Dirty* dirty_new(Image* image, int x1, int y1, int x2, int y2, bool tiled)
|
||||
Dirty::Dirty(int imgtype, int x1, int y1, int x2, int y2)
|
||||
: m_imgtype(imgtype)
|
||||
, m_x1(x1), m_y1(y1)
|
||||
, m_x2(x2), m_y2(y2)
|
||||
{
|
||||
Dirty* dirty = new Dirty;
|
||||
|
||||
dirty->image = image;
|
||||
dirty->x1 = MID(0, x1, image->w-1);
|
||||
dirty->y1 = MID(0, y1, image->h-1);
|
||||
dirty->x2 = MID(x1, x2, image->w-1);
|
||||
dirty->y2 = MID(y1, y2, image->h-1);
|
||||
dirty->tiled = tiled;
|
||||
dirty->rows = 0;
|
||||
dirty->row = NULL;
|
||||
dirty->mask = NULL;
|
||||
|
||||
return dirty;
|
||||
}
|
||||
|
||||
Dirty* dirty_new_copy(Dirty* src)
|
||||
Dirty::Dirty(const Dirty& src)
|
||||
: m_imgtype(src.m_imgtype)
|
||||
, m_x1(src.m_x1), m_y1(src.m_y1)
|
||||
, m_x2(src.m_x2), m_y2(src.m_y2)
|
||||
{
|
||||
Dirty* dst = dirty_new(src->image, src->x1, src->y1, src->x2, src->y2, src->tiled);
|
||||
int u, v, size;
|
||||
m_rows.resize(src.m_rows.size());
|
||||
|
||||
dst->rows = src->rows;
|
||||
dst->row = (DirtyRow*)jmalloc(sizeof(DirtyRow) * src->rows);
|
||||
for (size_t v=0; v<m_rows.size(); ++v) {
|
||||
const Row& srcRow = src.getRow(v);
|
||||
Row* row = new Row(srcRow.y);
|
||||
|
||||
for (v=0; v<dst->rows; ++v) {
|
||||
dst->row[v].y = src->row[v].y;
|
||||
dst->row[v].cols = src->row[v].cols;
|
||||
dst->row[v].col = (DirtyCol*)jmalloc(sizeof(DirtyCol) * dst->row[v].cols);
|
||||
row->cols.resize(srcRow.cols.size());
|
||||
|
||||
for (u=0; u<dst->row[v].cols; ++u) {
|
||||
dst->row[v].col[u].x = src->row[v].col[u].x;
|
||||
dst->row[v].col[u].w = src->row[v].col[u].w;
|
||||
dst->row[v].col[u].flags = src->row[v].col[u].flags;
|
||||
dst->row[v].col[u].ptr = src->row[v].col[u].ptr;
|
||||
|
||||
size = dst->row[v].col[u].w << image_shift(dst->image);
|
||||
|
||||
dst->row[v].col[u].data = jmalloc(size);
|
||||
|
||||
memcpy(dst->row[v].col[u].data, src->row[v].col[u].data, size);
|
||||
for (size_t u=0; u<row->cols.size(); ++u) {
|
||||
Col* col = new Col(*srcRow.cols[u]);
|
||||
row->cols[u] = col;
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
m_rows[v] = row;
|
||||
}
|
||||
}
|
||||
|
||||
Dirty* dirty_new_from_differences(Image* image, Image* image_diff)
|
||||
Dirty::Dirty(Image* image, Image* image_diff)
|
||||
: m_imgtype(image->imgtype)
|
||||
, m_x1(0), m_y1(0)
|
||||
, m_x2(image->w-1), m_y2(image->h-1)
|
||||
{
|
||||
Dirty* dirty = dirty_new(image, 0, 0, image->w, image->h, false);
|
||||
int x, y, x1, x2;
|
||||
|
||||
for (y=0; y<image->h; y++) {
|
||||
x1 = x2 = -1;
|
||||
|
||||
x1 = -1;
|
||||
for (x=0; x<image->w; x++) {
|
||||
if (image_getpixel(image, x, y) != image_getpixel(image_diff, x, y)) {
|
||||
x1 = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x1 < 0)
|
||||
continue;
|
||||
|
||||
for (x=image->w-1; x>=0; x--) {
|
||||
if (image_getpixel(image, x, y) != image_getpixel(image_diff, x, y)) {
|
||||
x2 = x;
|
||||
for (x2=image->w-1; x2>x1; x2--) {
|
||||
if (image_getpixel(image, x2, y) != image_getpixel(image_diff, x2, y))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (x1 >= 0 && x2 >= 0)
|
||||
dirty_hline(dirty, x1, y, x2);
|
||||
}
|
||||
Col* col = new Col(x1, x2-x1+1);
|
||||
col->data.resize(getLineSize(col->w));
|
||||
|
||||
return dirty;
|
||||
Row* row = new Row(y);
|
||||
row->cols.push_back(col);
|
||||
|
||||
m_rows.push_back(row);
|
||||
}
|
||||
}
|
||||
|
||||
void dirty_free(Dirty* dirty)
|
||||
Dirty::~Dirty()
|
||||
{
|
||||
register DirtyRow* row;
|
||||
register DirtyCol* col;
|
||||
DirtyRow* rowend;
|
||||
DirtyCol* colend;
|
||||
RowsList::iterator row_it = m_rows.begin();
|
||||
RowsList::iterator row_end = m_rows.end();
|
||||
|
||||
if (dirty->row) {
|
||||
row = dirty->row;
|
||||
rowend = row+dirty->rows;
|
||||
for (; row<rowend; ++row) {
|
||||
col = row->col;
|
||||
colend = col+row->cols;
|
||||
for (; col<colend; ++col)
|
||||
jfree(col->data);
|
||||
for (; row_it != row_end; ++row_it) {
|
||||
ColsList::iterator col_it = (*row_it)->cols.begin();
|
||||
ColsList::iterator col_end = (*row_it)->cols.end();
|
||||
|
||||
jfree(row->col);
|
||||
}
|
||||
for (; col_it != col_end; ++col_it)
|
||||
delete *col_it;
|
||||
|
||||
jfree(dirty->row);
|
||||
delete *row_it;
|
||||
}
|
||||
jfree(dirty);
|
||||
}
|
||||
|
||||
int Dirty::getMemSize() const
|
||||
{
|
||||
int u, v, size = 4+1+2*4+2; /* DWORD+BYTE+WORD[4]+WORD */
|
||||
int size = 4+1+2*4+2; // DWORD+BYTE+WORD[4]+WORD
|
||||
|
||||
for (v=0; v<this->rows; v++) {
|
||||
size += 4; /* y, cols (WORD[2]) */
|
||||
for (u=0; u<this->row[v].cols; u++) {
|
||||
size += 4; /* x, w (WORD[2]) */
|
||||
size += image_line_size(this->image, this->row[v].col[u].w);
|
||||
RowsList::const_iterator row_it = m_rows.begin();
|
||||
RowsList::const_iterator row_end = m_rows.end();
|
||||
for (; row_it != row_end; ++row_it) {
|
||||
size += 4; // y, cols (WORD[2])
|
||||
|
||||
ColsList::const_iterator col_it = (*row_it)->cols.begin();
|
||||
ColsList::const_iterator col_end = (*row_it)->cols.end();
|
||||
for (; col_it != col_end; ++col_it) {
|
||||
size += 4; // x, w (WORD[2])
|
||||
size += getLineSize((*col_it)->w);
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void dirty_hline(Dirty* dirty, int x1, int y, int x2)
|
||||
void Dirty::saveImagePixels(Image* image)
|
||||
{
|
||||
DirtyRow* row; /* row=dirty->row+v */
|
||||
DirtyCol* col; /* col=row->col+u */
|
||||
int x, u, v, w;
|
||||
int u2, u3, to_x2;
|
||||
RowsList::iterator row_it = m_rows.begin();
|
||||
RowsList::iterator row_end = m_rows.end();
|
||||
for (; row_it != row_end; ++row_it) {
|
||||
Row* row = *row_it;
|
||||
|
||||
if (dirty->tiled) {
|
||||
if (x1 > x2)
|
||||
return;
|
||||
ColsList::iterator col_it = (*row_it)->cols.begin();
|
||||
ColsList::iterator col_end = (*row_it)->cols.end();
|
||||
for (; col_it != col_end; ++col_it) {
|
||||
Col* col = *col_it;
|
||||
|
||||
dirty->tiled = false;
|
||||
|
||||
if (y < 0)
|
||||
y = dirty->image->h - (-(y+1) % dirty->image->h) - 1;
|
||||
else
|
||||
y = y % dirty->image->h;
|
||||
|
||||
w = x2-x1+1;
|
||||
if (w >= dirty->image->w)
|
||||
dirty_hline(dirty, 0, y, dirty->image->w-1);
|
||||
else {
|
||||
x = x1;
|
||||
if (x < 0)
|
||||
x = dirty->image->w - (-(x+1) % dirty->image->w) - 1;
|
||||
else
|
||||
x = x % dirty->image->w;
|
||||
|
||||
if (x+w-1 <= dirty->image->w-1)
|
||||
dirty_hline(dirty, x, y, x+w-1);
|
||||
else {
|
||||
dirty_hline(dirty, x, y, dirty->image->w-1);
|
||||
dirty_hline(dirty, 0, y, w-(dirty->image->w-x)-1);
|
||||
}
|
||||
}
|
||||
|
||||
dirty->tiled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/* clip */
|
||||
if ((y < dirty->y1) || (y > dirty->y2))
|
||||
return;
|
||||
|
||||
if (x1 < dirty->x1)
|
||||
x1 = dirty->x1;
|
||||
|
||||
if (x2 > dirty->x2)
|
||||
x2 = dirty->x2;
|
||||
|
||||
if (x1 > x2)
|
||||
return;
|
||||
|
||||
/* mask clip */
|
||||
if (dirty->mask) {
|
||||
if ((y < dirty->mask->y) || (y >= dirty->mask->y+dirty->mask->h))
|
||||
return;
|
||||
|
||||
if (x1 < dirty->mask->x)
|
||||
x1 = dirty->mask->x;
|
||||
|
||||
if (x2 > dirty->mask->x+dirty->mask->w-1)
|
||||
x2 = dirty->mask->x+dirty->mask->w-1;
|
||||
|
||||
if (dirty->mask->bitmap) {
|
||||
for (; x1<=x2; ++x1)
|
||||
if (dirty->mask->bitmap->getpixel(x1-dirty->mask->x,
|
||||
y-dirty->mask->y))
|
||||
break;
|
||||
|
||||
for (; x2>=x1; x2--)
|
||||
if (dirty->mask->bitmap->getpixel(x2-dirty->mask->x,
|
||||
y-dirty->mask->y))
|
||||
break;
|
||||
}
|
||||
|
||||
if (x1 > x2)
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if the row exists */
|
||||
row = NULL;
|
||||
|
||||
for (v=0; v<dirty->rows; ++v)
|
||||
if (dirty->row[v].y == y) {
|
||||
row = dirty->row+v;
|
||||
break;
|
||||
}
|
||||
else if (dirty->row[v].y > y)
|
||||
break;
|
||||
|
||||
/* we must add a new row? */
|
||||
if (!row) {
|
||||
ADD_ROW(dirty, row, v);
|
||||
|
||||
row->y = y;
|
||||
row->cols = 0;
|
||||
row->col = NULL;
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
/* HLINE for Dirty with mask */
|
||||
|
||||
if (dirty->mask && dirty->mask->bitmap) {
|
||||
for (x=x1; x<=x2; ++x) {
|
||||
if (!dirty->mask->bitmap->getpixel(x-dirty->mask->x,
|
||||
y-dirty->mask->y)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check if the pixel is inside some column */
|
||||
col = row->col;
|
||||
for (u=0; u<row->cols; ++u, ++col) {
|
||||
/* inside a existent column */
|
||||
if ((x >= col->x) && (x <= col->x+col->w-1))
|
||||
goto done;
|
||||
/* the pixel is in the right of the column */
|
||||
else if (x == col->x+col->w) {
|
||||
RESTORE_IMAGE(col);
|
||||
|
||||
++col->w;
|
||||
|
||||
/* there is a left column? */
|
||||
if (u < row->cols-1 && x == (col+1)->x-1) {
|
||||
if ((col+1)->flags & DIRTY_VALID_COLUMN) {
|
||||
(col+1)->flags ^= DIRTY_VALID_COLUMN;
|
||||
|
||||
memcpy((col+1)->ptr,
|
||||
(col+1)->data,
|
||||
dirty_line_size(dirty, (col+1)->w));
|
||||
}
|
||||
|
||||
col->w += (col+1)->w;
|
||||
|
||||
/* remove the col[u+1] */
|
||||
if ((col+1)->data)
|
||||
jfree((col+1)->data);
|
||||
|
||||
if (u+1 < row->cols-1)
|
||||
memmove(col+1, col+2,
|
||||
sizeof(DirtyCol) * (row->cols-2-u));
|
||||
|
||||
row->cols--;
|
||||
row->col = (DirtyCol*)jrealloc(row->col, sizeof(DirtyCol) * row->cols);
|
||||
col = row->col+u;
|
||||
}
|
||||
|
||||
col->data = jrealloc(col->data, dirty_line_size(dirty, col->w));
|
||||
goto done;
|
||||
}
|
||||
/* the pixel is in the left of the column */
|
||||
else if (x == col->x-1) {
|
||||
if (col->flags & DIRTY_VALID_COLUMN) {
|
||||
col->flags ^= DIRTY_VALID_COLUMN;
|
||||
|
||||
memcpy(col->ptr,
|
||||
col->data,
|
||||
dirty_line_size(dirty, col->w));
|
||||
}
|
||||
|
||||
--col->x;
|
||||
++col->w;
|
||||
col->data = jrealloc(col->data, dirty_line_size(dirty, col->w));
|
||||
col->ptr = image_address(dirty->image, x, y);
|
||||
goto done;
|
||||
}
|
||||
else if (x < col->x)
|
||||
break;
|
||||
}
|
||||
|
||||
/* add a new column */
|
||||
++row->cols;
|
||||
row->col = (DirtyCol*)jrealloc(row->col, sizeof(DirtyCol) * row->cols);
|
||||
col = row->col+u;
|
||||
|
||||
if (u < row->cols-1)
|
||||
memmove(col+1, col, sizeof(DirtyCol) * (row->cols-1-u));
|
||||
|
||||
col->x = x;
|
||||
col->w = 1;
|
||||
col->flags = 0;
|
||||
col->data = jmalloc(dirty_line_size(dirty, 1));
|
||||
col->ptr = image_address(dirty->image, x, y);
|
||||
|
||||
done:;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
/* HLINE for Dirty without mask */
|
||||
|
||||
else {
|
||||
/* go column by column */
|
||||
col = row->col;
|
||||
for (u=0; u<row->cols; ++u, ++col) {
|
||||
/* the hline is to right of the column */
|
||||
if ((x1 >= col->x) && (x1 <= col->x+col->w)) {
|
||||
/* inside the column */
|
||||
if (x2 <= col->x+col->w-1)
|
||||
return;
|
||||
/* extend this column to "x2" */
|
||||
else {
|
||||
RESTORE_IMAGE(col);
|
||||
EAT_COLUMNS();
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* the hline is to left of the column */
|
||||
else if ((x1 < col->x) && (x2 >= col->x-1)) {
|
||||
RESTORE_IMAGE(col);
|
||||
|
||||
/* extend to left */
|
||||
col->w += col->x - x1;
|
||||
col->x = x1;
|
||||
col->ptr = image_address(dirty->image, x1, y);
|
||||
|
||||
/* inside the column */
|
||||
if (x2 <= col->x+col->w-1) {
|
||||
col->data = jrealloc(col->data, dirty_line_size(dirty, col->w));
|
||||
return;
|
||||
}
|
||||
/* extend this column to "x2" */
|
||||
else {
|
||||
EAT_COLUMNS();
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* the next column is more too far */
|
||||
else if (x2 < col->x-1)
|
||||
break;
|
||||
}
|
||||
|
||||
/* add a new column */
|
||||
ADD_COLUMN(row, col, u);
|
||||
|
||||
col->x = x1;
|
||||
col->w = x2-x1+1;
|
||||
col->flags = 0;
|
||||
col->data = jmalloc(dirty_line_size(dirty, col->w));
|
||||
col->ptr = image_address(dirty->image, x1, y);
|
||||
}
|
||||
}
|
||||
|
||||
void dirty_save_image_data(Dirty* dirty)
|
||||
{
|
||||
register int v, u, shift = image_shift(dirty->image);
|
||||
|
||||
for (v=0; v<dirty->rows; ++v)
|
||||
for (u=0; u<dirty->row[v].cols; ++u) {
|
||||
if (!(dirty->row[v].col[u].flags & DIRTY_VALID_COLUMN)) {
|
||||
memcpy(dirty->row[v].col[u].data,
|
||||
dirty->row[v].col[u].ptr,
|
||||
dirty->row[v].col[u].w<<shift);
|
||||
|
||||
dirty->row[v].col[u].flags |= DIRTY_VALID_COLUMN;
|
||||
dirty->row[v].col[u].flags |= DIRTY_MUSTBE_UPDATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dirty_swap(Dirty* dirty)
|
||||
{
|
||||
register DirtyRow* row;
|
||||
register DirtyCol* col;
|
||||
DirtyRow* rowend;
|
||||
DirtyCol* colend;
|
||||
HLineSwapper proc;
|
||||
|
||||
proc = swap_hline(dirty->image);
|
||||
|
||||
row = dirty->row;
|
||||
rowend = row+dirty->rows;
|
||||
for (; row<rowend; ++row) {
|
||||
col = row->col;
|
||||
colend = col+row->cols;
|
||||
for (; col<colend; ++col) {
|
||||
if (col->flags & DIRTY_VALID_COLUMN) {
|
||||
(*proc)(col->ptr,
|
||||
col->data,
|
||||
col->x,
|
||||
col->x+col->w-1);
|
||||
}
|
||||
ase_uint8* address = (ase_uint8*)image_address(image, col->x, row->y);
|
||||
std::copy(address, address+col->w, col->data.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static HLineSwapper swap_hline(Image* image)
|
||||
void Dirty::swapImagePixels(Image* image)
|
||||
{
|
||||
register HLineSwapper proc;
|
||||
switch (image->imgtype) {
|
||||
case IMAGE_RGB: proc = swap_hline32; break;
|
||||
case IMAGE_GRAYSCALE: proc = swap_hline16; break;
|
||||
case IMAGE_INDEXED: proc = swap_hline8; break;
|
||||
default:
|
||||
proc = NULL;
|
||||
RowsList::iterator row_it = m_rows.begin();
|
||||
RowsList::iterator row_end = m_rows.end();
|
||||
for (; row_it != row_end; ++row_it) {
|
||||
Row* row = *row_it;
|
||||
|
||||
ColsList::iterator col_it = (*row_it)->cols.begin();
|
||||
ColsList::iterator col_end = (*row_it)->cols.end();
|
||||
for (; col_it != col_end; ++col_it) {
|
||||
Col* col = *col_it;
|
||||
|
||||
ase_uint8* address = (ase_uint8*)image_address(image, col->x, row->y);
|
||||
std::swap_ranges(address, address+col->w, col->data.begin());
|
||||
}
|
||||
}
|
||||
return proc;
|
||||
}
|
||||
|
||||
#define SWAP_HLINE(type) \
|
||||
register type* address1 = (type*)image; \
|
||||
register type* address2 = (type*)data; \
|
||||
register int c; \
|
||||
int x; \
|
||||
\
|
||||
for (x=x1; x<=x2; ++x) { \
|
||||
c = *address1; \
|
||||
*address1 = *address2; \
|
||||
*address2 = c; \
|
||||
++address1; \
|
||||
++address2; \
|
||||
}
|
||||
|
||||
static void swap_hline32(void* image, void* data, int x1, int x2)
|
||||
{
|
||||
SWAP_HLINE(ase_uint32);
|
||||
}
|
||||
|
||||
static void swap_hline16(void* image, void* data, int x1, int x2)
|
||||
{
|
||||
SWAP_HLINE(ase_uint16);
|
||||
}
|
||||
|
||||
static void swap_hline8(void* image, void* data, int x1, int x2)
|
||||
{
|
||||
SWAP_HLINE(ase_uint8);
|
||||
}
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
#include "raster/image.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Pen;
|
||||
class Image;
|
||||
class Mask;
|
||||
@ -28,48 +30,68 @@ class Mask;
|
||||
#define DIRTY_VALID_COLUMN 1
|
||||
#define DIRTY_MUSTBE_UPDATED 2
|
||||
|
||||
struct DirtyCol
|
||||
{
|
||||
int x, w;
|
||||
char flags;
|
||||
void* data;
|
||||
void* ptr;
|
||||
};
|
||||
class Dirty {
|
||||
public:
|
||||
struct Col;
|
||||
struct Row;
|
||||
|
||||
struct DirtyRow
|
||||
{
|
||||
int y;
|
||||
int cols;
|
||||
DirtyCol* col;
|
||||
};
|
||||
typedef std::vector<Col*> ColsList;
|
||||
typedef std::vector<Row*> RowsList;
|
||||
|
||||
struct Dirty
|
||||
{
|
||||
Image* image;
|
||||
int x1, y1;
|
||||
int x2, y2;
|
||||
bool tiled;
|
||||
int rows;
|
||||
DirtyRow* row;
|
||||
Mask* mask;
|
||||
struct Col {
|
||||
int x, w;
|
||||
std::vector<ase_uint8> data;
|
||||
|
||||
Col(int x, int w) : x(x), w(w) { }
|
||||
};
|
||||
|
||||
struct Row {
|
||||
int y;
|
||||
ColsList cols;
|
||||
|
||||
Row(int y) : y(y) { }
|
||||
};
|
||||
|
||||
Dirty(int imgtype, int x1, int y1, int x2, int y2);
|
||||
Dirty(const Dirty& src);
|
||||
Dirty(Image* image1, Image* image2);
|
||||
~Dirty();
|
||||
|
||||
int getMemSize() const;
|
||||
|
||||
int getImgType() const { return m_imgtype; }
|
||||
int x1() const { return m_x1; }
|
||||
int y1() const { return m_y1; }
|
||||
int x2() const { return m_x2; }
|
||||
int y2() const { return m_y2; }
|
||||
|
||||
int getRowsCount() const { return m_rows.size(); }
|
||||
const Row& getRow(int i) const { return *m_rows[i]; }
|
||||
|
||||
inline int getLineSize(int width) const {
|
||||
return imgtype_line_size(m_imgtype, width);
|
||||
}
|
||||
|
||||
void saveImagePixels(Image* image);
|
||||
void swapImagePixels(Image* image);
|
||||
|
||||
Dirty* clone() const { return new Dirty(*this); }
|
||||
|
||||
private:
|
||||
// Disable copying through operator=
|
||||
Dirty& operator=(const Dirty&);
|
||||
|
||||
//private: // TODO these fields are public because Undo creates
|
||||
public: // a Dirty instance from a deserialization process,
|
||||
// remember to "privatize" these members when the
|
||||
// new Undo implementation is finished.
|
||||
|
||||
int m_imgtype;
|
||||
int m_x1, m_y1;
|
||||
int m_x2, m_y2;
|
||||
RowsList m_rows;
|
||||
|
||||
};
|
||||
|
||||
Dirty* dirty_new(Image* image, int x1, int y1, int x2, int y2, bool tiled);
|
||||
Dirty* dirty_new_copy(Dirty* src);
|
||||
Dirty* dirty_new_from_differences(Image* image, Image* image_diff);
|
||||
void dirty_free(Dirty* dirty);
|
||||
|
||||
void dirty_hline(Dirty* dirty, int x1, int y, int x2);
|
||||
|
||||
void dirty_save_image_data(Dirty* dirty);
|
||||
void dirty_swap(Dirty* dirty);
|
||||
|
||||
inline int dirty_line_size(Dirty* dirty, int width)
|
||||
{
|
||||
return image_line_size(dirty->image, width);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -149,7 +149,7 @@ static void chunk_image_invert(UndoStream* stream, UndoChunkImage* chunk);
|
||||
static void chunk_flip_new(UndoStream* stream, Image* image, int x1, int y1, int x2, int y2, bool horz);
|
||||
static void chunk_flip_invert(UndoStream* stream, UndoChunkFlip *chunk);
|
||||
|
||||
static void chunk_dirty_new(UndoStream* stream, Dirty *dirty);
|
||||
static void chunk_dirty_new(UndoStream* stream, Image* image, Dirty *dirty);
|
||||
static void chunk_dirty_invert(UndoStream* stream, UndoChunkDirty *chunk);
|
||||
|
||||
static void chunk_add_image_new(UndoStream* stream, Stock *stock, int image_index);
|
||||
@ -244,7 +244,7 @@ static UndoAction undo_actions[] = {
|
||||
/* Raw data */
|
||||
|
||||
static Dirty *read_raw_dirty(ase_uint8* raw_data);
|
||||
static ase_uint8* write_raw_dirty(ase_uint8* raw_data, Dirty *dirty);
|
||||
static ase_uint8* write_raw_dirty(ase_uint8* raw_data, Dirty* dirty);
|
||||
static int get_raw_dirty_size(Dirty *dirty);
|
||||
|
||||
static Image* read_raw_image(ase_uint8* raw_data);
|
||||
@ -781,6 +781,7 @@ static void chunk_flip_invert(UndoStream* stream, UndoChunkFlip* chunk)
|
||||
|
||||
"dirty"
|
||||
|
||||
DWORD image ID
|
||||
DIRTY_DATA see read/write_raw_dirty
|
||||
|
||||
***********************************************************************/
|
||||
@ -788,33 +789,40 @@ static void chunk_flip_invert(UndoStream* stream, UndoChunkFlip* chunk)
|
||||
struct UndoChunkDirty
|
||||
{
|
||||
UndoChunk head;
|
||||
ase_uint32 image_id;
|
||||
ase_uint8 data[0];
|
||||
};
|
||||
|
||||
void Undo::undo_dirty(Dirty *dirty)
|
||||
void Undo::undo_dirty(Image* image, Dirty* dirty)
|
||||
{
|
||||
chunk_dirty_new(m_undoStream, dirty);
|
||||
chunk_dirty_new(m_undoStream, image, dirty);
|
||||
updateUndo();
|
||||
}
|
||||
|
||||
static void chunk_dirty_new(UndoStream* stream, Dirty *dirty)
|
||||
static void chunk_dirty_new(UndoStream* stream, Image* image, Dirty *dirty)
|
||||
{
|
||||
UndoChunkDirty *chunk = (UndoChunkDirty *)
|
||||
undo_chunk_new(stream,
|
||||
UNDO_TYPE_DIRTY,
|
||||
sizeof(UndoChunkDirty)+get_raw_dirty_size(dirty));
|
||||
|
||||
chunk->image_id = image->getId();
|
||||
write_raw_dirty(chunk->data, dirty);
|
||||
}
|
||||
|
||||
static void chunk_dirty_invert(UndoStream* stream, UndoChunkDirty *chunk)
|
||||
{
|
||||
Dirty *dirty = read_raw_dirty(chunk->data);
|
||||
Image* image = (Image*)GfxObj::find(chunk->image_id);
|
||||
|
||||
if (dirty != NULL) {
|
||||
dirty_swap(dirty);
|
||||
chunk_dirty_new(stream, dirty);
|
||||
dirty_free(dirty);
|
||||
if ((image) &&
|
||||
(image->getType() == GFXOBJ_IMAGE)) {
|
||||
Dirty* dirty = read_raw_dirty(chunk->data);
|
||||
|
||||
if (dirty != NULL) {
|
||||
dirty->swapImagePixels(image);
|
||||
chunk_dirty_new(stream, image, dirty);
|
||||
delete dirty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1863,7 +1871,6 @@ static void undo_chunk_free(UndoChunk* chunk)
|
||||
|
||||
Raw dirty data
|
||||
|
||||
DWORD image ID
|
||||
BYTE image type
|
||||
WORD[4] x1, y1, x2, y2
|
||||
WORD rows
|
||||
@ -1880,102 +1887,97 @@ static void undo_chunk_free(UndoChunk* chunk)
|
||||
|
||||
static Dirty *read_raw_dirty(ase_uint8* raw_data)
|
||||
{
|
||||
ase_uint32 dword;
|
||||
ase_uint16 word;
|
||||
int x1, y1, x2, y2, size;
|
||||
unsigned int image_id;
|
||||
int u, v, x, y;
|
||||
int u, v, x, y, w;
|
||||
int imgtype;
|
||||
Image* image;
|
||||
Dirty *dirty = NULL;
|
||||
|
||||
read_raw_uint32(image_id);
|
||||
read_raw_uint8(imgtype);
|
||||
read_raw_uint16(x1);
|
||||
read_raw_uint16(y1);
|
||||
read_raw_uint16(x2);
|
||||
read_raw_uint16(y2);
|
||||
|
||||
image = (Image*)GfxObj::find(image_id);
|
||||
dirty = new Dirty(imgtype, x1, y1, x2, y2);
|
||||
|
||||
if ((image) &&
|
||||
(image->getType() == GFXOBJ_IMAGE) &&
|
||||
(image->imgtype == imgtype)) {
|
||||
int noRows = 0;
|
||||
read_raw_uint16(noRows);
|
||||
if (noRows > 0) {
|
||||
dirty->m_rows.resize(noRows);
|
||||
|
||||
read_raw_uint16(x1);
|
||||
read_raw_uint16(y1);
|
||||
read_raw_uint16(x2);
|
||||
read_raw_uint16(y2);
|
||||
for (v=0; v<dirty->getRowsCount(); v++) {
|
||||
y = 0;
|
||||
read_raw_uint16(y);
|
||||
|
||||
dirty = dirty_new(image, x1, y1, x2, y2, false);
|
||||
read_raw_uint16(dirty->rows);
|
||||
Dirty::Row* row = new Dirty::Row(y);
|
||||
|
||||
if (dirty->rows > 0) {
|
||||
dirty->row = (DirtyRow*)jmalloc(sizeof(DirtyRow) * dirty->rows);
|
||||
int noCols = 0;
|
||||
read_raw_uint16(noCols);
|
||||
row->cols.resize(noCols);
|
||||
|
||||
for (v=0; v<dirty->rows; v++) {
|
||||
read_raw_uint16(dirty->row[v].y);
|
||||
read_raw_uint16(dirty->row[v].cols);
|
||||
for (u=0; u<noCols; u++) {
|
||||
read_raw_uint16(x);
|
||||
read_raw_uint16(w);
|
||||
|
||||
y = dirty->row[v].y;
|
||||
|
||||
dirty->row[v].col = (DirtyCol*)jmalloc(sizeof(DirtyCol) * dirty->row[v].cols);
|
||||
for (u=0; u<dirty->row[v].cols; u++) {
|
||||
read_raw_uint16(dirty->row[v].col[u].x);
|
||||
read_raw_uint16(dirty->row[v].col[u].w);
|
||||
Dirty::Col* col = new Dirty::Col(x, w);
|
||||
|
||||
x = dirty->row[v].col[u].x;
|
||||
size = dirty->getLineSize(col->w);
|
||||
ASSERT(size > 0);
|
||||
|
||||
size = image_line_size(dirty->image, dirty->row[v].col[u].w);
|
||||
col->data.resize(size);
|
||||
read_raw_data(&col->data[0], size);
|
||||
|
||||
dirty->row[v].col[u].flags = DIRTY_VALID_COLUMN;
|
||||
dirty->row[v].col[u].data = jmalloc(size);
|
||||
dirty->row[v].col[u].ptr = image_address(dirty->image, x, y);
|
||||
|
||||
read_raw_data(dirty->row[v].col[u].data, size);
|
||||
}
|
||||
row->cols[u] = col;
|
||||
}
|
||||
|
||||
dirty->m_rows[v] = row;
|
||||
}
|
||||
}
|
||||
|
||||
return dirty;
|
||||
}
|
||||
|
||||
static ase_uint8* write_raw_dirty(ase_uint8* raw_data, Dirty *dirty)
|
||||
static ase_uint8* write_raw_dirty(ase_uint8* raw_data, Dirty* dirty)
|
||||
{
|
||||
ase_uint32 dword;
|
||||
ase_uint16 word;
|
||||
int u, v, size;
|
||||
|
||||
write_raw_uint32(dirty->image->getId());
|
||||
write_raw_uint8(dirty->image->imgtype);
|
||||
write_raw_uint16(dirty->x1);
|
||||
write_raw_uint16(dirty->y1);
|
||||
write_raw_uint16(dirty->x2);
|
||||
write_raw_uint16(dirty->y2);
|
||||
write_raw_uint16(dirty->rows);
|
||||
write_raw_uint8(dirty->getImgType());
|
||||
write_raw_uint16(dirty->x1());
|
||||
write_raw_uint16(dirty->y1());
|
||||
write_raw_uint16(dirty->x2());
|
||||
write_raw_uint16(dirty->y2());
|
||||
write_raw_uint16(dirty->getRowsCount());
|
||||
|
||||
for (v=0; v<dirty->rows; v++) {
|
||||
write_raw_uint16(dirty->row[v].y);
|
||||
write_raw_uint16(dirty->row[v].cols);
|
||||
for (int v=0; v<dirty->getRowsCount(); v++) {
|
||||
const Dirty::Row& row = dirty->getRow(v);
|
||||
|
||||
for (u=0; u<dirty->row[v].cols; u++) {
|
||||
write_raw_uint16(dirty->row[v].col[u].x);
|
||||
write_raw_uint16(dirty->row[v].col[u].w);
|
||||
write_raw_uint16(row.y);
|
||||
write_raw_uint16(row.cols.size());
|
||||
|
||||
size = image_line_size(dirty->image, dirty->row[v].col[u].w);
|
||||
write_raw_data(dirty->row[v].col[u].data, size);
|
||||
for (size_t u=0; u<row.cols.size(); u++) {
|
||||
write_raw_uint16(row.cols[u]->x);
|
||||
write_raw_uint16(row.cols[u]->w);
|
||||
|
||||
size_t size = dirty->getLineSize(row.cols[u]->w);
|
||||
write_raw_data(&row.cols[u]->data[0], size);
|
||||
}
|
||||
}
|
||||
|
||||
return raw_data;
|
||||
}
|
||||
|
||||
static int get_raw_dirty_size(Dirty *dirty)
|
||||
static int get_raw_dirty_size(Dirty* dirty)
|
||||
{
|
||||
int u, v, size = 4+1+2*4+2; /* DWORD+BYTE+WORD[4]+WORD */
|
||||
int size = 1+2*4+2; // BYTE+WORD[4]+WORD
|
||||
|
||||
for (v=0; v<dirty->rows; v++) {
|
||||
size += 4; /* y, cols (WORD[2]) */
|
||||
for (u=0; u<dirty->row[v].cols; u++) {
|
||||
size += 4; /* x, w (WORD[2]) */
|
||||
size += image_line_size(dirty->image, dirty->row[v].col[u].w);
|
||||
for (int v=0; v<dirty->getRowsCount(); v++) {
|
||||
const Dirty::Row& row = dirty->getRow(v);
|
||||
|
||||
size += 4; // y, cols (WORD[2])
|
||||
for (size_t u=0; u<row.cols.size(); u++) {
|
||||
size += 4; // x, w (WORD[2])
|
||||
size += dirty->getLineSize(row.cols[u]->w);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,14 +25,13 @@
|
||||
#include "ase_exception.h"
|
||||
|
||||
class Cel;
|
||||
class Dirty;
|
||||
class Image;
|
||||
class Layer;
|
||||
class Mask;
|
||||
class Palette;
|
||||
class Sprite;
|
||||
class Stock;
|
||||
|
||||
struct Dirty;
|
||||
class UndoStream;
|
||||
|
||||
class UndoException : public ase_exception
|
||||
@ -72,7 +71,7 @@ public:
|
||||
void undo_data(GfxObj *gfxobj, void *data, int size);
|
||||
void undo_image(Image *image, int x, int y, int w, int h);
|
||||
void undo_flip(Image *image, int x1, int y1, int x2, int y2, bool horz);
|
||||
void undo_dirty(Dirty *dirty);
|
||||
void undo_dirty(Image* image, Dirty *dirty);
|
||||
void undo_add_image(Stock *stock, int image_index);
|
||||
void undo_remove_image(Stock *stock, int image_index);
|
||||
void undo_replace_image(Stock *stock, int image_index);
|
||||
|
@ -540,9 +540,10 @@ void Undoable::flattenLayers(int bgcolor)
|
||||
|
||||
/* we have to save the current state of `cel_image' in the undo */
|
||||
if (isEnabled()) {
|
||||
Dirty* dirty = dirty_new_from_differences(cel_image, image);
|
||||
dirty_save_image_data(dirty);
|
||||
m_sprite->getUndo()->undo_dirty(dirty);
|
||||
Dirty* dirty = new Dirty(cel_image, image);
|
||||
dirty->saveImagePixels(cel_image);
|
||||
m_sprite->getUndo()->undo_dirty(cel_image, dirty);
|
||||
delete dirty;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -1959,15 +1959,14 @@ public:
|
||||
else {
|
||||
/* undo the dirty region */
|
||||
if (m_sprite->getUndo()->isEnabled()) {
|
||||
Dirty* dirty = dirty_new_from_differences(m_cel_image,
|
||||
m_dst_image);
|
||||
Dirty* dirty = new Dirty(m_cel_image, m_dst_image);
|
||||
// TODO error handling
|
||||
|
||||
dirty_save_image_data(dirty);
|
||||
dirty->saveImagePixels(m_cel_image);
|
||||
if (dirty != NULL)
|
||||
m_sprite->getUndo()->undo_dirty(dirty);
|
||||
m_sprite->getUndo()->undo_dirty(m_cel_image, dirty);
|
||||
|
||||
dirty_free(dirty);
|
||||
delete dirty;
|
||||
}
|
||||
|
||||
/* copy the 'dst_image' to the cel_image */
|
||||
|
Loading…
x
Reference in New Issue
Block a user