implement layers merge down
This commit is contained in:
@@ -165,7 +165,7 @@
|
||||
</border>
|
||||
</layout>
|
||||
|
||||
<!-- Dialog Relane Layer -->
|
||||
<!-- Dialog Rename Layer -->
|
||||
<layout id="dialog-layer-rename">
|
||||
<border positioning="absolute" position="0 0" color=".4 .4 .4 .8" width="100%" height="100%" align="center" justify="center">
|
||||
<border thickness="1" border-color=".2" pad="3">
|
||||
@@ -345,6 +345,10 @@
|
||||
<icon icon="application_edit" width="20"/>
|
||||
<text id="menu-label" text="Rename Layer" margin="0 0 0 5" font-face="arial" font-size="11"/>
|
||||
</button-custom>
|
||||
<button-custom id="layer-merge" height="30" align="center" color=".2" pad="0 0 0 10" dir="row">
|
||||
<icon icon="application_edit" width="20"/>
|
||||
<text id="menu-label" text="Merge with" margin="0 0 0 5" font-face="arial" font-size="11"/>
|
||||
</button-custom>
|
||||
</popup-menu>
|
||||
</layout>
|
||||
|
||||
|
||||
@@ -175,6 +175,7 @@
|
||||
<ClCompile Include="engine\node_canvas.cpp" />
|
||||
<ClCompile Include="engine\node_checkbox.cpp" />
|
||||
<ClCompile Include="engine\node_color_quad.cpp" />
|
||||
<ClCompile Include="engine\node_dialog_layer_rename.cpp" />
|
||||
<ClCompile Include="engine\node_dialog_open.cpp" />
|
||||
<ClCompile Include="engine\node_icon.cpp" />
|
||||
<ClCompile Include="engine\node_image.cpp" />
|
||||
@@ -262,6 +263,7 @@
|
||||
<ClInclude Include="engine\node_canvas.h" />
|
||||
<ClInclude Include="engine\node_checkbox.h" />
|
||||
<ClInclude Include="engine\node_color_quad.h" />
|
||||
<ClInclude Include="engine\node_dialog_layer_rename.h" />
|
||||
<ClInclude Include="engine\node_dialog_open.h" />
|
||||
<ClInclude Include="engine\node_icon.h" />
|
||||
<ClInclude Include="engine\node_image.h" />
|
||||
|
||||
@@ -195,6 +195,9 @@
|
||||
<ClCompile Include="libs\wacom\WinTab\Utils.cpp">
|
||||
<Filter>Source Files\libs\WinTab</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="engine\node_dialog_layer_rename.cpp">
|
||||
<Filter>Source Files\ui</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="engine\app.h">
|
||||
@@ -362,5 +365,8 @@
|
||||
<ClInclude Include="libs\wacom\WinTab\MSGPACK.H">
|
||||
<Filter>Source Files\libs\WinTab</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="engine\node_dialog_layer_rename.h">
|
||||
<Filter>Header Files\ui</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -376,8 +376,8 @@ void App::initLayout()
|
||||
popup->mouse_release();
|
||||
popup->destroy();
|
||||
};
|
||||
|
||||
popup->find<NodeButtonCustom>("layer-rename")->on_click = [this](Node*) {
|
||||
// load thumbnail test
|
||||
auto open_dialog = std::make_shared<NodeDialogLayerRename>();
|
||||
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<NodeButtonCustom>("layer-rename")->
|
||||
find<NodeText>("menu-label")->
|
||||
set_text("Rename Layer (Select a layer)");
|
||||
|
||||
popup->find<NodeButtonCustom>("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<NodeButtonCustom>("layer-merge")->
|
||||
find<NodeText>("menu-label")->
|
||||
set_text(("Merge with " + canvas->m_canvas->m_layers[down_layer_idx].m_name).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
popup->find<NodeButtonCustom>("layer-merge")->
|
||||
find<NodeText>("menu-label")->
|
||||
set_text("Merge Layer (Select upper layers)");
|
||||
}
|
||||
}
|
||||
else
|
||||
popup->find<NodeButtonCustom>("layer-merge")->
|
||||
find<NodeText>("menu-label")->
|
||||
set_text("Merge Layer (Select a layer)");
|
||||
|
||||
};
|
||||
}
|
||||
if (auto* toolbar = layout[main_id]->find<Node>("toolbar"))
|
||||
|
||||
@@ -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<uint8_t[]>(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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user