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);
}