add flood fill mode with custom cursor
This commit is contained in:
BIN
data/cursor/bucket-fill.png
Normal file
BIN
data/cursor/bucket-fill.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 655 B |
3577
extra/ui/icons.ai
3577
extra/ui/icons.ai
File diff suppressed because one or more lines are too long
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user