From 2782d864ed19f38348a5973ac6f2bc9932c8f646 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sun, 23 Jun 2019 14:58:26 +0200 Subject: [PATCH] add undo action for bucket fill --- src/action.h | 1 + src/canvas.cpp | 53 ++++++++++++++++++++++---------- src/canvas.h | 12 +++++++- src/canvas_modes.cpp | 69 +++++++++++++++++++++++++++++++++++++----- src/node_panel_layer.h | 1 - src/rtt.h | 1 + 6 files changed, 112 insertions(+), 25 deletions(-) diff --git a/src/action.h b/src/action.h index 3729edf..1e60e1d 100644 --- a/src/action.h +++ b/src/action.h @@ -3,6 +3,7 @@ class Action { public: + enum class Direction { Undo, Redo } m_direction; bool was_saved = false; virtual void run() = 0; virtual void undo() = 0; diff --git a/src/canvas.cpp b/src/canvas.cpp index 5fe59f5..21e5262 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -1342,7 +1342,7 @@ void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index */ } -void Canvas::flood_fill(int layer, int plane, std::vector pos, std::map>& plane_mask, +void Canvas::flood_fill(int layer, int plane, std::vector pos, FloodData& plane_data, float threshold, glm::vec4 dest_color, std::unique_ptr& source_color) { struct adj_t @@ -1365,12 +1365,19 @@ void Canvas::flood_fill(int layer, int plane, std::vector pos, std:: LOG("flood_fill plane %d", plane); auto& rtt = m_layers[layer]->m_rtt[plane]; - auto sz = glm::ivec2(rtt.getWidth(), rtt.getHeight()); - auto rgb = reinterpret_cast(m_layers[layer]->m_rtt[plane].readTextureData()); + auto sz = rtt.getSize(); - if (plane_mask.find(plane) == plane_mask.end()) - plane_mask.insert({ plane, std::make_unique((size_t)sz.x * sz.y) }); - auto& mask = plane_mask[plane]; + if (!plane_data.mask[plane]) + { + plane_data.mask[plane] = std::make_unique((size_t)sz.x * sz.y); + plane_data.rgb[plane] = std::unique_ptr( + reinterpret_cast(m_layers[layer]->m_rtt[plane].readTextureData())); + plane_data.bb[plane] = { sz.x, sz.y, 0, 0 }; + plane_data.dirty[plane] = false; + plane_data.layer = m_layers[layer]; + } + auto& mask = plane_data.mask[plane]; + auto& rgb = plane_data.rgb[plane]; if (!source_color) source_color = std::make_unique(rgb[pos.back().y * sz.x + pos.back().x]); @@ -1378,35 +1385,35 @@ void Canvas::flood_fill(int layer, int plane, std::vector pos, std:: std::array, 4> edges; static const std::array adj[6] = { - // front - ok + // front { adj_t(3, 1, 0, 0), adj_t(4, 1, 1, 0), adj_t(1, 0, 0, 0), adj_t(5, 1, 0, 0), }, - // right - ok + // right { adj_t(0, 1, 0, 0), adj_t(4, 1, 0, 1), adj_t(2, 0, 0, 0), adj_t(5, 0, 0, 1), }, - // back - ok + // back { adj_t(1, 1, 0, 0), adj_t(4, 0, 0, 0), adj_t(3, 0, 0, 0), adj_t(5, 0, 1, 0), }, - // left - ok + // left { adj_t(2, 1, 0, 0), adj_t(4, 0, 1, 1), adj_t(0, 0, 0, 0), adj_t(5, 1, 1, 1), }, - // top - ok + // top { adj_t(1, 1, 1, 1), adj_t(0, 1, 1, 0), @@ -1454,6 +1461,10 @@ void Canvas::flood_fill(int layer, int plane, std::vector pos, std:: { mask[i] = true; rgb[i] = dest_color * 255.f; + plane_data.dirty[plane] = true; + glm::vec2 bb_min = glm::min((glm::vec2)p, xy(plane_data.bb[plane])); + glm::vec2 bb_max = glm::max((glm::vec2)p, zw(plane_data.bb[plane])); + plane_data.bb[plane] = { bb_min, bb_max }; } pos.push_back(p); } @@ -1478,20 +1489,30 @@ void Canvas::flood_fill(int layer, int plane, std::vector pos, std:: // test(p + glm::ivec2(x, y), false); } - rtt.bindTexture(); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, sz.x, sz.y, GL_RGBA, GL_UNSIGNED_BYTE, rgb); - rtt.unbindTexture(); - for (int i = 0; i < 4; i++) { if (!edges[i].empty()) { - flood_fill(layer, adj[plane][i].plane, edges[i], plane_mask, threshold, dest_color, source_color); + flood_fill(layer, adj[plane][i].plane, edges[i], plane_data, threshold, dest_color, source_color); //LOG("continue to plane %d -> %d", plane, adj[plane][i].plane); } } } +void Canvas::FloodData::apply() +{ + for (int plane = 0; plane < 6; plane++) + { + if (!dirty[plane]) + continue; + auto& rtt = layer->m_rtt[plane]; + rtt.bindTexture(); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rtt.getWidth(), rtt.getHeight(), + GL_RGBA, GL_UNSIGNED_BYTE, rgb[plane].get()); + rtt.unbindTexture(); + } +} + void Canvas::resize(int width, int height) { m_width = width; diff --git a/src/canvas.h b/src/canvas.h index 5bc9c70..4711c99 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -66,6 +66,16 @@ class Canvas }; public: + struct FloodData + { + std::shared_ptr layer; + std::unique_ptr mask[6]; + std::unique_ptr rgb[6] = SIXPLETTE(0); + bool dirty[6] = SIXPLETTE(false); + glm::vec4 bb[6]; + void apply(); + }; + Plane m_plane; Plane m_plane_brush; DynamicShape m_brush_shape; @@ -166,7 +176,7 @@ public: void layer_add(std::string name, std::shared_ptr layer = nullptr, int index = 0); void layer_order(int idx, int pos); void layer_merge(int source_idx, int dest_idx); - void flood_fill(int layer, int plane, std::vector pos, std::map>& plane_mask, + void flood_fill(int layer, int plane, std::vector pos, FloodData& plane_data, float threshold, glm::vec4 dest_color, std::unique_ptr& source_color); void stroke_start(glm::vec3 point, float pressure); void stroke_update(glm::vec3 point, float pressure); diff --git a/src/canvas_modes.cpp b/src/canvas_modes.cpp index 8cf997e..b34fe7b 100644 --- a/src/canvas_modes.cpp +++ b/src/canvas_modes.cpp @@ -1549,11 +1549,6 @@ void CanvasModeTransform::on_MouseEvent(MouseEvent* me, glm::vec2& loc) } } -void CanvasModeFloodFill::init() -{ - TextureManager::load(m_cursor_path.c_str()); -} - //////////////////////////////////////////////////////////////////// void CanvasModeFloodFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) @@ -1566,6 +1561,48 @@ void CanvasModeFloodFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch) return; + struct ActionFloodFill : public Action + { + std::shared_ptr m_layer; + std::shared_ptr m_snap; + glm::ivec2 m_pos; + glm::vec4 m_color; + float m_threshold; + int m_layer_index; + int m_plane; + virtual void run() override { } + virtual size_t memory() override { return m_snap->memsize(); } + virtual Action* get_redo() override + { + auto a = new ActionFloodFill; + a->m_direction = (Direction)(1 - (int)m_direction); + a->m_layer = m_layer; + a->m_snap = m_snap; + a->m_pos = m_pos; + a->m_color = m_color; + a->m_layer_index = m_layer_index; + a->m_threshold = m_threshold; + a->m_plane = m_plane; + return a; + } + virtual void undo() override + { + if (m_direction == Direction::Undo) + { + m_layer->restore(*m_snap); + } + else + { + Canvas::FloodData plane_data; + std::unique_ptr color; + Canvas::I->flood_fill(m_layer_index, m_plane, { m_pos }, + plane_data, m_threshold, m_color, color); + plane_data.apply(); + } + } + }; + + switch (me->m_type) { case kEventType::MouseUpL: @@ -1574,10 +1611,23 @@ void CanvasModeFloodFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) int plane; if (Canvas::I->point_trace(loc, ro, rd, hit, pos, n, plane)) { - std::map> plane_mask; + Canvas::FloodData plane_data; std::unique_ptr color; Canvas::I->flood_fill(Canvas::I->m_current_layer_idx, plane, { (glm::ivec2)pos }, - plane_mask, m_tool->get_threshold(), Canvas::I->m_current_brush->m_tip_color, color); + plane_data, m_tool->get_threshold(), Canvas::I->m_current_brush->m_tip_color, color); + + auto a = new ActionFloodFill; + a->m_direction = Action::Direction::Undo; + a->m_layer = plane_data.layer; + a->m_snap = std::make_shared(plane_data.layer->snapshot()); + a->m_pos = (glm::ivec2)pos; + a->m_color = Canvas::I->m_current_brush->m_tip_color; + a->m_layer_index = Canvas::I->m_current_layer_idx; + a->m_threshold = m_tool->get_threshold(); + a->m_plane = plane; + ActionManager::add(a); + + plane_data.apply(); } break; default: @@ -1585,6 +1635,11 @@ void CanvasModeFloodFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) } } +void CanvasModeFloodFill::init() +{ + TextureManager::load(m_cursor_path.c_str()); +} + void CanvasModeFloodFill::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) { if (m_draw_tip) diff --git a/src/node_panel_layer.h b/src/node_panel_layer.h index 9464883..41de78b 100644 --- a/src/node_panel_layer.h +++ b/src/node_panel_layer.h @@ -136,7 +136,6 @@ public: struct ActionLayerMerge : public Action { - enum class Direction { Undo, Redo } m_direction; std::shared_ptr m_snap; std::shared_ptr m_layer; std::shared_ptr m_layer_node; diff --git a/src/rtt.h b/src/rtt.h index a15d2dd..ac54f04 100644 --- a/src/rtt.h +++ b/src/rtt.h @@ -36,6 +36,7 @@ public: GLuint getTextureID() const { return texID; } int getWidth() const { return w; } int getHeight() const { return h; } + glm::ivec2 getSize() const { return { w, h }; } int bytes() const { return w * h * 4; } int stride() const { return w * 4; } GLuint getFBO() const { return fboID; }