add flood fill mode with custom cursor

This commit is contained in:
2019-06-22 10:44:36 +02:00
parent 3f13c8a61e
commit 228263c70f
8 changed files with 1999 additions and 1707 deletions

BIN
data/cursor/bucket-fill.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

File diff suppressed because one or more lines are too long

View File

@@ -620,6 +620,7 @@ void App::update(float dt)
layout[main_id]->find<NodeButton>("btn-cut")->set_active(mode == kCanvasMode::Cut);
layout[main_id]->find<NodeButtonCustom>("btn-mask-free")->set_active(mode == kCanvasMode::MaskFree);
layout[main_id]->find<NodeButtonCustom>("btn-mask-line")->set_active(mode == kCanvasMode::MaskLine);
layout[main_id]->find<NodeButtonCustom>("btn-bucket")->set_active(mode == kCanvasMode::FloodFill);
}
auto observer = std::bind(&App::update_ui_observer, this, std::placeholders::_1);

View File

@@ -388,6 +388,7 @@ void select_button(Node* main, T* button) {
//main->find<NodeButton>("btn-fill")->set_color(color_button_normal);
main->find<NodeButtonCustom>("btn-mask-free")->set_active(false);
main->find<NodeButtonCustom>("btn-mask-line")->set_active(false);
main->find<NodeButtonCustom>("btn-bucket")->set_active(false);
button->set_active(false);
};
@@ -466,6 +467,7 @@ void App::init_toolbar_draw()
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-fill"))
{
// polygon fill
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
Canvas::set_mode(kCanvasMode::Fill);
@@ -487,8 +489,9 @@ void App::init_toolbar_draw()
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-bucket"))
{
button->on_click = [this](Node*) {
canvas->m_canvas->clear(Canvas::I->m_current_brush->m_tip_color);
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
Canvas::set_mode(kCanvasMode::FloodFill);
};
}
}

View File

