Skip to content

Commit

Permalink
Improve creation of Dirty() instance (fix issue #239)
Browse files Browse the repository at this point in the history
Now Dirty() ctor receives the bounds, so we don't need to iterate over
the whole image to find/shrink the modified region.
  • Loading branch information
dacap committed Nov 10, 2013
1 parent ba4937a commit 13946b3
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 22 deletions.
4 changes: 2 additions & 2 deletions src/app/document_api.cpp
Expand Up @@ -850,7 +850,7 @@ void DocumentApi::flattenLayers(Sprite* sprite, int bgcolor)

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

m_undoers->pushUndoer(new undoers::DirtyArea(getObjects(), image, dirty));
Expand Down
4 changes: 3 additions & 1 deletion src/app/ui/editor/tool_loop_impl.cpp
Expand Up @@ -86,6 +86,7 @@ class ToolLoopImpl : public tools::ToolLoop,
UndoTransaction m_undoTransaction;
ExpandCelCanvas m_expandCelCanvas;
gfx::Region m_dirtyArea;
gfx::Rect m_dirtyBounds;
tools::ShadeTable8* m_shadeTable;

public:
Expand Down Expand Up @@ -175,7 +176,7 @@ class ToolLoopImpl : public tools::ToolLoop,
if (!m_canceled) {
// Paint ink
if (getInk()->isPaint()) {
m_expandCelCanvas.commit();
m_expandCelCanvas.commit(m_dirtyBounds);
}
// Selection ink
else if (getInk()->isSelection()) {
Expand Down Expand Up @@ -247,6 +248,7 @@ class ToolLoopImpl : public tools::ToolLoop,

void updateDirtyArea() OVERRIDE
{
m_dirtyBounds = m_dirtyBounds.createUnion(m_dirtyArea.getBounds());
m_document->notifySpritePixelsModified(m_sprite, m_dirtyArea);
}

Expand Down
7 changes: 5 additions & 2 deletions src/app/util/expand_cel_canvas.cpp
Expand Up @@ -151,7 +151,7 @@ ExpandCelCanvas::~ExpandCelCanvas()
delete m_dstImage;
}

void ExpandCelCanvas::commit()
void ExpandCelCanvas::commit(const gfx::Rect& bounds)
{
ASSERT(!m_closed);
ASSERT(!m_committed);
Expand Down Expand Up @@ -192,7 +192,10 @@ void ExpandCelCanvas::commit()
else {
// Add to the undo history the differences between m_celImage and m_dstImage
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);
if (dirty != NULL)
Expand Down
3 changes: 2 additions & 1 deletion src/app/util/expand_cel_canvas.h
Expand Up @@ -20,6 +20,7 @@
#define APP_UTIL_EXPAND_CEL_CANVAS_H_INCLUDED

#include "filters/tiled_mode.h"
#include "gfx/rect.h"

namespace raster {
class Cel;
Expand Down Expand Up @@ -50,7 +51,7 @@ namespace app {
// Commit changes made in getDestCanvas() in the cel's image. Adds
// information in the undo history so the user can undo the
// modifications in the canvas.
void commit();
void commit(const gfx::Rect& bounds = gfx::Rect());

// Restore the cel as its original state as when ExpandCelCanvas()
// was created.
Expand Down
61 changes: 46 additions & 15 deletions src/raster/dirty.cpp
Expand Up @@ -24,6 +24,7 @@

#include "raster/image.h"
#include "raster/primitives.h"
#include "raster/primitives_fast.h"

#include <algorithm>

Expand Down Expand Up @@ -58,28 +59,58 @@ Dirty::Dirty(const Dirty& src)
}
}

Dirty::Dirty(Image* image, Image* image_diff)
template<typename ImageTraits>
inline bool shrink_row(const Image* image, const Image* image_diff, int& x1, int y, int& x2)
{
for (; x1<=x2; ++x1) {
if (get_pixel_fast<ImageTraits>(image, x1, y) !=
get_pixel_fast<ImageTraits>(image_diff, x1, y))
break;
}

if (x1 > x2)
return false;

for (; x2>x1; x2--) {
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(0), m_y1(0)
, m_x2(image->getWidth()-1), m_y2(image->getHeight()-1)
, m_x1(bounds.x), m_y1(bounds.y)
, m_x2(bounds.x2()-1), m_y2(bounds.y2()-1)
{
int x, y, x1, x2;
int y, x1, x2;

for (y=0; y<image->getHeight(); y++) {
x1 = -1;
for (x=0; x<image->getWidth(); x++) {
if (get_pixel(image, x, y) != get_pixel(image_diff, x, y)) {
x1 = x;
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;
}
}
if (x1 < 0)
continue;

for (x2=image->getWidth()-1; x2>x1; x2--) {
if (get_pixel(image, x2, y) != get_pixel(image_diff, x2, y))
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 (!res)
continue;

Col* col = new Col(x1, x2-x1+1);
col->data.resize(getLineSize(col->w));
Expand Down
3 changes: 2 additions & 1 deletion src/raster/dirty.h
Expand Up @@ -54,9 +54,10 @@ namespace raster {
Row(int y) : y(y) { }
};

public:
Dirty(PixelFormat format, int x1, int y1, int x2, int y2);
Dirty(const Dirty& src);
Dirty(Image* image1, Image* image2);
Dirty(Image* image1, Image* image2, const gfx::Rect& bounds);
~Dirty();

int getMemSize() const;
Expand Down

0 comments on commit 13946b3

Please sign in to comment.