Improve creation of Dirty() instance (fix issue #239)

Now Dirty() ctor receives the bounds, so we don't need to iterate over
the whole image to find/shrink the modified region.
This commit is contained in:
David Capello 2013-11-10 15:54:36 -03:00
parent ba4937ab07
commit 13946b310c
6 changed files with 62 additions and 24 deletions

View File

@ -850,7 +850,7 @@ void DocumentApi::flattenLayers(Sprite* sprite, int bgcolor)
// We have to save the current state of `cel_image' in the undo. // We have to save the current state of `cel_image' in the undo.
if (undo->isEnabled()) { if (undo->isEnabled()) {
Dirty* dirty = new Dirty(cel_image, image); Dirty* dirty = new Dirty(cel_image, image, image->getBounds());
dirty->saveImagePixels(cel_image); dirty->saveImagePixels(cel_image);
m_undoers->pushUndoer(new undoers::DirtyArea( m_undoers->pushUndoer(new undoers::DirtyArea(
getObjects(), cel_image, dirty)); getObjects(), cel_image, dirty));
@ -1033,7 +1033,7 @@ void DocumentApi::flipImageWithMask(Image* image, const Mask* mask, raster::algo
// Insert the undo operation. // Insert the undo operation.
DocumentUndo* undo = m_document->getUndo(); DocumentUndo* undo = m_document->getUndo();
if (undo->isEnabled()) { if (undo->isEnabled()) {
base::UniquePtr<Dirty> dirty((new Dirty(image, flippedImage))); base::UniquePtr<Dirty> dirty((new Dirty(image, flippedImage, image->getBounds())));
dirty->saveImagePixels(image); dirty->saveImagePixels(image);
m_undoers->pushUndoer(new undoers::DirtyArea(getObjects(), image, dirty)); m_undoers->pushUndoer(new undoers::DirtyArea(getObjects(), image, dirty));

View File

@ -86,6 +86,7 @@ class ToolLoopImpl : public tools::ToolLoop,
UndoTransaction m_undoTransaction; UndoTransaction m_undoTransaction;
ExpandCelCanvas m_expandCelCanvas; ExpandCelCanvas m_expandCelCanvas;
gfx::Region m_dirtyArea; gfx::Region m_dirtyArea;
gfx::Rect m_dirtyBounds;
tools::ShadeTable8* m_shadeTable; tools::ShadeTable8* m_shadeTable;
public: public:
@ -175,7 +176,7 @@ public:
if (!m_canceled) { if (!m_canceled) {
// Paint ink // Paint ink
if (getInk()->isPaint()) { if (getInk()->isPaint()) {
m_expandCelCanvas.commit(); m_expandCelCanvas.commit(m_dirtyBounds);
} }
// Selection ink // Selection ink
else if (getInk()->isSelection()) { else if (getInk()->isSelection()) {
@ -247,6 +248,7 @@ public:
void updateDirtyArea() OVERRIDE void updateDirtyArea() OVERRIDE
{ {
m_dirtyBounds = m_dirtyBounds.createUnion(m_dirtyArea.getBounds());
m_document->notifySpritePixelsModified(m_sprite, m_dirtyArea); m_document->notifySpritePixelsModified(m_sprite, m_dirtyArea);
} }

View File

@ -151,7 +151,7 @@ ExpandCelCanvas::~ExpandCelCanvas()
delete m_dstImage; delete m_dstImage;
} }
void ExpandCelCanvas::commit() void ExpandCelCanvas::commit(const gfx::Rect& bounds)
{ {
ASSERT(!m_closed); ASSERT(!m_closed);
ASSERT(!m_committed); ASSERT(!m_committed);
@ -192,7 +192,10 @@ void ExpandCelCanvas::commit()
else { else {
// Add to the undo history the differences between m_celImage and m_dstImage // Add to the undo history the differences between m_celImage and m_dstImage
if (m_undo.isEnabled()) { if (m_undo.isEnabled()) {
base::UniquePtr<Dirty> dirty(new Dirty(m_celImage, m_dstImage)); base::UniquePtr<Dirty> dirty
(new Dirty(m_celImage, m_dstImage,
(bounds.isEmpty() ? m_celImage->getBounds():
bounds)));
dirty->saveImagePixels(m_celImage); dirty->saveImagePixels(m_celImage);
if (dirty != NULL) if (dirty != NULL)

View File

@ -20,6 +20,7 @@
#define APP_UTIL_EXPAND_CEL_CANVAS_H_INCLUDED #define APP_UTIL_EXPAND_CEL_CANVAS_H_INCLUDED
#include "filters/tiled_mode.h" #include "filters/tiled_mode.h"
#include "gfx/rect.h"
namespace raster { namespace raster {
class Cel; class Cel;
@ -50,7 +51,7 @@ namespace app {
// Commit changes made in getDestCanvas() in the cel's image. Adds // Commit changes made in getDestCanvas() in the cel's image. Adds
// information in the undo history so the user can undo the // information in the undo history so the user can undo the
// modifications in the canvas. // modifications in the canvas.
void commit(); void commit(const gfx::Rect& bounds = gfx::Rect());
// Restore the cel as its original state as when ExpandCelCanvas() // Restore the cel as its original state as when ExpandCelCanvas()
// was created. // was created.

View File

@ -24,6 +24,7 @@
#include "raster/image.h" #include "raster/image.h"
#include "raster/primitives.h" #include "raster/primitives.h"
#include "raster/primitives_fast.h"
#include <algorithm> #include <algorithm>
@ -58,29 +59,59 @@ Dirty::Dirty(const Dirty& src)
} }
} }
Dirty::Dirty(Image* image, Image* image_diff) template<typename ImageTraits>
: m_format(image->getPixelFormat()) inline bool shrink_row(const Image* image, const Image* image_diff, int& x1, int y, int& x2)
, m_x1(0), m_y1(0)
, m_x2(image->getWidth()-1), m_y2(image->getHeight()-1)
{ {
int x, y, x1, x2; for (; x1<=x2; ++x1) {
if (get_pixel_fast<ImageTraits>(image, x1, y) !=
get_pixel_fast<ImageTraits>(image_diff, x1, y))
break;
}
for (y=0; y<image->getHeight(); y++) { if (x1 > x2)
x1 = -1; return false;
for (x=0; x<image->getWidth(); x++) {
if (get_pixel(image, x, y) != get_pixel(image_diff, x, y)) { for (; x2>x1; x2--) {
x1 = x; if (get_pixel_fast<ImageTraits>(image, x2, y) !=
get_pixel_fast<ImageTraits>(image_diff, x2, y))
break;
}
return true;
}
Dirty::Dirty(Image* image, Image* image_diff, const gfx::Rect& bounds)
: m_format(image->getPixelFormat())
, m_x1(bounds.x), m_y1(bounds.y)
, m_x2(bounds.x2()-1), m_y2(bounds.y2()-1)
{
int y, x1, x2;
for (y=m_y1; y<=m_y2; y++) {
x1 = m_x1;
x2 = m_x2;
bool res;
switch (image->getPixelFormat()) {
case IMAGE_RGB:
res = shrink_row<RgbTraits>(image, image_diff, x1, y, x2);
break; break;
}
case IMAGE_GRAYSCALE:
res = shrink_row<GrayscaleTraits>(image, image_diff, x1, y, x2);
break;
case IMAGE_INDEXED:
res = shrink_row<IndexedTraits>(image, image_diff, x1, y, x2);
break;
default:
ASSERT(false && "Not implemented for bitmaps");
return;
} }
if (x1 < 0) if (!res)
continue; continue;
for (x2=image->getWidth()-1; x2>x1; x2--) {
if (get_pixel(image, x2, y) != get_pixel(image_diff, x2, y))
break;
}
Col* col = new Col(x1, x2-x1+1); Col* col = new Col(x1, x2-x1+1);
col->data.resize(getLineSize(col->w)); col->data.resize(getLineSize(col->w));

View File

@ -54,9 +54,10 @@ namespace raster {
Row(int y) : y(y) { } Row(int y) : y(y) { }
}; };
public:
Dirty(PixelFormat format, int x1, int y1, int x2, int y2); Dirty(PixelFormat format, int x1, int y1, int x2, int y2);
Dirty(const Dirty& src); Dirty(const Dirty& src);
Dirty(Image* image1, Image* image2); Dirty(Image* image1, Image* image2, const gfx::Rect& bounds);
~Dirty(); ~Dirty();
int getMemSize() const; int getMemSize() const;