diff --git a/cmake/PanoPainterSources.cmake b/cmake/PanoPainterSources.cmake index 277641be..906f6760 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_draw_toolbar.cpp src/app_layout_ui_state.cpp src/app_layout_sidebar.cpp src/app_layout_main_toolbar.cpp diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index ea85fb62..17e83acf 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`: 353 lines +- `src/app_layout.cpp`: 285 lines - `src/canvas_modes.cpp`: 1798 lines - `src/node.cpp`: 1594 lines -- `src/main.cpp`: 487 lines +- `src/main.cpp`: 434 lines - `src/node_panel_brush.cpp`: 1197 lines - `src/node_stroke_preview.cpp`: 890 lines -- `src/node_canvas.cpp`: 910 lines +- `src/node_canvas.cpp`: 881 lines - `src/app.cpp`: 502 lines - `src/app_dialogs.cpp`: 142 lines @@ -129,7 +129,10 @@ Current architecture mismatches that must be treated as real blockers: `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`, where the post-draw/display-resolve tail now also - routes through `execute_node_canvas_draw_merge_tail(...)`. + routes through `execute_node_canvas_draw_merge_tail(...)`, while the + unmerged-path onion-range planning, plane filtering, per-layer visit + handling, and per-visit layer-path execution now also route through + `execute_legacy_canvas_draw_unmerged_node_canvas_shell(...)`. - `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 @@ -146,8 +149,9 @@ Current architecture mismatches that must be treated as real blockers: binding now also lives in `src/app_layout_edit_menu.cpp` and `App::init_menu_edit()` is now a thin call-through, while UI-direction and persisted floating/docked panel-state ownership now also live in - `src/app_layout_ui_state.cpp`, and `src/app_layout.cpp` is now mostly - layout/bootstrap composition, while the + `src/app_layout_ui_state.cpp`, while draw-toolbar binding now also lives in + `src/app_layout_draw_toolbar.cpp`, and `src/app_layout.cpp` is now mostly + brush-refresh and layout/bootstrap composition, 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 @@ -195,7 +199,9 @@ Current architecture mismatches that must be treated as real blockers: `src/platform_windows/windows_bootstrap_helpers.*` for runtime-data discovery, startup-state initialization, window creation, pixel-format setup, GL loader init, runtime-info logging, and core-context upgrade - sequencing, while the Win32 window procedure and retained message-handling + sequencing, while BugTrap/SEH recovery setup now also lives in + `src/platform_windows/windows_bootstrap_helpers.cpp` instead of + `src/main.cpp`, while the Win32 window procedure and retained message-handling shell now also live in `src/platform_windows/windows_window_shell.*` instead of `src/main.cpp`, which materially thins `src/main.cpp` even though broader entrypoint/runtime composition still remains there, diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index 0e663fa8..9965045e 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -225,6 +225,11 @@ Current slice: `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`. +- `NodeCanvas` unmerged-path onion-range planning, plane filtering, per-layer + visit handling, and per-visit layer-path execution now also route through + `execute_legacy_canvas_draw_unmerged_node_canvas_shell(...)`, which trims + another outer draw-shell block even though the broader node draw loop still + lives in `src/node_canvas.cpp`. Write scope: - `src/node_stroke_preview.cpp` @@ -303,7 +308,7 @@ targets look like helpers under one old monolith. Status: In Progress Why now: -`src/app_layout.cpp` is still a 353-line mixed file that builds menus, +`src/app_layout.cpp` is still a 285-line mixed file that builds menus, attaches callbacks, computes planner inputs, and mutates UI state directly. Current slice: @@ -333,6 +338,9 @@ Current slice: - UI-direction plus persisted floating/docked panel-state ownership now also lives in `src/app_layout_ui_state.cpp`, and `src/app_layout.cpp` is down to the remaining draw-toolbar, brush-refresh, and layout/bootstrap composition. +- Draw-toolbar binding now also lives in `src/app_layout_draw_toolbar.cpp`, and + `src/app_layout.cpp` is down to the remaining brush-refresh and + layout/bootstrap composition. Write scope: - `src/app_layout.cpp` @@ -498,6 +506,9 @@ Current slice: discovery, startup-state initialization, window creation, pixel-format setup, GL loader init, runtime-info logging, and core-context upgrade sequencing +- BugTrap/SEH recovery setup now also lives in + `src/platform_windows/windows_bootstrap_helpers.cpp` instead of + `src/main.cpp` - the Win32 window procedure and retained message-handling shell now also live in `src/platform_windows/windows_window_shell.*` instead of `src/main.cpp`, which materially thins the entry file even though broader runtime/entrypoint diff --git a/src/app_layout.cpp b/src/app_layout.cpp index 6cf2e0ac..606b3664 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -10,15 +10,12 @@ #include "app_core/about_menu.h" #include "app_core/app_preferences.h" #include "app_core/brush_ui.h" -#include "app_core/canvas_tool_ui.h" #include "app_core/document_layer.h" #include "app_core/document_canvas.h" #include "app_core/app_status.h" #include "app_core/tools_menu.h" #include "legacy_app_preference_services.h" #include "legacy_app_shell_services.h" -#include "legacy_brush_ui_services.h" -#include "legacy_canvas_tool_services.h" #include "legacy_document_layer_services.h" #include "legacy_preference_storage.h" #include "font.h" @@ -38,21 +35,6 @@ 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) -{ - 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); -} - [[nodiscard]] bool should_open_tools_panel(const pp::app::ToolsPanelPlan& plan) noexcept { return plan.action == pp::app::ToolsPanelAction::open_floating_panel; @@ -112,64 +94,6 @@ void App::init_toolbar_main() pp::panopainter::bind_legacy_main_toolbar(*this); } -[[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; -} - -template -void execute_canvas_tool_toolbar_binding( - App& app, - const pp::app::CanvasToolToolbarBinding& binding, - T* button) -{ - const auto plan = pp::app::plan_canvas_tool_toolbar_binding_action( - binding, - current_canvas_mode_is_draw(app)); - const auto status = binding.action == pp::app::CanvasToolToolbarAction::select_mode - ? pp::panopainter::execute_legacy_canvas_tool_plan(app, plan, button) - : pp::panopainter::execute_legacy_canvas_tool_plan(app, plan); - if (!status.ok()) - LOG("Canvas toolbar action failed: %s", status.message); -} - -template -void bind_canvas_tool_toolbar_button( - App& app, - const pp::app::CanvasToolToolbarBinding& binding, - T* button) -{ - button->on_click = [&app, binding, button](Node*) { - execute_canvas_tool_toolbar_binding(app, binding, button); - }; -} - -void App::init_toolbar_draw() -{ - const auto toolbar = pp::app::plan_canvas_tool_toolbar(); - bool apply_default_tool = false; - for (const auto& binding : toolbar.bindings) { - if (binding.custom_button) { - if (auto* button = layout[main_id]->find(binding.button_id.data())) { - bind_canvas_tool_toolbar_button(*this, binding, button); - apply_default_tool = apply_default_tool || binding.applies_default_on_init; - } - } else { - if (auto* button = layout[main_id]->find(binding.button_id.data())) { - bind_canvas_tool_toolbar_button(*this, binding, button); - apply_default_tool = apply_default_tool || binding.applies_default_on_init; - } - } - } - - if (apply_default_tool) { - const auto default_plan = pp::app::plan_canvas_tool_select(toolbar.default_mode); - const auto status = pp::panopainter::execute_legacy_canvas_tool_plan(*this, default_plan); - if (!status.ok()) - LOG("Canvas default tool action failed: %s", status.message); - } -} - void App::init_menu_file() { pp::panopainter::bind_legacy_file_menu(*this); diff --git a/src/app_layout_draw_toolbar.cpp b/src/app_layout_draw_toolbar.cpp new file mode 100644 index 00000000..d3114469 --- /dev/null +++ b/src/app_layout_draw_toolbar.cpp @@ -0,0 +1,68 @@ +#include "pch.h" +#include "app.h" +#include "app_core/canvas_tool_ui.h" +#include "legacy_canvas_tool_services.h" +#include "node_button.h" +#include "node_button_custom.h" + +namespace { + +[[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; +} + +template +void execute_canvas_tool_toolbar_binding( + App& app, + const pp::app::CanvasToolToolbarBinding& binding, + T* button) +{ + const auto plan = pp::app::plan_canvas_tool_toolbar_binding_action( + binding, + current_canvas_mode_is_draw(app)); + const auto status = binding.action == pp::app::CanvasToolToolbarAction::select_mode + ? pp::panopainter::execute_legacy_canvas_tool_plan(app, plan, button) + : pp::panopainter::execute_legacy_canvas_tool_plan(app, plan); + if (!status.ok()) + LOG("Canvas toolbar action failed: %s", status.message); +} + +template +void bind_canvas_tool_toolbar_button( + App& app, + const pp::app::CanvasToolToolbarBinding& binding, + T* button) +{ + button->on_click = [&app, binding, button](Node*) { + execute_canvas_tool_toolbar_binding(app, binding, button); + }; +} + +} // namespace + +void App::init_toolbar_draw() +{ + const auto toolbar = pp::app::plan_canvas_tool_toolbar(); + bool apply_default_tool = false; + for (const auto& binding : toolbar.bindings) { + if (binding.custom_button) { + if (auto* button = layout[main_id]->find(binding.button_id.data())) { + bind_canvas_tool_toolbar_button(*this, binding, button); + apply_default_tool = apply_default_tool || binding.applies_default_on_init; + } + } else { + if (auto* button = layout[main_id]->find(binding.button_id.data())) { + bind_canvas_tool_toolbar_button(*this, binding, button); + apply_default_tool = apply_default_tool || binding.applies_default_on_init; + } + } + } + + if (apply_default_tool) { + const auto default_plan = pp::app::plan_canvas_tool_select(toolbar.default_mode); + const auto status = pp::panopainter::execute_legacy_canvas_tool_plan(*this, default_plan); + if (!status.ok()) + LOG("Canvas default tool action failed: %s", status.message); + } +} diff --git a/src/legacy_canvas_draw_merge_services.h b/src/legacy_canvas_draw_merge_services.h index 29e0703d..4c3506b9 100644 --- a/src/legacy_canvas_draw_merge_services.h +++ b/src/legacy_canvas_draw_merge_services.h @@ -1,5 +1,7 @@ #pragma once +#include "app.h" +#include "app_core/document_animation.h" #include "legacy_canvas_stroke_composite_services.h" #include "legacy_canvas_stroke_erase_services.h" #include "shader.h" @@ -988,6 +990,128 @@ inline void execute_legacy_canvas_draw_unmerged_shell( } } +template < + typename MakeLayerPathExecution, + typename ShouldDrawTemporaryErase, + typename ShouldDrawTemporaryPaint, + typename FrameAlpha> +inline void execute_legacy_canvas_draw_unmerged_layer_path( + const LegacyCanvasDrawLayerVisit& visit, + const auto& onion_range, + bool use_blend, + const glm::mat4& proj, + const glm::mat4& camera, + const glm::mat4& orientation, + const auto& plane_transform, + MakeLayerPathExecution&& make_layer_path_execution, + ShouldDrawTemporaryErase&& should_draw_temporary_erase, + ShouldDrawTemporaryPaint&& should_draw_temporary_paint, + FrameAlpha&& frame_alpha) +{ + const auto plane_index = visit.plane_index; + const auto plane_mvp_z = proj * camera * + glm::scale(glm::vec3(visit.z + 1)) * + orientation * + plane_transform[plane_index] * + glm::translate(glm::vec3(0, 0, -1)); + const auto layer_path_execution = make_layer_path_execution(visit.layer_index, plane_index, plane_mvp_z); + + execute_legacy_canvas_draw_merge_layer_path( + should_draw_temporary_erase(visit), + should_draw_temporary_paint(visit), + use_blend, + visit.first_frame, + visit.last_frame, + [&](int frame) { + return frame_alpha(onion_range, frame); + }, + layer_path_execution); +} + +template < + typename NodeCanvasT, + typename PrepareBlendCache, + typename DrawBackground, + typename ConfigureBlendState, + typename DisableDepthTest, + typename MakeLayerPathExecution, + typename LogOnionRangeFailure, + typename CompositeBlendCache> +inline void execute_legacy_canvas_draw_unmerged_node_canvas_shell( + NodeCanvasT& node_canvas, + bool use_blend, + const glm::mat4& proj, + const glm::mat4& camera, + const glm::mat4& orientation, + PrepareBlendCache&& prepare_blend_cache, + DrawBackground&& draw_background, + ConfigureBlendState&& configure_blend_state, + DisableDepthTest&& disable_depth_test, + MakeLayerPathExecution&& make_layer_path_execution, + 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(); + + const auto plan_onion_range = [&](size_t layer_index) { + return pp::app::plan_animation_onion_frame_range( + node_canvas.m_canvas->m_layers[layer_index]->frames_count(), + node_canvas.m_canvas->m_layers[layer_index]->m_frame_index, + App::I->animation->get_onion_size()); + }; + + const auto should_draw_plane = [&](size_t layer_index, int plane_index, int first_frame, int last_frame) { + bool faces = false; + for (int frame = first_frame; frame <= last_frame; ++frame) { + faces |= node_canvas.m_canvas->m_layers[layer_index]->face(plane_index, frame); + } + + if (node_canvas.m_canvas->m_show_tmp && node_canvas.m_canvas->m_current_layer_idx == layer_index) { + return true; + } + + return node_canvas.m_canvas->m_layers[layer_index]->m_visible && + node_canvas.m_canvas->m_layers[layer_index]->m_opacity != .0f && + faces; + }; + + execute_legacy_canvas_draw_layer_traversal( + node_canvas.m_canvas->m_layers.size(), + plan_onion_range, + should_draw_plane, + [&](const LegacyCanvasDrawLayerVisit& visit, const auto& onion_range) { + execute_legacy_canvas_draw_unmerged_layer_path( + visit, + onion_range, + use_blend, + proj, + camera, + orientation, + node_canvas.m_canvas->m_plane_transform, + make_layer_path_execution, + [&](const LegacyCanvasDrawLayerVisit& visit) { + return node_canvas.m_canvas->m_current_stroke && node_canvas.m_canvas->m_current_mode == kCanvasMode::Erase && node_canvas.m_canvas->m_show_tmp && node_canvas.m_canvas->m_current_layer_idx == visit.layer_index; + }, + [&](const LegacyCanvasDrawLayerVisit& visit) { + return node_canvas.m_canvas->m_current_stroke && node_canvas.m_canvas->m_show_tmp && node_canvas.m_canvas->m_current_layer_idx == visit.layer_index; + }, + [&](const auto& onion_range, int frame) { + return pp::app::animation_onion_frame_alpha(onion_range, frame); + }); + }, + 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 4e404e23..ccffd9e5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,10 +21,6 @@ #include "wacom.h" #include "abr.h" -#include -#include -#include - namespace pp::platform::windows { void set_async_render_context(HDC hdc, HGLRC hrc); void lock_async_render_context(); @@ -323,62 +319,6 @@ int read_WMI_info() return 0; } -INT_PTR g_iLogHandle = -1; -static void SetupExceptionHandler() -{ - // Setup exception handler - BT_SetAppName(_T("PanoPainter")); - BT_SetAppVersion(g_version_w); - //BT_SetSupportEMail(_T("your@email.com")); - BT_SetFlags(BTF_DETAILEDMODE | BTF_ATTACHREPORT | BTF_SCREENCAPTURE); - - // = BugTrapServer =========================================== - //BT_SetSupportServer(_T("omigamedev.ddns.net"), 8088); - BT_SetSupportEMail(_T("info@panopainter.com")); - // - or - - //BT_SetSupportServer(_T("127.0.0.1"), 9999); - - // = BugTrapWebServer ======================================== - //BT_SetSupportServer(_T("http://localhost/BugTrapWebServer/RequestHandler.aspx"), BUGTRAP_HTTP_PORT); - //BT_SetSupportServer(_T("http://omigamedev.ddns.net:8088/source/Server/BugTrapWebServer/RequestHandler.aspx"), BUGTRAP_HTTP_PORT); - BT_SetSupportServer(_T("http://panopainter.com/bug/"), BUGTRAP_HTTP_PORT); - - // required for VS 2005 & 2008 - BT_InstallSehFilter(); - - // Add custom log file using default name -// g_iLogHandle = BT_OpenLogFile(NULL, BTLF_TEXT); -// BT_SetLogSizeInEntries(g_iLogHandle, 100); -// BT_SetLogFlags(g_iLogHandle, BTLF_SHOWTIMESTAMP); -// BT_SetLogEchoMode(g_iLogHandle, BTLE_STDERR | BTLE_DBGOUT); -// -// PCTSTR pszLogFileName = BT_GetLogFileName(g_iLogHandle); - TCHAR wpath[MAX_PATH]; - //GetFullPathNameW(L"panopainter-log.txt", 1024, wpath, nullptr); - auto log_file = App::I->data_path + "/panopainter-log.txt"; - std::mbstowcs(wpath, log_file.c_str(), log_file.size()); - BT_AddLogFile(wpath); - - BT_SetPreErrHandler([](INT_PTR){ - if (Canvas::I && Canvas::I->m_unsaved) - { - auto t = std::time(nullptr); - auto tm = *std::localtime(&t); - std::ostringstream oss; - oss << std::put_time(&tm, "%d-%m-%Y %H-%M-%S"); - - auto path = App::I->data_path + "/" + App::I->doc_name + "-recovery (" + oss.str() + ").ppi"; - Canvas::I->project_save_thread(path, false); - static char abspath[MAX_PATH]; - GetFullPathNameA(path.c_str(), MAX_PATH, abspath, NULL); - static char message[4096]; - snprintf(message, sizeof(message), "File recovered in: %s", abspath); - MessageBoxA(retained_state().hWnd, message, "File Recovery", MB_OK | MB_ICONWARNING); - } - LogRemote::I.file_close(); - }, 0); -} - // create a reverse map from kKey to VK_XXX void init_vk_map() { @@ -439,8 +379,7 @@ int main(int argc, char** argv) init_vk_map(); - SetupExceptionHandler(); - BT_SetTerminate(); + pp::platform::windows::setup_exception_handler(); read_WMI_info(); diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index cfd1aaba..26d4ca7f 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -667,11 +667,15 @@ void NodeCanvas::draw() m_canvas->m_current_stroke ? m_canvas->m_current_stroke->m_brush.get() : nullptr); const bool use_blend = blend_gate.shader_blend; const bool copy_blend_destination = use_blend && !blend_gate.reads_destination_color; + const auto layer_orientation = glm::eulerAngleYXZ(yaw, pitch, roll); const auto& b = m_canvas->m_current_stroke->m_brush; - pp::panopainter::execute_legacy_canvas_draw_unmerged_shell( + pp::panopainter::execute_legacy_canvas_draw_unmerged_node_canvas_shell( + *this, use_blend, - m_canvas->m_layers.size(), + proj, + camera, + layer_orientation, [&] { apply_node_canvas_viewport(0, 0, m_cache_rtt.getWidth(), m_cache_rtt.getHeight()); m_cache_rtt.bindFramebuffer(); @@ -703,33 +707,8 @@ void NodeCanvas::draw() [&] { 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(), - m_canvas->m_layers[layer_index]->m_frame_index, - App::I->animation->get_onion_size()); - }, - [&](size_t layer_index, int plane_index, int first_frame, int last_frame) { - bool faces = false; - for (int frame = first_frame; frame <= last_frame; ++frame) - faces |= m_canvas->m_layers[layer_index]->face(plane_index, frame); - - if (m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) - return true; - - return m_canvas->m_layers[layer_index]->m_visible && - m_canvas->m_layers[layer_index]->m_opacity != .0f && - faces; - }, - [&](const pp::panopainter::LegacyCanvasDrawLayerVisit& visit, const auto& onion_range) { - const auto layer_index = visit.layer_index; - const auto plane_index = visit.plane_index; - const auto plane_mvp_z = proj * camera * - glm::scale(glm::vec3(visit.z + 1)) * - glm::eulerAngleYXZ(yaw, pitch, roll) * - m_canvas->m_plane_transform[plane_index] * - glm::translate(glm::vec3(0, 0, -1)); - const auto layer_path_execution = make_node_canvas_layer_path_execution( + [&](size_t layer_index, int plane_index, const glm::mat4& plane_mvp_z) { + return make_node_canvas_layer_path_execution( *this, layer_index, plane_index, @@ -737,17 +716,6 @@ void NodeCanvas::draw() b.get(), copy_blend_destination, m_canvas->m_cam_fov < 20.f); - - 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, - visit.first_frame, - visit.last_frame, - [&](int frame) { - return pp::app::animation_onion_frame_alpha(onion_range, frame); - }, - layer_path_execution); }, [&](const char* message) { LOG("NodeCanvas onion frame range failed: %s", message); diff --git a/src/platform_windows/windows_bootstrap_helpers.cpp b/src/platform_windows/windows_bootstrap_helpers.cpp index 7a44ece0..273a0bec 100644 --- a/src/platform_windows/windows_bootstrap_helpers.cpp +++ b/src/platform_windows/windows_bootstrap_helpers.cpp @@ -4,10 +4,16 @@ #include "platform_windows/windows_window_shell.h" #include "app.h" +#include "canvas.h" #include "legacy_gl_runtime_dispatch.h" #include "legacy_preference_storage.h" #include "log.h" +#include +#include +#include +#include +#include #include #include @@ -105,6 +111,57 @@ void ensure_runtime_data_directory() LOG("data files ok"); } +void setup_exception_handler() +{ + // Setup exception handler + BT_SetAppName(_T("PanoPainter")); + BT_SetAppVersion(g_version_w); + //BT_SetSupportEMail(_T("your@email.com")); + BT_SetFlags(BTF_DETAILEDMODE | BTF_ATTACHREPORT | BTF_SCREENCAPTURE); + + // = BugTrapServer =========================================== + //BT_SetSupportServer(_T("omigamedev.ddns.net"), 8088); + BT_SetSupportEMail(_T("info@panopainter.com")); + // - or - + //BT_SetSupportServer(_T("127.0.0.1"), 9999); + + // = BugTrapWebServer ======================================== + //BT_SetSupportServer(_T("http://localhost/BugTrapWebServer/RequestHandler.aspx"), BUGTRAP_HTTP_PORT); + //BT_SetSupportServer(_T("http://omigamedev.ddns.net:8088/source/Server/BugTrapWebServer/RequestHandler.aspx"), BUGTRAP_HTTP_PORT); + BT_SetSupportServer(_T("http://panopainter.com/bug/"), BUGTRAP_HTTP_PORT); + + // required for VS 2005 & 2008 + BT_InstallSehFilter(); + + // Add custom log file using default name + TCHAR wpath[MAX_PATH]; + //GetFullPathNameW(L"panopainter-log.txt", 1024, wpath, nullptr); + auto log_file = App::I->data_path + "/panopainter-log.txt"; + std::mbstowcs(wpath, log_file.c_str(), log_file.size()); + BT_AddLogFile(wpath); + + BT_SetPreErrHandler([](INT_PTR){ + if (Canvas::I && Canvas::I->m_unsaved) + { + auto t = std::time(nullptr); + auto tm = *std::localtime(&t); + std::ostringstream oss; + oss << std::put_time(&tm, "%d-%m-%Y %H-%M-%S"); + + auto path = App::I->data_path + "/" + App::I->doc_name + "-recovery (" + oss.str() + ").ppi"; + Canvas::I->project_save_thread(path, false); + static char abspath[MAX_PATH]; + GetFullPathNameA(path.c_str(), MAX_PATH, abspath, NULL); + static char message[4096]; + snprintf(message, sizeof(message), "File recovered in: %s", abspath); + MessageBoxA(retained_state().hWnd, message, "File Recovery", MB_OK | MB_ICONWARNING); + } + LogRemote::I.file_close(); + }, 0); + + BT_SetTerminate(); +} + MainWindowStartupState initialize_main_window_startup_state() { auto startup = MainWindowStartupState {}; diff --git a/src/platform_windows/windows_bootstrap_helpers.h b/src/platform_windows/windows_bootstrap_helpers.h index 0c9e1870..6eefa156 100644 --- a/src/platform_windows/windows_bootstrap_helpers.h +++ b/src/platform_windows/windows_bootstrap_helpers.h @@ -46,6 +46,7 @@ enum class MainStartupResult }; void ensure_runtime_data_directory(); +void setup_exception_handler(); MainWindowStartupState initialize_main_window_startup_state(); void create_main_window(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title); void initialize_pixel_format_descriptor(PIXELFORMATDESCRIPTOR& pixel_format);