Add "Contiguous" option/checkbox for the paint bucket tool (true by default)

This commit is contained in:
David Capello 2014-08-07 00:07:24 -03:00
parent d74944c885
commit 7db6ea53c3
9 changed files with 128 additions and 21 deletions

View File

@ -1,5 +1,5 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -101,6 +101,7 @@ namespace app {
virtual int getOpacity() = 0;
virtual int getTolerance() = 0;
virtual bool getContiguous() = 0;
virtual bool getFilled() = 0;
virtual bool getPreviewFilled() = 0;
virtual int getSprayWidth() = 0;
@ -110,6 +111,7 @@ namespace app {
virtual void setOpacity(int opacity) = 0;
virtual void setTolerance(int tolerance) = 0;
virtual void setContiguous(bool state) = 0;
virtual void setFilled(bool state) = 0;
virtual void setPreviewFilled(bool state) = 0;
virtual void setSprayWidth(int width) = 0;

View File

@ -1,5 +1,5 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -694,6 +694,7 @@ class UIToolSettingsImpl
UIBrushSettingsImpl m_brush;
int m_opacity;
int m_tolerance;
bool m_contiguous;
bool m_filled;
bool m_previewFilled;
int m_spray_width;
@ -712,6 +713,7 @@ public:
m_opacity = MID(0, m_opacity, 255);
m_tolerance = get_config_int(cfg_section.c_str(), "Tolerance", 0);
m_tolerance = MID(0, m_tolerance, 255);
m_contiguous = get_config_bool(cfg_section.c_str(), "Contiguous", true);
m_filled = false;
m_previewFilled = get_config_bool(cfg_section.c_str(), "PreviewFilled", false);
m_spray_width = 16;
@ -750,6 +752,7 @@ public:
set_config_int(cfg_section.c_str(), "Opacity", m_opacity);
set_config_int(cfg_section.c_str(), "Tolerance", m_tolerance);
set_config_bool(cfg_section.c_str(), "Contiguous", m_contiguous);
set_config_int(cfg_section.c_str(), "BrushType", m_brush.getType());
set_config_int(cfg_section.c_str(), "BrushSize", m_brush.getSize());
set_config_int(cfg_section.c_str(), "BrushAngle", m_brush.getAngle());
@ -773,6 +776,7 @@ public:
int getOpacity() OVERRIDE { return m_opacity; }
int getTolerance() OVERRIDE { return m_tolerance; }
bool getContiguous() OVERRIDE { return m_contiguous; }
bool getFilled() OVERRIDE { return m_filled; }
bool getPreviewFilled() OVERRIDE { return m_previewFilled; }
int getSprayWidth() OVERRIDE { return m_spray_width; }
@ -782,6 +786,7 @@ public:
void setOpacity(int opacity) OVERRIDE { m_opacity = opacity; }
void setTolerance(int tolerance) OVERRIDE { m_tolerance = tolerance; }
void setContiguous(bool state) OVERRIDE { m_contiguous = state; }
void setFilled(bool state) OVERRIDE { m_filled = state; }
void setPreviewFilled(bool state) OVERRIDE { m_previewFilled = state; }
void setSprayWidth(int width) OVERRIDE { m_spray_width = width; }

View File

@ -1,5 +1,5 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -75,11 +75,14 @@ public:
void transformPoint(ToolLoop* loop, int x, int y)
{
algo_floodfill(loop->getSrcImage(), x, y, loop->getTolerance(), loop, (AlgoHLine)doInkHline);
algo_floodfill(loop->getSrcImage(), x, y,
loop->getTolerance(), loop->getContiguous(),
loop, (AlgoHLine)doInkHline);
}
void getModifiedArea(ToolLoop* loop, int x, int y, Rect& area)
{
area = Rect(0, 0, 9999, 9999);
area = Rect(0, 0, loop->sprite()->width(), loop->sprite()->height());
}
};

View File

@ -1,5 +1,5 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -124,6 +124,10 @@ namespace app {
// Returns the tolerance to be used by the ink (Ink).
virtual int getTolerance() = 0;
// Returns true if the flood fill algorithm should take care
// contiguous pixels or not.
virtual bool getContiguous() = 0;
// Returns the selection mode (if the ink is of selection type).
virtual SelectionMode getSelectionMode() = 0;

View File

@ -1,5 +1,5 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -268,6 +268,30 @@ protected:
}
};
class ContextBar::ContiguousField : public CheckBox
{
public:
ContiguousField() : CheckBox("Contiguous") {
setup_mini_font(this);
}
void setContiguous(bool state) {
setSelected(state);
}
protected:
void onClick(Event& ev) OVERRIDE {
CheckBox::onClick(ev);
ISettings* settings = UIContext::instance()->settings();
Tool* currentTool = settings->getCurrentTool();
settings->getToolSettings(currentTool)
->setContiguous(isSelected());
releaseFocus();
}
};
class ContextBar::InkTypeField : public ComboBox
{
public:
@ -721,6 +745,7 @@ ContextBar::ContextBar()
addChild(m_toleranceLabel = new Label("Tolerance:"));
addChild(m_tolerance = new ToleranceField());
addChild(m_contiguous = new ContiguousField());
addChild(m_inkType = new InkTypeField());
@ -848,6 +873,7 @@ void ContextBar::updateFromTool(tools::Tool* tool)
m_brushAngle->setTextf("%d", brushSettings->getAngle());
m_tolerance->setTextf("%d", toolSettings->getTolerance());
m_contiguous->setSelected(toolSettings->getContiguous());
m_inkType->setInkType(toolSettings->getInkType());
m_inkOpacity->setTextf("%d", toolSettings->getOpacity());
@ -899,6 +925,7 @@ void ContextBar::updateFromTool(tools::Tool* tool)
m_freehandBox->setVisible(isFreehand && hasOpacity);
m_toleranceLabel->setVisible(hasTolerance);
m_tolerance->setVisible(hasTolerance);
m_contiguous->setVisible(hasTolerance);
m_sprayBox->setVisible(hasSprayOptions);
m_selectionOptionsBox->setVisible(hasSelectOptions);
m_selectionMode->setVisible(true);

View File

@ -1,5 +1,5 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -66,6 +66,7 @@ namespace app {
class BrushAngleField;
class BrushSizeField;
class ToleranceField;
class ContiguousField;
class InkTypeField;
class InkOpacityField;
class SprayWidthField;
@ -83,6 +84,7 @@ namespace app {
BrushSizeField* m_brushSize;
ui::Label* m_toleranceLabel;
ToleranceField* m_tolerance;
ContiguousField* m_contiguous;
InkTypeField* m_inkType;
ui::Label* m_opacityLabel;
InkOpacityField* m_inkOpacity;

View File

@ -1,5 +1,5 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -74,6 +74,7 @@ class ToolLoopImpl : public tools::ToolLoop,
gfx::Point m_maskOrigin;
int m_opacity;
int m_tolerance;
bool m_contiguous;
gfx::Point m_offset;
gfx::Point m_speed;
bool m_canceled;
@ -174,6 +175,7 @@ public:
m_opacity = m_toolSettings->getOpacity();
m_tolerance = m_toolSettings->getTolerance();
m_contiguous = m_toolSettings->getContiguous();
m_speed.x = 0;
m_speed.y = 0;
@ -224,6 +226,7 @@ public:
void setSecondaryColor(int color) OVERRIDE { m_secondary_color = color; }
int getOpacity() OVERRIDE { return m_opacity; }
int getTolerance() OVERRIDE { return m_tolerance; }
bool getContiguous() OVERRIDE { return m_contiguous; }
SelectionMode getSelectionMode() OVERRIDE { return m_selectionMode; }
ISettings* settings() OVERRIDE { return m_settings; }
IDocumentSettings* getDocumentSettings() OVERRIDE { return m_docSettings; }

View File

@ -1,5 +1,5 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -42,7 +42,9 @@ namespace raster {
double x2, double y2, double x3, double y3,
double in_x);
void algo_floodfill(Image* image, int x, int y, int tolerance, void* data, AlgoHLine proc);
void algo_floodfill(Image* image, int x, int y,
int tolerance, bool contiguous,
void* data, AlgoHLine proc);
void algo_polygon(int vertices, const int* points, void* data, AlgoHLine proc);

View File

@ -1,6 +1,7 @@
// The floodfill routine.
// By Shawn Hargreaves.
// Adapted to Aseprite by David Capello
// Added non-contiguous mode by David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -89,6 +90,30 @@ static inline bool color_equal_8(color_t c1, color_t c2, int tolerance)
return ABS((int)c1 - (int)c2) <= tolerance;
}
template<typename ImageTraits>
static inline bool color_equal(color_t c1, color_t c2, int tolerance)
{
// TODO static_assert(false)
}
template<>
static inline bool color_equal<RgbTraits>(color_t c1, color_t c2, int tolerance)
{
return color_equal_32(c1, c2, tolerance);
}
template<>
static inline bool color_equal<GrayscaleTraits>(color_t c1, color_t c2, int tolerance)
{
return color_equal_16(c1, c2, tolerance);
}
template<>
static inline bool color_equal<IndexedTraits>(color_t c1, color_t c2, int tolerance)
{
return color_equal_8(c1, c2, tolerance);
}
/* flooder:
@ -254,7 +279,7 @@ static int check_flood_line(Image* image, int y, int left, int right,
c = p->next;
if (!c) {
left = flooder (image, left, y, src_color, tolerance, data, proc);
left = flooder(image, left, y, src_color, tolerance, data, proc);
ret = true;
break;
}
@ -264,29 +289,62 @@ static int check_flood_line(Image* image, int y, int left, int right,
return ret;
}
template<typename ImageTraits>
static void replace_color(Image* image, int src_color, int tolerance, void *data, AlgoHLine proc)
{
typename ImageTraits::address_t address;
int w = image->width();
int h = image->height();
for (int y=0; y<h; ++y) {
address = reinterpret_cast<ImageTraits::address_t>(image->getPixelAddress(0, y));
for (int x=0; x<w; ++x, ++address) {
int right = -1;
if (color_equal<ImageTraits>((int)(*address), src_color, tolerance)) {
++address;
for (right=x+1; right<w; ++right, ++address) {
if (!color_equal<ImageTraits>((int)(*address), src_color, tolerance))
break;
}
(*proc)(x, y, right-1, data);
x = right;
}
}
}
}
/* floodfill:
* Fills an enclosed area (starting at point x, y) with the specified color.
*/
void algo_floodfill(Image* image, int x, int y, int tolerance, void *data, AlgoHLine proc)
void algo_floodfill(Image* image, int x, int y,
int tolerance, bool contiguous,
void* data, AlgoHLine proc)
{
int c, done;
FLOODED_LINE *p;
/* make sure we have a valid starting point */
// Make sure we have a valid starting point
if ((x < 0) || (x >= image->width()) ||
(y < 0) || (y >= image->height()))
return;
/* what color to replace? */
// What color to replace?
color_t src_color = get_pixel(image, x, y);
// Non-contiguous case, we replace colors in the whole image.
if (!contiguous) {
switch (image->pixelFormat()) {
case IMAGE_RGB: replace_color<RgbTraits>(image, src_color, tolerance, data, proc); break;
case IMAGE_GRAYSCALE: replace_color<GrayscaleTraits>(image, src_color, tolerance, data, proc); break;
case IMAGE_INDEXED: replace_color<IndexedTraits>(image, src_color, tolerance, data, proc); break;
}
return;
}
/* set up the list of flooded segments */
_grow_scratch_mem(sizeof(FLOODED_LINE) * image->height());
flood_count = image->height();
p = (FLOODED_LINE*)_scratch_mem;
for (c=0; c<flood_count; c++) {
FLOODED_LINE* p = (FLOODED_LINE*)_scratch_mem;
for (int c=0; c<flood_count; c++) {
p[c].flags = 0;
p[c].lpos = SHRT_MAX;
p[c].rpos = SHRT_MIN;
@ -298,11 +356,12 @@ void algo_floodfill(Image* image, int x, int y, int tolerance, void *data, AlgoH
flooder(image, x, y, src_color, tolerance, data, proc);
/* continue as long as there are some segments still to test */
bool done;
do {
done = true;
/* for each line on the screen */
for (c=0; c<flood_count; c++) {
for (int c=0; c<flood_count; c++) {
p = FLOOD_LINE(c);