@@ -25,6 +25,7 @@ std::vector<CanvasMode*> Canvas::modes[] = {
{ new CanvasModeFill, new CanvasModeBasicCamera }, // fill
{ new CanvasModeMaskFree, new CanvasModeBasicCamera }, // mask-free
{ new CanvasModeMaskLine, new CanvasModeBasicCamera }, // mask-poly
{ new CanvasModeFloodFill, new CanvasModeBasicCamera }, // flood-fill
};
glm::vec3 Canvas::m_plane_origin[6] = {
{ 0, 0,-1}, // front
@@ -1352,7 +1353,7 @@ void Canvas::flood_fill(int layer, int plane, std::vector<glm::ivec2> pos, std::
bool flipcoord;
adj_t(int plane, bool flipx, bool flipy, int flipcoord) :
plane(plane), flipx(flipx), flipy(flipy), flipcoord(flipcoord) { }
glm::ivec2 compute(glm::ivec2 p, glm::ivec2 sz)
glm::ivec2 compute(glm::ivec2 p, glm::ivec2 sz) const
{
glm::ivec2 ret;
ret[flipcoord] = flipx ? sz.x - p.x : p.x;
@@ -1373,10 +1374,10 @@ void Canvas::flood_fill(int layer, int plane, std::vector<glm::ivec2> pos, std::
if (!source_color)
source_color = std::make_unique<glm::vec4>(rgb[pos.back().y * sz.x + pos.back().x]);
glm::vec3 c = *source_color;
const glm::vec4 c = *source_color;
std::array<std::vector<glm::ivec2>, 4> edges;
std::array<adj_t, 4> adj[6] = {
static const std::array<adj_t, 4> adj[6] = {
// front - ok
{
adj_t(3, 1, 0, 0),
@@ -1444,14 +1445,18 @@ void Canvas::flood_fill(int layer, int plane, std::vector<glm::ivec2> pos, std::
edges[1].push_back(adj[plane][1].compute({ p.x, sz.y - p.y + 1 }, sz));
return false;
}
if (!mask[i] && rgb[i].a > 0 && glm::distance(c, glm::vec3(rgb[i])) < threshold)
if (!mask[i])
{
if (set_color)
if (c.a == 0 && glm::abs(rgb[i].a - c.a) < threshold ||
c.a > 0 && rgb[i].a > 0 && glm::distance(glm::vec3(c), glm::vec3(rgb[i])) < threshold)
{
mask[i] = true;
rgb[i] = dest_color * 255.f;
if (set_color)
{
mask[i] = true;
rgb[i] = dest_color * 255.f;
}
pos.push_back(p);
}
pos.push_back(p);
return true;
}
return false;
@@ -1464,9 +1469,13 @@ void Canvas::flood_fill(int layer, int plane, std::vector<glm::ivec2> pos, std::
if(!test(p + glm::ivec2( 0, 0), true))
continue;
test(p + glm::ivec2(-1, 0), false);
test(p + glm::ivec2( 1, 0), false);
test(p + glm::ivec2( 0, 1), false);
test(p + glm::ivec2( 0,-1), false);
test(p + glm::ivec2(1, 0), false);
test(p + glm::ivec2(0, 1), false);
test(p + glm::ivec2(0, -1), false);
//for (int x = -1; x <= 1; x++)
// for (int y = -1; y <= 1; y++)
// if (x != 0 && y != 0)
// test(p + glm::ivec2(x, y), false);
}
rtt.bindTexture();

View File

@@ -1548,3 +1548,62 @@ void CanvasModeTransform::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
break;
}
}
void CanvasModeFloodFill::init()
{
TextureManager::load(m_cursor_path.c_str());
}
////////////////////////////////////////////////////////////////////
void CanvasModeFloodFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
#if defined(__IOS__)
m_draw_tip = (me->m_source == kEventSource::Mouse && me->m_type != kEventType::MouseUpL);
#else
m_draw_tip = (me->m_source == kEventSource::Mouse || me->m_source == kEventSource::Stylus);
#endif
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
return;
switch (me->m_type)
{
case kEventType::MouseUpL:
glm::vec3 ro, rd, hit, n;
glm::vec2 pos;
int plane;
if (Canvas::I->point_trace(loc, ro, rd, hit, pos, n, plane))
{
std::map<int, std::unique_ptr<bool[]>> plane_mask;
std::unique_ptr<glm::vec4> color;
Canvas::I->flood_fill(Canvas::I->m_current_layer_idx, plane, { (glm::ivec2)pos },
plane_mask, 200, Canvas::I->m_current_brush->m_tip_color, color);
}
break;
default:
break;
}
}
void CanvasModeFloodFill::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
if (m_draw_tip)
{
ShaderManager::use(kShader::Texture);
ShaderManager::u_mat4(kShaderUniform::MVP,
glm::scale(glm::vec3(1, -1, 1))
* ortho
* glm::translate(glm::vec3(Canvas::I->m_cur_pos, 0.f))
* glm::scale(glm::vec3(32, 32, 1))
* glm::translate(glm::vec3(0.5f, -0.5f, 0))
);
ShaderManager::u_int(kShaderUniform::Tex, 0);
auto& t = TextureManager::get(m_cursor_id);
Canvas::I->m_sampler_linear.bind(0);
t.bind();
Canvas::I->m_plane.draw_fill();
t.unbind();
}
}

View File

@@ -19,6 +19,7 @@ enum class kCanvasMode
Fill,
MaskFree,
MaskLine,
FloodFill,
COUNT,
};
@@ -37,6 +38,8 @@ class CanvasMode
{
public:
static class NodeCanvas* node;
bool hide_curor = false;
bool m_draw_tip = false;
//static Canvas* canvas;
virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) {}
virtual void on_KeyEvent(KeyEvent* ke) {}
@@ -78,7 +81,7 @@ class CanvasModePen : public CanvasMode
// resizing the tip
bool m_resizing = false;
public:
CanvasModePen() = default;
CanvasModePen() { hide_curor = true; }
virtual void on_GestureEvent(GestureEvent* ge) override;
virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) override;
@@ -87,7 +90,6 @@ public:
virtual void leave(kCanvasMode next) override;
bool m_picking = false;
glm::vec2 m_cur_pos;
bool m_draw_tip = false;
bool m_draw_outline = true;
};
@@ -99,7 +101,6 @@ class CanvasModeLine : public CanvasMode
glm::vec2 m_drag_pos;
public:
glm::vec2 m_cur_pos;
bool m_draw_tip = false;
virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) override;
virtual void on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) override;
virtual void init() override;
@@ -107,6 +108,19 @@ public:
virtual void leave(kCanvasMode next) override;
};
class CanvasModeFloodFill : public CanvasMode
{
const std::string m_cursor_path = "data/cursor/bucket-fill.png";
const uint16_t m_cursor_id = const_hash(m_cursor_path.c_str());
public:
CanvasModeFloodFill() { hide_curor = true; }
glm::vec2 m_cur_pos;
virtual void init() override;
virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) override;
virtual void on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) override;
};
struct ray_t { glm::vec3 o, d; };
class CanvasModeGrid : public CanvasMode
{

View File

@@ -564,15 +564,11 @@ kEventResult NodeCanvas::handle_event(Event* e)
mode->on_MouseEvent(me, loc);
break;
case kEventType::MouseUnfocus:
if (auto m = dynamic_cast<CanvasModePen*>(m_canvas->modes[(int)m_canvas->m_current_mode][0]))
m->m_draw_tip = false;
if (auto m = dynamic_cast<CanvasModeLine*>(m_canvas->modes[(int)m_canvas->m_current_mode][0]))
m->m_draw_tip = false;
(*m_canvas->m_mode)[0]->m_draw_tip = false;
App::I.show_cursor();
break;
case kEventType::MouseFocus:
(m_canvas->m_current_mode == kCanvasMode::Draw ||
m_canvas->m_current_mode == kCanvasMode::Erase) &&
(*m_canvas->m_mode)[0]->hide_curor &&
!App::I.keys[(int)kKey::KeyAlt] ?
App::I.hide_cursor() : App::I.show_cursor();
break;
@@ -589,8 +585,7 @@ kEventResult NodeCanvas::handle_event(Event* e)
break;
case kEventType::KeyUp:
if (ke->m_key == kKey::KeyAlt && m_mouse_focus)
m_canvas->m_current_mode == kCanvasMode::Draw ||
m_canvas->m_current_mode == kCanvasMode::Erase ?
(*m_canvas->m_mode)[0]->hide_curor ?
App::I.hide_cursor() : App::I.show_cursor();
if (ke->m_key == kKey::KeyE)
Canvas::set_mode(kCanvasMode::Draw);