diff --git a/data/layout.xml b/data/layout.xml index 2f24734..3bcb434 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -35,15 +35,14 @@ - - - - - - - - - + + + + + + + + @@ -54,6 +53,17 @@ + + + + + + + + + + + @@ -69,9 +79,6 @@ - - - @@ -1116,7 +1123,7 @@ Here's a list of what's available in this release. - + diff --git a/data/ui/check-layer-visibility.png b/data/ui/check-layer-visibility.png new file mode 100644 index 0000000..7328d2c Binary files /dev/null and b/data/ui/check-layer-visibility.png differ diff --git a/data/ui/check-lock-transparency.png b/data/ui/check-lock-transparency.png new file mode 100644 index 0000000..2267b43 Binary files /dev/null and b/data/ui/check-lock-transparency.png differ diff --git a/data/ui/check-test.png b/data/ui/check-test.png new file mode 100644 index 0000000..d0a8463 Binary files /dev/null and b/data/ui/check-test.png differ diff --git a/extra/ui/checkbox-icons.psd b/extra/ui/checkbox-icons.psd new file mode 100644 index 0000000..e593023 Binary files /dev/null and b/extra/ui/checkbox-icons.psd differ diff --git a/src/app.cpp b/src/app.cpp index a344355..0b3da56 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -44,10 +44,7 @@ void App::open_document(std::string path) async_start(); title_update(); for (auto& i : canvas->m_canvas->m_order) - { - auto* l = layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str()); - l->m_opacity->m_value.x = canvas->m_canvas->m_layers[i].m_opacity; - } + layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str()); async_end(); } else diff --git a/src/app_layout.cpp b/src/app_layout.cpp index b2cbd9d..d72f080 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -88,6 +88,26 @@ void App::init_toolbar_main() } } +template std::shared_ptr find_or_create_panel(NodeScroll* panels) +{ + std::shared_ptr ret; + auto node_find = std::find_if(panels->m_children.begin(), panels->m_children.end(), + [](const std::shared_ptr&p) { return (bool)std::dynamic_pointer_cast(p); }); + if (node_find != panels->m_children.end()) + { + ret = std::static_pointer_cast(*node_find); + } + else + { + ret = std::make_shared(); + ret->m_manager = panels->m_manager; + ret->init(); + ret->create(); + ret->loaded(); + } + return ret; +} + void App::init_sidebar() { sidebar = layout[main_id]->find("sidebar"); @@ -99,50 +119,12 @@ void App::init_sidebar() //color = layout[main_id]->find("panel-color"); //stroke = layout[main_id]->find("panel-stroke"); - brushes = std::make_shared(); - brushes->m_manager = &layout; - brushes->init(); - brushes->create(); - brushes->loaded(); - - layers = std::make_shared(); - layers->m_manager = &layout; - layers->init(); - layers->create(); - layers->loaded(); - - color = std::make_shared(); - color->m_manager = &layout; - color->init(); - color->create(); - color->loaded(); - - stroke = std::make_shared(); - stroke->m_manager = &layout; - stroke->init(); - stroke->create(); - stroke->loaded(); - - auto grid_find = std::find_if(panels->m_children.begin(), panels->m_children.end(), - [](const std::shared_ptr&p) { return (bool)std::dynamic_pointer_cast(p); }); - if (grid_find != panels->m_children.end()) - { - grid = std::static_pointer_cast(*grid_find); - } - else - { - grid = std::make_shared(); - grid->m_manager = &layout; - grid->init(); - grid->create(); - grid->loaded(); - } - - presets = std::make_shared(); - presets->m_manager = &layout; - presets->init(); - presets->create(); - presets->loaded(); + brushes = find_or_create_panel(panels); + layers = find_or_create_panel(panels); + color = find_or_create_panel(panels); + stroke = find_or_create_panel(panels); + grid = find_or_create_panel(panels); + presets = find_or_create_panel(panels); // if (canvas) // { @@ -175,6 +157,8 @@ void App::init_sidebar() layers->on_layer_add = [this](Node*) { canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str()); + canvas->m_canvas->m_unsaved = true; + title_update(); }; layers->on_layer_change = [this](Node*, int old_idx, int new_idx) { @@ -183,18 +167,38 @@ void App::init_sidebar() layers->on_layer_order = [this](Node*, int old_idx, int new_idx) { canvas->m_canvas->layer_order(old_idx, new_idx); + canvas->m_canvas->m_unsaved = true; + title_update(); }; layers->on_layer_delete = [this](Node*, int idx) { canvas->m_canvas->layer_remove(idx); + canvas->m_canvas->m_unsaved = true; + title_update(); }; 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_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_alpha_locked = visible; + canvas->m_canvas->m_layers[canvas->m_canvas->m_order[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_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_unsaved = true; + title_update(); }; layers->on_layer_highlight_changed = [this](Node*, int idx, bool highlight) { diff --git a/src/app_shaders.cpp b/src/app_shaders.cpp index 400431b..a602480 100644 --- a/src/app_shaders.cpp +++ b/src/app_shaders.cpp @@ -77,17 +77,32 @@ void App::initShaders() SHADER_VERSION "uniform sampler2D tex;\n" "uniform sampler2D tex_stroke;\n" + "uniform sampler2D tex_mask;\n" "uniform mediump float alpha;\n" + "uniform mediump float stroke_alpha;\n" "uniform mediump vec2 resolution;\n" "uniform bool fragUV2;\n" + "uniform bool mask;\n" "in mediump vec2 uv;\n" "out mediump vec4 frag;\n" + "mediump vec4 blur(sampler2D t, mediump vec2 uv){\n" + " mediump vec4 sum = texture(t, uv);\n" + " sum += textureOffset(t, uv, ivec2(-1, -1));\n" + " sum += textureOffset(t, uv, ivec2(-1, 0));\n" + " sum += textureOffset(t, uv, ivec2(-1, 1));\n" + " sum += textureOffset(t, uv, ivec2( 0, -1));\n" + " sum += textureOffset(t, uv, ivec2( 0, 1));\n" + " sum += textureOffset(t, uv, ivec2( 1, -1));\n" + " sum += textureOffset(t, uv, ivec2( 1, 0));\n" + " sum += textureOffset(t, uv, ivec2( 1, 1));\n" + " return sum / vec4(9.0);\n" + "}\n" "void main(){\n" " mediump vec2 uv2 = fragUV2 ? (gl_FragCoord.st / resolution) : uv;\n" " mediump vec4 base = texture(tex, uv2);\n" " mediump vec4 stroke = texture(tex_stroke, uv);\n" - " mediump float a = base.a - (stroke.a * alpha);\n" - " frag = vec4(base.rgb, clamp(a, 0.0, 1.0));\n" + " stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv2).r : stroke.a * stroke_alpha;\n" + " frag = vec4(base.rgb, clamp((base.a - stroke.a) * alpha, 0.0, 1.0));\n" "}\n"; // TEXTURE COMP DRAW static const char* shader_comp_draw_f = @@ -97,6 +112,7 @@ void App::initShaders() "uniform sampler2D tex_mask;\n" "uniform sampler2D tex_stencil;\n" "uniform mediump float alpha;\n" + "uniform mediump float stroke_alpha;\n" "uniform mediump int blend_mode;\n" "uniform mediump vec2 resolution;\n" "uniform bool lock;\n" @@ -141,13 +157,12 @@ void App::initShaders() " mediump vec2 uv2 = fragUV2 ? (gl_FragCoord.st / resolution) : uv;\n" " mediump vec4 base = texture(tex, uv2);\n" " mediump vec4 stroke = texture(tex_stroke, uv);\n" - " stroke.a = mask ? stroke.a * alpha * blur(tex_mask, uv2).r : stroke.a * alpha;\n" - - " if (!lock && base.a == 0.0) { frag = stroke; return; }\n" + " stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv2).r : stroke.a * stroke_alpha;\n" + " if (!lock && base.a == 0.0) { frag = stroke * vec4(1.0, 1.0, 1.0, alpha); return; }\n" " mediump float contribution = (1.0 - base.a) * stroke.a;\n" " mediump float alpha_tot = base.a + contribution;" " mediump vec3 rgb = blend(base, stroke, alpha_tot, blend_mode);\n" - " frag = vec4(rgb, (lock ? base.a : alpha_tot));\n" + " frag = vec4(rgb, (lock ? base.a : alpha_tot) * alpha);\n" "}\n"; // TEXTURE ATLAS diff --git a/src/app_vr.cpp b/src/app_vr.cpp index c4a7330..e7fde59 100644 --- a/src/app_vr.cpp +++ b/src/app_vr.cpp @@ -46,7 +46,7 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat auto layer_index = canvas->m_canvas->m_order[i]; for (int plane_index = 0; plane_index < 6; plane_index++) { - if (canvas->m_canvas->m_layers[layer_index].m_opacity == .0f) + if (!canvas->m_canvas->m_layers[layer_index].m_visible || canvas->m_canvas->m_layers[layer_index].m_opacity == .0f) continue; int z = (int)(canvas->m_canvas->m_order.size() - i); @@ -62,10 +62,11 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat ShaderManager::use(kShader::CompErase); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexStroke, 1); - //ShaderManager::u_int(kShaderUniform::TexMask, 2); - ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_int(kShaderUniform::TexMask, 2); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_layers[layer_index].m_opacity); //ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked); - //ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active); + ShaderManager::u_int(kShaderUniform::Mask, canvas->m_canvas->m_smask_active); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); glActiveTexture(GL_TEXTURE0); canvas->m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture(); @@ -90,7 +91,8 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat ShaderManager::u_int(kShaderUniform::TexMask, 2); ShaderManager::u_vec2(kShaderUniform::Resolution, canvas->m_canvas->m_size); //ShaderManager::u_int(kShaderUniform::TexStencil, 3); - ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_layers[layer_index].m_opacity); ShaderManager::u_int(kShaderUniform::Lock, canvas->m_canvas->m_layers[layer_index].m_alpha_locked); ShaderManager::u_int(kShaderUniform::Mask, canvas->m_canvas->m_smask_active); ShaderManager::u_int(kShaderUniform::BlendMode, canvas->m_canvas->m_current_stroke->m_brush.m_blend_mode); diff --git a/src/canvas.cpp b/src/canvas.cpp index 097f7cf..5c819bd 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -91,6 +91,8 @@ void Canvas::pick_update(int plane) m_sampler.bind(0); for (auto layer_index : m_order) { + if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == 0.f) + continue; ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index].m_opacity); m_layers[layer_index].m_rtt[i].bindTexture(); m_plane.draw_fill(); @@ -242,7 +244,7 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz) auto layer_index = m_current_layer_idx; for (int plane_index = 0; plane_index < 6; plane_index++) { - if (m_layers[layer_index].m_opacity == .0f) + if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == .0f) continue; glm::mat4 proj = glm::perspective(glm::radians(m_cam_fov), (float)m_mixer.getWidth() / m_mixer.getHeight(), 0.1f, 1000.f); @@ -293,7 +295,8 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz) ShaderManager::u_int(kShaderUniform::TexMask, 2); //ShaderManager::u_vec2(kShaderUniform::Resolution, m_size); //ShaderManager::u_int(kShaderUniform::TexStencil, 3); - ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::Alpha, 1); ShaderManager::u_int(kShaderUniform::Lock, m_layers[layer_index].m_alpha_locked); ShaderManager::u_int(kShaderUniform::Mask, m_smask_active); ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false); @@ -804,9 +807,11 @@ void Canvas::stroke_commit() ShaderManager::use(kShader::CompErase); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexStroke, 1); - //ShaderManager::u_int(kShaderUniform::TexMask, 2); + ShaderManager::u_int(kShaderUniform::TexMask, 2); + ShaderManager::u_int(kShaderUniform::Mask, m_smask_active); ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false); - ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::Alpha, 1); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); glActiveTexture(GL_TEXTURE0); @@ -831,7 +836,8 @@ void Canvas::stroke_commit() ShaderManager::u_int(kShaderUniform::TexStroke, 1); ShaderManager::u_int(kShaderUniform::TexMask, 2); //ShaderManager::u_vec2(kShaderUniform::Resolution, m_size); - ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::Alpha, 1); ShaderManager::u_int(kShaderUniform::Mask, m_smask_active); ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false); ShaderManager::u_int(kShaderUniform::BlendMode, m_current_stroke->m_brush.m_blend_mode); @@ -1009,6 +1015,7 @@ void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index ShaderManager::u_int(kShaderUniform::TexStroke, 1); // source //ShaderManager::u_vec2(kShaderUniform::Resolution, m_size); ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, 1); ShaderManager::u_float(kShaderUniform::Alpha, m_layers[source_idx].m_opacity); ShaderManager::u_int(kShaderUniform::Lock, false); ShaderManager::u_int(kShaderUniform::BlendMode, 0); // TODO: defaulted to normal, change to layer blend mode when implemented @@ -1284,6 +1291,8 @@ void Canvas::export_equirectangular_thread(std::string file_path) m_sampler_mask.bind(0); for (auto layer_index : m_order) { + if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == 0.f) + continue; ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index].m_opacity); m_layers[layer_index].m_rtt[i].bindTexture(); m_plane.draw_fill(); diff --git a/src/canvas.h b/src/canvas.h index 42034c3..e6aa04e 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -20,6 +20,7 @@ public: bool m_alpha_locked = false; float m_opacity = 1.f; bool m_hightlight = false; + bool m_blend_mode = 0; std::string m_name; int w = 0; int h = 0; diff --git a/src/canvas_modes.cpp b/src/canvas_modes.cpp index 0df2fc1..7afc7d6 100644 --- a/src/canvas_modes.cpp +++ b/src/canvas_modes.cpp @@ -1112,6 +1112,7 @@ void CanvasModeTransform::leave() ShaderManager::u_int(kShaderUniform::TexStroke, 1); ShaderManager::u_int(kShaderUniform::TexMask, 2); ShaderManager::u_float(kShaderUniform::Alpha, 1); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, 1); ShaderManager::u_int(kShaderUniform::Lock, false); ShaderManager::u_int(kShaderUniform::Mask, false); ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, true); diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index 878585a..2351f3b 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -137,7 +137,7 @@ void NodeCanvas::draw() auto layer_index = m_canvas->m_order[i]; for (int plane_index = 0; plane_index < 6; plane_index++) { - if (m_canvas->m_layers[layer_index].m_opacity == .0f) + if (!m_canvas->m_layers[layer_index].m_visible || m_canvas->m_layers[layer_index].m_opacity == .0f) continue; int z = (int)(m_canvas->m_order.size() - i); @@ -153,11 +153,12 @@ void NodeCanvas::draw() ShaderManager::use(kShader::CompErase); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexStroke, 1); - //ShaderManager::u_int(kShaderUniform::TexMask, 2); - ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_int(kShaderUniform::TexMask, 2); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity); ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false); //ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked); - //ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active); + ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); glActiveTexture(GL_TEXTURE0); m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture(); @@ -182,7 +183,8 @@ void NodeCanvas::draw() ShaderManager::u_int(kShaderUniform::TexMask, 2); //ShaderManager::u_vec2(kShaderUniform::Resolution, zw(m_canvas->m_box) / zoom); //ShaderManager::u_int(kShaderUniform::TexStencil, 3); - ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity); + ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity); ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked); ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active); ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false); diff --git a/src/node_checkbox.cpp b/src/node_checkbox.cpp index b549c50..4e89700 100644 --- a/src/node_checkbox.cpp +++ b/src/node_checkbox.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "log.h" #include "node_checkbox.h" +#include "texture.h" Node* NodeCheckBox::clone_instantiate() const { @@ -13,7 +14,9 @@ void NodeCheckBox::clone_children(Node* dest) const NodeCheckBox* n = static_cast(dest); n->m_outer = (NodeBorder*)n->m_children[0].get(); n->m_inner = (NodeBorder*)n->m_outer->m_children[0].get(); + n->m_icon = n->m_inner->m_children.empty() ? nullptr : (NodeImage*)n->m_inner->m_children[0].get(); n->m_mouse_ignore = false; + n->m_icon_path = m_icon_path; } void NodeCheckBox::init() @@ -43,6 +46,8 @@ void NodeCheckBox::create() { m_outer->create(); m_inner->create(); + if (!m_icon_path.empty()) + set_icon(m_icon_path); } kEventResult NodeCheckBox::handle_event(Event* e) @@ -58,6 +63,7 @@ kEventResult NodeCheckBox::handle_event(Event* e) break; case kEventType::MouseUpL: checked = !checked; + update_icon(); if (on_value_changed) on_value_changed(this, checked); break; @@ -73,3 +79,42 @@ void NodeCheckBox::draw() m_inner->m_color = checked ? glm::vec4(.4, .4, .4, 1) : glm::vec4(.8, .8, .8, 1); Node::draw(); } + +void NodeCheckBox::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) +{ + switch (ka) + { + case kAttribute::Icon: + m_icon_path = attr->Value(); + break; + default: + Node::parse_attributes(ka, attr); + break; + } +} + +void NodeCheckBox::set_icon(const std::string& icon_path) +{ + if (icon_path.empty() || !TextureManager::load(icon_path.c_str())) + { + if (m_icon) + m_icon->destroy(); + m_icon = nullptr; + return; + } + m_icon_path = icon_path; + update_icon(); +} + +void NodeCheckBox::update_icon() +{ + auto& t = TextureManager::get(const_hash(m_icon_path.c_str())); + if (!m_icon) + m_icon = m_inner->add_child(); + auto region = checked ? glm::vec4(.5f, 0, 1, 1) : glm::vec4(0, 0, .5f, 1); + m_icon->m_region = region * glm::vec4(t.size(), t.size()); + m_icon->m_use_atlas = true; + m_icon->set_image(m_icon_path); + m_icon->SetWidthP(100); + m_icon->SetHeightP(100); +} diff --git a/src/node_checkbox.h b/src/node_checkbox.h index c7e5fd1..9b45b88 100644 --- a/src/node_checkbox.h +++ b/src/node_checkbox.h @@ -1,6 +1,7 @@ #pragma once #include "node.h" #include "node_border.h" +#include "node_image.h" class NodeCheckBox : public Node { @@ -8,6 +9,8 @@ public: std::function on_value_changed; NodeBorder* m_outer; NodeBorder* m_inner; + NodeImage* m_icon; + std::string m_icon_path; bool checked = false; virtual Node* clone_instantiate() const override; virtual void clone_children(Node* dest) const override; @@ -15,4 +18,8 @@ public: virtual void create() override; virtual kEventResult handle_event(Event* e) override; virtual void draw() override; + virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override; + void set_icon(const std::string& icon_path); + void set_value(bool checked) { this->checked = checked; update_icon(); } + void update_icon(); }; diff --git a/src/node_combobox.cpp b/src/node_combobox.cpp index 1995a1b..fefa424 100644 --- a/src/node_combobox.cpp +++ b/src/node_combobox.cpp @@ -13,7 +13,9 @@ void NodeComboBox::clone_copy(Node* dest) const NodeButton::clone_copy(dest); NodeComboBox* n = static_cast(dest); n->m_data = m_data; + n->m_items = m_items; n->m_current_index = m_current_index; + n->m_selected_child_index = m_selected_child_index; } void NodeComboBox::loaded() @@ -85,6 +87,9 @@ void NodeComboBox::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* case kAttribute::ComboList: { m_data = split(attr->Value(), ','); + m_items.clear(); + for (auto& i : m_data) + if (i != "-") m_items.push_back(i); break; } case kAttribute::Default: @@ -94,3 +99,12 @@ void NodeComboBox::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* break; } } + +void NodeComboBox::set_index(int index) +{ + m_current_index = index; + m_selected_child_index = index; + m_text->set_text(m_items[index].c_str()); + //if (on_select) + // on_select(this, index); +} diff --git a/src/node_combobox.h b/src/node_combobox.h index a505a90..72230b4 100644 --- a/src/node_combobox.h +++ b/src/node_combobox.h @@ -13,4 +13,5 @@ public: virtual void clone_copy(Node* dest) const override; virtual void loaded() override; virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override; + void set_index(int index); }; diff --git a/src/node_image.cpp b/src/node_image.cpp index 18e803f..1f68214 100644 --- a/src/node_image.cpp +++ b/src/node_image.cpp @@ -105,3 +105,19 @@ void NodeImage::draw() TextureManager::get(m_tex_id).unbind(); glDisable(GL_BLEND); } + +bool NodeImage::set_image(const std::string& path) +{ + m_path = path; + m_tex_id = const_hash(path.c_str()); + if (!m_path.empty() && TextureManager::load(m_path.c_str(), m_use_mipmaps)) + { + auto tex_sz = TextureManager::get(m_tex_id).size(); + m_off = xy(m_region) / tex_sz; + m_sz = (zw(m_region) - xy(m_region)) / tex_sz; + if (m_autosize) + SetAspectRatio(tex_sz.x / tex_sz.y); + return true; + } + return false; +} diff --git a/src/node_image.h b/src/node_image.h index 1280607..e4bdeaa 100644 --- a/src/node_image.h +++ b/src/node_image.h @@ -24,4 +24,5 @@ public: virtual void restore_context() override; virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override; virtual void draw() override; + bool set_image(const std::string& path); }; diff --git a/src/node_panel_layer.cpp b/src/node_panel_layer.cpp index 0c9532f..f58d40c 100644 --- a/src/node_panel_layer.cpp +++ b/src/node_panel_layer.cpp @@ -1,6 +1,8 @@ #include "pch.h" #include "log.h" #include "node_panel_layer.h" +#include "canvas.h" +#include "node_combobox.h" Node* NodeLayer::clone_instantiate() const { @@ -31,7 +33,6 @@ void NodeLayer::init() m_thinkness = m_template->m_thinkness; m_label = find("label"); m_visibility = find("cb"); - m_opacity = find("sl-opacity"); } void NodeLayer::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) @@ -54,10 +55,6 @@ void NodeLayer::loaded() NodeBorder::loaded(); if (!m_label_text.empty()) m_label->set_text(m_label_text.c_str()); - m_opacity->on_value_changed = [this](Node*, float value) { - if (on_opacity_changed) - on_opacity_changed(this, value); - }; m_visibility->on_value_changed = [this](Node*, bool checked) { if (on_visibility_changed) on_visibility_changed(this, checked); @@ -159,6 +156,18 @@ void NodePanelLayer::init() on_layer_order(this, old_idx, new_idx); } }; + m_opacity = find("opacity"); + m_opacity->on_value_changed = [this](Node*, float value) { + handle_layer_opacity(m_current_layer, value); + }; + m_alpha_lock = find("alpha-lock"); + m_alpha_lock->on_value_changed = [this](Node*, bool locked) { + handle_layer_alpha_lock(m_current_layer, locked); + }; + m_blend_mode = find("blend-mode"); + m_blend_mode->on_select = [this](Node*, int index) { + handle_layer_blend_mode(m_current_layer, index); + }; LOG("done init"); } @@ -170,8 +179,8 @@ NodeLayer* NodePanelLayer::add_layer(const char* name) l->create(); l->loaded(); l->set_name(name); + l->m_visibility->set_value(true); 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); l->on_highlight = std::bind(&NodePanelLayer::handle_layer_highlight, this, std::placeholders::_1, std::placeholders::_2); if (m_current_layer) @@ -179,6 +188,7 @@ NodeLayer* NodePanelLayer::add_layer(const char* name) m_current_layer = l; m_current_layer->m_selected = true; m_layers.push_back(l); + update_attributes(); return l; } @@ -208,6 +218,7 @@ void NodePanelLayer::remove_layer(NodeLayer* layer) on_layer_delete(this, old_idx); if (on_layer_change) on_layer_change(this, -1, i); + update_attributes(); } void NodePanelLayer::handle_layer_opacity(NodeLayer* target, float value) @@ -228,6 +239,18 @@ void NodePanelLayer::handle_layer_visibility(NodeLayer* target, bool visible) on_layer_visibility_changed(this, m_layers_container->get_child_index(target), visible); } +void NodePanelLayer::handle_layer_alpha_lock(NodeLayer* target, bool locked) +{ + if (on_layer_alpha_lock_changed) + on_layer_alpha_lock_changed(this, m_layers_container->get_child_index(target), locked); +} + +void NodePanelLayer::handle_layer_blend_mode(NodeLayer* target, int mode) +{ + if (on_layer_blend_mode_changed) + on_layer_blend_mode_changed(this, m_layers_container->get_child_index(target), mode); +} + void NodePanelLayer::handle_layer_selected(NodeLayer* target) { if (m_current_layer) @@ -236,6 +259,7 @@ void NodePanelLayer::handle_layer_selected(NodeLayer* target) m_current_layer->m_selected = true; if (on_layer_change) on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer)); + update_attributes(); } void NodePanelLayer::clear() @@ -244,3 +268,11 @@ void NodePanelLayer::clear() m_layers.clear(); m_current_layer = nullptr; } + +void NodePanelLayer::update_attributes() +{ + auto& l = Canvas::I->m_layers[Canvas::I->m_current_layer_idx]; + m_opacity->set_value(l.m_opacity); + m_alpha_lock->set_value(l.m_alpha_locked); + m_blend_mode->set_index(l.m_blend_mode); +} diff --git a/src/node_panel_layer.h b/src/node_panel_layer.h index 93330f6..f069cf2 100644 --- a/src/node_panel_layer.h +++ b/src/node_panel_layer.h @@ -4,12 +4,12 @@ #include "node_checkbox.h" #include "node_slider.h" #include "node_button_custom.h" +#include "node_combobox.h" class NodeLayer : public NodeBorder { public: std::function on_selected; - std::function on_opacity_changed; std::function on_visibility_changed; std::function on_highlight; bool m_selected = false; @@ -19,7 +19,6 @@ public: std::string m_label_text; NodeText* m_label; NodeCheckBox* m_visibility; - NodeSliderH* m_opacity; virtual Node* clone_instantiate() const override; virtual void clone_children(Node* dest) const override; virtual void clone_copy(Node* dest) const override; @@ -42,13 +41,18 @@ public: std::function on_layer_change; std::function on_layer_opacity_changed; std::function on_layer_visibility_changed; + std::function on_layer_alpha_lock_changed; std::function on_layer_highlight_changed; + std::function on_layer_blend_mode_changed; std::function on_layer_delete; std::function on_layer_add; std::function on_layer_order; NodeLayer* m_current_layer = nullptr; std::vector m_layers; NodeBorder* m_layers_container; + NodeSliderH* m_opacity; + NodeCheckBox* m_alpha_lock; + NodeComboBox* m_blend_mode; virtual Node* clone_instantiate() const override; virtual void init() override; void add_layer(); @@ -57,7 +61,10 @@ public: void remove_layer(NodeLayer* layer); void handle_layer_opacity(NodeLayer* target, float value); void handle_layer_visibility(NodeLayer* target, bool visible); + void handle_layer_alpha_lock(NodeLayer* target, bool locked); void handle_layer_highlight(NodeLayer* target, bool highlight); + void handle_layer_blend_mode(NodeLayer* target, int mode); void handle_layer_selected(NodeLayer* target); void clear(); + void update_attributes(); }; diff --git a/src/node_slider.cpp b/src/node_slider.cpp index 16aad8e..b5ace62 100644 --- a/src/node_slider.cpp +++ b/src/node_slider.cpp @@ -42,8 +42,8 @@ void NodeSliderH::draw() void NodeSliderH::set_value(float value) { m_value = glm::vec2(value) * m_mask; - if (on_value_changed) - on_value_changed(this, glm::length(m_value)); + //if (on_value_changed) + // on_value_changed(this, glm::length(m_value)); } float NodeSliderH::get_value() diff --git a/src/shader.h b/src/shader.h index 2ca307b..d103acd 100644 --- a/src/shader.h +++ b/src/shader.h @@ -16,6 +16,7 @@ enum class kShaderUniform : uint16_t StencilOffset = const_hash("stencil_offset"), StencilAlpha = const_hash("stencil_alpha"), MixAlpha = const_hash("mix_alpha"), + StrokeAlpha = const_hash("stroke_alpha"), Wet = const_hash("wet"), Lock = const_hash("lock"), Col = const_hash("col"),