From 4a5bb68fe22cfbf8fa7a806ceadb442c84456c2b Mon Sep 17 00:00:00 2001 From: omigamedev Date: Tue, 16 Jun 2026 10:13:59 +0200 Subject: [PATCH] Thin canvas state, tools menu, and node canvas draw --- docs/modernization/roadmap.md | 26 +- docs/modernization/tasks.md | 26 +- src/app_layout.cpp | 440 +------------------- src/app_layout_tools_menu.cpp | 507 ++++++++++++++++++++++++ src/legacy_canvas_draw_merge_services.h | 92 +++++ src/legacy_canvas_state_services.cpp | 20 + src/node_canvas.cpp | 139 +++---- 7 files changed, 729 insertions(+), 521 deletions(-) create mode 100644 src/app_layout_tools_menu.cpp diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 38dc26fd..e0cca580 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -79,14 +79,14 @@ What is still carrying too much live ownership: Current hotspot files: -- `src/canvas.cpp`: 4128 lines -- `src/app_layout.cpp`: 2026 lines +- `src/canvas.cpp`: 3622 lines +- `src/app_layout.cpp`: 1498 lines - `src/canvas_modes.cpp`: 1798 lines - `src/node.cpp`: 1551 lines - `src/main.cpp`: 1374 lines - `src/node_panel_brush.cpp`: 1197 lines - `src/node_stroke_preview.cpp`: 1129 lines -- `src/node_canvas.cpp`: 962 lines +- `src/node_canvas.cpp`: 888 lines - `src/app.cpp`: 950 lines - `src/app_dialogs.cpp`: 908 lines @@ -120,9 +120,14 @@ Current architecture mismatches that must be treated as real blockers: merged-texture draw callback plus non-`draw_merged` per-frame layer draw callback plus the smoothing-mask face shader/draw pass plus heightmap, current-mode, and grid-mode callback setup now routed through the same - retained helper family. + retained helper family, while post-draw callback assembly and the remaining + per-layer render-path orchestration now also route through retained + draw-merge helpers even though the broader node draw loop is still inline. - `app_layout.cpp` and `app_dialogs.cpp` are still mixed shell/controller files - rather than thin composition/binding surfaces. + rather than thin composition/binding surfaces, even though tools-menu binding + plus nested panels/options submenu wiring now live in + `src/app_layout_tools_menu.cpp` and `App::init_menu_tools()` is now a thin + call-through. - `App`, `Canvas`, `Node`, retained workers, and platform entrypoints still use global singleton reach, raw observer pointers, retained static worker ownership in several app families, and ad hoc mutex/condition-variable @@ -145,10 +150,13 @@ Current architecture mismatches that must be treated as real blockers: prepared-file worker and the canvas async import/export/save/open worker now live under `AppRuntime` instead of retained static app-events/canvas workers, `App::rec_loop()` now delegates worker-iteration orchestration into - the retained recording bridge, and `App::update_rec_frames()` now delegates - recording label refresh through that same retained recording path even though - the bridge still owns worker-side readback flow and encoder-state label - reads. + the retained recording bridge, `App::update_rec_frames()` now delegates + recording label refresh through that same retained recording path, and the + canvas state-management cluster for picking, clear/clear-all, layer + add/remove/order/lookups, animation frame control, resize, and snapshot + save/restore now lives in `src/legacy_canvas_state_services.cpp` instead of + `src/canvas.cpp`, even though the bridge still owns worker-side readback flow + and encoder-state label reads. - Modern C++23 usage exists in extracted components, especially `std::span`, explicit result/status objects, and a few concepts, but the live app still does not consistently express ownership, thread affinity, or renderer diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index a320124f..d21c0b90 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -87,11 +87,18 @@ looks like a wrapper around the old renderer shell. #### ARC-RND-001 - Split `canvas.cpp` Into Document State And Render Execution Shells -Status: Ready +Status: In Progress Why now: `src/canvas.cpp` is still the biggest single architectural blocker at about -4128 lines. +3622 lines. + +Current slice: +- Canvas state-management helpers for picking, clear/clear-all, layer + add/remove/order/lookups, animation frame control, resize, and snapshot + save/restore now live in `src/legacy_canvas_state_services.cpp` instead of + staying inline in `src/canvas.cpp`, but the file still owns the larger + document-plus-render shell. Write scope: - `src/canvas.cpp` @@ -171,6 +178,11 @@ Current slice: now also routes through `execute_legacy_canvas_draw_merge_layer_plane(...)`, but the node still owns substantial live layer traversal and renderer state orchestration. +- `NodeCanvas` post-draw callback assembly now also routes through + `execute_legacy_canvas_draw_merge_post_draw_callbacks(...)`, and the + remaining per-layer render-path orchestration now also routes through + `execute_legacy_canvas_draw_merge_layer_path(...)`, but the node still owns + broader draw-loop and renderer-state shell sequencing. Write scope: - `src/node_stroke_preview.cpp` @@ -246,12 +258,18 @@ targets look like helpers under one old monolith. #### ARC-APP-001 - Split `app_layout.cpp` Into UI Binding Modules -Status: Ready +Status: In Progress Why now: -`src/app_layout.cpp` is still a 2026-line mixed file that builds menus, +`src/app_layout.cpp` is still a 1498-line mixed file that builds menus, attaches callbacks, computes planner inputs, and mutates UI state directly. +Current slice: +- Tools-menu UI binding, including the nested panels/options submenu wiring, + now lives in `src/app_layout_tools_menu.cpp`, and `App::init_menu_tools()` + is now a thin call-through, but file/about/layer/sidebar and broader layout + composition are still inline in `src/app_layout.cpp`. + Write scope: - `src/app_layout.cpp` - `src/legacy_app_shell_services.*` diff --git a/src/app_layout.cpp b/src/app_layout.cpp index 131cbbc9..0f220496 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -33,6 +33,10 @@ #include +namespace pp::panopainter { +void bind_legacy_tools_menu(App& app); +} + namespace { bool apply_brush_color_plan(App& app, glm::vec4 color, bool update_quick, bool update_color_panel) @@ -897,441 +901,7 @@ void App::init_menu_edit() void App::init_menu_tools() { - auto main = layout[main_id]; - - if (auto menu_exp = main->find("menu-tools")) - { - menu_exp->on_click = [this, menu_exp, main](Node*) { - glm::vec2 pos = menu_exp->m_pos + glm::vec2(0, menu_exp->m_size.y); - auto popup_exp = add_menu_popup(*this, "tools-menu", pos, menu_exp->m_size.x); - if (!popup_exp) - return; - - if (auto tick = popup_exp->find("tools-panels")) tick->on_click = [this, popup_exp, main](Node* b) - { - const auto menu_plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::panels); - if (menu_plan.action != pp::app::ToolsMenuAction::show_panels_submenu) - return; - - pp::panopainter::detach_legacy_node_from_parent(*popup_exp); - const auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*main, popup_exp); - if (!popup_exp_overlay) - return; - const auto popup_exp_handle = popup_exp_overlay.value(); - - glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0); - auto popup_time = add_menu_popup(*this, "panels-menu", pos, b->m_size.x); - if (!popup_time) - { - close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle); - return; - } - pp::panopainter::detach_legacy_node_from_parent(*popup_time); - const auto popup_time_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*main, popup_time); - if (!popup_time_overlay) - { - close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle); - return; - } - const auto popup_time_handle = popup_time_overlay.value(); - - const auto close_panel_popups = [main, popup_exp_handle, popup_time_handle]() - { - close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle); - close_legacy_overlay_handle_ignoring_status(*main, popup_time_handle); - }; - - auto visible = [this](Node* panel) { - if (!panel) - return false; - for (auto& c : floatings_container->m_children) - { - if (auto fp = std::static_pointer_cast(c)) - { - if (fp->m_container->is_child(panel)) - return true; - } - } - return false; - }; - - popup_time->find("panel-presets")->on_click = [this, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::presets, - visible(floating_presets.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Presets; - apply_tools_panel_chrome(*fpanel, plan); - if (!floating_presets) - { - floating_presets = fpanel->m_container->add_child_ref(); - floating_presets->SetHeightP(100); - //floating_presets->SetFlexGrow(1); - //floating_presets->find("toolbar")->destroy(); - floating_presets->on_brush_changed = [this](Node* target, std::shared_ptr& b) { - apply_brush_preset_plan(*this, b); - }; - } - else - { - fpanel->m_container->add_child(floating_presets); - } - close_panel_popups(); - }; - - popup_time->find("panel-color")->on_click = [this, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::color, - visible(floating_color.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Color; - apply_tools_panel_chrome(*fpanel, plan); - if (!floating_color) - { - floating_color = fpanel->m_container->add_child_ref(); - floating_color->SetHeightP(100); - //floating_color->SetMinHeight(300); - if (plan.hides_embedded_title) - floating_color->find("title")->SetVisibility(false); - floating_color->on_color_changed = [this](Node* target, glm::vec4 color) { - apply_brush_color_plan(*this, color, false, false); - }; - } - else - { - fpanel->m_container->add_child(floating_color); - } - close_panel_popups(); - }; - popup_time->find("panel-color-adv")->on_click = [this, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::color_advanced, - visible(floating_picker.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::ColorAdv; - apply_tools_panel_chrome(*fpanel, plan); - if (!floating_picker) - { - floating_picker = fpanel->m_container->add_child_ref(); - //floating_picker->find("title")->SetVisibility(false); - //floating_picker->SetHeightP(100); - //floating_picker->SetWidth(250); - floating_picker->m_autohide = false; - floating_picker->on_color_change = [this](Node* target, glm::vec3 color) { - apply_brush_color_plan(*this, glm::vec4(color, 1.f), false, false); - }; - } - else - { - fpanel->m_container->add_child(floating_picker); - } - close_panel_popups(); - }; - popup_time->find("panel-layers")->on_click = [this, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::layers, - visible(layers.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Layers; - apply_tools_panel_chrome(*fpanel, plan); - fpanel->m_container->add_child(layers); - layers->SetPositioning(YGPositionTypeRelative); - layers->SetPosition(0, 0); - layers->SetWidthP(100); - layers->SetHeightP(100); - layers->SetFlexShrink(0); - if (plan.hides_embedded_title) - layers->find("title")->SetVisibility(false); - - close_panel_popups(); - }; - popup_time->find("panel-brush")->on_click = [this, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::brush, - visible(stroke.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Brush; - fpanel->m_container->add_child(stroke); - apply_tools_panel_chrome(*fpanel, plan); - stroke->SetPositioning(YGPositionTypeRelative); - stroke->SetPosition(0, 0); - stroke->SetWidthP(100); - stroke->SetHeightP(100); - if (plan.hides_embedded_title) - stroke->find("title")->SetVisibility(false); - - close_panel_popups(); - }; - popup_time->find("panel-grids")->on_click = [this, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::grids, - visible(grid.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Grids; - fpanel->m_container->add_child(grid); - apply_tools_panel_chrome(*fpanel, plan); - grid->SetPositioning(YGPositionTypeRelative); - grid->SetPosition(0, 0); - grid->SetWidthP(100); - grid->SetHeightP(100); - if (plan.hides_embedded_title) - grid->find("title")->SetVisibility(false); - - close_panel_popups(); - }; - popup_time->find("panel-animation")->on_click = [this, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::animation, - visible(animation.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Animation; - fpanel->m_container->add_child(animation); - apply_tools_panel_chrome(*fpanel, plan); - animation->SetPositioning(YGPositionTypeRelative); - animation->SetPosition(0, 0); - animation->SetWidthP(100); - animation->SetHeightP(100); - - close_panel_popups(); - }; - }; - - if (auto options = popup_exp->find("tools-options")) options->on_click = [this, options, main](Node* b) - { - const auto menu_plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::options); - if (menu_plan.action != pp::app::ToolsMenuAction::show_options_submenu) - return; - - glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0); - auto popup_time = add_menu_popup(*this, "options-menu", pos, b->m_size.x); - if (!popup_time) - return; - - if (auto ui_scale = popup_time->find("tools-ui-scale")) - { - std::vector scale_options; - scale_options.reserve(ui_scale->m_data.size()); - for (int i = 0; i < ui_scale->m_data.size(); i++) - scale_options.push_back(ui_scale->get_float(i)); - - const auto selection = pp::app::plan_scale_option_selection(App::I->zoom, scale_options); - if (selection.has_selection) - ui_scale->set_index(static_cast(selection.index)); - - ui_scale->on_select = [ui_scale](Node* target, int index) - { - const auto status = pp::panopainter::execute_legacy_ui_scale_preference( - *App::I, - ui_scale->get_float(index)); - if (!status.ok()) - LOG("UI scale preference failed: %s", status.message); - }; - } - - if (auto vp_scale = popup_time->find("tools-vp-scale")) - { - std::vector scale_options; - scale_options.reserve(vp_scale->m_data.size()); - for (int i = 0; i < vp_scale->m_data.size(); i++) - scale_options.push_back(vp_scale->get_float(i)); - - const auto selection = pp::app::plan_scale_option_selection(App::I->canvas->m_density, scale_options); - if (selection.has_selection) - vp_scale->set_index(static_cast(selection.index)); - - vp_scale->on_select = [vp_scale](Node* target, int index) - { - const auto status = pp::panopainter::execute_legacy_viewport_scale_preference( - *App::I, - vp_scale->get_float(index)); - if (!status.ok()) - LOG("Viewport scale preference failed: %s", status.message); - }; - } - - if (auto rtl_btn = popup_time->find("tools-rtl")) - { - NodeCheckBox* cb = rtl_btn->find("tools-rtl-check"); - cb->set_value(ui_rtl, false); - - rtl_btn->on_click = [this, rtl_btn](Node* b) - { - NodeCheckBox* cb = rtl_btn->find("tools-rtl-check"); - cb->set_value(!cb->checked, true); - }; - - rtl_btn->find("tools-rtl-check")->on_value_changed = [this, main](Node*, bool checked) - { - const auto status = pp::panopainter::execute_legacy_interface_direction_preference( - *this, - checked); - if (!status.ok()) - LOG("Interface direction preference failed: %s", status.message); - }; - } - - if (auto vr_btn = popup_time->find("tools-vr")) - { - NodeCheckBox* cb = vr_btn->find("tools-vr-check"); - cb->set_value(has_vr); - - vr_btn->on_click = [this, vr_btn](Node* b) - { - NodeCheckBox* cb = vr_btn->find("tools-vr-check"); - cb->set_value(!cb->checked, true); - }; - - vr_btn->find("tools-vr-check")->on_value_changed = [this, main](Node* target, bool checked) - { - const auto status = pp::panopainter::execute_legacy_vr_mode_preference( - *this, - checked); - if (!status.ok()) { - auto cb = static_cast(target); - cb->set_value(false); - message_box("VR Failed", "Couldn't start Virtual Reality mode"); - } - }; - } - - if (auto vr_btn = popup_time->find("tools-vr-controllers")) - { - NodeCheckBox* cb = vr_btn->find("tools-vr-controllers-check"); - cb->set_value(vr_controllers_enabled); - - vr_btn->on_click = [this, vr_btn](Node* b) - { - NodeCheckBox* cb = vr_btn->find("tools-vr-controllers-check"); - cb->set_value(!cb->checked, true); - }; - - vr_btn->find("tools-vr-controllers-check")->on_value_changed = [this, main](Node* target, bool checked) - { - const auto status = pp::panopainter::execute_legacy_vr_controllers_preference( - *this, - checked); - if (!status.ok()) - LOG("VR controllers preference failed: %s", status.message); - }; - } - - if (auto btn = popup_time->find("tools-timelapse")) - { - NodeCheckBox* cb = btn->find("tools-timelapse-check"); - cb->set_value( - pp::panopainter::read_legacy_startup_preferences(vr_controllers_enabled).auto_timelapse, - false); - - btn->on_click = [this, btn](Node* b) - { - NodeCheckBox* cb = btn->find("tools-timelapse-check"); - cb->set_value(!cb->checked, true); - }; - - btn->find("tools-timelapse-check")->on_value_changed = [this, main](Node*, bool checked) - { - const auto status = pp::panopainter::execute_legacy_timelapse_preference( - *this, - checked); - if (!status.ok()) - LOG("Timelapse preference failed: %s", status.message); - }; - } - - if (auto mode = popup_time->find("tools-show-cursor")) - { - mode->set_index(pp::panopainter::read_legacy_canvas_preferences().cursor_mode); - - mode->on_select = [mode](Node* target, int index) - { - const auto status = pp::panopainter::execute_legacy_canvas_cursor_mode_preference( - *App::I, - index); - if (!status.ok()) - LOG("Cursor mode preference failed: %s", status.message); - }; - } - }; - - popup_exp->find("clear-grids")->on_click = [this, popup_exp](Node*) { - auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp); - if (!popup_exp_overlay) - return; - const auto popup_exp_handle = popup_exp_overlay.value(); - const auto plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::clear_grids); - execute_tools_menu_plan(*this, plan); - if (plan.closes_root_popup) - { - close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle); - } - }; - - popup_exp->find("camera-reset")->on_click = [this, popup_exp](Node*) { - auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp); - if (!popup_exp_overlay) - return; - const auto popup_exp_handle = popup_exp_overlay.value(); - const auto plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::reset_camera); - execute_tools_menu_plan(*this, plan); - if (plan.closes_root_popup) - { - close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle); - } - }; - - popup_exp->find("shortcuts")->on_click = [this, popup_exp](Node*) { - auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp); - if (!popup_exp_overlay) - return; - const auto popup_exp_handle = popup_exp_overlay.value(); - const auto plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::shortcuts); - execute_tools_menu_plan(*this, plan); - if (plan.closes_root_popup) - { - close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle); - } - }; - -/* - popup_exp->find("mp4test")->on_click = [this, popup_exp](Node*) { - dialog_export_mp4(); - pp::panopainter::close_legacy_popup_overlay(*popup_exp); - }; -*/ - - if (platform_supports_sonarpen()) - { - popup_exp->find("sonarpen")->on_click = [this, popup_exp](Node*) { - auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp); - if (!popup_exp_overlay) - return; - const auto popup_exp_handle = popup_exp_overlay.value(); - const auto plan = pp::app::plan_tools_menu_command( - pp::app::ToolsMenuCommand::sonarpen, - platform_supports_sonarpen()); - execute_tools_menu_plan(*this, plan); - if (plan.closes_root_popup) - { - close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle); - } - }; - } - }; - } + pp::panopainter::bind_legacy_tools_menu(*this); } void App::init_menu_about() diff --git a/src/app_layout_tools_menu.cpp b/src/app_layout_tools_menu.cpp new file mode 100644 index 00000000..0dbfce8b --- /dev/null +++ b/src/app_layout_tools_menu.cpp @@ -0,0 +1,507 @@ +#include "pch.h" +#include "app.h" +#include "app_core/app_preferences.h" +#include "app_core/brush_ui.h" +#include "app_core/tools_menu.h" +#include "legacy_brush_ui_services.h" +#include "legacy_app_preference_services.h" +#include "legacy_app_shell_services.h" +#include "legacy_preference_storage.h" +#include "legacy_ui_overlay_services.h" +#include "node_button_custom.h" +#include "node_checkbox.h" +#include "node_combobox.h" +#include "node_dialog_picker.h" +#include "node_panel_animation.h" +#include "node_panel_brush.h" +#include "node_panel_color.h" +#include "node_panel_floating.h" +#include "node_panel_grid.h" +#include "node_panel_layer.h" +#include "node_panel_stroke.h" +#include "node_popup_menu.h" + +#include + +namespace { + +[[nodiscard]] bool should_open_tools_panel(const pp::app::ToolsPanelPlan& plan) noexcept +{ + return plan.action == pp::app::ToolsPanelAction::open_floating_panel; +} + +void apply_tools_panel_chrome(NodePanelFloating& panel, const pp::app::ToolsPanelPlan& plan) +{ + if (plan.width > 0 && plan.height > 0) { + panel.SetSize(static_cast(plan.width), static_cast(plan.height)); + } else { + if (plan.width > 0) + panel.SetWidth(static_cast(plan.width)); + if (plan.height > 0) + panel.SetHeight(static_cast(plan.height)); + } + if (plan.min_width > 0) + panel.SetMinWidth(static_cast(plan.min_width)); + if (plan.min_height > 0) + panel.SetMinHeight(static_cast(plan.min_height)); + panel.m_title->set_text(plan.title.data()); + panel.m_droppable = plan.droppable; +} + +std::shared_ptr add_menu_popup( + App& app, + const char* template_id, + glm::vec2 position, + float rtl_anchor_width) +{ + const auto popup = pp::panopainter::add_legacy_popup_menu( + app, + template_id, + position.x, + position.y, + rtl_anchor_width); + if (!popup) { + LOG("Popup menu '%s' failed: %s", template_id ? template_id : "", popup.status().message); + return nullptr; + } + return popup.value(); +} + +} // namespace + +namespace pp::panopainter { + +void bind_legacy_tools_menu(App& app) +{ + auto main = app.layout[app.main_id]; + + if (auto menu_exp = main->find("menu-tools")) + { + menu_exp->on_click = [&app, menu_exp, main](Node*) { + glm::vec2 pos = menu_exp->m_pos + glm::vec2(0, menu_exp->m_size.y); + auto popup_exp = add_menu_popup(app, "tools-menu", pos, menu_exp->m_size.x); + if (!popup_exp) + return; + + if (auto tick = popup_exp->find("tools-panels")) tick->on_click = [&app, popup_exp, main](Node* b) + { + const auto menu_plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::panels); + if (menu_plan.action != pp::app::ToolsMenuAction::show_panels_submenu) + return; + + pp::panopainter::detach_legacy_node_from_parent(*popup_exp); + const auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*main, popup_exp); + if (!popup_exp_overlay) + return; + const auto popup_exp_handle = popup_exp_overlay.value(); + + glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0); + auto popup_time = add_menu_popup(app, "panels-menu", pos, b->m_size.x); + if (!popup_time) + { + close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle); + return; + } + pp::panopainter::detach_legacy_node_from_parent(*popup_time); + const auto popup_time_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*main, popup_time); + if (!popup_time_overlay) + { + close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle); + return; + } + const auto popup_time_handle = popup_time_overlay.value(); + + const auto close_panel_popups = [main, popup_exp_handle, popup_time_handle]() + { + close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle); + close_legacy_overlay_handle_ignoring_status(*main, popup_time_handle); + }; + + auto visible = [&app](Node* panel) { + if (!panel) + return false; + for (auto& c : app.floatings_container->m_children) + { + if (auto fp = std::static_pointer_cast(c)) + { + if (fp->m_container->is_child(panel)) + return true; + } + } + return false; + }; + + popup_time->find("panel-presets")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::presets, + visible(app.floating_presets.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Presets; + apply_tools_panel_chrome(*fpanel, plan); + if (!app.floating_presets) + { + app.floating_presets = fpanel->m_container->add_child_ref(); + app.floating_presets->SetHeightP(100); + app.floating_presets->on_brush_changed = [&app](Node*, std::shared_ptr& b) { + (void)pp::panopainter::apply_legacy_brush_preset_plan(app, b); + }; + } + else + { + fpanel->m_container->add_child(app.floating_presets); + } + close_panel_popups(); + }; + + popup_time->find("panel-color")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::color, + visible(app.floating_color.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Color; + apply_tools_panel_chrome(*fpanel, plan); + if (!app.floating_color) + { + app.floating_color = fpanel->m_container->add_child_ref(); + app.floating_color->SetHeightP(100); + if (plan.hides_embedded_title) + app.floating_color->find("title")->SetVisibility(false); + app.floating_color->on_color_changed = [&app](Node*, glm::vec4 color) { + (void)pp::panopainter::apply_legacy_brush_color_plan(app, color, false, false); + }; + } + else + { + fpanel->m_container->add_child(app.floating_color); + } + close_panel_popups(); + }; + popup_time->find("panel-color-adv")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::color_advanced, + visible(app.floating_picker.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::ColorAdv; + apply_tools_panel_chrome(*fpanel, plan); + if (!app.floating_picker) + { + app.floating_picker = fpanel->m_container->add_child_ref(); + app.floating_picker->m_autohide = false; + app.floating_picker->on_color_change = [&app](Node*, glm::vec3 color) { + (void)pp::panopainter::apply_legacy_brush_color_plan(app, glm::vec4(color, 1.f), false, false); + }; + } + else + { + fpanel->m_container->add_child(app.floating_picker); + } + close_panel_popups(); + }; + popup_time->find("panel-layers")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::layers, + visible(app.layers.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Layers; + apply_tools_panel_chrome(*fpanel, plan); + fpanel->m_container->add_child(app.layers); + app.layers->SetPositioning(YGPositionTypeRelative); + app.layers->SetPosition(0, 0); + app.layers->SetWidthP(100); + app.layers->SetHeightP(100); + app.layers->SetFlexShrink(0); + if (plan.hides_embedded_title) + app.layers->find("title")->SetVisibility(false); + + close_panel_popups(); + }; + popup_time->find("panel-brush")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::brush, + visible(app.stroke.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Brush; + fpanel->m_container->add_child(app.stroke); + apply_tools_panel_chrome(*fpanel, plan); + app.stroke->SetPositioning(YGPositionTypeRelative); + app.stroke->SetPosition(0, 0); + app.stroke->SetWidthP(100); + app.stroke->SetHeightP(100); + if (plan.hides_embedded_title) + app.stroke->find("title")->SetVisibility(false); + + close_panel_popups(); + }; + popup_time->find("panel-grids")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::grids, + visible(app.grid.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Grids; + fpanel->m_container->add_child(app.grid); + apply_tools_panel_chrome(*fpanel, plan); + app.grid->SetPositioning(YGPositionTypeRelative); + app.grid->SetPosition(0, 0); + app.grid->SetWidthP(100); + app.grid->SetHeightP(100); + if (plan.hides_embedded_title) + app.grid->find("title")->SetVisibility(false); + + close_panel_popups(); + }; + popup_time->find("panel-animation")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::animation, + visible(app.animation.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Animation; + fpanel->m_container->add_child(app.animation); + apply_tools_panel_chrome(*fpanel, plan); + app.animation->SetPositioning(YGPositionTypeRelative); + app.animation->SetPosition(0, 0); + app.animation->SetWidthP(100); + app.animation->SetHeightP(100); + + close_panel_popups(); + }; + }; + + if (auto options = popup_exp->find("tools-options")) options->on_click = [&app, options, main](Node* b) + { + const auto menu_plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::options); + if (menu_plan.action != pp::app::ToolsMenuAction::show_options_submenu) + return; + + glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0); + auto popup_time = add_menu_popup(app, "options-menu", pos, b->m_size.x); + if (!popup_time) + return; + + if (auto ui_scale = popup_time->find("tools-ui-scale")) + { + std::vector scale_options; + scale_options.reserve(ui_scale->m_data.size()); + for (int i = 0; i < ui_scale->m_data.size(); i++) + scale_options.push_back(ui_scale->get_float(i)); + + const auto selection = pp::app::plan_scale_option_selection(App::I->zoom, scale_options); + if (selection.has_selection) + ui_scale->set_index(static_cast(selection.index)); + + ui_scale->on_select = [ui_scale](Node*, int index) + { + const auto status = pp::panopainter::execute_legacy_ui_scale_preference( + *App::I, + ui_scale->get_float(index)); + if (!status.ok()) + LOG("UI scale preference failed: %s", status.message); + }; + } + + if (auto vp_scale = popup_time->find("tools-vp-scale")) + { + std::vector scale_options; + scale_options.reserve(vp_scale->m_data.size()); + for (int i = 0; i < vp_scale->m_data.size(); i++) + scale_options.push_back(vp_scale->get_float(i)); + + const auto selection = pp::app::plan_scale_option_selection(App::I->canvas->m_density, scale_options); + if (selection.has_selection) + vp_scale->set_index(static_cast(selection.index)); + + vp_scale->on_select = [vp_scale](Node*, int index) + { + const auto status = pp::panopainter::execute_legacy_viewport_scale_preference( + *App::I, + vp_scale->get_float(index)); + if (!status.ok()) + LOG("Viewport scale preference failed: %s", status.message); + }; + } + + if (auto rtl_btn = popup_time->find("tools-rtl")) + { + NodeCheckBox* cb = rtl_btn->find("tools-rtl-check"); + cb->set_value(app.ui_rtl, false); + + rtl_btn->on_click = [rtl_btn](Node*) + { + NodeCheckBox* cb = rtl_btn->find("tools-rtl-check"); + cb->set_value(!cb->checked, true); + }; + + rtl_btn->find("tools-rtl-check")->on_value_changed = [&app](Node*, bool checked) + { + const auto status = pp::panopainter::execute_legacy_interface_direction_preference( + app, + checked); + if (!status.ok()) + LOG("Interface direction preference failed: %s", status.message); + }; + } + + if (auto vr_btn = popup_time->find("tools-vr")) + { + NodeCheckBox* cb = vr_btn->find("tools-vr-check"); + cb->set_value(app.has_vr); + + vr_btn->on_click = [vr_btn](Node*) + { + NodeCheckBox* cb = vr_btn->find("tools-vr-check"); + cb->set_value(!cb->checked, true); + }; + + vr_btn->find("tools-vr-check")->on_value_changed = [&app](Node* target, bool checked) + { + const auto status = pp::panopainter::execute_legacy_vr_mode_preference( + app, + checked); + if (!status.ok()) { + auto cb = static_cast(target); + cb->set_value(false); + app.message_box("VR Failed", "Couldn't start Virtual Reality mode"); + } + }; + } + + if (auto vr_btn = popup_time->find("tools-vr-controllers")) + { + NodeCheckBox* cb = vr_btn->find("tools-vr-controllers-check"); + cb->set_value(app.vr_controllers_enabled); + + vr_btn->on_click = [vr_btn](Node*) + { + NodeCheckBox* cb = vr_btn->find("tools-vr-controllers-check"); + cb->set_value(!cb->checked, true); + }; + + vr_btn->find("tools-vr-controllers-check")->on_value_changed = [&app](Node*, bool checked) + { + const auto status = pp::panopainter::execute_legacy_vr_controllers_preference( + app, + checked); + if (!status.ok()) + LOG("VR controllers preference failed: %s", status.message); + }; + } + + if (auto btn = popup_time->find("tools-timelapse")) + { + NodeCheckBox* cb = btn->find("tools-timelapse-check"); + cb->set_value( + pp::panopainter::read_legacy_startup_preferences(app.vr_controllers_enabled).auto_timelapse, + false); + + btn->on_click = [btn](Node*) + { + NodeCheckBox* cb = btn->find("tools-timelapse-check"); + cb->set_value(!cb->checked, true); + }; + + btn->find("tools-timelapse-check")->on_value_changed = [&app](Node*, bool checked) + { + const auto status = pp::panopainter::execute_legacy_timelapse_preference( + app, + checked); + if (!status.ok()) + LOG("Timelapse preference failed: %s", status.message); + }; + } + + if (auto mode = popup_time->find("tools-show-cursor")) + { + mode->set_index(pp::panopainter::read_legacy_canvas_preferences().cursor_mode); + + mode->on_select = [](Node*, int index) + { + const auto status = pp::panopainter::execute_legacy_canvas_cursor_mode_preference( + *App::I, + index); + if (!status.ok()) + LOG("Cursor mode preference failed: %s", status.message); + }; + } + }; + + popup_exp->find("clear-grids")->on_click = [&app, popup_exp](Node*) { + auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp); + if (!popup_exp_overlay) + return; + const auto popup_exp_handle = popup_exp_overlay.value(); + const auto plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::clear_grids); + pp::panopainter::execute_legacy_tools_menu_plan(app, plan); + if (plan.closes_root_popup) + { + close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle); + } + }; + + popup_exp->find("camera-reset")->on_click = [&app, popup_exp](Node*) { + auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp); + if (!popup_exp_overlay) + return; + const auto popup_exp_handle = popup_exp_overlay.value(); + const auto plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::reset_camera); + pp::panopainter::execute_legacy_tools_menu_plan(app, plan); + if (plan.closes_root_popup) + { + close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle); + } + }; + + popup_exp->find("shortcuts")->on_click = [&app, popup_exp](Node*) { + auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp); + if (!popup_exp_overlay) + return; + const auto popup_exp_handle = popup_exp_overlay.value(); + const auto plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::shortcuts); + pp::panopainter::execute_legacy_tools_menu_plan(app, plan); + if (plan.closes_root_popup) + { + close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle); + } + }; + +/* + popup_exp->find("mp4test")->on_click = [this, popup_exp](Node*) { + dialog_export_mp4(); + pp::panopainter::close_legacy_popup_overlay(*popup_exp); + }; +*/ + + if (app.platform_supports_sonarpen()) + { + popup_exp->find("sonarpen")->on_click = [&app, popup_exp](Node*) { + auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp); + if (!popup_exp_overlay) + return; + const auto popup_exp_handle = popup_exp_overlay.value(); + const auto plan = pp::app::plan_tools_menu_command( + pp::app::ToolsMenuCommand::sonarpen, + app.platform_supports_sonarpen()); + pp::panopainter::execute_legacy_tools_menu_plan(app, plan); + if (plan.closes_root_popup) + { + close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle); + } + }; + } + }; + } +} + +} // namespace pp::panopainter diff --git a/src/legacy_canvas_draw_merge_services.h b/src/legacy_canvas_draw_merge_services.h index c4c9d627..26e26a3d 100644 --- a/src/legacy_canvas_draw_merge_services.h +++ b/src/legacy_canvas_draw_merge_services.h @@ -4,6 +4,7 @@ #include #include +#include namespace pp::panopainter { @@ -114,6 +115,21 @@ struct LegacyCanvasDrawMergeLayerPlaneExecution { std::function draw_blend; }; +struct LegacyCanvasDrawMergeLayerPathExecution { + std::function bind_blender_framebuffer; + std::function clear_blender_framebuffer; + std::function unbind_blender_framebuffer; + std::function prepare_temporary_erase; + std::function cleanup_temporary_erase; + std::function prepare_temporary_paint; + std::function cleanup_temporary_paint; + std::function prepare_layer_texture; + std::function cleanup_layer_texture; + std::function draw_blend; + std::function draw_debug_outline; + std::function draw_frame; +}; + struct LegacyCanvasDrawMergeTemporaryCompositeExecution { std::function setup; std::function bind_samplers; @@ -613,6 +629,48 @@ inline void execute_legacy_canvas_draw_merge_layer_plane( } } +inline void execute_legacy_canvas_draw_merge_layer_path( + bool is_temporary_erase, + bool is_temporary_paint, + bool use_blend, + int first_frame, + int last_frame, + const std::function& frame_alpha, + const LegacyCanvasDrawMergeLayerPathExecution& execution) +{ + if (use_blend) { + execution.bind_blender_framebuffer(); + execution.clear_blender_framebuffer(); + } + + if (is_temporary_erase) { + execution.prepare_temporary_erase(); + for (int frame = first_frame; frame <= last_frame; frame++) { + execution.draw_frame(frame, frame_alpha(frame)); + } + execution.cleanup_temporary_erase(); + } else if (is_temporary_paint) { + execution.prepare_temporary_paint(); + for (int frame = first_frame; frame <= last_frame; frame++) { + execution.draw_frame(frame, frame_alpha(frame)); + } + execution.cleanup_temporary_paint(); + } else { + execution.prepare_layer_texture(); + for (int frame = first_frame; frame <= last_frame; frame++) { + execution.draw_frame(frame, frame_alpha(frame)); + } + execution.cleanup_layer_texture(); + } + + if (use_blend) { + execution.unbind_blender_framebuffer(); + execution.draw_blend(); + } + + execution.draw_debug_outline(); +} + inline void execute_legacy_canvas_draw_merge_temporary_composite( const LegacyCanvasDrawMergeTemporaryCompositeExecution& execution) { @@ -759,6 +817,40 @@ inline void execute_legacy_canvas_draw_merge_post_draw( execution.draw_current_modes(); } +template < + typename DrawMaskFree, + typename DrawMaskLine, + typename DrawSmaskFaces, + typename DrawGridModes, + typename DrawHeightmap, + typename DrawCurrentModes> +inline void execute_legacy_canvas_draw_merge_post_draw_callbacks( + bool smask_active, + bool draw_mask_overlay, + int smask_mode, + bool draw_grid_modes_enabled, + DrawMaskFree&& draw_mask_free, + DrawMaskLine&& draw_mask_line, + DrawSmaskFaces&& draw_smask_faces, + DrawGridModes&& draw_grid_modes_callback, + DrawHeightmap&& draw_heightmap, + DrawCurrentModes&& draw_current_modes) +{ + execute_legacy_canvas_draw_merge_post_draw( + smask_active, + draw_mask_overlay, + smask_mode, + draw_grid_modes_enabled, + LegacyCanvasDrawMergePostDrawExecution { + .draw_mask_free = std::forward(draw_mask_free), + .draw_mask_line = std::forward(draw_mask_line), + .draw_smask_faces = std::forward(draw_smask_faces), + .draw_grid_modes = std::forward(draw_grid_modes_callback), + .draw_heightmap = std::forward(draw_heightmap), + .draw_current_modes = std::forward(draw_current_modes), + }); +} + inline void execute_legacy_canvas_draw_merge_smask_faces( const LegacyCanvasDrawMergeTextureMaskUniforms& uniforms, const glm::mat4& proj, diff --git a/src/legacy_canvas_state_services.cpp b/src/legacy_canvas_state_services.cpp index ebfb8581..536ede60 100644 --- a/src/legacy_canvas_state_services.cpp +++ b/src/legacy_canvas_state_services.cpp @@ -3,6 +3,26 @@ #include "canvas.h" #include "app.h" +#include "renderer_gl/opengl_capabilities.h" + +namespace { + +GLint current_canvas_stroke_internal_format() +{ + const auto renderer_features = ShaderManager::render_device_features(); + if (renderer_features.float32_linear_filtering) + return static_cast(pp::renderer::gl::rgba32f_internal_format()); + if (renderer_features.float16_render_targets) + return static_cast(pp::renderer::gl::rgba16f_internal_format()); + return static_cast(pp::renderer::gl::rgba8_internal_format()); +} + +GLint rgba8_internal_format() +{ + return static_cast(pp::renderer::gl::rgba8_internal_format()); +} + +} // namespace void Canvas::pick_start() { diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index a9af7b5d..156c0fe7 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -476,7 +476,7 @@ void NodeCanvas::draw() plane_index, m_canvas->m_layers[layer_index]->m_opacity); - pp::panopainter::execute_legacy_canvas_draw_merge_layer_plane( + pp::panopainter::execute_legacy_canvas_draw_merge_layer_path( m_canvas->m_current_stroke && m_canvas->m_current_mode == kCanvasMode::Erase && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index, m_canvas->m_current_stroke && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index, use_blend, @@ -515,9 +515,6 @@ void NodeCanvas::draw() set_active_texture_unit(2); m_canvas->m_smask.rtt(plane_index).bindTexture(); }, - .draw_temporary_erase_frame = [&](int frame, float onion_alpha) { - draw_layer_frame(frame, onion_alpha); - }, .cleanup_temporary_erase = [&] { set_active_texture_unit(2); m_canvas->m_smask.rtt(plane_index).unbindTexture(); @@ -571,9 +568,6 @@ void NodeCanvas::draw() b->m_pattern_texture->bind() : unbind_texture_2d(); }, - .draw_temporary_paint_frame = [&](int frame, float onion_alpha) { - draw_layer_frame(frame, onion_alpha); - }, .cleanup_temporary_paint = [&] { set_active_texture_unit(3); if (b->m_dual_enabled) @@ -593,9 +587,6 @@ void NodeCanvas::draw() .highlight = m_canvas->m_layers[layer_index]->m_hightlight, }); }, - .draw_layer_texture_frame = [&](int frame, float onion_alpha) { - draw_layer_frame(frame, onion_alpha); - }, .cleanup_layer_texture = [&] { }, .draw_blend = [&] { @@ -637,24 +628,28 @@ void NodeCanvas::draw() set_active_texture_unit(0); m_blender_rtt.unbindTexture(); }, + .draw_debug_outline = +#ifdef _DEBUG + [&] { + auto bb = m_canvas->m_layers[layer_index]->box(plane_index) / (float)m_canvas->m_layers[layer_index]->w; + glm::vec2 bbmin = xy(bb); + glm::vec2 bbsz = zw(bb) - xy(bb); + pp::panopainter::configure_legacy_ui_color_shader( + plane_mvp_z + * glm::translate(glm::vec3(bbmin * 2.f, 0)) + * glm::translate(glm::vec3(-1, -1, 0)) + * glm::scale(glm::vec3(bbsz, 1)) + * glm::translate(glm::vec3(1, 1, 0)), + { 1, 0, 0, 1 }); + m_face_plane.draw_stroke(); + }, +#else + [] { + }, +#endif + .draw_frame = draw_layer_frame, }); - #ifdef _DEBUG - // draw dirty area - { - auto bb = m_canvas->m_layers[layer_index]->box(plane_index) / (float)m_canvas->m_layers[layer_index]->w; - glm::vec2 bbmin = xy(bb); - glm::vec2 bbsz = zw(bb) - xy(bb); - pp::panopainter::configure_legacy_ui_color_shader( - plane_mvp_z - * glm::translate(glm::vec3(bbmin * 2.f, 0)) - * glm::translate(glm::vec3(-1, -1, 0)) - * glm::scale(glm::vec3(bbsz, 1)) - * glm::translate(glm::vec3(1, 1, 0)), - { 1, 0, 0, 1 }); - m_face_plane.draw_stroke(); - } - #endif } } if (use_blend) @@ -705,58 +700,56 @@ void NodeCanvas::draw() apply_node_canvas_capability(pp::renderer::gl::depth_test_state(), false); - pp::panopainter::execute_legacy_canvas_draw_merge_post_draw( + pp::panopainter::execute_legacy_canvas_draw_merge_post_draw_callbacks( m_canvas->m_smask_active, m_canvas->m_current_mode == kCanvasMode::Copy || m_canvas->m_current_mode == kCanvasMode::Cut, m_canvas->m_smask_mode, m_canvas->m_current_mode != kCanvasMode::Grid, - { - .draw_mask_free = [&] { - m_canvas->modes[(int)kCanvasMode::MaskFree][0]->on_Draw(ortho_proj, proj, camera); - }, - .draw_mask_line = [&] { - m_canvas->modes[(int)kCanvasMode::MaskLine][0]->on_Draw(ortho_proj, proj, camera); - }, - .draw_smask_faces = [&] { - pp::panopainter::execute_legacy_canvas_draw_merge_smask_faces( - pp::panopainter::LegacyCanvasDrawMergeTextureMaskUniforms { - .texture_slot = 0, - .pattern_offset = m_outline_pan, + [&] { + m_canvas->modes[(int)kCanvasMode::MaskFree][0]->on_Draw(ortho_proj, proj, camera); + }, + [&] { + m_canvas->modes[(int)kCanvasMode::MaskLine][0]->on_Draw(ortho_proj, proj, camera); + }, + [&] { + pp::panopainter::execute_legacy_canvas_draw_merge_smask_faces( + pp::panopainter::LegacyCanvasDrawMergeTextureMaskUniforms { + .texture_slot = 0, + .pattern_offset = m_outline_pan, + }, + proj, + camera, + m_canvas->m_layers.size() + 500.f, + std::to_array(m_canvas->m_plane_transform), + { + .set_active_texture_unit = [&] { + set_active_texture_unit(0); }, - proj, - camera, - m_canvas->m_layers.size() + 500.f, - std::to_array(m_canvas->m_plane_transform), - { - .set_active_texture_unit = [&] { - set_active_texture_unit(0); - }, - .enable_blend = [&] { - apply_node_canvas_capability(pp::renderer::gl::blend_state(), true); - }, - .bind_face_texture = [&](int plane_index) { - m_canvas->m_smask.rtt(plane_index).bindTexture(); - }, - .draw_face = [&] { - m_face_plane.draw_fill(); - }, - .unbind_face_texture = [&](int plane_index) { - m_canvas->m_smask.rtt(plane_index).unbindTexture(); - }, - }); - }, - .draw_grid_modes = pp::panopainter::make_legacy_canvas_draw_merge_grid_modes_draw( - &Canvas::modes[(int)kCanvasMode::Grid], - ortho_proj, - proj, - camera), - .draw_heightmap = pp::panopainter::make_legacy_canvas_draw_merge_heightmap_draw(App::I->grid.get(), proj, camera), - .draw_current_modes = pp::panopainter::make_legacy_canvas_draw_merge_current_modes_draw( - m_canvas->m_mode, - ortho_proj, - proj, - camera), - }); + .enable_blend = [&] { + apply_node_canvas_capability(pp::renderer::gl::blend_state(), true); + }, + .bind_face_texture = [&](int plane_index) { + m_canvas->m_smask.rtt(plane_index).bindTexture(); + }, + .draw_face = [&] { + m_face_plane.draw_fill(); + }, + .unbind_face_texture = [&](int plane_index) { + m_canvas->m_smask.rtt(plane_index).unbindTexture(); + }, + }); + }, + pp::panopainter::make_legacy_canvas_draw_merge_grid_modes_draw( + &Canvas::modes[(int)kCanvasMode::Grid], + ortho_proj, + proj, + camera), + pp::panopainter::make_legacy_canvas_draw_merge_heightmap_draw(App::I->grid.get(), proj, camera), + pp::panopainter::make_legacy_canvas_draw_merge_current_modes_draw( + m_canvas->m_mode, + ortho_proj, + proj, + camera)); if (m_density != 1.f) {