From acd34540e0a939a94122bb2343803ab283d5e002 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Tue, 16 Jun 2026 12:23:27 +0200 Subject: [PATCH] Extract sidebar, lifecycle shell, and canvas unmerged draw --- cmake/PanoPainterSources.cmake | 3 + docs/modernization/roadmap.md | 15 +- docs/modernization/tasks.md | 13 + src/app_layout.cpp | 406 ---------------- src/app_layout_sidebar.cpp | 435 ++++++++++++++++++ src/legacy_canvas_draw_merge_services.h | 43 ++ src/main.cpp | 62 +-- src/node_canvas.cpp | 148 +++--- .../windows_lifecycle_shell.cpp | 96 ++++ .../windows_lifecycle_shell.h | 29 ++ 10 files changed, 720 insertions(+), 530 deletions(-) create mode 100644 src/app_layout_sidebar.cpp create mode 100644 src/platform_windows/windows_lifecycle_shell.cpp create mode 100644 src/platform_windows/windows_lifecycle_shell.h diff --git a/cmake/PanoPainterSources.cmake b/cmake/PanoPainterSources.cmake index ea801bc9..32efe9e1 100644 --- a/cmake/PanoPainterSources.cmake +++ b/cmake/PanoPainterSources.cmake @@ -97,6 +97,7 @@ set(PP_PANOPAINTER_APP_SOURCES src/app_dialogs_info_openers.cpp src/app_events.cpp src/app_layout.cpp + src/app_layout_sidebar.cpp src/app_layout_about_layer_menu.cpp src/app_layout_file_menu.cpp src/app_layout_tools_menu.cpp @@ -166,6 +167,8 @@ set(PP_PANOPAINTER_UI_SOURCES set(PP_WINDOWS_PLATFORM_SOURCES src/main.cpp src/platform_windows/windows_bootstrap_helpers.cpp + src/platform_windows/windows_lifecycle_shell.cpp + src/platform_windows/windows_lifecycle_shell.h src/platform_windows/windows_platform_services.cpp src/platform_windows/windows_platform_services.h src/platform_windows/windows_splash.cpp diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 097e1415..d2e5fc9d 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -80,13 +80,13 @@ What is still carrying too much live ownership: Current hotspot files: - `src/canvas.cpp`: 2645 lines -- `src/app_layout.cpp`: 1249 lines +- `src/app_layout.cpp`: 785 lines - `src/canvas_modes.cpp`: 1798 lines - `src/node.cpp`: 1551 lines -- `src/main.cpp`: 909 lines +- `src/main.cpp`: 882 lines - `src/node_panel_brush.cpp`: 1197 lines - `src/node_stroke_preview.cpp`: 933 lines -- `src/node_canvas.cpp`: 905 lines +- `src/node_canvas.cpp`: 910 lines - `src/app.cpp`: 502 lines - `src/app_dialogs.cpp`: 142 lines @@ -138,7 +138,9 @@ Current architecture mismatches that must be treated as real blockers: live in `src/app_layout_file_menu.cpp` and `App::init_menu_file()` is now a thin call-through, while about-menu and layer-menu wiring now also live in `src/app_layout_about_layer_menu.cpp` and `App::init_menu_about()` plus - `App::init_menu_layer()` are now thin call-throughs, while the informational + `App::init_menu_layer()` are now thin call-throughs, while sidebar panel + binding and popup wiring now also live in `src/app_layout_sidebar.cpp` and + `App::init_sidebar()` is now a thin call-through, while the informational overlay opener family now also lives in `src/app_dialogs_info_openers.cpp` and the corresponding `App::dialog_*` entrypoints are thinner, while the export/video/PPBR dialog family now also lives in @@ -177,7 +179,10 @@ Current architecture mismatches that must be treated as real blockers: `src/main.cpp`, while RenderDoc startup/frame capture, SHCore DPI bootstrap, Win32 error-string conversion, and the GL debug pre/post callbacks now also live in `src/platform_windows/windows_bootstrap_helpers.cpp` instead of - `src/main.cpp`, + `src/main.cpp`, while Win32 lifecycle running-state, close/shutdown + sequencing, FPS title update/wakeup posting, stylus frame update, window + preference save, and VR lifecycle wrappers now also live in + `src/platform_windows/windows_lifecycle_shell.cpp` instead of `src/main.cpp`, while `App::rec_loop()` now delegates worker-iteration orchestration into the retained recording bridge, `App::update_rec_frames()` now delegates recording label refresh through that same retained recording path, and the diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index b401f776..d4999e1e 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -210,6 +210,11 @@ Current slice: `execute_node_canvas_draw_merge_tail(...)`, which trims another live tail block from `NodeCanvas::draw()` even though the broader outer draw shell is still inline. +- `NodeCanvas` non-`draw_merged` cache/background/layer-traversal/cache- + composite shell now also routes through + `execute_legacy_canvas_draw_unmerged_shell(...)`, which removes another + coherent orchestration block from `NodeCanvas::draw()` even though the + broader node draw loop still lives in `src/node_canvas.cpp`. Write scope: - `src/node_stroke_preview.cpp` @@ -304,6 +309,10 @@ Current slice: `src/app_layout_about_layer_menu.cpp`, and `App::init_menu_about()` plus `App::init_menu_layer()` are now thin call-throughs, but edit/sidebar and broader layout composition are still inline in `src/app_layout.cpp`. +- Sidebar panel binding plus popup wiring now also live in + `src/app_layout_sidebar.cpp`, and `App::init_sidebar()` is now a thin + call-through, but edit-menu wiring and broader layout composition are still + inline in `src/app_layout.cpp`. Write scope: - `src/app_layout.cpp` @@ -460,6 +469,10 @@ Current slice: conversion, `UnadjustWindowRectEx`, and GL debug pre/post callbacks now also live in `src/platform_windows/windows_bootstrap_helpers.cpp` instead of `src/main.cpp` +- Win32 lifecycle running-state, close/shutdown handling, FPS title update and + wakeup posting, stylus frame update, window preference save, and VR + lifecycle wrappers now also live in + `src/platform_windows/windows_lifecycle_shell.cpp` instead of `src/main.cpp` - prepared-file background work now runs through an `AppRuntime`-owned worker queue instead of a retained static worker in `src/app_events.cpp` - canvas async import/export/save/open background work now also runs through an diff --git a/src/app_layout.cpp b/src/app_layout.cpp index 4edb945e..882c5a56 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -74,27 +74,6 @@ std::shared_ptr add_menu_popup( return popup.value(); } -void close_legacy_overlay_handle_ignoring_status( - Node& anchor, - pp::ui::NodeHandle overlay) noexcept -{ - (void)pp::panopainter::close_legacy_overlay_node(anchor, overlay); -} - -template -void close_legacy_overlay_handles_if_open( - Node& anchor, - const PopupOverlay& popup_overlay, - const TickOverlay& tick_overlay) noexcept -{ - if (popup_overlay) { - close_legacy_overlay_handle_ignoring_status(anchor, popup_overlay.value()); - } - if (tick_overlay) { - close_legacy_overlay_handle_ignoring_status(anchor, tick_overlay.value()); - } -} - [[nodiscard]] bool should_open_tools_panel(const pp::app::ToolsPanelPlan& plan) noexcept { return plan.action == pp::app::ToolsPanelAction::open_floating_panel; @@ -135,16 +114,6 @@ void execute_document_layer_merge_plan(App& app, const pp::app::DocumentLayerMer LOG("Layer merge failed: %s", status.message); } -void execute_document_layer_operation_plan( - App& app, - const pp::app::DocumentLayerOperationPlan& plan, - const std::shared_ptr& pending_layer = nullptr) -{ - const auto status = pp::panopainter::execute_legacy_document_layer_operation_plan(app, plan, pending_layer); - if (!status.ok()) - LOG("Layer operation failed: %s", status.message); -} - } // namespace void App::title_update() @@ -263,381 +232,6 @@ void App::init_toolbar_main() } } -template std::shared_ptr create_panel(LayoutManager& manager) -{ - std::shared_ptr ret; - ret = std::make_shared(); - ret->set_manager(&manager); - ret->init(); - ret->create(); - ret->loaded(); - return ret; -} - -void App::init_sidebar() -{ - sidebar = layout[main_id]->find("sidebar"); - canvas = layout[main_id]->find("paint-canvas"); - quick = layout[main_id]->find("panel-quick"); - floatings_container = layout[main_id]->find("floatings"); - - //brushes = layout[main_id]->find("panel-brush"); - //layers = layout[main_id]->find("panel-layer"); - //color = layout[main_id]->find("panel-color"); - //stroke = layout[main_id]->find("panel-stroke"); - - //brushes = find_or_create_panel(panels); - layers = create_panel(layout); - color = create_panel(layout); - stroke = create_panel(layout); - grid = create_panel(layout); - presets = create_panel(layout); - animation = create_panel(layout); - //presets = find_or_create_panel(panels); - - canvas->m_canvas->on_mode_changed = [this](kCanvasMode prev, kCanvasMode mode) { - quick_mode_state[prev] = quick->get_state(); - if (quick_mode_state.find(mode) != quick_mode_state.end()) - quick->set_state(quick_mode_state[mode], true); - else - quick->reset_state(true); - brush_update(true, true); - }; - color->on_color_changed = [this](Node* target, glm::vec4 color) { - apply_brush_color_plan(*this, color, true, false); - }; - - stroke->on_brush_changed = [this](Node* target, const std::string& path, const std::string& thumb) { - apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::tip, path, thumb); - }; - stroke->on_pattern_changed = [this](Node*target, const std::string& path, const std::string& thumb) { - apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::pattern, path, thumb); - }; - stroke->on_dual_changed = [this](Node*target, const std::string& path, const std::string& thumb) { - apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::dual, path, thumb); - }; - stroke->on_stroke_change = [this](Node*) { - const auto status = pp::panopainter::execute_legacy_brush_stroke_changed_plan(*this); - if (!status.ok()) - LOG("Brush stroke settings action failed: %s", status.message); - }; - - quick->on_color_change = [this](Node*, glm::vec3 c) { - apply_brush_color_plan(*this, glm::vec4(c, 1.f), false, true); - }; - quick->on_flow_change = [this](Node*, float value) { - stroke->set_flow(value, true, true); - }; - quick->on_size_change = [this](Node*, float value) { - stroke->set_size(value, true, true); - }; - quick->on_brush_change = [this](Node*, std::shared_ptr b) { - apply_brush_preset_plan(*this, b); - }; - - layers->on_layer_add = [this](Node*, std::shared_ptr layer, int index) { - const auto plan = pp::app::plan_document_layer_add( - static_cast(Canvas::I->m_layers.size()), - index, - layers->m_layers.back()->m_label_text); - if (!plan) - return; - execute_document_layer_operation_plan(*this, plan.value(), layer); - }; - - layers->on_layer_duplicate = [this](Node*, int source_index) { - const auto plan = pp::app::plan_document_layer_duplicate( - static_cast(Canvas::I->m_layers.size()), - source_index); - if (!plan) - return; - execute_document_layer_operation_plan(*this, plan.value()); - }; - - layers->on_layer_change = [this](Node*, int, int new_idx) { - const auto plan = pp::app::plan_document_layer_select( - static_cast(canvas->m_canvas->m_layers.size()), - new_idx); - if (!plan) - return; - execute_document_layer_operation_plan(*this, plan.value()); - }; - - layers->on_layer_order = [this](Node*, int old_idx, int new_idx) { - const auto plan = pp::app::plan_document_layer_reorder( - static_cast(canvas->m_canvas->m_layers.size()), - old_idx, - new_idx); - if (!plan) - return; - execute_document_layer_operation_plan(*this, plan.value()); - }; - - layers->on_layer_delete = [this](Node*, int idx) { - const auto plan = pp::app::plan_document_layer_remove( - static_cast(canvas->m_canvas->m_layers.size()), - idx); - if (!plan) - return; - execute_document_layer_operation_plan(*this, plan.value()); - }; - - layers->on_layer_opacity_changed = [this](Node*, int idx, float value) { - const auto plan = pp::app::plan_document_layer_opacity( - static_cast(canvas->m_canvas->m_layers.size()), - idx, - value); - if (!plan) - return; - execute_document_layer_operation_plan(*this, plan.value()); - }; - - layers->on_layer_visibility_changed = [this](Node*, int idx, bool visible) { - const auto plan = pp::app::plan_document_layer_visibility( - static_cast(canvas->m_canvas->m_layers.size()), - idx, - visible); - if (!plan) - return; - execute_document_layer_operation_plan(*this, plan.value()); - }; - - layers->on_layer_alpha_lock_changed = [this](Node*, int idx, bool locked) { - const auto plan = pp::app::plan_document_layer_alpha_lock( - static_cast(canvas->m_canvas->m_layers.size()), - idx, - locked); - if (!plan) - return; - execute_document_layer_operation_plan(*this, plan.value()); - }; - - layers->on_layer_blend_mode_changed = [this](Node*, int idx, int mode) { - const auto plan = pp::app::plan_document_layer_blend_mode( - static_cast(canvas->m_canvas->m_layers.size()), - idx, - mode); - if (!plan) - return; - execute_document_layer_operation_plan(*this, plan.value()); - }; - - layers->on_layer_highlight_changed = [this](Node*, int idx, bool highlight) { - const auto plan = pp::app::plan_document_layer_highlight( - static_cast(canvas->m_canvas->m_layers.size()), - idx, - highlight); - if (!plan) - return; - execute_document_layer_operation_plan(*this, plan.value()); - }; - if (auto* button = layout[main_id]->find("btn-stroke")) - { - button->on_click = [this, button](Node*) { - auto* popup_root = layout[main_id]; - if (!popup_root) { - return; - } - auto screen = popup_root->m_size; - glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y); - if (stroke->m_parent) - { - if (auto fp = dynamic_cast(stroke->m_parent->m_parent)) - { - pp::panopainter::detach_legacy_node_from_parent(*stroke); - pp::panopainter::close_legacy_dialog_node(*fp); - } - } - const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, stroke); - if (!popup_overlay) { - return; - } - stroke->SetSize(350, glm::max(100.f, screen.y - pos.y - 50.f)); - stroke->find("title")->SetVisibility(true); - auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor(*popup_root); - tick->SetPositioning(YGPositionTypeAbsolute); - tick->SetSize(32, 16); - tick->SetPosition(pos.x - 16, pos.y); - tick->set_image("data/ui/popup-tick-up.png"); - auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick); - if (!popup_overlay || !tick_overlay) - { - close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay); - return; - } - const auto popup_handle = popup_overlay.value(); - const auto tick_handle = tick_overlay.value(); - popup_root->update(); - - stroke->SetPosition(pos.x - stroke->m_size.x / 2.f, pos.y + 16); - stroke->SetPositioning(YGPositionTypeAbsolute); - pp::panopainter::activate_legacy_popup_overlay(*stroke); - auto scroll = stroke->find("scroller"); - //scroll->SetHeight(glm::max(100.f, screen.y - pos.y - 200.f)); - stroke->m_popup_overlay_handle = popup_handle; - stroke->m_tick_overlay_handle = tick_handle; - - }; - } - //if (auto* button = layout[main_id]->find("btn-brush")) - //{ - // button->on_click = [this, button](Node*) { - // panels->get_child_index(brushes.get()) == -1 ? panels->add_child(brushes) : panels->remove_child(brushes.get()); - // panels->fix_scroll(); - // button->set_color(panels->get_child_index(brushes.get()) == -1 ? color_button_normal : color_button_hlight); - // }; - //} - //if (auto* button = layout[main_id]->find("btn-brush-preset")) - //{ - // button->on_click = [this, button](Node*) { - // panels->get_child_index(presets.get()) == -1 ? panels->add_child(presets) : panels->remove_child(presets.get()); - // panels->fix_scroll(); - // button->set_color(panels->get_child_index(presets.get()) == -1 ? color_button_normal : color_button_hlight); - // }; - //} - if (auto* button = layout[main_id]->find("btn-color")) - { - button->on_click = [this, button](Node*) { - auto* popup_root = layout[main_id]; - if (!popup_root) { - return; - } - glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y); - const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, color); - if (!popup_overlay) - { - LOG("Color popup overlay failed: %s", popup_overlay.status().message); - return; - } - color->find("title")->SetVisibility(true); - color->SetSize(350, 350); - auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor(*layout[main_id]); - tick->SetPositioning(YGPositionTypeAbsolute); - tick->SetSize(32, 16); - tick->SetPosition(pos.x - 16, pos.y); - tick->set_image("data/ui/popup-tick-up.png"); - auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick); - if (!popup_overlay || !tick_overlay) - { - close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay); - return; - } - const auto popup_handle = popup_overlay.value(); - const auto tick_handle = tick_overlay.value(); - popup_root->update(); - - color->SetPosition(pos.x - color->m_size.x / 2.f, pos.y + 16); - color->SetPositioning(YGPositionTypeAbsolute); - pp::panopainter::activate_legacy_popup_overlay(*color); - color->on_popup_close = [popup_root, popup_handle, tick_handle](Node*) { - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - close_legacy_overlay_handle_ignoring_status(*popup_root, tick_handle); - }; - }; - } - if (auto* button = layout[main_id]->find("btn-layer")) - { - button->on_click = [this, button](Node*) { - auto* popup_root = layout[main_id]; - if (!popup_root) { - return; - } - auto screen = popup_root->m_size; - glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y); - layers->find("title")->SetVisibility(true); - layers->SetSize(350, YGUndefined); - if (layers->m_parent) - { - if (auto fp = dynamic_cast(layers->m_parent->m_parent)) - { - pp::panopainter::detach_legacy_node_from_parent(*layers); - pp::panopainter::close_legacy_dialog_node(*fp); - } - } - const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, layers); - if (!popup_overlay) { - return; - } - auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor(*popup_root); - tick->SetPositioning(YGPositionTypeAbsolute); - tick->SetSize(32, 16); - tick->SetPosition(pos.x - 16, pos.y); - tick->set_image("data/ui/popup-tick-up.png"); - auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick); - if (!popup_overlay || !tick_overlay) - { - close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay); - return; - } - const auto popup_handle = popup_overlay.value(); - const auto tick_handle = tick_overlay.value(); - popup_root->update(); - - layers->SetPosition(pos.x - layers->m_size.x / 2.f, pos.y + 16); - layers->SetPositioning(YGPositionTypeAbsolute); - pp::panopainter::activate_legacy_popup_overlay(*layers); - auto scroll = layers->find("layers-container"); - scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 200.f)); - layers->on_popup_close = [popup_root, popup_handle, tick_handle](Node*) { - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - close_legacy_overlay_handle_ignoring_status(*popup_root, tick_handle); - }; - - }; - } - if (auto* button = layout[main_id]->find("btn-grids-panel")) - { - button->on_click = [this, button](Node*) { - auto* popup_root = layout[main_id]; - if (!popup_root) { - return; - } - auto screen = popup_root->m_size; - glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y); - grid->find("title")->SetVisibility(true); - grid->SetSize(350, YGUndefined); - if (grid->m_parent) - { - if (auto fp = dynamic_cast(grid->m_parent->m_parent)) - { - pp::panopainter::detach_legacy_node_from_parent(*grid); - pp::panopainter::close_legacy_dialog_node(*fp); - } - } - const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, grid); - if (!popup_overlay) - { - LOG("Grid popup overlay failed: %s", popup_overlay.status().message); - return; - } - auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor(*popup_root); - tick->SetPositioning(YGPositionTypeAbsolute); - tick->SetSize(32, 16); - tick->SetPosition(pos.x - 16, pos.y); - tick->set_image("data/ui/popup-tick-up.png"); - auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick); - if (!popup_overlay || !tick_overlay) - { - close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay); - return; - } - const auto popup_handle = popup_overlay.value(); - const auto tick_handle = tick_overlay.value(); - popup_root->update(); - - grid->SetPosition(pos.x - grid->m_size.x / 2.f, pos.y + 16); - grid->SetPositioning(YGPositionTypeAbsolute); - pp::panopainter::activate_legacy_popup_overlay(*grid); - auto scroll = grid->find("scroller"); - scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 250.f)); - - grid->on_popup_close = [popup_root, popup_handle, tick_handle](Node*) { - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - close_legacy_overlay_handle_ignoring_status(*popup_root, tick_handle); - }; - }; - } -} [[nodiscard]] bool current_canvas_mode_is_draw(App& app) noexcept { return app.canvas && app.canvas->m_canvas && app.canvas->m_canvas->m_current_mode == kCanvasMode::Draw; diff --git a/src/app_layout_sidebar.cpp b/src/app_layout_sidebar.cpp new file mode 100644 index 00000000..49834f18 --- /dev/null +++ b/src/app_layout_sidebar.cpp @@ -0,0 +1,435 @@ +#include "pch.h" +#include "app.h" +#include "node_panel_grid.h" +#include "node_panel_floating.h" +#include "app_core/brush_ui.h" +#include "app_core/document_layer.h" +#include "legacy_brush_ui_services.h" +#include "legacy_document_layer_services.h" +#include "legacy_ui_overlay_services.h" + +namespace { + +bool apply_brush_color_plan(App& app, glm::vec4 color, bool update_quick, bool update_color_panel) +{ + return pp::panopainter::apply_legacy_brush_color_plan(app, color, update_quick, update_color_panel); +} + +bool apply_brush_texture_plan(App& app, pp::app::BrushUiTextureSlot slot, const std::string& path, const std::string& thumb) +{ + return pp::panopainter::apply_legacy_brush_texture_plan(app, slot, path, thumb); +} + +bool apply_brush_preset_plan(App& app, const std::shared_ptr& brush) +{ + return pp::panopainter::apply_legacy_brush_preset_plan(app, brush); +} + +void execute_document_layer_operation_plan( + App& app, + const pp::app::DocumentLayerOperationPlan& plan, + const std::shared_ptr& pending_layer = nullptr) +{ + const auto status = pp::panopainter::execute_legacy_document_layer_operation_plan(app, plan, pending_layer); + if (!status.ok()) + LOG("Layer operation failed: %s", status.message); +} + +void close_legacy_overlay_handle_ignoring_status( + Node& anchor, + pp::ui::NodeHandle overlay) noexcept +{ + (void)pp::panopainter::close_legacy_overlay_node(anchor, overlay); +} + +template +void close_legacy_overlay_handles_if_open( + Node& anchor, + const PopupOverlay& popup_overlay, + const TickOverlay& tick_overlay) noexcept +{ + if (popup_overlay) { + close_legacy_overlay_handle_ignoring_status(anchor, popup_overlay.value()); + } + if (tick_overlay) { + close_legacy_overlay_handle_ignoring_status(anchor, tick_overlay.value()); + } +} + +template +std::shared_ptr create_panel(LayoutManager& manager) +{ + auto ret = std::make_shared(); + ret->set_manager(&manager); + ret->init(); + ret->create(); + ret->loaded(); + return ret; +} + +} // namespace + +void App::init_sidebar() +{ + sidebar = layout[main_id]->find("sidebar"); + canvas = layout[main_id]->find("paint-canvas"); + quick = layout[main_id]->find("panel-quick"); + floatings_container = layout[main_id]->find("floatings"); + + //brushes = layout[main_id]->find("panel-brush"); + //layers = layout[main_id]->find("panel-layer"); + //color = layout[main_id]->find("panel-color"); + //stroke = layout[main_id]->find("panel-stroke"); + + //brushes = find_or_create_panel(panels); + layers = create_panel(layout); + color = create_panel(layout); + stroke = create_panel(layout); + grid = create_panel(layout); + presets = create_panel(layout); + animation = create_panel(layout); + //presets = find_or_create_panel(panels); + + canvas->m_canvas->on_mode_changed = [this](kCanvasMode prev, kCanvasMode mode) { + quick_mode_state[prev] = quick->get_state(); + if (quick_mode_state.find(mode) != quick_mode_state.end()) + quick->set_state(quick_mode_state[mode], true); + else + quick->reset_state(true); + brush_update(true, true); + }; + color->on_color_changed = [this](Node* target, glm::vec4 color) { + apply_brush_color_plan(*this, color, true, false); + }; + + stroke->on_brush_changed = [this](Node* target, const std::string& path, const std::string& thumb) { + apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::tip, path, thumb); + }; + stroke->on_pattern_changed = [this](Node* target, const std::string& path, const std::string& thumb) { + apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::pattern, path, thumb); + }; + stroke->on_dual_changed = [this](Node* target, const std::string& path, const std::string& thumb) { + apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::dual, path, thumb); + }; + stroke->on_stroke_change = [this](Node*) { + const auto status = pp::panopainter::execute_legacy_brush_stroke_changed_plan(*this); + if (!status.ok()) + LOG("Brush stroke settings action failed: %s", status.message); + }; + + quick->on_color_change = [this](Node*, glm::vec3 c) { + apply_brush_color_plan(*this, glm::vec4(c, 1.f), false, true); + }; + quick->on_flow_change = [this](Node*, float value) { + stroke->set_flow(value, true, true); + }; + quick->on_size_change = [this](Node*, float value) { + stroke->set_size(value, true, true); + }; + quick->on_brush_change = [this](Node*, std::shared_ptr b) { + apply_brush_preset_plan(*this, b); + }; + + layers->on_layer_add = [this](Node*, std::shared_ptr layer, int index) { + const auto plan = pp::app::plan_document_layer_add( + static_cast(Canvas::I->m_layers.size()), + index, + layers->m_layers.back()->m_label_text); + if (!plan) + return; + execute_document_layer_operation_plan(*this, plan.value(), layer); + }; + + layers->on_layer_duplicate = [this](Node*, int source_index) { + const auto plan = pp::app::plan_document_layer_duplicate( + static_cast(Canvas::I->m_layers.size()), + source_index); + if (!plan) + return; + execute_document_layer_operation_plan(*this, plan.value()); + }; + + layers->on_layer_change = [this](Node*, int, int new_idx) { + const auto plan = pp::app::plan_document_layer_select( + static_cast(canvas->m_canvas->m_layers.size()), + new_idx); + if (!plan) + return; + execute_document_layer_operation_plan(*this, plan.value()); + }; + + layers->on_layer_order = [this](Node*, int old_idx, int new_idx) { + const auto plan = pp::app::plan_document_layer_reorder( + static_cast(canvas->m_canvas->m_layers.size()), + old_idx, + new_idx); + if (!plan) + return; + execute_document_layer_operation_plan(*this, plan.value()); + }; + + layers->on_layer_delete = [this](Node*, int idx) { + const auto plan = pp::app::plan_document_layer_remove( + static_cast(canvas->m_canvas->m_layers.size()), + idx); + if (!plan) + return; + execute_document_layer_operation_plan(*this, plan.value()); + }; + + layers->on_layer_opacity_changed = [this](Node*, int idx, float value) { + const auto plan = pp::app::plan_document_layer_opacity( + static_cast(canvas->m_canvas->m_layers.size()), + idx, + value); + if (!plan) + return; + execute_document_layer_operation_plan(*this, plan.value()); + }; + + layers->on_layer_visibility_changed = [this](Node*, int idx, bool visible) { + const auto plan = pp::app::plan_document_layer_visibility( + static_cast(canvas->m_canvas->m_layers.size()), + idx, + visible); + if (!plan) + return; + execute_document_layer_operation_plan(*this, plan.value()); + }; + + layers->on_layer_alpha_lock_changed = [this](Node*, int idx, bool locked) { + const auto plan = pp::app::plan_document_layer_alpha_lock( + static_cast(canvas->m_canvas->m_layers.size()), + idx, + locked); + if (!plan) + return; + execute_document_layer_operation_plan(*this, plan.value()); + }; + + layers->on_layer_blend_mode_changed = [this](Node*, int idx, int mode) { + const auto plan = pp::app::plan_document_layer_blend_mode( + static_cast(canvas->m_canvas->m_layers.size()), + idx, + mode); + if (!plan) + return; + execute_document_layer_operation_plan(*this, plan.value()); + }; + + layers->on_layer_highlight_changed = [this](Node*, int idx, bool highlight) { + const auto plan = pp::app::plan_document_layer_highlight( + static_cast(canvas->m_canvas->m_layers.size()), + idx, + highlight); + if (!plan) + return; + execute_document_layer_operation_plan(*this, plan.value()); + }; + if (auto* button = layout[main_id]->find("btn-stroke")) + { + button->on_click = [this, button](Node*) { + auto* popup_root = layout[main_id]; + if (!popup_root) { + return; + } + auto screen = popup_root->m_size; + glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y); + if (stroke->m_parent) + { + if (auto fp = dynamic_cast(stroke->m_parent->m_parent)) + { + pp::panopainter::detach_legacy_node_from_parent(*stroke); + pp::panopainter::close_legacy_dialog_node(*fp); + } + } + const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, stroke); + if (!popup_overlay) { + return; + } + stroke->SetSize(350, glm::max(100.f, screen.y - pos.y - 50.f)); + stroke->find("title")->SetVisibility(true); + auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor(*popup_root); + tick->SetPositioning(YGPositionTypeAbsolute); + tick->SetSize(32, 16); + tick->SetPosition(pos.x - 16, pos.y); + tick->set_image("data/ui/popup-tick-up.png"); + auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick); + if (!popup_overlay || !tick_overlay) + { + close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay); + return; + } + const auto popup_handle = popup_overlay.value(); + const auto tick_handle = tick_overlay.value(); + popup_root->update(); + + stroke->SetPosition(pos.x - stroke->m_size.x / 2.f, pos.y + 16); + stroke->SetPositioning(YGPositionTypeAbsolute); + pp::panopainter::activate_legacy_popup_overlay(*stroke); + auto scroll = stroke->find("scroller"); + (void)scroll; + stroke->m_popup_overlay_handle = popup_handle; + stroke->m_tick_overlay_handle = tick_handle; + + }; + } + //if (auto* button = layout[main_id]->find("btn-brush")) + //{ + // button->on_click = [this, button](Node*) { + // panels->get_child_index(brushes.get()) == -1 ? panels->add_child(brushes) : panels->remove_child(brushes.get()); + // panels->fix_scroll(); + // button->set_color(panels->get_child_index(brushes.get()) == -1 ? color_button_normal : color_button_hlight); + // }; + //} + //if (auto* button = layout[main_id]->find("btn-brush-preset")) + //{ + // button->on_click = [this, button](Node*) { + // panels->get_child_index(presets.get()) == -1 ? panels->add_child(presets) : panels->remove_child(presets.get()); + // panels->fix_scroll(); + // button->set_color(panels->get_child_index(presets.get()) == -1 ? color_button_normal : color_button_hlight); + // }; + //} + if (auto* button = layout[main_id]->find("btn-color")) + { + button->on_click = [this, button](Node*) { + auto* popup_root = layout[main_id]; + if (!popup_root) { + return; + } + glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y); + const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, color); + if (!popup_overlay) + { + LOG("Color popup overlay failed: %s", popup_overlay.status().message); + return; + } + color->find("title")->SetVisibility(true); + color->SetSize(350, 350); + auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor(*layout[main_id]); + tick->SetPositioning(YGPositionTypeAbsolute); + tick->SetSize(32, 16); + tick->SetPosition(pos.x - 16, pos.y); + tick->set_image("data/ui/popup-tick-up.png"); + auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick); + if (!popup_overlay || !tick_overlay) + { + close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay); + return; + } + const auto popup_handle = popup_overlay.value(); + const auto tick_handle = tick_overlay.value(); + popup_root->update(); + + color->SetPosition(pos.x - color->m_size.x / 2.f, pos.y + 16); + color->SetPositioning(YGPositionTypeAbsolute); + pp::panopainter::activate_legacy_popup_overlay(*color); + color->on_popup_close = [popup_root, popup_handle, tick_handle](Node*) { + close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); + close_legacy_overlay_handle_ignoring_status(*popup_root, tick_handle); + }; + }; + } + if (auto* button = layout[main_id]->find("btn-layer")) + { + button->on_click = [this, button](Node*) { + auto* popup_root = layout[main_id]; + if (!popup_root) { + return; + } + auto screen = popup_root->m_size; + glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y); + layers->find("title")->SetVisibility(true); + layers->SetSize(350, YGUndefined); + if (layers->m_parent) + { + if (auto fp = dynamic_cast(layers->m_parent->m_parent)) + { + pp::panopainter::detach_legacy_node_from_parent(*layers); + pp::panopainter::close_legacy_dialog_node(*fp); + } + } + const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, layers); + if (!popup_overlay) { + return; + } + auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor(*popup_root); + tick->SetPositioning(YGPositionTypeAbsolute); + tick->SetSize(32, 16); + tick->SetPosition(pos.x - 16, pos.y); + tick->set_image("data/ui/popup-tick-up.png"); + auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick); + if (!popup_overlay || !tick_overlay) + { + close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay); + return; + } + const auto popup_handle = popup_overlay.value(); + const auto tick_handle = tick_overlay.value(); + popup_root->update(); + + layers->SetPosition(pos.x - layers->m_size.x / 2.f, pos.y + 16); + layers->SetPositioning(YGPositionTypeAbsolute); + pp::panopainter::activate_legacy_popup_overlay(*layers); + auto scroll = layers->find("layers-container"); + scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 200.f)); + layers->on_popup_close = [popup_root, popup_handle, tick_handle](Node*) { + close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); + close_legacy_overlay_handle_ignoring_status(*popup_root, tick_handle); + }; + + }; + } + if (auto* button = layout[main_id]->find("btn-grids-panel")) + { + button->on_click = [this, button](Node*) { + auto* popup_root = layout[main_id]; + if (!popup_root) { + return; + } + auto screen = popup_root->m_size; + glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y); + grid->find("title")->SetVisibility(true); + grid->SetSize(350, YGUndefined); + if (grid->m_parent) + { + if (auto fp = dynamic_cast(grid->m_parent->m_parent)) + { + pp::panopainter::detach_legacy_node_from_parent(*grid); + pp::panopainter::close_legacy_dialog_node(*fp); + } + } + const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, grid); + if (!popup_overlay) + { + LOG("Grid popup overlay failed: %s", popup_overlay.status().message); + return; + } + auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor(*popup_root); + tick->SetPositioning(YGPositionTypeAbsolute); + tick->SetSize(32, 16); + tick->SetPosition(pos.x - 16, pos.y); + tick->set_image("data/ui/popup-tick-up.png"); + auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick); + if (!popup_overlay || !tick_overlay) + { + close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay); + return; + } + const auto popup_handle = popup_overlay.value(); + const auto tick_handle = tick_overlay.value(); + popup_root->update(); + + grid->SetPosition(pos.x - grid->m_size.x / 2.f, pos.y + 16); + grid->SetPositioning(YGPositionTypeAbsolute); + pp::panopainter::activate_legacy_popup_overlay(*grid); + auto scroll = grid->find("scroller"); + scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 250.f)); + + grid->on_popup_close = [popup_root, popup_handle, tick_handle](Node*) { + close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); + close_legacy_overlay_handle_ignoring_status(*popup_root, tick_handle); + }; + }; + } +} diff --git a/src/legacy_canvas_draw_merge_services.h b/src/legacy_canvas_draw_merge_services.h index 820aafd7..29e0703d 100644 --- a/src/legacy_canvas_draw_merge_services.h +++ b/src/legacy_canvas_draw_merge_services.h @@ -945,6 +945,49 @@ inline void execute_legacy_canvas_draw_merge_background_setup( } } +template < + typename PrepareBlendCache, + typename DrawBackground, + typename ConfigureBlendState, + typename DisableDepthTest, + typename PlanOnionRange, + typename ShouldDrawPlane, + typename VisitLayerPlane, + typename LogOnionRangeFailure, + typename CompositeBlendCache> +inline void execute_legacy_canvas_draw_unmerged_shell( + bool use_blend, + size_t layer_count, + PrepareBlendCache&& prepare_blend_cache, + DrawBackground&& draw_background, + ConfigureBlendState&& configure_blend_state, + DisableDepthTest&& disable_depth_test, + PlanOnionRange&& plan_onion_range, + ShouldDrawPlane&& should_draw_plane, + VisitLayerPlane&& visit_layer_plane, + LogOnionRangeFailure&& log_onion_range_failure, + CompositeBlendCache&& composite_blend_cache) +{ + if (use_blend) { + prepare_blend_cache(); + } + + draw_background(); + configure_blend_state(use_blend); + disable_depth_test(); + + execute_legacy_canvas_draw_layer_traversal( + layer_count, + std::forward(plan_onion_range), + std::forward(should_draw_plane), + std::forward(visit_layer_plane), + std::forward(log_onion_range_failure)); + + if (use_blend) { + composite_blend_cache(); + } +} + inline void execute_legacy_canvas_draw_merge_plane_setup( const LegacyCanvasDrawMergePlaneSetupUniforms& uniforms, const LegacyCanvasDrawMergePlaneSetupExecution& execution) diff --git a/src/main.cpp b/src/main.cpp index 2570cd8b..7962edd3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,7 @@ #include "legacy_preference_storage.h" #include "renderer_gl/opengl_capabilities.h" #include "platform_windows/windows_platform_services.h" +#include "platform_windows/windows_lifecycle_shell.h" #include "platform_windows/windows_splash.h" #include "platform_windows/windows_stylus_input.h" #include "platform_windows/windows_vr_shell.h" @@ -30,10 +31,6 @@ #include #include #include -#include - -#define WM_USER_CLOSE (WM_USER + 1) -#define WM_USER_WAKEUP (WM_USER + 2) LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp); namespace pp::platform::windows { @@ -127,13 +124,10 @@ void pp_windows_enqueue_main_task(std::packaged_task task) enqueue_main_task_bridge(std::move(task)); } -std::atomic running{-1}; - void destroy_window() { - auto& state = retained_state(); - enqueue_main_task([hWnd = state.hWnd] { - PostMessage(hWnd, WM_USER_CLOSE, 0, 0); + enqueue_main_task([hWnd = retained_state().hWnd] { + pp::platform::windows::request_window_close(hWnd); }); } @@ -159,25 +153,15 @@ void async_unlock() void win32_update_stylus(float dt) { - pp::platform::windows::update_stylus_state(dt); + pp::platform::windows::update_stylus_frame(dt); } void win32_update_fps(int frames) { - static wchar_t title_fps[512]; auto& state = retained_state(); - const int vr_fps = pp::platform::windows::current_vr_fps(state.vr); - if (App::I->vr_active) - swprintf_s(title_fps, L"%s - %d fps - %d vr fps", state.window_title, frames, vr_fps); - else - swprintf_s(title_fps, L"%s - %d fps", state.window_title, frames); - - { - enqueue_main_task([hWnd = state.hWnd] { - SetWindowText(hWnd, title_fps); - }); - } - PostMessage(state.hWnd, WM_USER_WAKEUP, 0, 0); + enqueue_main_task([hWnd = state.hWnd, window_title = state.window_title, &vr = state.vr, frames] { + pp::platform::windows::update_window_fps(hWnd, window_title, vr, frames); + }); } int read_WMI_info() @@ -455,25 +439,17 @@ void init_vk_map() bool win32_vr_start() { auto& state = retained_state(); - return pp::platform::windows::start_vr_shell(state.vr, state.sandboxed, running); + return pp::platform::windows::start_window_vr(state.vr, state.sandboxed); } void win32_vr_stop() { - auto& state = retained_state(); - pp::platform::windows::stop_vr_shell(state.vr); + pp::platform::windows::stop_window_vr(retained_state().vr); } void win32_save_window_state() { - auto& state = retained_state(); - WINDOWPLACEMENT p; - GetWindowPlacement(state.hWnd, &p); - pp::panopainter::set_legacy_window_preferences(p.showCmd, { - p.rcNormalPosition.left, - p.rcNormalPosition.top, - p.rcNormalPosition.right, - p.rcNormalPosition.bottom }); + pp::platform::windows::save_window_preferences(retained_state().hWnd); } int main(int argc, char** argv) { @@ -678,7 +654,7 @@ int main(int argc, char** argv) wglMakeCurrent(NULL, NULL); - running.store(1, std::memory_order_relaxed); + pp::platform::windows::mark_lifecycle_running(); App::I->runtime().render_thread_start(*App::I); App::I->runtime().ui_thread_start(*App::I); @@ -724,14 +700,14 @@ int main(int argc, char** argv) MSG msg; LOG("start main loop"); - while (running.load(std::memory_order_relaxed) == 1) + while (pp::platform::windows::lifecycle_is_running()) { // If there any message in the queue process it auto present = App::I->animate || App::I->redraw ? PeekMessage(&msg, 0, 0, 0, PM_REMOVE) : GetMessage(&msg, 0, 0, 0); if (msg.message == WM_QUIT) - running.store(0, std::memory_order_relaxed); + pp::platform::windows::mark_lifecycle_stopped(); if (present) { @@ -762,14 +738,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) switch (msg) { - case WM_USER_CLOSE: - running.store(0, std::memory_order_relaxed); - pp::platform::windows::request_stop_and_join_vr_thread(state.vr); - App::I->runtime().ui_thread_stop(); - App::I->runtime().render_thread_stop(); - App::I->terminate(); - delete App::I; - PostQuitMessage(0); + case pp::platform::windows::kUserCloseMessage: + pp::platform::windows::handle_window_close_message(state.vr); return 0; case WM_PAINT: App::I->redraw = true; @@ -792,7 +762,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { auto w = (float)LOWORD(lp); auto h = (float)HIWORD(lp); - if (h != 0 && running.load(std::memory_order_relaxed) == 1) + if (h != 0 && pp::platform::windows::lifecycle_is_running()) { App::I->ui_task_async([=] { diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index e88066a2..cfd1aaba 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -668,38 +668,41 @@ void NodeCanvas::draw() const bool use_blend = blend_gate.shader_blend; const bool copy_blend_destination = use_blend && !blend_gate.reads_destination_color; - if (use_blend) - { - apply_node_canvas_viewport(0, 0, m_cache_rtt.getWidth(), m_cache_rtt.getHeight()); - m_cache_rtt.bindFramebuffer(); - m_cache_rtt.clear({ 1, 1, 1, 0 }); - } - - pp::panopainter::execute_legacy_canvas_draw_merge_background_setup( - { - .use_blend = use_blend, - }, - { - .disable_blend = [&] { - apply_node_canvas_capability(pp::renderer::gl::blend_state(), false); - }, - .draw_checkerboard_plane = pp::panopainter::make_legacy_canvas_draw_merge_background_checkerboard_plane( - proj, - camera, - m_canvas->m_layers.size() + 500.f, - m_canvas->m_plane_transform, - [&] { - m_face_plane.draw_fill(); - }), - }); - - // if not using shader blend, use gl rasterizer blend - use_blend ? apply_node_canvas_capability(pp::renderer::gl::blend_state(), false) : apply_node_canvas_capability(pp::renderer::gl::blend_state(), true); - apply_node_canvas_capability(pp::renderer::gl::depth_test_state(), false); - const auto& b = m_canvas->m_current_stroke->m_brush; - pp::panopainter::execute_legacy_canvas_draw_layer_traversal( + pp::panopainter::execute_legacy_canvas_draw_unmerged_shell( + use_blend, m_canvas->m_layers.size(), + [&] { + apply_node_canvas_viewport(0, 0, m_cache_rtt.getWidth(), m_cache_rtt.getHeight()); + m_cache_rtt.bindFramebuffer(); + m_cache_rtt.clear({ 1, 1, 1, 0 }); + }, + [&] { + pp::panopainter::execute_legacy_canvas_draw_merge_background_setup( + { + .use_blend = use_blend, + }, + { + .disable_blend = [&] { + apply_node_canvas_capability(pp::renderer::gl::blend_state(), false); + }, + .draw_checkerboard_plane = pp::panopainter::make_legacy_canvas_draw_merge_background_checkerboard_plane( + proj, + camera, + m_canvas->m_layers.size() + 500.f, + m_canvas->m_plane_transform, + [&] { + m_face_plane.draw_fill(); + }), + }); + }, + [&](bool enable_shader_blend) { + // if not using shader blend, use gl rasterizer blend + apply_node_canvas_capability(pp::renderer::gl::blend_state(), !enable_shader_blend); + }, + [&] { + apply_node_canvas_capability(pp::renderer::gl::depth_test_state(), false); + }, [&](size_t layer_index) { return pp::app::plan_animation_onion_frame_range( m_canvas->m_layers[layer_index]->frames_count(), @@ -748,51 +751,50 @@ void NodeCanvas::draw() }, [&](const char* message) { LOG("NodeCanvas onion frame range failed: %s", message); - }); - if (use_blend) - { - m_cache_rtt.unbindFramebuffer(); - if (m_density != 1.f) - apply_node_canvas_viewport(0, 0, m_rtt.getWidth(), m_rtt.getHeight()); - else - apply_node_canvas_viewport(c.x + App::I->off_x, c.y + App::I->off_y, c.z, c.w); - pp::panopainter::execute_legacy_canvas_draw_merge_cache_to_screen_composite( - pp::panopainter::LegacyCanvasDrawMergeCacheToScreenCompositeUniforms { - .checkerboard = { - .colorize = false, + }, + [&] { + m_cache_rtt.unbindFramebuffer(); + if (m_density != 1.f) + apply_node_canvas_viewport(0, 0, m_rtt.getWidth(), m_rtt.getHeight()); + else + apply_node_canvas_viewport(c.x + App::I->off_x, c.y + App::I->off_y, c.z, c.w); + pp::panopainter::execute_legacy_canvas_draw_merge_cache_to_screen_composite( + pp::panopainter::LegacyCanvasDrawMergeCacheToScreenCompositeUniforms { + .checkerboard = { + .colorize = false, + }, + .texture = { + .mvp = glm::ortho(-1, 1, -1, 1), + .texture_slot = 0, + }, }, - .texture = { - .mvp = glm::ortho(-1, 1, -1, 1), - .texture_slot = 0, - }, - }, - { - .enable_blend = [&] { - apply_node_canvas_capability(pp::renderer::gl::blend_state(), true); - }, - .draw_checkerboard_plane = pp::panopainter::make_legacy_canvas_draw_merge_cache_to_screen_checkerboard_plane( - proj, - camera, - m_canvas->m_layers.size() + 500.f, - m_canvas->m_plane_transform, - [&] { + { + .enable_blend = [&] { + apply_node_canvas_capability(pp::renderer::gl::blend_state(), true); + }, + .draw_checkerboard_plane = pp::panopainter::make_legacy_canvas_draw_merge_cache_to_screen_checkerboard_plane( + proj, + camera, + m_canvas->m_layers.size() + 500.f, + m_canvas->m_plane_transform, + [&] { + m_face_plane.draw_fill(); + }), + .bind_sampler = [&] { + m_sampler.bind(0); + set_active_texture_unit(0); + }, + .bind_cache_texture = [&] { + m_cache_rtt.bindTexture(); + }, + .draw_cache_texture = [&] { m_face_plane.draw_fill(); - }), - .bind_sampler = [&] { - m_sampler.bind(0); - set_active_texture_unit(0); - }, - .bind_cache_texture = [&] { - m_cache_rtt.bindTexture(); - }, - .draw_cache_texture = [&] { - m_face_plane.draw_fill(); - }, - .unbind_cache_texture = [&] { - m_cache_rtt.unbindTexture(); - }, - }); - } + }, + .unbind_cache_texture = [&] { + m_cache_rtt.unbindTexture(); + }, + }); + }); } execute_node_canvas_draw_merge_tail(*this, ortho_proj, proj, camera, c); diff --git a/src/platform_windows/windows_lifecycle_shell.cpp b/src/platform_windows/windows_lifecycle_shell.cpp new file mode 100644 index 00000000..1a25db29 --- /dev/null +++ b/src/platform_windows/windows_lifecycle_shell.cpp @@ -0,0 +1,96 @@ +#include "pch.h" + +#include "platform_windows/windows_lifecycle_shell.h" + +#include "app.h" +#include "legacy_preference_storage.h" +#include "platform_windows/windows_stylus_input.h" + +namespace pp::platform::windows { + +namespace { + +[[nodiscard]] std::atomic& retained_running_state() noexcept +{ + static std::atomic running{-1}; + return running; +} + +} + +std::atomic& lifecycle_running_state() noexcept +{ + return retained_running_state(); +} + +void mark_lifecycle_running() noexcept +{ + retained_running_state().store(1, std::memory_order_relaxed); +} + +void mark_lifecycle_stopped() noexcept +{ + retained_running_state().store(0, std::memory_order_relaxed); +} + +bool lifecycle_is_running() noexcept +{ + return retained_running_state().load(std::memory_order_relaxed) == 1; +} + +void request_window_close(HWND hWnd) +{ + PostMessage(hWnd, kUserCloseMessage, 0, 0); +} + +void handle_window_close_message(VrShellState& vr) +{ + mark_lifecycle_stopped(); + request_stop_and_join_vr_thread(vr); + App::I->runtime().ui_thread_stop(); + App::I->runtime().render_thread_stop(); + App::I->terminate(); + delete App::I; + PostQuitMessage(0); +} + +void update_stylus_frame(float dt) +{ + update_stylus_state(dt); +} + +void update_window_fps(HWND hWnd, const wchar_t* window_title, VrShellState& vr, int frames) +{ + static wchar_t title_fps[512]; + const int vr_fps = current_vr_fps(vr); + if (App::I->vr_active) + swprintf_s(title_fps, L"%s - %d fps - %d vr fps", window_title, frames, vr_fps); + else + swprintf_s(title_fps, L"%s - %d fps", window_title, frames); + + SetWindowText(hWnd, title_fps); + PostMessage(hWnd, kUserWakeupMessage, 0, 0); +} + +void save_window_preferences(HWND hWnd) +{ + WINDOWPLACEMENT placement{}; + GetWindowPlacement(hWnd, &placement); + pp::panopainter::set_legacy_window_preferences(placement.showCmd, { + placement.rcNormalPosition.left, + placement.rcNormalPosition.top, + placement.rcNormalPosition.right, + placement.rcNormalPosition.bottom }); +} + +bool start_window_vr(VrShellState& vr, bool sandboxed) +{ + return start_vr_shell(vr, sandboxed, retained_running_state()); +} + +void stop_window_vr(VrShellState& vr) +{ + stop_vr_shell(vr); +} + +} diff --git a/src/platform_windows/windows_lifecycle_shell.h b/src/platform_windows/windows_lifecycle_shell.h new file mode 100644 index 00000000..eb177eda --- /dev/null +++ b/src/platform_windows/windows_lifecycle_shell.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include + +#include "platform_windows/windows_vr_shell.h" + +namespace pp::platform::windows { + +inline constexpr UINT kUserCloseMessage = WM_USER + 1; +inline constexpr UINT kUserWakeupMessage = WM_USER + 2; + +[[nodiscard]] std::atomic& lifecycle_running_state() noexcept; +void mark_lifecycle_running() noexcept; +void mark_lifecycle_stopped() noexcept; +[[nodiscard]] bool lifecycle_is_running() noexcept; + +void request_window_close(HWND hWnd); +void handle_window_close_message(VrShellState& vr); + +void update_stylus_frame(float dt); +void update_window_fps(HWND hWnd, const wchar_t* window_title, VrShellState& vr, int frames); +void save_window_preferences(HWND hWnd); + +[[nodiscard]] bool start_window_vr(VrShellState& vr, bool sandboxed); +void stop_window_vr(VrShellState& vr); + +}