#include "pch.h" #include "log.h" #include "node_panel_stroke.h" #include "canvas.h" #include "node_button.h" #include "app.h" Node* NodePanelStroke::clone_instantiate() const { return new NodePanelStroke(); } void NodePanelStroke::clone_finalize(Node* dest) const { NodePanelStroke* n = static_cast(dest); n->init_controls(); } void NodePanelStroke::init() { init_template("tpl-panel-stroke"); init_controls(); } void NodePanelStroke::update_controls() { const auto& b = Canvas::I->m_current_brush; m_tip_size->m_value.x = glm::pow(b->m_tip_size, 1.f/3.f); m_tip_spacing->m_value.x = glm::pow(b->m_tip_spacing, 1.f/2.f) / 4.f; m_tip_flow->m_value.x = glm::pow(b->m_tip_flow, 1.f/2.f); m_tip_opacity->m_value.x = b->m_tip_opacity; m_tip_angle->m_value.x = b->m_tip_angle; m_tip_stencil->m_value.x = b->m_tip_stencil; m_tip_wet->m_value.x = b->m_tip_wet; m_tip_noise->m_value.x = b->m_tip_noise; m_jitter_scale->m_value.x = b->m_jitter_scale; m_jitter_angle->m_value.x = b->m_jitter_angle; m_jitter_spread->m_value.x = b->m_jitter_spread; m_jitter_flow->m_value.x = b->m_jitter_flow; m_jitter_hue->m_value.x = b->m_jitter_hue; m_jitter_sat->m_value.x = b->m_jitter_sat; m_jitter_val->m_value.x = b->m_jitter_val; m_tip_angle_follow->checked = b->m_tip_angle_follow; m_tip_flow_pressure->checked = b->m_tip_flow_pressure; m_tip_size_pressure->checked = b->m_tip_size_pressure; m_preview->m_brush = b; m_preview->draw_stroke(); } void NodePanelStroke::init_controls() { m_brush_popup = std::make_shared(); m_brush_popup->m_manager = m_manager; m_brush_popup->init(); m_brush_popup->create(); m_brush_popup->loaded(); m_brush_popup->SetPositioning(YGPositionTypeAbsolute); m_brush_popup->SetSize(400, 400); m_brush_popup->m_mouse_ignore = false; m_brush_popup->m_flood_events = true; m_brush_popup->m_capture_children = false; auto b = std::make_shared(); int br_idx = m_brush_popup->find_brush("Round-Hard"); b->load_texture(m_brush_popup->get_texture_path(br_idx), m_brush_popup->get_thumb_path(br_idx)); //b->load_stencil("data/paper.jpg"); b->m_tip_size = .1f; b->m_tip_flow = .5f; b->m_tip_spacing = .1f; b->m_tip_opacity = 1.f; Canvas::I->m_current_brush = b; m_brush_thumb = find("tip-change-thumb"); m_brush_thumb->set_image(m_brush_popup->get_thumb_path(br_idx)); m_brush_button = find("tip-change"); m_brush_button->on_click = [this](Node*) { glm::vec2 pos = m_brush_button->m_pos + glm::vec2(m_brush_button->m_size.x, 0); root()->add_child(m_brush_popup); m_brush_popup->SetPosition(pos.x, pos.y); m_brush_popup->mouse_capture(); root()->update(); m_brush_popup->on_brush_changed = [this](Node*, int index) { if (on_brush_changed) on_brush_changed(this, m_brush_popup->get_texture_path(index), m_brush_popup->get_thumb_path(index)); m_brush_thumb->set_image(m_brush_popup->get_thumb_path(index)); m_brush_popup->mouse_release(); m_brush_popup->parent->remove_child(m_brush_popup.get()); }; }; m_preview = find("canvas"); m_blend_mode = find("blend-mode"); m_blend_mode->on_select = [](Node*, int index) { Canvas::I->m_current_brush->m_blend_mode = index; }; init_slider(m_tip_size, "tip-size", &Brush::m_tip_size); init_slider(m_tip_spacing, "tip-spacing", &Brush::m_tip_spacing); init_slider(m_tip_flow, "tip-flow", &Brush::m_tip_flow); init_slider(m_tip_opacity, "tip-opacity", &Brush::m_tip_opacity); init_slider(m_tip_angle, "tip-angle", &Brush::m_tip_angle); init_slider(m_tip_mix, "tip-mix", &Brush::m_tip_mix); init_slider(m_tip_stencil, "tip-stencil", &Brush::m_tip_stencil); init_slider(m_tip_wet, "tip-wet", &Brush::m_tip_wet); init_slider(m_tip_noise, "tip-noise", &Brush::m_tip_noise); init_slider(m_tip_hue, "tip-hue", &Brush::m_tip_hue); init_slider(m_tip_sat, "tip-sat", &Brush::m_tip_sat); init_slider(m_tip_val, "tip-val", &Brush::m_tip_val); init_slider(m_jitter_scale, "jitter-scale", &Brush::m_jitter_scale); init_slider(m_jitter_angle, "jitter-angle", &Brush::m_jitter_angle); init_slider(m_jitter_spread, "jitter-spread", &Brush::m_jitter_spread); init_slider(m_jitter_flow, "jitter-flow", &Brush::m_jitter_flow); init_slider(m_jitter_hue, "jitter-hue", &Brush::m_jitter_hue); init_slider(m_jitter_sat, "jitter-sat", &Brush::m_jitter_sat); init_slider(m_jitter_val, "jitter-val", &Brush::m_jitter_val); m_curves[m_tip_size] = [](float v){ return glm::pow(v, 3.f); }; m_curves[m_tip_spacing] = [](float v){ return glm::pow(v * 4.f, 2.f); }; m_curves[m_tip_flow] = [](float v){ return glm::pow(v, 2.f); }; init_checkbox(m_tip_angle_follow, "tip-angle-follow", &Brush::m_tip_angle_follow); init_checkbox(m_tip_flow_pressure, "tip-flow-pressure", &Brush::m_tip_flow_pressure); init_checkbox(m_tip_size_pressure, "tip-size-pressure", &Brush::m_tip_size_pressure); init_checkbox(m_tip_hue_pressure, "tip-hue-pressure", &Brush::m_tip_hue_pressure); init_checkbox(m_tip_sat_pressure, "tip-sat-pressure", &Brush::m_tip_sat_pressure); init_checkbox(m_tip_val_pressure, "tip-val-pressure", &Brush::m_tip_val_pressure); m_preview->m_brush = Canvas::I->m_current_brush; m_preview->draw_stroke(); auto load_stencil = find("tip-stencil-load"); load_stencil->on_click = [this](Node*) { App::I.pick_image([this](std::string path) { App::I.async_start(); if (TextureManager::load(path.c_str())) { if (on_stencil_changed) on_stencil_changed(this, path); } App::I.async_redraw(); App::I.async_end(); }); }; } void NodePanelStroke::init_slider(NodeSliderH*& target, const char* id, float Brush::* prop) { target = find(id); target->on_value_changed = std::bind(&NodePanelStroke::handle_slide, this, prop, std::placeholders::_1, std::placeholders::_2); //m_canvas->m_brush->*prop = target->m_value.x; } void NodePanelStroke::handle_slide(float Brush::* prop, Node* target, float value) { auto curve = m_curves.find((NodeSliderH*)target); Canvas::I->m_current_brush.get()->*prop = curve != m_curves.end() ? curve->second(value) : value; m_preview->m_brush = Canvas::I->m_current_brush; m_preview->draw_stroke(); if (on_stroke_change) on_stroke_change(this); } void NodePanelStroke::init_checkbox(NodeCheckBox*& target, const char* id, bool Brush::* prop) { target = find(id); target->on_value_changed = std::bind(&NodePanelStroke::handle_checkbox, this, prop, std::placeholders::_1, std::placeholders::_2); Canvas::I->m_current_brush.get()->*prop = target->checked; } void NodePanelStroke::handle_checkbox(bool Brush::* prop, Node *target, bool value) { Canvas::I->m_current_brush.get()->*prop = value; m_preview->m_brush = Canvas::I->m_current_brush; m_preview->draw_stroke(); if (on_stroke_change) on_stroke_change(this); }