From 9ee4bc42b9fcb5d6722f92b4d7ca9348f2d07e84 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Tue, 18 Jun 2019 17:39:35 +0200 Subject: [PATCH] add history to layer create, delete, move, rename, and merge --- src/app.cpp | 6 +- src/app_cloud.cpp | 4 +- src/app_dialogs.cpp | 31 +++++++- src/app_layout.cpp | 43 ++++------- src/app_vr.cpp | 8 +- src/canvas.cpp | 78 ++++++++----------- src/canvas.h | 5 +- src/canvas_layer.cpp | 2 + src/canvas_layer.h | 8 +- src/node_canvas.cpp | 19 +++-- src/node_panel_layer.cpp | 159 +++++++++++++++++++++++++++++++-------- src/node_panel_layer.h | 33 ++++++-- 12 files changed, 259 insertions(+), 137 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index d95c53e..bf72e1b 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -55,10 +55,10 @@ void App::open_document(std::string path) { async_start(); title_update(); - for (auto& i : canvas->m_canvas->m_order) + for (int layer_index = 0; layer_index < canvas->m_canvas->m_layers.size(); layer_index++) { - auto l = layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str(), false); - l->m_visibility->set_value(canvas->m_canvas->m_layers[i]->m_visible); + auto l = layers->add_layer(canvas->m_canvas->m_layers[layer_index]->m_name.c_str(), false); + l->m_visibility->set_value(canvas->m_canvas->m_layers[layer_index]->m_visible); } async_end(); } diff --git a/src/app_cloud.cpp b/src/app_cloud.cpp index f6660e7..61ff50f 100644 --- a/src/app_cloud.cpp +++ b/src/app_cloud.cpp @@ -169,8 +169,8 @@ void App::cloud_browse() async_start(); doc_name = dialog->selected_name; title_update(); - for (auto& i : canvas->m_canvas->m_order) - layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str(), false); + for (auto& l : canvas->m_canvas->m_layers) + layers->add_layer(l->m_name.c_str(), false); ActionManager::clear(); m->destroy(); async_redraw(); diff --git a/src/app_dialogs.cpp b/src/app_dialogs.cpp index 5626677..b6745b6 100644 --- a/src/app_dialogs.cpp +++ b/src/app_dialogs.cpp @@ -114,12 +114,11 @@ void App::dialog_newdoc() layers->clear(); canvas->m_canvas->m_layers.clear(); - canvas->m_canvas->m_order.clear(); canvas->m_canvas->resize(res, res); canvas->reset_camera(); ActionManager::clear(); - layers->add_layer("Default", false); + layers->add_layer("Default", false, true); canvas->m_canvas->m_unsaved = true; canvas->m_canvas->m_newdoc = false; @@ -536,8 +535,32 @@ void App::dialog_layer_rename() dialog->btn_ok->on_click = [this,dialog](Node*) { - layers->m_current_layer->set_name(dialog->get_name().c_str()); - canvas->m_canvas->m_layers[canvas->m_canvas->m_current_layer_idx]->m_name = dialog->get_name(); + struct ActionLayerRename : public Action + { + std::string m_old_name; + std::string m_new_name; + bool m_unsaved; + Layer* m_layer; + std::shared_ptr m_layer_node; + ActionLayerRename(std::string old_name, std::string new_name, std::shared_ptr layer_node, Layer* layer) : + m_old_name(old_name), m_new_name(new_name), m_layer_node(layer_node), m_layer(layer) { } + virtual void run() override { } + virtual size_t memory() override { return 0; } + virtual void undo() override + { + m_layer_node->set_name(m_old_name.c_str()); + m_layer->m_name = m_old_name; + } + virtual Action* get_redo() override + { + return new ActionLayerRename(m_new_name, m_old_name, m_layer_node, m_layer); + } + }; + auto layer_node = std::static_pointer_cast(layers->m_current_layer->shared_from_this()); + auto* layer = canvas->m_canvas->m_layers[canvas->m_canvas->m_current_layer_idx].get(); + ActionManager::add(new ActionLayerRename(layers->m_current_layer->m_label_text, dialog->get_name(), layer_node, layer)); + layer_node->set_name(dialog->get_name().c_str()); + layer->m_name = dialog->get_name(); dialog->destroy(); App::I.hideKeyboard(); }; diff --git a/src/app_layout.cpp b/src/app_layout.cpp index ad37f86..303d39e 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -166,16 +166,16 @@ void App::init_sidebar() brush_update(); }; - layers->on_layer_add = [this](Node*, std::unique_ptr layer, int index) { - canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str(), std::move(layer), index); + layers->on_layer_add = [this](Node*, std::shared_ptr layer, int index) { + canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str(), layer, index); canvas->m_canvas->m_unsaved = true; title_update(); }; layers->on_layer_duplicate = [this](Node*, int source_index) { - Canvas::I->layer_add(layers->m_layers.back()->m_label_text.c_str()); - auto& dst = Canvas::I->m_layers.back(); - auto& src = Canvas::I->m_layers[Canvas::I->m_order[source_index]]; + Canvas::I->layer_add(layers->m_layers.back()->m_label_text.c_str(), nullptr, source_index + 1); + auto& dst = Canvas::I->m_layers[source_index + 1]; + auto& src = Canvas::I->m_layers[source_index]; for (int i = 0; i < 6; i++) { if (!src->m_dirty_face[i]) @@ -192,7 +192,7 @@ void App::init_sidebar() }; layers->on_layer_change = [this](Node*, int old_idx, int new_idx) { - canvas->m_canvas->m_current_layer_idx = canvas->m_canvas->m_order[new_idx]; + canvas->m_canvas->m_current_layer_idx = new_idx; }; layers->on_layer_order = [this](Node*, int old_idx, int new_idx) { @@ -208,31 +208,31 @@ void App::init_sidebar() }; layers->on_layer_opacity_changed = [this](Node*, int idx, float value) { - canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]]->m_opacity = value; + canvas->m_canvas->m_layers[idx]->m_opacity = value; canvas->m_canvas->m_unsaved = true; title_update(); }; layers->on_layer_visibility_changed = [this](Node*, int idx, bool visible) { - canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]]->m_visible = visible; + canvas->m_canvas->m_layers[idx]->m_visible = visible; canvas->m_canvas->m_unsaved = true; title_update(); }; layers->on_layer_alpha_lock_changed = [this](Node*, int idx, bool locked) { - canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]]->m_alpha_locked = locked; + canvas->m_canvas->m_layers[idx]->m_alpha_locked = locked; canvas->m_canvas->m_unsaved = true; title_update(); }; layers->on_layer_blend_mode_changed = [this](Node*, int idx, int mode) { - canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]]->m_blend_mode = mode; + canvas->m_canvas->m_layers[idx]->m_blend_mode = mode; canvas->m_canvas->m_unsaved = true; title_update(); }; layers->on_layer_highlight_changed = [this](Node*, int idx, bool highlight) { - canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]]->m_hightlight = highlight; + canvas->m_canvas->m_layers[idx]->m_hightlight = highlight; }; if (auto* button = layout[main_id]->find("btn-stroke")) { @@ -1152,32 +1152,21 @@ void App::init_menu_layer() set_text("Rename Layer (Select a layer)"); popup->find("layer-merge")->on_click = [this, popup](Node*) { - const auto& order = canvas->m_canvas->m_order; //layers->get_child_index(layers->) - int current_idx_order = (int)std::distance(order.begin(), std::find(order.begin(), order.end(), canvas->m_canvas->m_current_layer_idx)); + int current_idx_order = Canvas::I->m_current_layer_idx; if (current_idx_order > 0) { - int dest_layer_idx = order[current_idx_order - 1]; - canvas->m_canvas->layer_merge(canvas->m_canvas->m_current_layer_idx, dest_layer_idx); - canvas->m_canvas->layer_remove(current_idx_order); - layers->clear(); - for (auto& i : canvas->m_canvas->m_order) - layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str(), false); - layers->m_current_layer->m_selected = false; - layers->m_current_layer = layers->m_layers[current_idx_order - 1]; - layers->m_current_layer->m_selected = true; - layers->m_current_layer->on_selected(layers->m_current_layer); + layers->merge(current_idx_order, current_idx_order - 1, true); } popup->mouse_release(); popup->destroy(); }; if (layers->m_current_layer) { - const auto& order = canvas->m_canvas->m_order; - int current_idx_order = (int)std::distance(order.begin(), std::find(order.begin(), order.end(), canvas->m_canvas->m_current_layer_idx)); + int current_idx_order = canvas->m_canvas->m_current_layer_idx; if (current_idx_order > 0) { - int down_layer_idx = order[current_idx_order - 1]; + int down_layer_idx = current_idx_order - 1; popup->find("layer-merge")-> find("menu-label")-> set_text(("Merge with " + canvas->m_canvas->m_layers[down_layer_idx]->m_name).c_str()); @@ -1219,7 +1208,7 @@ void App::initLayout() init_sidebar(); - layers->add_layer("Default", false); + layers->add_layer("Default", false, true); init_toolbar_draw(); init_toolbar_main(); diff --git a/src/app_vr.cpp b/src/app_vr.cpp index 2cbbf0a..59132e3 100644 --- a/src/app_vr.cpp +++ b/src/app_vr.cpp @@ -203,7 +203,7 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat for (int plane_index = 0; plane_index < 6; plane_index++) { auto plane_mvp = proj * camera * - glm::scale(glm::vec3(canvas->m_canvas->m_order.size() * 20)) * + glm::scale(glm::vec3(canvas->m_canvas->m_layers.size() * 20)) * canvas->m_canvas->m_plane_transform[plane_index] * glm::translate(glm::vec3(0, 0, -1)); @@ -217,9 +217,9 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat glEnable(GL_DEPTH_TEST); glClear(GL_DEPTH_BUFFER_BIT); - for (size_t i = 0; i < canvas->m_canvas->m_order.size(); i++) + for (size_t i = 0; i < canvas->m_canvas->m_layers.size(); i++) { - auto layer_index = canvas->m_canvas->m_order[i]; + auto layer_index = i; for (int plane_index = 0; plane_index < 6; plane_index++) { if (!(canvas->m_canvas->m_show_tmp && canvas->m_canvas->m_current_layer_idx == layer_index) && @@ -228,7 +228,7 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat !canvas->m_canvas->m_layers[layer_index]->m_dirty_face[plane_index])) continue; - int z = (int)(canvas->m_canvas->m_order.size() - i); + int z = (int)(canvas->m_canvas->m_layers.size() - i); auto plane_mvp_z = proj * camera * glm::scale(glm::vec3(z) * 20.f) * //glm::eulerAngleYXZ(yaw, pitch, roll) * diff --git a/src/canvas.cpp b/src/canvas.cpp index ca43d03..6e9a7b1 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -92,14 +92,14 @@ void Canvas::pick_update(int plane) ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); glActiveTexture(GL_TEXTURE0); m_sampler.bind(0); - for (auto layer_index : m_order) + for (auto& l : m_layers) { - if (!m_layers[layer_index]->m_visible || m_layers[layer_index]->m_opacity == 0.f) + if (!l->m_visible || l->m_opacity == 0.f) continue; - ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index]->m_opacity); - m_layers[layer_index]->m_rtt[i].bindTexture(); + ShaderManager::u_float(kShaderUniform::Alpha, l->m_opacity); + l->m_rtt[i].bindTexture(); m_plane.draw_fill(); - m_layers[layer_index]->m_rtt[i].unbindTexture(); + l->m_rtt[i].unbindTexture(); } m_sampler.unbind(); @@ -905,10 +905,9 @@ void Canvas::draw_merge(std::array faces /*= SIXPLETTE(false)*/) // check if any layer use blend, otherwise draw directly on main framebuffer bool use_blend = false; - for (size_t i = 0; i < m_order.size(); i++) + for (auto& l : m_layers) { - auto layer_index = m_order[i]; - use_blend |= m_layers[layer_index]->m_blend_mode != 0; + use_blend |= l->m_blend_mode != 0; } // if not using shader blend, use gl rasterizer blend @@ -935,7 +934,7 @@ void Canvas::draw_merge(std::array faces /*= SIXPLETTE(false)*/) glEnable(GL_BLEND); } - for (int layer_index : m_order) + for (int layer_index = 0; layer_index < m_layers.size(); layer_index++) { if (!(m_show_tmp && m_current_layer_idx == layer_index) && (!m_layers[layer_index]->m_visible || @@ -1223,37 +1222,31 @@ void Canvas::stroke_start(glm::vec3 point, float pressure) } m_show_tmp = true; } -void Canvas::layer_add(std::string name, std::unique_ptr layer /*= nullptr*/, int index /*= 0*/) +void Canvas::layer_add(std::string name, std::shared_ptr layer /*= nullptr*/, int index /*= 0*/) { LOG("canvas layer_add %s", name.c_str()); int idx = (int)m_layers.size(); if (layer) { - m_layers.push_back(std::move(layer)); + m_layers.insert(m_layers.begin() + index, layer); } else { - m_layers.push_back(std::make_unique()); - m_layers.back()->create(m_width, m_height, name); + m_layers.insert(m_layers.begin() + index, std::make_unique()); + m_layers[index]->create(m_width, m_height, name); } - m_order.push_back(idx); - m_current_layer_idx = idx; + m_current_layer_idx = index; } void Canvas::layer_remove(int idx) // m_order index { LOG("canvas layer_remove %d", idx); - int n = m_order[idx]; - for (auto& i : m_order) - if (i > n) - i--; //m_layers[n]->destroy(); - m_layers.erase(m_layers.begin() + n); - m_order.erase(m_order.begin() + idx); - m_current_layer_idx = m_order[std::min((int)m_layers.size() - 1, idx)]; + m_layers.erase(m_layers.begin() + idx); + m_current_layer_idx = std::min((int)m_layers.size() - 1, idx); } void Canvas::layer_order(int idx, int pos) // m_order index { - std::swap(m_order[idx], m_order[pos]); + std::swap(m_layers[idx], m_layers[pos]); } void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index { @@ -1635,7 +1628,7 @@ void Canvas::export_equirectangular_thread(std::string file_path) } m_sampler_bg.bind(0); // nearest m_sampler_mask.bind(1); // linear - for (auto layer_index : m_order) + for (int layer_index = 0; layer_index < m_layers.size(); layer_index++) { if (!m_layers[layer_index]->m_visible || m_layers[layer_index]->m_opacity == 0.f || @@ -1918,9 +1911,8 @@ void Canvas::export_depth_thread(std::string file_name) delete rgba_data; rtt.clear({ 0, 0, 0, 1 }); - for (size_t i = 0; i < m_order.size(); i++) + for (int layer_index = 0; layer_index < m_layers.size(); layer_index++) { - auto layer_index = m_order[i]; for (int plane_index = 0; plane_index < 6; plane_index++) { if ((!m_layers[layer_index]->m_visible || @@ -1937,7 +1929,7 @@ void Canvas::export_depth_thread(std::string file_name) m_sampler_linear.bind(1); ShaderManager::use(kShader::TextureColorize); ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_vec4(kShaderUniform::Col, { glm::vec3((float)(i + 1) / (float)(m_order.size() + 1)), 1.f }); + ShaderManager::u_vec4(kShaderUniform::Col, { glm::vec3((float)(layer_index + 1) / (float)(m_layers.size() + 1)), 1.f }); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); glActiveTexture(GL_TEXTURE0); @@ -2000,7 +1992,7 @@ void Canvas::export_layers_thread(std::string file_name) App::I.async_update(); } int progress = 0; - int total = (int)(m_order.size() + 1) * 6; + int total = (int)(m_layers.size() + 1) * 6; // prepare common states glViewport(0, 0, m_width, m_height); @@ -2023,7 +2015,7 @@ void Canvas::export_layers_thread(std::string file_name) }; int seq = 0; - for (auto layer_index : m_order) + for (int layer_index = 0; layer_index < m_layers.size(); layer_index++) { glViewport(0, 0, m_width, m_height); for (int i = 0; i < 6; i++) @@ -2150,11 +2142,11 @@ void Canvas::export_cubes() const int stride = m_width * 4; auto buffer = std::make_unique(m_width * m_height * 4); auto flipped = std::make_unique(m_width * m_height * 4); - for (int layer = 0; layer < m_order.size(); layer++) - { + for (int layer = 0; layer < m_layers.size(); layer++) + { for (int plane = 0; plane < 6; plane++) { - auto& l = m_layers[m_order[layer]]; + auto& l = m_layers[layer]; l->m_rtt[plane].bindFramebuffer(); glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.get()); l->m_rtt[plane].unbindFramebuffer(); @@ -2332,7 +2324,7 @@ bool Canvas::project_save_thread(std::string file_path) for (int i = 0; i < (int)m_layers.size(); i++) { - int n_order = m_order[i]; + int n_order = i; fwrite(&n_order, sizeof(int), 1, fp); float layer_alpha = m_layers[i]->m_opacity; @@ -2504,13 +2496,11 @@ bool Canvas::project_open_thread(std::string file_path) for (auto& l : m_layers) l->destroy(); m_layers.clear(); - m_order.clear(); //clear_all(); resize(m_width, m_height); App::I.async_end(); - std::vector tmp_order; - std::vector> tmp_layers; + std::vector> tmp_layers; for (int i = 0; i < n_layers; i++) { @@ -2580,11 +2570,9 @@ bool Canvas::project_open_thread(std::string file_path) tmp_layers.back()->create(m_width, m_height, name.c_str()); tmp_layers.back()->clear({ 0, 0, 0, 0 }); tmp_layers.back()->restore(snap); - tmp_order.push_back(n_order); App::I.async_end(); } - std::swap(tmp_order, m_order); std::swap(tmp_layers, m_layers); fclose(fp); @@ -2665,7 +2653,7 @@ Image Canvas::thumbnail_generate(int w, int h) } m_sampler_bg.bind(0); // nearest m_sampler_mask.bind(1); // linear - for (auto layer_index : m_order) + for (int layer_index = 0; layer_index < m_layers.size(); layer_index++) { if (!m_layers[layer_index]->m_visible || m_layers[layer_index]->m_opacity == 0.f || @@ -3080,7 +3068,7 @@ void Layer::restore(const Snapshot& snap) } } -Layer::Snapshot Layer::snapshot() +Layer::Snapshot Layer::snapshot(glm::vec4 dirty_box[6] /*= nullptr*/, bool dirty_face[6] /*= nullptr*/) { Snapshot snap; static int counter = 0; @@ -3088,18 +3076,18 @@ Layer::Snapshot Layer::snapshot() //glBindFramebuffer(GL_FRAMEBUFFER, 0); for (int i = 0; i < 6; i++) { - snap.m_dirty_box[i] = m_dirty_box[i]; - snap.m_dirty_face[i] = m_dirty_face[i]; + snap.m_dirty_box[i] = dirty_box ? dirty_box[i] : m_dirty_box[i]; + snap.m_dirty_face[i] = dirty_face ? dirty_face[i] : m_dirty_face[i]; - if (!m_dirty_face[i]) + if (!snap.m_dirty_face[i]) continue; snap.image[i] = std::make_unique(m_rtt[i].bytes()); //glReadBuffer(GL_BACK); m_rtt[i].bindFramebuffer(); - glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]); - glReadPixels(m_dirty_box[i].x, m_dirty_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, snap.image[i].get()); + glm::vec2 box_sz = zw(snap.m_dirty_box[i]) - xy(snap.m_dirty_box[i]); + glReadPixels(snap.m_dirty_box[i].x, snap.m_dirty_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, snap.image[i].get()); m_rtt[i].unbindFramebuffer(); //glReadBuffer(GL_NONE); } diff --git a/src/canvas.h b/src/canvas.h index bc72282..9befffb 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -94,9 +94,8 @@ public: std::unique_ptr m_current_stroke; std::unique_ptr m_dual_stroke; bool m_show_tmp = false; - std::vector> m_layers; + std::vector> m_layers; Layer m_layers_merge; - std::vector m_order; std::vector m_plane_shape[6]; // screen space projection of the plane glm::mat4 m_plane_unproject[6] = SIXPLETTE(glm::mat4(1)); glm::vec3 m_plane_dir[6] = SIXPLETTE(glm::vec3(0)); @@ -164,7 +163,7 @@ public: bool create(int width, int height); void resize(int width, int height); void layer_remove(int idx); - void layer_add(std::string name, std::unique_ptr layer = nullptr, int index = 0); + 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 stroke_start(glm::vec3 point, float pressure); diff --git a/src/canvas_layer.cpp b/src/canvas_layer.cpp index 62fad2f..c638057 100644 --- a/src/canvas_layer.cpp +++ b/src/canvas_layer.cpp @@ -1,6 +1,8 @@ #include "pch.h" #include "canvas_layer.h" +uint32_t Layer::s_count = 0; + void Layer::Snapshot::create(int w, int h) { for (int i = 0; i < 6; i++) diff --git a/src/canvas_layer.h b/src/canvas_layer.h index 433e98d..1028dfa 100644 --- a/src/canvas_layer.h +++ b/src/canvas_layer.h @@ -9,10 +9,12 @@ class LayerFrame class Layer { + static uint32_t s_count; public: - Layer() = default; + Layer() { id = s_count++; } Layer(const Layer&) = delete; ~Layer() { LOG("LAYER AUTO DESTROY"); destroy(); } + uint32_t id; RTT m_rtt[6]; glm::vec4 m_dirty_box[6] = SIXPLETTE(glm::vec4(0)); bool m_dirty_face[6] = SIXPLETTE(false); @@ -26,7 +28,7 @@ public: int h = 0; struct Snapshot { - std::unique_ptr image[6] = SIXPLETTE(0); + std::shared_ptr image[6] = SIXPLETTE(0); glm::vec4 m_dirty_box[6] = SIXPLETTE(glm::vec4(0)); bool m_dirty_face[6] = SIXPLETTE(false); int width = 0; @@ -38,7 +40,7 @@ public: void resize(int width, int height); bool create(int width, int height, std::string name); void clear(const glm::vec4& c); - Snapshot snapshot(); + Snapshot snapshot(glm::vec4 dirty_box[6] = nullptr, bool dirty_face[6] = nullptr); void restore(const Snapshot& snap); void destroy(); void optimize(); diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index d88b6b4..eb2cc01 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -133,7 +133,7 @@ void NodeCanvas::draw() for (int plane_index = 0; plane_index < 6; plane_index++) { auto plane_mvp = proj * camera * - glm::scale(glm::vec3(m_canvas->m_order.size() + 500)) * + glm::scale(glm::vec3(m_canvas->m_layers.size() + 500)) * m_canvas->m_plane_transform[plane_index] * glm::translate(glm::vec3(0, 0, -1)); @@ -175,10 +175,9 @@ void NodeCanvas::draw() { // check if any layer use blend, otherwise draw directly on main framebuffer bool use_blend = false; - for (size_t i = 0; i < m_canvas->m_order.size(); i++) + for (size_t i = 0; i < m_canvas->m_layers.size(); i++) { - auto layer_index = m_canvas->m_order[i]; - use_blend |= m_canvas->m_layers[layer_index]->m_blend_mode != 0; + use_blend |= m_canvas->m_layers[i]->m_blend_mode != 0; } if (use_blend) @@ -192,7 +191,7 @@ void NodeCanvas::draw() for (int plane_index = 0; plane_index < 6; plane_index++) { auto plane_mvp = proj * camera * - glm::scale(glm::vec3(m_canvas->m_order.size() + 500)) * + glm::scale(glm::vec3(m_canvas->m_layers.size() + 500)) * m_canvas->m_plane_transform[plane_index] * glm::translate(glm::vec3(0, 0, -1)); @@ -209,9 +208,9 @@ void NodeCanvas::draw() const auto& b = m_canvas->m_current_stroke->m_brush; - for (size_t i = 0; i < m_canvas->m_order.size(); i++) + for (size_t i = 0; i < m_canvas->m_layers.size(); i++) { - auto layer_index = m_canvas->m_order[i]; + auto layer_index = i; for (int plane_index = 0; plane_index < 6; plane_index++) { if (!(m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) && @@ -226,7 +225,7 @@ void NodeCanvas::draw() m_blender_rtt.clear(); } - int z = (int)(m_canvas->m_order.size() - i); + int z = (int)(m_canvas->m_layers.size() - i); auto plane_mvp_z = proj * camera * glm::scale(glm::vec3(z + 1)) * glm::eulerAngleYXZ(yaw, pitch, roll) * @@ -418,7 +417,7 @@ void NodeCanvas::draw() for (int plane_index = 0; plane_index < 6; plane_index++) { auto plane_mvp = proj * camera * - glm::scale(glm::vec3(m_canvas->m_order.size() + 500.f)) * + glm::scale(glm::vec3(m_canvas->m_layers.size() + 500.f)) * m_canvas->m_plane_transform[plane_index] * glm::translate(glm::vec3(0, 0, -1.f)); @@ -462,7 +461,7 @@ void NodeCanvas::draw() for (int plane_index = 0; plane_index < 6; plane_index++) { auto plane_mvp = proj * camera * - glm::scale(glm::vec3(m_canvas->m_order.size() + 500.f)) * + glm::scale(glm::vec3(m_canvas->m_layers.size() + 500.f)) * m_canvas->m_plane_transform[plane_index] * glm::translate(glm::vec3(0, 0, -1.f)); diff --git a/src/node_panel_layer.cpp b/src/node_panel_layer.cpp index 7d034a7..d14fcd2 100644 --- a/src/node_panel_layer.cpp +++ b/src/node_panel_layer.cpp @@ -131,20 +131,22 @@ void NodePanelLayer::init() next = tmp; } int source_index = m_layers_container->get_child_index(m_current_layer); - add_layer(next.c_str()); + auto l = add_layer(next.c_str(), false, false, nullptr, nullptr, source_index + 1); if (on_layer_duplicate) on_layer_duplicate(this, source_index); if (on_layer_change) on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer)); update_attributes(); + + auto a = new ActionLayerAdd; + a->m_panel = this; + a->m_layer_node = l->shared_from_this(); + a->m_layer_order = m_layers_container->get_child_index(l); + a->m_layer_id = Canvas::I->m_layers[a->m_layer_order]->id; + ActionManager::add(a); }; btn_add->on_click = [this](Node*) { - add_layer(); - if (on_layer_add) - on_layer_add(this, nullptr, 0); - if (on_layer_change) - on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer)); - update_attributes(); + add_layer(true, true); }; btn_remove->on_click = [this](Node*) { if (m_layers.size() == 1) @@ -159,6 +161,11 @@ void NodePanelLayer::init() { on_layer_order(this, old_idx, new_idx); } + auto a = new ActionLayerMove; + a->m_panel = this; + a->m_layer_node = m_current_layer->shared_from_this(); + a->m_offset = -1; + ActionManager::add(a); }; btn_down->on_click = [this](Node*) { int old_idx = m_layers_container->get_child_index(m_current_layer); @@ -168,6 +175,11 @@ void NodePanelLayer::init() { on_layer_order(this, old_idx, new_idx); } + auto a = new ActionLayerMove; + a->m_panel = this; + a->m_layer_node = m_current_layer->shared_from_this(); + a->m_offset = +1; + ActionManager::add(a); }; m_opacity = find("opacity"); m_opacity->on_value_changed = [this](Node*, float value) { @@ -183,13 +195,13 @@ void NodePanelLayer::init() }; } -NodeLayer* NodePanelLayer::add_layer(const char* name, bool add_history /*= true*/, std::unique_ptr layer /*= nullptr*/, int index /*= 0*/) +NodeLayer* NodePanelLayer::add_layer(const char* name, bool add_history /*= true*/, bool create_events /*= false*/, + std::shared_ptr layer /*= nullptr*/, std::shared_ptr layer_node /*= nullptr*/, int index /*= 0*/) { - NodeLayer* l = new NodeLayer; - if (layer) - m_layers_container->add_child(l, index); - else - m_layers_container->add_child(l); + if (index == -1) + index = m_layers_container->m_children.size(); + auto l = layer_node ? layer_node : std::make_shared(); + m_layers_container->add_child(l, index); l->init(); l->create(); l->loaded(); @@ -200,36 +212,45 @@ NodeLayer* NodePanelLayer::add_layer(const char* name, bool add_history /*= true l->on_highlight = std::bind(&NodePanelLayer::handle_layer_highlight, this, std::placeholders::_1, std::placeholders::_2); if (m_current_layer) m_current_layer->m_selected = false; - m_current_layer = l; + m_current_layer = l.get(); m_current_layer->m_selected = true; - m_layers.push_back(l); + m_layers.push_back(l.get()); if (add_history) { + if (create_events) + { + if (on_layer_add) + on_layer_add(this, nullptr, m_layers_container->get_child_index(m_current_layer)); + if (on_layer_change) + on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer)); + update_attributes(); + } + auto a = new ActionLayerAdd; a->m_panel = this; a->m_layer_node = l->shared_from_this(); - a->m_layer_order = m_layers_container->get_child_index(l); + a->m_layer_order = m_layers_container->get_child_index(l.get()); + a->m_layer_id = Canvas::I->m_layers[a->m_layer_order]->id; ActionManager::add(a); - update_attributes(); } - else + else if (create_events) { if (on_layer_add) - on_layer_add(this, std::move(layer), index); + on_layer_add(this, layer, index); if (on_layer_change) on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer)); update_attributes(); } - return l; + return l.get(); } -void NodePanelLayer::add_layer() +void NodePanelLayer::add_layer(bool add_history /*= true*/, bool create_events /*= false*/) { static char s[64]; sprintf(s, "Layer-%d", id_counter++); - add_layer(s); + add_layer(s, add_history, create_events); } NodeLayer* NodePanelLayer::get_layer_at(int index) @@ -239,11 +260,12 @@ NodeLayer* NodePanelLayer::get_layer_at(int index) void NodePanelLayer::remove_layer(NodeLayer* layer, bool add_history /*= true*/) { - auto it = std::find(m_layers.begin(), m_layers.end(), m_current_layer); - auto i = m_layers_container->get_child_index(m_current_layer); + auto it = std::find(m_layers.begin(), m_layers.end(), layer); + auto i = m_layers_container->get_child_index(layer); int old_idx = i;// (int)std::distance(m_layers.begin(), it); + (*it)->m_selected = false; auto copy = (*it)->shared_from_this(); - m_layers_container->remove_child(m_current_layer); + m_layers_container->remove_child(layer); m_layers.erase(it); i = std::min(i, (int)m_layers.size() - 1); m_current_layer = (NodeLayer*)m_layers_container->get_child_at(i); @@ -254,7 +276,7 @@ void NodePanelLayer::remove_layer(NodeLayer* layer, bool add_history /*= true*/) auto a = new ActionLayerRemove; a->m_panel = this; a->m_layer_node = copy; - a->m_layer = std::move(Canvas::I->m_layers[Canvas::I->m_order[old_idx]]); + a->m_layer = Canvas::I->m_layers[old_idx]; a->m_layer_order = old_idx; ActionManager::add(a); } @@ -342,6 +364,31 @@ kEventResult NodePanelLayer::handle_event(Event* e) return kEventResult::Available; } +void NodePanelLayer::merge(int src_index, int dst_index, bool create_history) +{ + if (create_history) + { + auto a = new ActionLayerMerge; + a->m_direction = ActionLayerMerge::Direction::Undo; + for (int i = 0; i < 6; i++) + { + a->m_dirty_box[i] = Canvas::I->m_layers[dst_index]->m_dirty_box[i]; + a->m_dirty_face[i] = Canvas::I->m_layers[dst_index]->m_dirty_face[i]; + } + a->m_snap = Canvas::I->m_layers[dst_index]->snapshot( + Canvas::I->m_layers[src_index]->m_dirty_box, Canvas::I->m_layers[src_index]->m_dirty_face); + a->m_layer = Canvas::I->m_layers[src_index]; + a->m_layer_node = std::static_pointer_cast(m_layers_container->m_children[src_index]); + a->m_layer_node->m_selected = false; + a->m_panel = std::static_pointer_cast(shared_from_this()); + a->m_src_index = src_index; + a->m_dst_index = dst_index; + ActionManager::add(a); + } + Canvas::I->layer_merge(Canvas::I->m_current_layer_idx, dst_index); + remove_layer((NodeLayer*)m_layers_container->m_children[src_index].get(), false); +} + /////////////////////////////////////////////////////////////////////////////// Action* ActionLayerAdd::get_redo() @@ -349,8 +396,10 @@ Action* ActionLayerAdd::get_redo() auto a = new ActionLayerRemove; a->m_panel = m_panel; a->m_layer_node = m_layer_node; - a->m_layer = std::move(Canvas::I->m_layers[Canvas::I->m_order[m_layer_order]]); + a->m_layer = *std::find_if(Canvas::I->m_layers.begin(), Canvas::I->m_layers.end(), + [id=m_layer_id](const auto& x){ return x->id == id; }); a->m_layer_order = m_layer_order; + LOG("ActionLayerAdd::get_redo %s", a->m_layer->m_name.c_str()); return a; } @@ -372,13 +421,17 @@ Action* ActionLayerRemove::get_redo() a->m_panel = m_panel; a->m_layer_node = m_layer_node; a->m_layer_order = m_layer_order; + a->m_layer_id = m_layer->id; + LOG("ActionLayerRemove::get_redo %s", ((NodeLayer*)m_layer_node.get())->m_label_text.c_str()); return a; } void ActionLayerRemove::undo() { std::string name = m_layer->m_name; - m_panel->add_layer(name.c_str(), false, std::move(m_layer), m_layer_order); + m_panel->add_layer(name.c_str(), false, true, m_layer, + std::dynamic_pointer_cast(m_layer_node), m_layer_order); + LOG("ActionLayerRemove::undo %s", name.c_str()); } size_t ActionLayerRemove::memory() @@ -390,15 +443,61 @@ size_t ActionLayerRemove::memory() Action* ActionLayerMove::get_redo() { - return nullptr; + auto a = new ActionLayerMove; + a->m_panel = m_panel; + a->m_layer_node = m_layer_node; + a->m_offset = -m_offset; + return a; } void ActionLayerMove::undo() { - + int old_idx = m_panel->m_layers_container->get_child_index(m_layer_node.get()); + m_panel->m_layers_container->move_child_offset(m_layer_node.get(), -m_offset); + int new_idx = m_panel->m_layers_container->get_child_index(m_layer_node.get()); + if (m_panel->on_layer_order && old_idx != new_idx) + { + m_panel->on_layer_order(m_panel, old_idx, new_idx); + } } size_t ActionLayerMove::memory() { return 0; } + +/////////////////////////////////////////////////////////////////////////////// + +void ActionLayerMerge::undo() +{ + if (m_direction == Direction::Undo) + { + Canvas::I->m_layers[m_dst_index]->restore(m_snap); + for (int i = 0; i < 6; i++) + { + Canvas::I->m_layers[m_dst_index]->m_dirty_box[i] = m_dirty_box[i]; + Canvas::I->m_layers[m_dst_index]->m_dirty_face[i] = m_dirty_face[i]; + } + auto name = m_layer->m_name; + m_panel->add_layer(name.c_str(), false, true, m_layer, m_layer_node, m_src_index); + } + else if (m_direction == Direction::Redo) + { + m_panel->merge(m_src_index, m_dst_index, false); + } +} + +Action* ActionLayerMerge::get_redo() +{ + auto a = new ActionLayerMerge; + a->m_dirty_box = m_dirty_box; + a->m_dirty_face = m_dirty_face; + a->m_dst_index = m_dst_index; + a->m_src_index = m_src_index; + a->m_layer = m_layer; + a->m_layer_node = m_layer_node; + a->m_panel = m_panel; + a->m_snap = m_snap; + a->m_direction = m_direction == Direction::Undo ? Direction::Redo : Direction::Undo; + return a; +} diff --git a/src/node_panel_layer.h b/src/node_panel_layer.h index eb4b299..2e9ad3f 100644 --- a/src/node_panel_layer.h +++ b/src/node_panel_layer.h @@ -7,6 +7,7 @@ #include "node_combobox.h" #include "node_scroll.h" #include "action.h" +#include "canvas_layer.h" class NodeLayer : public NodeBorder { @@ -50,7 +51,7 @@ public: std::function on_layer_blend_mode_changed; std::function on_layer_delete; std::function on_layer_duplicate; - std::function layer, int index)> on_layer_add; + std::function layer, int index)> on_layer_add; std::function on_layer_order; NodeLayer* m_current_layer = nullptr; std::vector m_layers; @@ -61,8 +62,10 @@ public: virtual Node* clone_instantiate() const override; virtual void init() override; virtual kEventResult handle_event(Event* e) override; - void add_layer(); - NodeLayer* add_layer(const char* name, bool add_history = true, std::unique_ptr layer = nullptr, int index = 0); + void merge(int src_index, int dst_index, bool create_history); + void add_layer(bool add_history = true, bool create_events = false); + NodeLayer* add_layer(const char* name, bool add_history = true, bool create_events = false, + std::shared_ptr layer = nullptr, std::shared_ptr layer_node = nullptr, int index = -1); NodeLayer* get_layer_at(int index); void remove_layer(NodeLayer* layer, bool add_history = true); void handle_layer_opacity(NodeLayer* target, float value); @@ -81,6 +84,7 @@ public: NodePanelLayer* m_panel; std::shared_ptr m_layer_node; int m_layer_order; + uint32_t m_layer_id; virtual void run() override { } virtual Action* get_redo() override; virtual void undo() override; @@ -92,7 +96,7 @@ class ActionLayerRemove : public Action public: NodePanelLayer* m_panel; std::shared_ptr m_layer_node; - std::unique_ptr m_layer; + std::shared_ptr m_layer; int m_layer_order; virtual void run() override { } virtual Action* get_redo() override; @@ -103,11 +107,28 @@ public: class ActionLayerMove : public Action { public: - int m_index_old; - int m_index_new; + NodePanelLayer* m_panel; + std::shared_ptr m_layer_node; + int m_offset; virtual void run() override { } virtual Action* get_redo() override; virtual void undo() override; virtual size_t memory() override; }; +struct ActionLayerMerge : public Action +{ + enum class Direction { Undo, Redo } m_direction; + Layer::Snapshot m_snap; + std::shared_ptr m_layer; + std::shared_ptr m_layer_node; + std::shared_ptr m_panel; + int m_src_index = 0; // removed layer + int m_dst_index = 0; + std::array m_dirty_box; + std::array m_dirty_face; + virtual void run() override { } + virtual size_t memory() override { return 0; } + virtual void undo() override; + virtual Action* get_redo() override; +};