diff --git a/data/layout.xml b/data/layout.xml index 649be86..73438e0 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -165,7 +165,7 @@ - + @@ -345,6 +345,10 @@ + + + + diff --git a/engine.vcxproj b/engine.vcxproj index 671a321..c57b0bc 100644 --- a/engine.vcxproj +++ b/engine.vcxproj @@ -175,6 +175,7 @@ + @@ -262,6 +263,7 @@ + diff --git a/engine.vcxproj.filters b/engine.vcxproj.filters index b036542..3097ac9 100644 --- a/engine.vcxproj.filters +++ b/engine.vcxproj.filters @@ -195,6 +195,9 @@ Source Files\libs\WinTab + + Source Files\ui + @@ -362,5 +365,8 @@ Source Files\libs\WinTab + + Header Files\ui + \ No newline at end of file diff --git a/engine/app_layout.cpp b/engine/app_layout.cpp index 30ab044..295debe 100644 --- a/engine/app_layout.cpp +++ b/engine/app_layout.cpp @@ -376,8 +376,8 @@ void App::initLayout() popup->mouse_release(); popup->destroy(); }; + popup->find("layer-rename")->on_click = [this](Node*) { - // load thumbnail test auto open_dialog = std::make_shared(); open_dialog->m_manager = &layout; open_dialog->data_path = data_path; @@ -391,6 +391,7 @@ void App::initLayout() open_dialog->btn_ok->on_click = [this,open_dialog](Node*) { layers->m_current_layer->set_name(open_dialog->get_name().c_str()); + canvas->m_canvas->m_layers[canvas->m_canvas->m_current_layer_idx].m_name = open_dialog->get_name(); open_dialog->destroy(); }; @@ -405,6 +406,47 @@ void App::initLayout() popup->find("layer-rename")-> find("menu-label")-> set_text("Rename Layer (Select a layer)"); + + popup->find("layer-merge")->on_click = [this](Node*) { + const auto& order = canvas->m_canvas->m_order; + int current_idx_order = std::distance(order.begin(), std::find(order.begin(), order.end(), canvas->m_canvas->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()); + layers->m_current_layer = layers->m_layers[current_idx_order - 1]; + layers->m_current_layer->m_selected = true; + } + popup->mouse_release(); + popup->destroy(); + }; + if (layers->m_current_layer) + { + const auto& order = canvas->m_canvas->m_order; + int current_idx_order = std::distance(order.begin(), std::find(order.begin(), order.end(), canvas->m_canvas->m_current_layer_idx)); + if (current_idx_order > 0) + { + int down_layer_idx = order[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()); + } + else + { + popup->find("layer-merge")-> + find("menu-label")-> + set_text("Merge Layer (Select upper layers)"); + } + } + else + popup->find("layer-merge")-> + find("menu-label")-> + set_text("Merge Layer (Select a layer)"); + }; } if (auto* toolbar = layout[main_id]->find("toolbar")) diff --git a/engine/canvas.cpp b/engine/canvas.cpp index e21751e..8db8041 100644 --- a/engine/canvas.cpp +++ b/engine/canvas.cpp @@ -612,6 +612,89 @@ void ui::Canvas::layer_order(int idx, int pos) { std::swap(m_order[idx], m_order[pos]); } +void ui::Canvas::layer_merge(int source_idx, int dest_idx) +{ + m_dirty = false; + + // save viewport and clear color states + GLint vp[4]; + GLfloat cc[4]; + glGetIntegerv(GL_VIEWPORT, vp); + glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); + GLboolean blend = glIsEnabled(GL_BLEND); + + // allocate action to add to history + auto action = new ActionStroke; + + // prepare common states + glViewport(0, 0, m_width, m_height); + glDisable(GL_BLEND); + + for (int i = 0; i < 6; i++) + { + if (!m_layers[source_idx].m_dirty_face[i]) + continue; // no stroke on this face, skip it + + m_layers[dest_idx].m_rtt[i].bindFramebuffer(); + +/* + // save image before commit + glm::vec2 box_sz = m_dirty_box[i].zw() - m_dirty_box[i].xy(); + action->m_image[i] = std::make_unique(box_sz.x * box_sz.y * 4); + glReadPixels(m_dirty_box[i].x, m_dirty_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get()); + + action->m_box[i] = m_dirty_box[i]; + action->m_old_box[i] = m_layers[m_current_layer_idx].m_dirty_box[i]; + action->m_old_dirty[i] = m_layers[m_current_layer_idx].m_dirty_face[i]; +*/ + + auto& lbox = m_layers[dest_idx].m_dirty_box[i]; + lbox.xy = glm::min(m_layers[source_idx].m_dirty_box[i].xy(), lbox.xy()); + lbox.zw = glm::max(m_layers[source_idx].m_dirty_box[i].zw(), lbox.zw()); + m_layers[dest_idx].m_dirty_face[i] = true; + + // copy to tmp2 for layer blending + glActiveTexture(GL_TEXTURE0); + m_tex2[i].bind(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); + m_tex2[i].unbind(); + + m_sampler.bind(0); + m_sampler_bg.bind(1); + { + ui::ShaderManager::use(kShader::CompDraw); + ui::ShaderManager::u_int(kShaderUniform::Tex, 0); // dest + ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1); // source + ui::ShaderManager::u_float(kShaderUniform::Alpha, 1); + ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); + + glActiveTexture(GL_TEXTURE0); + m_tex2[i].bind(); + glActiveTexture(GL_TEXTURE1); + m_layers[source_idx].m_rtt[i].bindTexture(); + m_plane.draw_fill(); + m_layers[source_idx].m_rtt[i].unbindTexture(); + glActiveTexture(GL_TEXTURE0); + m_tex2[i].unbind(); + } + + m_layers[dest_idx].m_rtt[i].unbindFramebuffer(); + } + + // restore viewport and clear color states + blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND); + glViewport(vp[0], vp[1], vp[2], vp[3]); + glClearColor(cc[0], cc[1], cc[2], cc[3]); + glActiveTexture(GL_TEXTURE0); + +/* + // save history + action->m_layer_idx = m_current_layer_idx; + action->m_canvas = this; + action->m_stroke = std::move(m_current_stroke); + ActionManager::add(action); +*/ +} void ui::Canvas::resize(int width, int height) { m_width = width; diff --git a/engine/canvas.h b/engine/canvas.h index ec4ae97..a3a6a36 100644 --- a/engine/canvas.h +++ b/engine/canvas.h @@ -101,6 +101,7 @@ public: void layer_remove(int idx); void layer_add(std::string name); void layer_order(int idx, int pos); + void layer_merge(int source_idx, int dest_idx); void stroke_start(glm::vec2 point, float pressure, const ui::Brush& brush); void stroke_update(glm::vec2 point, float pressure); void stroke_draw(); diff --git a/engine/main.cpp b/engine/main.cpp index 06d4b44..f25c500 100644 --- a/engine/main.cpp +++ b/engine/main.cpp @@ -330,12 +330,19 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) PostQuitMessage(0); break; case WM_SIZE: - App::I.resize((float)LOWORD(lp), (float)HIWORD(lp)); - App::I.clear(); - App::I.redraw = true; - App::I.update(0.f); - SwapBuffers(hDC); + { + auto w = (float)LOWORD(lp); + auto h = (float)HIWORD(lp); + if (h != 0) + { + App::I.resize(w, h); + App::I.clear(); + App::I.redraw = true; + App::I.update(0.f); + SwapBuffers(hDC); + } break; + } case WM_ACTIVATE: { int active = GET_WM_ACTIVATE_STATE(wp, lp); diff --git a/engine/node_canvas.cpp b/engine/node_canvas.cpp index ec5bba5..c5b098a 100644 --- a/engine/node_canvas.cpp +++ b/engine/node_canvas.cpp @@ -104,6 +104,7 @@ void NodeCanvas::draw() ui::ShaderManager::u_int(kShaderUniform::Tex, 0); ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1); ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity); + ui::ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[m_canvas->m_current_layer_idx].m_alpha_locked); } else if(m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) { @@ -111,6 +112,7 @@ void NodeCanvas::draw() ui::ShaderManager::u_int(kShaderUniform::Tex, 0); ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1); ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity); + ui::ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[m_canvas->m_current_layer_idx].m_alpha_locked); } else { @@ -119,7 +121,6 @@ void NodeCanvas::draw() ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity); } ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); - ui::ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[m_canvas->m_current_layer_idx].m_alpha_locked); // if (!(m_canvas->m_state == ui::Canvas::kCanvasMode::Erase && // m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index)) diff --git a/engine/node_panel_layer.cpp b/engine/node_panel_layer.cpp index df1954d..a11189e 100644 --- a/engine/node_panel_layer.cpp +++ b/engine/node_panel_layer.cpp @@ -167,6 +167,10 @@ void NodePanelLayer::add_layer(const char* name) l->on_selected = std::bind(&NodePanelLayer::handle_layer_selected, this, std::placeholders::_1); l->on_opacity_changed = std::bind(&NodePanelLayer::handle_layer_opacity, this, std::placeholders::_1, std::placeholders::_2); l->on_visibility_changed = std::bind(&NodePanelLayer::handle_layer_visibility, this, std::placeholders::_1, std::placeholders::_2); + if (m_current_layer) + m_current_layer->m_selected = false; + m_current_layer = l; + m_current_layer->m_selected = true; m_layers.push_back(l); }