Fix dirty area calculation

Dirty area region was not calculated correctly when the bottom part of the modified area fell on the intersection of the top left and top middle tile sprites on a tiled-mode-enabled canvas and the top part fell outside of the canvas.
This commit is contained in:
Martín Capello 2021-05-28 15:46:13 -03:00
parent 3bce6f2272
commit d79c193e40
3 changed files with 12 additions and 38 deletions

View File

@ -10,6 +10,7 @@
#pragma once
#include "app/shade.h"
#include "app/util/tiled_mode.h"
#include "app/tools/dynamics.h"
#include "app/tools/stroke.h"
#include "app/tools/tool_loop_modifiers.h"
@ -256,6 +257,8 @@ namespace app {
virtual void savePointshapeStrokePtArea(const int pti, const Stroke::Pt& pt) = 0;
virtual void restoreLastPts(const int pti, const tools::Stroke::Pt& pt) = 0;
virtual const app::TiledModeHelper& getTiledModeHelper() = 0;
};
} // namespace tools

View File

@ -327,42 +327,8 @@ void ToolLoopManager::calculateDirtyArea(const Strokes& strokes)
// Apply tiled mode
TiledMode tiledMode = m_toolLoop->getTiledMode();
if (tiledMode != TiledMode::NONE) {
int w = m_toolLoop->sprite()->width();
int h = m_toolLoop->sprite()->height();
Region sprite_area(Rect(0, 0, w, h));
Region outside;
outside.createSubtraction(m_dirtyArea, sprite_area);
switch (tiledMode) {
case TiledMode::X_AXIS:
outside.createIntersection(outside, Region(Rect(-w*10000, 0, w*20000, h)));
break;
case TiledMode::Y_AXIS:
outside.createIntersection(outside, Region(Rect(0, -h*10000, w, h*20000)));
break;
}
Rect outsideBounds = outside.bounds();
if (outsideBounds.x < 0) outside.offset(w * (1+((-outsideBounds.x) / w)), 0);
if (outsideBounds.y < 0) outside.offset(0, h * (1+((-outsideBounds.y) / h)));
int x1 = outside.bounds().x;
while (true) {
Region in_sprite;
in_sprite.createIntersection(outside, sprite_area);
outside.createSubtraction(outside, in_sprite);
m_dirtyArea.createUnion(m_dirtyArea, in_sprite);
outsideBounds = outside.bounds();
if (outsideBounds.isEmpty())
break;
else if (outsideBounds.x+outsideBounds.w > w)
outside.offset(-w, 0);
else if (outsideBounds.y+outsideBounds.h > h)
outside.offset(x1-outsideBounds.x, -h);
else
break;
}
m_toolLoop->getTiledModeHelper().wrapPosition(m_dirtyArea);
m_toolLoop->getTiledModeHelper().collapseRegionByTiledMode(m_dirtyArea);
}
}

View File

@ -148,6 +148,8 @@ protected:
// Last point index.
int m_lastPti;
app::TiledModeHelper m_tiledModeHelper;
public:
ToolLoopBase(Editor* editor,
Site& site, const doc::Grid& grid,
@ -193,6 +195,7 @@ public:
, m_primaryColor(m_button == tools::ToolLoop::Left ? m_fgColor: m_bgColor)
, m_secondaryColor(m_button == tools::ToolLoop::Left ? m_bgColor: m_fgColor)
, m_staticToolModifiers(params.modifiers)
, m_tiledModeHelper(m_docPref.tiled.mode(), m_sprite)
{
ASSERT(m_tool);
ASSERT(m_ink);
@ -436,6 +439,10 @@ public:
void restoreLastPts(const int pti, const tools::Stroke::Pt& pt) override { }
const app::TiledModeHelper& getTiledModeHelper() override {
return m_tiledModeHelper;
}
#ifdef ENABLE_UI
protected:
void updateAllVisibleRegion() {
@ -473,7 +480,6 @@ class ToolLoopImpl : public ToolLoopBase,
std::unique_ptr<ExpandCelCanvas> m_expandCelCanvas;
Image* m_floodfillSrcImage;
bool m_saveLastPoint;
app::TiledModeHelper m_tiledModeHelper;
public:
ToolLoopImpl(Editor* editor,
@ -494,7 +500,6 @@ public:
ModifyDocument))
, m_floodfillSrcImage(nullptr)
, m_saveLastPoint(saveLastPoint)
, m_tiledModeHelper(m_docPref.tiled.mode(), m_sprite)
{
if (m_pointShape->isFloodFill()) {
if (m_tilesMode) {