mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-01 18:00:26 +00:00
Add "Contiguous" option/checkbox for the paint bucket tool (true by default)
This commit is contained in:
parent
d74944c885
commit
7db6ea53c3
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user