diff --git a/cmake/PanoPainterSources.cmake b/cmake/PanoPainterSources.cmake index 22402ed0..ea801bc9 100644 --- a/cmake/PanoPainterSources.cmake +++ b/cmake/PanoPainterSources.cmake @@ -92,6 +92,7 @@ set(PP_PANOPAINTER_APP_SOURCES src/app_cloud.cpp src/app_commands.cpp src/app_dialogs.cpp + src/app_dialogs_workflow.cpp src/app_dialogs_export.cpp src/app_dialogs_info_openers.cpp src/app_events.cpp @@ -164,6 +165,7 @@ set(PP_PANOPAINTER_UI_SOURCES set(PP_WINDOWS_PLATFORM_SOURCES src/main.cpp + src/platform_windows/windows_bootstrap_helpers.cpp 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 4f7afbc5..097e1415 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -83,12 +83,12 @@ Current hotspot files: - `src/app_layout.cpp`: 1249 lines - `src/canvas_modes.cpp`: 1798 lines - `src/node.cpp`: 1551 lines -- `src/main.cpp`: 1117 lines +- `src/main.cpp`: 909 lines - `src/node_panel_brush.cpp`: 1197 lines - `src/node_stroke_preview.cpp`: 933 lines -- `src/node_canvas.cpp`: 897 lines +- `src/node_canvas.cpp`: 905 lines - `src/app.cpp`: 502 lines -- `src/app_dialogs.cpp`: 441 lines +- `src/app_dialogs.cpp`: 142 lines Current architecture mismatches that must be treated as real blockers: @@ -128,7 +128,8 @@ Current architecture mismatches that must be treated as real blockers: per-layer GL setup now also routes through `make_legacy_canvas_draw_merge_layer_path_gl_execution(...)` even though the remaining draw lambdas and broader node draw loop still live in - `src/node_canvas.cpp`. + `src/node_canvas.cpp`, where the post-draw/display-resolve tail now also + routes through `execute_node_canvas_draw_merge_tail(...)`. - `app_layout.cpp` and `app_dialogs.cpp` are still mixed shell/controller files rather than thin composition/binding surfaces, even though tools-menu binding plus nested panels/options submenu wiring now live in @@ -142,7 +143,9 @@ Current architecture mismatches that must be treated as real blockers: and the corresponding `App::dialog_*` entrypoints are thinner, while the export/video/PPBR dialog family now also lives in `src/app_dialogs_export.cpp` and those `App::dialog_*` entrypoints are - thinner too. + thinner too, while new/open/save/browse/resize workflow entrypoints now also + live in `src/app_dialogs_workflow.cpp` and `src/app_dialogs.cpp` is now + mostly a thin dialog dispatch surface. - `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 @@ -171,6 +174,9 @@ Current architecture mismatches that must be treated as real blockers: in `src/platform_windows/windows_stylus_input.cpp` instead of `src/main.cpp`, while the retained Win32 VR/HMD shell now also routes through `src/platform_windows/windows_vr_shell.h` instead of staying inline in + `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`, while `App::rec_loop()` now delegates worker-iteration orchestration into the retained recording bridge, `App::update_rec_frames()` now delegates diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index 241bb26c..b401f776 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -205,6 +205,11 @@ Current slice: `make_node_canvas_layer_path_execution(...)` helper, which materially thins `NodeCanvas::draw()` even though the broader draw loop still lives in `src/node_canvas.cpp`. +- `NodeCanvas` post-draw callback assembly, smoothing-mask face execution, and + optional display resolve now also route through + `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. Write scope: - `src/node_stroke_preview.cpp` @@ -343,6 +348,9 @@ Current slice: `src/app_dialogs_export.cpp`, and the corresponding `App::dialog_*` entrypoints are now thin call-throughs, but new/open/save/browse/resize and retained dialog execution are still inline in `src/app_dialogs.cpp`. +- New/open/save/browse/resize workflow entrypoints now also live in + `src/app_dialogs_workflow.cpp`, and `src/app_dialogs.cpp` is down to the + remaining thin entrypoints plus layer-rename retained dialog glue. Write scope: - `src/app_dialogs.cpp` @@ -448,6 +456,10 @@ Current slice: state, now routes through `src/platform_windows/windows_vr_shell.h` instead of staying inline in `src/main.cpp`, but broader retained Win32 shell state is still open +- RenderDoc startup/frame capture, SHCore DPI bootstrap, Win32 error-string + conversion, `UnadjustWindowRectEx`, and GL debug pre/post callbacks now also + live in `src/platform_windows/windows_bootstrap_helpers.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_dialogs.cpp b/src/app_dialogs.cpp index 65e923d4..9ea3bed8 100644 --- a/src/app_dialogs.cpp +++ b/src/app_dialogs.cpp @@ -2,100 +2,29 @@ #include "app.h" #include "app_core/app_dialog.h" #include "app_core/document_layer.h" -#include "app_core/document_resize.h" -#include "app_core/document_export.h" -#include "app_core/document_session.h" -#include "legacy_document_canvas_services.h" #include "legacy_app_dialog_services.h" -#include "legacy_brush_package_export_services.h" -#include "legacy_document_export_services.h" #include "legacy_document_layer_services.h" -#include "legacy_document_session_services.h" #include "legacy_ui_overlay_services.h" -#include "node_dialog_open.h" -#include "node_dialog_browse.h" -#include "node_dialog_resize.h" -#include "node_dialog_cloud.h" +#include "node_dialog_layer_rename.h" #ifdef __QUEST__ #include "oculus_vr.h" #endif namespace pp::panopainter { -void open_usermanual_dialog(App& app); -void open_changelog_dialog(App& app); -void open_about_dialog(App& app); -void open_whatsnew_dialog(App& app, bool force_show); -void open_shortcuts_dialog(App& app); void open_document_export_dialog(App& app, std::string ext); void open_document_export_layers_dialog(App& app); void open_document_export_anim_frames_dialog(App& app); void open_document_export_depth_dialog(App& app); void open_document_export_cube_faces_dialog(App& app); +void open_ppbr_export_dialog(App& app); void open_document_timelapse_export_dialog(App& app); void open_document_export_mp4_dialog(App& app); -void open_ppbr_export_dialog(App& app); -} - -namespace { - -void wire_document_browse_dialog_actions( - App& app, - const std::shared_ptr& dialog, - Node& overlay_anchor, - pp::ui::NodeHandle overlay_handle) -{ - const auto close_dialog = [&overlay_anchor, overlay_handle]() { - const auto close_status = - pp::panopainter::close_legacy_overlay_node(overlay_anchor, overlay_handle); - (void)close_status; - }; - - dialog->btn_ok->on_click = [&app, dialog, close_dialog](Node*) - { - if (dialog->is_selected()) - { - app.open_document(dialog->selected_path); - close_dialog(); - } - }; - dialog->btn_cancel->on_click = [close_dialog](Node*) - { - close_dialog(); - }; -} - -void wire_document_save_dialog_buttons( - App& app, - const std::shared_ptr& dialog, - std::function close_dialog) -{ - dialog->btn_ok->on_click = [&app, dialog](Node*) - { - std::string name = dialog->input->m_text; - const auto plan = pp::app::plan_document_file_save( - app.work_path, - name, - [](const std::string& path) { - return Asset::exist(path); - }); - if (!plan) - { - app.message_box("Warning", "You need to specify a name to file."); - return; - } - - const auto status = - pp::panopainter::execute_legacy_document_file_save_plan(app, plan.value(), dialog); - if (!status.ok()) - LOG("Document file save action failed: %s", status.message); - }; - dialog->btn_cancel->on_click = [close_dialog](Node*) - { - close_dialog(); - }; -} - +void open_usermanual_dialog(App& app); +void open_changelog_dialog(App& app); +void open_about_dialog(App& app); +void open_whatsnew_dialog(App& app, bool force_show); +void open_shortcuts_dialog(App& app); } std::shared_ptr App::show_progress(const std::string& title, int total /*= 0*/) @@ -139,234 +68,6 @@ void App::dialog_about() pp::panopainter::open_about_dialog(*this); } -void App::continue_document_workflow_after_optional_save(std::function action) -{ - const bool has_canvas = canvas != nullptr; - const bool has_unsaved_changes = has_canvas && Canvas::I->m_unsaved; - const auto decision = pp::app::plan_document_workflow(has_canvas, has_unsaved_changes); - const auto status = pp::panopainter::execute_legacy_document_workflow_decision( - *this, - decision, - std::move(action)); - if (!status.ok()) - LOG("Document workflow action failed: %s", status.message); -} - -void App::dialog_newdoc() -{ - auto show_dialog = [this] { - auto* overlay_anchor = layout[main_id]; - if (!overlay_anchor) { - LOG("New document dialog open failed: main layout anchor is missing"); - return; - } - - auto dialog = pp::panopainter::make_legacy_overlay_node(*this); - dialog->input->set_text("name"); - - App::I->showKeyboard(); - - const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); - if (!overlay) { - App::I->hideKeyboard(); - LOG("New document dialog open failed: %s", overlay.status().message); - return; - } - const auto overlay_handle = overlay.value(); - - const auto close_dialog = [this, overlay_anchor, overlay_handle]() { - const auto close_status = pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); - (void)close_status; - App::I->hideKeyboard(); - }; - - dialog->btn_ok->on_click = [this, dialog](Node*) - { - std::string name = dialog->input->m_text; - const auto plan = pp::app::plan_new_document( - work_path, - name, - dialog->m_resolution->m_current_index, - [](const std::string& path) { - return Asset::exist(path); - }); - if (!plan) - { - const bool missing_name = - plan.status().code == pp::foundation::StatusCode::invalid_argument; - message_box( - "Warning", - missing_name ? "You need to specify a name to file." : plan.status().message); - return; - } - - const auto status = pp::panopainter::execute_legacy_new_document_plan(*this, plan.value(), dialog); - if (!status.ok()) - LOG("New document action failed: %s", status.message); - - }; - dialog->btn_cancel->on_click = [close_dialog](Node*) - { - close_dialog(); - }; - }; - - continue_document_workflow_after_optional_save(show_dialog); -} - -// DEPRECATED -void App::dialog_open() -{ - auto show_dialog = [this] { - // load thumbnail test - auto* overlay_anchor = layout[main_id]; - if (!overlay_anchor) { - LOG("Open document dialog open failed: main layout anchor is missing"); - return; - } - - auto dialog = pp::panopainter::make_legacy_overlay_node(*this); - - const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); - if (!overlay) { - LOG("Open document dialog open failed: %s", overlay.status().message); - return; - } - const auto overlay_handle = overlay.value(); - - const auto close_dialog = [overlay_anchor, overlay_handle]() { - const auto close_status = pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); - (void)close_status; - }; - - dialog->btn_ok->on_click = [this, dialog](Node*) - { -// canvas->reset_camera(); -// layers->clear(); -// doc_name = dialog->selected_name; -// canvas->m_canvas->project_open(dialog->selected_path, [this](bool success) { -// // on complete -// async_start(); -// title_update(); -// for (auto& i : canvas->m_canvas->m_order) -// layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str()); -// async_end(); -// }); -// dialog->destroy(); -// ActionManager::clear(); - }; - dialog->btn_cancel->on_click = [close_dialog](Node*) - { - close_dialog(); - }; - }; - - continue_document_workflow_after_optional_save(show_dialog); -} - -void App::dialog_browse() -{ - auto show_dialog = [this] { - auto* overlay_anchor = layout[main_id]; - if (!overlay_anchor) { - LOG("Browse document dialog open failed: main layout anchor is missing"); - return; - } - - auto dialog = pp::panopainter::make_legacy_overlay_node(*this); - dialog->search_paths = document_browse_roots(); - - const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); - if (!overlay) { - LOG("Browse document dialog open failed: %s", overlay.status().message); - return; - } - const auto overlay_handle = overlay.value(); - wire_document_browse_dialog_actions(*this, dialog, *overlay_anchor, overlay_handle); - }; - - continue_document_workflow_after_optional_save(show_dialog); -} - -void save_document_version(App& app) -{ - const auto target = pp::app::find_next_document_version_target( - app.doc_dir, - app.doc_name, - [](const std::string& path) { - return Asset::exist(path); - }); - if (!target) { - app.message_box("Saving Error", target.status().message); - return; - } - - const auto status = pp::panopainter::execute_legacy_document_version_save(app, target.value()); - if (!status.ok()) - LOG("Document version save action failed: %s", status.message); -} - -void App::dialog_save_ver() -{ - if (!check_license()) - { - message_box("License", "This function is disabled in demo mode."); - return; - } - - save_document_version(*this); -} - -void App::save_document(pp::app::DocumentSaveIntent intent) -{ - const auto decision = pp::app::plan_document_save( - Canvas::I->m_newdoc, - Canvas::I->m_unsaved, - intent); - const auto status = pp::panopainter::execute_legacy_document_save_decision(*this, decision); - if (!status.ok()) - LOG("Document save action failed: %s", status.message); -} - -void App::dialog_save() -{ - if (!check_license()) - { - message_box("License", "This function is disabled in demo mode."); - return; - } - - if (canvas) - { - auto* overlay_anchor = layout[main_id]; - if (!overlay_anchor) { - LOG("Save document dialog open failed: main layout anchor is missing"); - return; - } - - auto dialog = pp::panopainter::make_legacy_overlay_node(*this); - dialog->input->set_text(doc_name); - - App::I->showKeyboard(); - - const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); - if (!overlay) { - App::I->hideKeyboard(); - LOG("Save document dialog open failed: %s", overlay.status().message); - return; - } - const auto overlay_handle = overlay.value(); - - const auto close_dialog = [this, overlay_anchor, overlay_handle]() { - const auto close_status = pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); - (void)close_status; - App::I->hideKeyboard(); - }; - - wire_document_save_dialog_buttons(*this, dialog, close_dialog); - } -} - void App::dialog_export(std::string ext) { pp::panopainter::open_document_export_dialog(*this, ext); @@ -387,47 +88,6 @@ void App::dialog_export_depth() pp::panopainter::open_document_export_depth_dialog(*this); } -void App::dialog_resize() -{ - auto* overlay_anchor = layout[main_id]; - if (!overlay_anchor) { - LOG("Resize dialog open failed: main layout anchor is missing"); - return; - } - - auto dialog = pp::panopainter::make_legacy_overlay_node(*this); - const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); - if (!overlay) { - LOG("Resize dialog open failed: %s", overlay.status().message); - return; - } - const auto overlay_handle = overlay.value(); - - const auto close_dialog = [overlay_anchor, overlay_handle]() { - const auto close_status = - pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); - (void)close_status; - }; - - dialog->btn_ok->on_click = [this, dialog, close_dialog](Node*) - { - const auto plan = pp::app::plan_document_resize( - dialog->combo ? dialog->combo->m_current_index : 0); - if (!plan) - { - close_dialog(); - return; - } - const auto status = pp::panopainter::execute_legacy_document_resize_plan(*this, plan.value()); - if (!status.ok()) - LOG("Document resize failed: %s", status.message); - close_dialog(); - }; - dialog->btn_cancel->on_click = [close_dialog](Node*) { - close_dialog(); - }; -} - void App::dialog_export_cube_faces() { pp::panopainter::open_document_export_cube_faces_dialog(*this); diff --git a/src/app_dialogs_workflow.cpp b/src/app_dialogs_workflow.cpp new file mode 100644 index 00000000..5f65df9d --- /dev/null +++ b/src/app_dialogs_workflow.cpp @@ -0,0 +1,343 @@ +#include "pch.h" +#include "app.h" +#include "app_core/document_resize.h" +#include "legacy_document_canvas_services.h" +#include "legacy_document_session_services.h" +#include "legacy_ui_overlay_services.h" +#include "node_dialog_browse.h" +#include "node_dialog_open.h" +#include "node_dialog_resize.h" + +namespace { + +void wire_document_browse_dialog_actions( + App& app, + const std::shared_ptr& dialog, + Node& overlay_anchor, + pp::ui::NodeHandle overlay_handle) +{ + const auto close_dialog = [&overlay_anchor, overlay_handle]() { + const auto close_status = + pp::panopainter::close_legacy_overlay_node(overlay_anchor, overlay_handle); + (void)close_status; + }; + + dialog->btn_ok->on_click = [&app, dialog, close_dialog](Node*) + { + if (dialog->is_selected()) + { + app.open_document(dialog->selected_path); + close_dialog(); + } + }; + dialog->btn_cancel->on_click = [close_dialog](Node*) + { + close_dialog(); + }; +} + +void wire_document_save_dialog_buttons( + App& app, + const std::shared_ptr& dialog, + std::function close_dialog) +{ + dialog->btn_ok->on_click = [&app, dialog](Node*) + { + std::string name = dialog->input->m_text; + const auto plan = pp::app::plan_document_file_save( + app.work_path, + name, + [](const std::string& path) { + return Asset::exist(path); + }); + if (!plan) + { + app.message_box("Warning", "You need to specify a name to file."); + return; + } + + const auto status = + pp::panopainter::execute_legacy_document_file_save_plan(app, plan.value(), dialog); + if (!status.ok()) + LOG("Document file save action failed: %s", status.message); + }; + dialog->btn_cancel->on_click = [close_dialog](Node*) + { + close_dialog(); + }; +} + +void save_document_version(App& app) +{ + const auto target = pp::app::find_next_document_version_target( + app.doc_dir, + app.doc_name, + [](const std::string& path) { + return Asset::exist(path); + }); + if (!target) { + app.message_box("Saving Error", target.status().message); + return; + } + + const auto status = pp::panopainter::execute_legacy_document_version_save(app, target.value()); + if (!status.ok()) + LOG("Document version save action failed: %s", status.message); +} + +} // namespace + +void App::continue_document_workflow_after_optional_save(std::function action) +{ + const bool has_canvas = canvas != nullptr; + const bool has_unsaved_changes = has_canvas && Canvas::I->m_unsaved; + const auto decision = pp::app::plan_document_workflow(has_canvas, has_unsaved_changes); + const auto status = pp::panopainter::execute_legacy_document_workflow_decision( + *this, + decision, + std::move(action)); + if (!status.ok()) + LOG("Document workflow action failed: %s", status.message); +} + +void App::dialog_newdoc() +{ + auto show_dialog = [this] { + auto* overlay_anchor = layout[main_id]; + if (!overlay_anchor) { + LOG("New document dialog open failed: main layout anchor is missing"); + return; + } + + auto dialog = pp::panopainter::make_legacy_overlay_node(*this); + dialog->input->set_text("name"); + + App::I->showKeyboard(); + + const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); + if (!overlay) { + App::I->hideKeyboard(); + LOG("New document dialog open failed: %s", overlay.status().message); + return; + } + const auto overlay_handle = overlay.value(); + + const auto close_dialog = [this, overlay_anchor, overlay_handle]() { + const auto close_status = + pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); + (void)close_status; + App::I->hideKeyboard(); + }; + + dialog->btn_ok->on_click = [this, dialog](Node*) + { + std::string name = dialog->input->m_text; + const auto plan = pp::app::plan_new_document( + work_path, + name, + dialog->m_resolution->m_current_index, + [](const std::string& path) { + return Asset::exist(path); + }); + if (!plan) + { + const bool missing_name = + plan.status().code == pp::foundation::StatusCode::invalid_argument; + message_box( + "Warning", + missing_name ? "You need to specify a name to file." : plan.status().message); + return; + } + + const auto status = + pp::panopainter::execute_legacy_new_document_plan(*this, plan.value(), dialog); + if (!status.ok()) + LOG("New document action failed: %s", status.message); + + }; + dialog->btn_cancel->on_click = [close_dialog](Node*) + { + close_dialog(); + }; + }; + + continue_document_workflow_after_optional_save(show_dialog); +} + +// DEPRECATED +void App::dialog_open() +{ + auto show_dialog = [this] { + // load thumbnail test + auto* overlay_anchor = layout[main_id]; + if (!overlay_anchor) { + LOG("Open document dialog open failed: main layout anchor is missing"); + return; + } + + auto dialog = pp::panopainter::make_legacy_overlay_node(*this); + + const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); + if (!overlay) { + LOG("Open document dialog open failed: %s", overlay.status().message); + return; + } + const auto overlay_handle = overlay.value(); + + const auto close_dialog = [overlay_anchor, overlay_handle]() { + const auto close_status = + pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); + (void)close_status; + }; + + dialog->btn_ok->on_click = [this, dialog](Node*) + { +// canvas->reset_camera(); +// layers->clear(); +// doc_name = dialog->selected_name; +// canvas->m_canvas->project_open(dialog->selected_path, [this](bool success) { +// // on complete +// async_start(); +// title_update(); +// for (auto& i : canvas->m_canvas->m_order) +// layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str()); +// async_end(); +// }); +// dialog->destroy(); +// ActionManager::clear(); + }; + dialog->btn_cancel->on_click = [close_dialog](Node*) + { + close_dialog(); + }; + }; + + continue_document_workflow_after_optional_save(show_dialog); +} + +void App::dialog_browse() +{ + auto show_dialog = [this] { + auto* overlay_anchor = layout[main_id]; + if (!overlay_anchor) { + LOG("Browse document dialog open failed: main layout anchor is missing"); + return; + } + + auto dialog = pp::panopainter::make_legacy_overlay_node(*this); + dialog->search_paths = document_browse_roots(); + + const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); + if (!overlay) { + LOG("Browse document dialog open failed: %s", overlay.status().message); + return; + } + const auto overlay_handle = overlay.value(); + wire_document_browse_dialog_actions(*this, dialog, *overlay_anchor, overlay_handle); + }; + + continue_document_workflow_after_optional_save(show_dialog); +} + +void App::dialog_save_ver() +{ + if (!check_license()) + { + message_box("License", "This function is disabled in demo mode."); + return; + } + + save_document_version(*this); +} + +void App::save_document(pp::app::DocumentSaveIntent intent) +{ + const auto decision = pp::app::plan_document_save( + Canvas::I->m_newdoc, + Canvas::I->m_unsaved, + intent); + const auto status = pp::panopainter::execute_legacy_document_save_decision(*this, decision); + if (!status.ok()) + LOG("Document save action failed: %s", status.message); +} + +void App::dialog_save() +{ + if (!check_license()) + { + message_box("License", "This function is disabled in demo mode."); + return; + } + + if (canvas) + { + auto* overlay_anchor = layout[main_id]; + if (!overlay_anchor) { + LOG("Save document dialog open failed: main layout anchor is missing"); + return; + } + + auto dialog = pp::panopainter::make_legacy_overlay_node(*this); + dialog->input->set_text(doc_name); + + App::I->showKeyboard(); + + const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); + if (!overlay) { + App::I->hideKeyboard(); + LOG("Save document dialog open failed: %s", overlay.status().message); + return; + } + const auto overlay_handle = overlay.value(); + + const auto close_dialog = [this, overlay_anchor, overlay_handle]() { + const auto close_status = + pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); + (void)close_status; + App::I->hideKeyboard(); + }; + + wire_document_save_dialog_buttons(*this, dialog, close_dialog); + } +} + +void App::dialog_resize() +{ + auto* overlay_anchor = layout[main_id]; + if (!overlay_anchor) { + LOG("Resize dialog open failed: main layout anchor is missing"); + return; + } + + auto dialog = pp::panopainter::make_legacy_overlay_node(*this); + const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); + if (!overlay) { + LOG("Resize dialog open failed: %s", overlay.status().message); + return; + } + const auto overlay_handle = overlay.value(); + + const auto close_dialog = [overlay_anchor, overlay_handle]() { + const auto close_status = + pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); + (void)close_status; + }; + + dialog->btn_ok->on_click = [this, dialog, close_dialog](Node*) + { + const auto plan = pp::app::plan_document_resize( + dialog->combo ? dialog->combo->m_current_index : 0); + if (!plan) + { + close_dialog(); + return; + } + const auto status = pp::panopainter::execute_legacy_document_resize_plan(*this, plan.value()); + if (!status.ok()) + LOG("Document resize failed: %s", status.message); + close_dialog(); + }; + dialog->btn_cancel->on_click = [close_dialog](Node*) { + close_dialog(); + }; +} diff --git a/src/main.cpp b/src/main.cpp index eae473a0..2570cd8b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,6 +43,15 @@ namespace pp::platform::windows { void unlock_async_render_context(); void swap_async_render_context(); } +extern HRESULT(*GetDpiForMonitor_fn)(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY); +extern HRESULT(*SetProcessDpiAwareness_fn)(PROCESS_DPI_AWARENESS value); +bool win32_renderdoc_init(); +void win32_renderdoc_frame_start(); +void win32_renderdoc_frame_end(); +void init_shcore_API(); +std::string GetLastErrorAsString(); +void _pre_call_callback(const char* name, void* funcptr, int len_args, ...); +void _post_call_callback(const char* name, void* funcptr, int len_args, ...); struct RetainedState { HINSTANCE hInst{}; @@ -120,71 +129,6 @@ void pp_windows_enqueue_main_task(std::packaged_task task) std::atomic running{-1}; -#ifdef USE_RENDERDOC -RENDERDOC_API_1_4_0* rdoc_api = NULL; -bool win32_renderdoc_init() -{ - // At init, on windows - if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) - { - pRENDERDOC_GetAPI RENDERDOC_GetAPI = - (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); - return RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void**)&rdoc_api); - } - return false; -} - -void win32_renderdoc_frame_start() -{ - if (rdoc_api) - rdoc_api->StartFrameCapture(NULL, NULL); -} - -void win32_renderdoc_frame_end() -{ - if (rdoc_api) - rdoc_api->EndFrameCapture(NULL, NULL); -} -#else -void win32_renderdoc_frame_start() { } -void win32_renderdoc_frame_end() { } -#endif - -HRESULT(*GetDpiForMonitor_fn)(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY); -HRESULT(*SetProcessDpiAwareness_fn)(PROCESS_DPI_AWARENESS value); -void init_shcore_API() -{ - HMODULE dll = LoadLibrary(L"Shcore.dll"); - if (!dll) - { - LOG("cannot load Shcore.dll"); - return; - } - LOG("loaded Shcore.dll"); - GetDpiForMonitor_fn = (decltype(GetDpiForMonitor_fn))GetProcAddress(dll, "GetDpiForMonitor"); - SetProcessDpiAwareness_fn = (decltype(SetProcessDpiAwareness_fn))GetProcAddress(dll, "SetProcessDpiAwareness"); -} - -//Returns the last Win32 error, in string format. Returns an empty string if there is no error. -std::string GetLastErrorAsString() -{ - //Get the error message, if any. - DWORD errorMessageID = ::GetLastError(); - if (errorMessageID == 0) - return std::string(); //No error message has been recorded - - LPSTR messageBuffer = nullptr; - size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); - - std::string message(messageBuffer, size); - - //Free the buffer. - LocalFree(messageBuffer); - - return message; -} - void destroy_window() { auto& state = retained_state(); @@ -531,36 +475,6 @@ void win32_save_window_state() p.rcNormalPosition.right, p.rcNormalPosition.bottom }); } -BOOL UnadjustWindowRectEx(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle) -{ - RECT rc; - SetRectEmpty(&rc); - BOOL fRc = AdjustWindowRectEx(&rc, dwStyle, fMenu, dwExStyle); - if (fRc) { - prc->left -= rc.left; - prc->top -= rc.top; - prc->right -= rc.right; - prc->bottom -= rc.bottom; - } - return fRc; -} - -void _pre_call_callback(const char* name, void* funcptr, int len_args, ...) -{ - assert(App::I->is_render_thread()); -} - -void _post_call_callback(const char* name, void* funcptr, int len_args, ...) -{ - GLenum error_code; - error_code = glad_glGetError(); - - if (error_code != pp::renderer::gl::no_error_code()) - { - LOG("ERROR %d in %s\n", error_code, name); - } -} - int main(int argc, char** argv) { auto& state = retained_state(); diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index bf7e0608..e88066a2 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -395,6 +395,101 @@ pp::panopainter::LegacyCanvasDrawMergeLayerPathExecution make_node_canvas_layer_ draw_layer_frame); } +void execute_node_canvas_draw_merge_tail( + NodeCanvas& node_canvas, + const glm::mat4& ortho_proj, + const glm::mat4& proj, + const glm::mat4& camera, + const glm::ivec4& c) +{ + apply_node_canvas_capability(pp::renderer::gl::depth_test_state(), false); + + pp::panopainter::execute_legacy_canvas_draw_merge_post_draw_callbacks( + node_canvas.m_canvas->m_smask_active, + node_canvas.m_canvas->m_current_mode == kCanvasMode::Copy || node_canvas.m_canvas->m_current_mode == kCanvasMode::Cut, + node_canvas.m_canvas->m_smask_mode, + node_canvas.m_canvas->m_current_mode != kCanvasMode::Grid, + [&] { + node_canvas.m_canvas->modes[(int)kCanvasMode::MaskFree][0]->on_Draw(ortho_proj, proj, camera); + }, + [&] { + node_canvas.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 = node_canvas.m_outline_pan, + }, + proj, + camera, + node_canvas.m_canvas->m_layers.size() + 500.f, + std::to_array(node_canvas.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) { + node_canvas.m_canvas->m_smask.rtt(plane_index).bindTexture(); + }, + .draw_face = [&] { + node_canvas.m_face_plane.draw_fill(); + }, + .unbind_face_texture = [&](int plane_index) { + node_canvas.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( + node_canvas.m_canvas->m_mode, + ortho_proj, + proj, + camera)); + + if (node_canvas.m_density != 1.f) { + pp::panopainter::execute_legacy_canvas_draw_merge_display_resolve( + pp::panopainter::LegacyCanvasDrawMergeDisplayResolveUniforms { + .texture = { + .mvp = glm::ortho(-1, 1, -1, 1), + .texture_slot = 0, + }, + }, + { + .unbind_resolve_framebuffer = [&] { + node_canvas.m_rtt.unbindFramebuffer(); + }, + .clear_color_buffer = [&] { + clear_node_canvas_color_buffer({ 1.f, 1.f, 1.f, 0.f }); + }, + .apply_viewport = [&] { + apply_node_canvas_viewport(c.x + App::I->off_x, c.y + App::I->off_y, c.z, c.w); + }, + .bind_sampler = [&] { + node_canvas.m_sampler_nearest.bind(0); + }, + .bind_resolve_texture = [&] { + set_active_texture_unit(0); + node_canvas.m_rtt.bindTexture(); + }, + .draw = [&] { + node_canvas.m_face_plane.draw_fill(); + }, + .unbind_resolve_texture = [&] { + node_canvas.m_rtt.unbindTexture(); + }, + }); + } +} + } Node* NodeCanvas::clone_instantiate() const @@ -700,93 +795,7 @@ void NodeCanvas::draw() } } - apply_node_canvas_capability(pp::renderer::gl::depth_test_state(), false); - - 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, - [&] { - 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); - }, - .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) - { - pp::panopainter::execute_legacy_canvas_draw_merge_display_resolve( - pp::panopainter::LegacyCanvasDrawMergeDisplayResolveUniforms { - .texture = { - .mvp = glm::ortho(-1, 1, -1, 1), - .texture_slot = 0, - }, - }, - { - .unbind_resolve_framebuffer = [&] { - m_rtt.unbindFramebuffer(); - }, - .clear_color_buffer = [&] { - clear_node_canvas_color_buffer({ 1.f, 1.f, 1.f, 0.f }); - }, - .apply_viewport = [&] { - apply_node_canvas_viewport(c.x + App::I->off_x, c.y + App::I->off_y, c.z, c.w); - }, - .bind_sampler = [&] { - m_sampler_nearest.bind(0); - }, - .bind_resolve_texture = [&] { - set_active_texture_unit(0); - m_rtt.bindTexture(); - }, - .draw = [&] { - m_face_plane.draw_fill(); - }, - .unbind_resolve_texture = [&] { - m_rtt.unbindTexture(); - }, - }); - } + execute_node_canvas_draw_merge_tail(*this, ortho_proj, proj, camera, c); scissor ? apply_node_canvas_capability(pp::renderer::gl::scissor_test_state(), true) : apply_node_canvas_capability(pp::renderer::gl::scissor_test_state(), false); blend ? apply_node_canvas_capability(pp::renderer::gl::blend_state(), true) : apply_node_canvas_capability(pp::renderer::gl::blend_state(), false); diff --git a/src/platform_windows/windows_bootstrap_helpers.cpp b/src/platform_windows/windows_bootstrap_helpers.cpp new file mode 100644 index 00000000..4bcb43bf --- /dev/null +++ b/src/platform_windows/windows_bootstrap_helpers.cpp @@ -0,0 +1,106 @@ +#include "pch.h" +#include "app.h" +#include "log.h" +#include "renderer_gl/opengl_capabilities.h" + +#include +#include + +#if __has_include() +#include +#define USE_RENDERDOC +#endif + +#ifdef USE_RENDERDOC +RENDERDOC_API_1_4_0* rdoc_api = NULL; + +bool win32_renderdoc_init() +{ + // At init, on windows + if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) + { + pRENDERDOC_GetAPI RENDERDOC_GetAPI = + (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); + return RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void**)&rdoc_api); + } + return false; +} + +void win32_renderdoc_frame_start() +{ + if (rdoc_api) + rdoc_api->StartFrameCapture(NULL, NULL); +} + +void win32_renderdoc_frame_end() +{ + if (rdoc_api) + rdoc_api->EndFrameCapture(NULL, NULL); +} +#else +void win32_renderdoc_frame_start() { } +void win32_renderdoc_frame_end() { } +#endif + +HRESULT(*GetDpiForMonitor_fn)(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY); +HRESULT(*SetProcessDpiAwareness_fn)(PROCESS_DPI_AWARENESS value); + +void init_shcore_API() +{ + HMODULE dll = LoadLibrary(L"Shcore.dll"); + if (!dll) + { + LOG("cannot load Shcore.dll"); + return; + } + LOG("loaded Shcore.dll"); + GetDpiForMonitor_fn = (decltype(GetDpiForMonitor_fn))GetProcAddress(dll, "GetDpiForMonitor"); + SetProcessDpiAwareness_fn = (decltype(SetProcessDpiAwareness_fn))GetProcAddress(dll, "SetProcessDpiAwareness"); +} + +// Returns the last Win32 error, in string format. Returns an empty string if there is no error. +std::string GetLastErrorAsString() +{ + DWORD errorMessageID = ::GetLastError(); + if (errorMessageID == 0) + return std::string(); + + LPSTR messageBuffer = nullptr; + size_t size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + + std::string message(messageBuffer, size); + LocalFree(messageBuffer); + return message; +} + +BOOL UnadjustWindowRectEx(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle) +{ + RECT rc; + SetRectEmpty(&rc); + BOOL fRc = AdjustWindowRectEx(&rc, dwStyle, fMenu, dwExStyle); + if (fRc) { + prc->left -= rc.left; + prc->top -= rc.top; + prc->right -= rc.right; + prc->bottom -= rc.bottom; + } + return fRc; +} + +void _pre_call_callback(const char* name, void* funcptr, int len_args, ...) +{ + assert(App::I->is_render_thread()); +} + +void _post_call_callback(const char* name, void* funcptr, int len_args, ...) +{ + GLenum error_code; + error_code = glad_glGetError(); + + if (error_code != pp::renderer::gl::no_error_code()) + { + LOG("ERROR %d in %s\n", error_code, name); + } +}