Extract draw toolbar and thin NodeCanvas and Win32 shell

This commit is contained in:
2026-06-16 13:37:08 +02:00
parent 8ea56cbd30
commit 9c33ecc22b
10 changed files with 285 additions and 186 deletions

View File

@@ -97,6 +97,7 @@ set(PP_PANOPAINTER_APP_SOURCES
src/app_dialogs_info_openers.cpp src/app_dialogs_info_openers.cpp
src/app_events.cpp src/app_events.cpp
src/app_layout.cpp src/app_layout.cpp
src/app_layout_draw_toolbar.cpp
src/app_layout_ui_state.cpp src/app_layout_ui_state.cpp
src/app_layout_sidebar.cpp src/app_layout_sidebar.cpp
src/app_layout_main_toolbar.cpp src/app_layout_main_toolbar.cpp

View File

@@ -80,13 +80,13 @@ What is still carrying too much live ownership:
Current hotspot files: Current hotspot files:
- `src/canvas.cpp`: 2645 lines - `src/canvas.cpp`: 2645 lines
- `src/app_layout.cpp`: 353 lines - `src/app_layout.cpp`: 285 lines
- `src/canvas_modes.cpp`: 1798 lines - `src/canvas_modes.cpp`: 1798 lines
- `src/node.cpp`: 1594 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_panel_brush.cpp`: 1197 lines
- `src/node_stroke_preview.cpp`: 890 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.cpp`: 502 lines
- `src/app_dialogs.cpp`: 142 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 `make_legacy_canvas_draw_merge_layer_path_gl_execution(...)` even though the
remaining draw lambdas and broader node draw loop still live in remaining draw lambdas and broader node draw loop still live in
`src/node_canvas.cpp`, where the post-draw/display-resolve tail now also `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 - `app_layout.cpp` and `app_dialogs.cpp` are still mixed shell/controller files
rather than thin composition/binding surfaces, even though tools-menu binding rather than thin composition/binding surfaces, even though tools-menu binding
plus nested panels/options submenu wiring now live in 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 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 `App::init_menu_edit()` is now a thin call-through, while UI-direction and
persisted floating/docked panel-state ownership now also live in persisted floating/docked panel-state ownership now also live in
`src/app_layout_ui_state.cpp`, and `src/app_layout.cpp` is now mostly `src/app_layout_ui_state.cpp`, while draw-toolbar binding now also lives in
layout/bootstrap composition, while the `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 informational overlay opener family now also lives in
`src/app_dialogs_info_openers.cpp` and the corresponding `App::dialog_*` `src/app_dialogs_info_openers.cpp` and the corresponding `App::dialog_*`
entrypoints are thinner, while the export/video/PPBR dialog family now also 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 `src/platform_windows/windows_bootstrap_helpers.*` for runtime-data
discovery, startup-state initialization, window creation, pixel-format discovery, startup-state initialization, window creation, pixel-format
setup, GL loader init, runtime-info logging, and core-context upgrade 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.*` shell now also live in `src/platform_windows/windows_window_shell.*`
instead of `src/main.cpp`, which materially thins `src/main.cpp` even instead of `src/main.cpp`, which materially thins `src/main.cpp` even
though broader entrypoint/runtime composition still remains there, though broader entrypoint/runtime composition still remains there,

View File

@@ -225,6 +225,11 @@ Current slice:
`execute_legacy_canvas_draw_unmerged_shell(...)`, which removes another `execute_legacy_canvas_draw_unmerged_shell(...)`, which removes another
coherent orchestration block from `NodeCanvas::draw()` even though the coherent orchestration block from `NodeCanvas::draw()` even though the
broader node draw loop still lives in `src/node_canvas.cpp`. 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: Write scope:
- `src/node_stroke_preview.cpp` - `src/node_stroke_preview.cpp`
@@ -303,7 +308,7 @@ targets look like helpers under one old monolith.
Status: In Progress Status: In Progress
Why now: 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. attaches callbacks, computes planner inputs, and mutates UI state directly.
Current slice: Current slice:
@@ -333,6 +338,9 @@ Current slice:
- UI-direction plus persisted floating/docked panel-state ownership now also - 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 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. 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: Write scope:
- `src/app_layout.cpp` - `src/app_layout.cpp`
@@ -498,6 +506,9 @@ Current slice:
discovery, startup-state initialization, window creation, pixel-format discovery, startup-state initialization, window creation, pixel-format
setup, GL loader init, runtime-info logging, and core-context upgrade setup, GL loader init, runtime-info logging, and core-context upgrade
sequencing 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 - the Win32 window procedure and retained message-handling shell now also live
in `src/platform_windows/windows_window_shell.*` instead of `src/main.cpp`, in `src/platform_windows/windows_window_shell.*` instead of `src/main.cpp`,
which materially thins the entry file even though broader runtime/entrypoint which materially thins the entry file even though broader runtime/entrypoint

View File

@@ -10,15 +10,12 @@
#include "app_core/about_menu.h" #include "app_core/about_menu.h"
#include "app_core/app_preferences.h" #include "app_core/app_preferences.h"
#include "app_core/brush_ui.h" #include "app_core/brush_ui.h"
#include "app_core/canvas_tool_ui.h"
#include "app_core/document_layer.h" #include "app_core/document_layer.h"
#include "app_core/document_canvas.h" #include "app_core/document_canvas.h"
#include "app_core/app_status.h" #include "app_core/app_status.h"
#include "app_core/tools_menu.h" #include "app_core/tools_menu.h"
#include "legacy_app_preference_services.h" #include "legacy_app_preference_services.h"
#include "legacy_app_shell_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_document_layer_services.h"
#include "legacy_preference_storage.h" #include "legacy_preference_storage.h"
#include "font.h" #include "font.h"
@@ -38,21 +35,6 @@ void bind_legacy_tools_menu(App& app);
namespace { 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>& brush)
{
return pp::panopainter::apply_legacy_brush_preset_plan(app, brush);
}
[[nodiscard]] bool should_open_tools_panel(const pp::app::ToolsPanelPlan& plan) noexcept [[nodiscard]] bool should_open_tools_panel(const pp::app::ToolsPanelPlan& plan) noexcept
{ {
return plan.action == pp::app::ToolsPanelAction::open_floating_panel; 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); 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<class T>
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<class T>
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<NodeButtonCustom>(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<NodeButton>(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() void App::init_menu_file()
{ {
pp::panopainter::bind_legacy_file_menu(*this); pp::panopainter::bind_legacy_file_menu(*this);

View File

@@ -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<class T>
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<class T>
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<NodeButtonCustom>(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<NodeButton>(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);
}
}

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include "app.h"
#include "app_core/document_animation.h"
#include "legacy_canvas_stroke_composite_services.h" #include "legacy_canvas_stroke_composite_services.h"
#include "legacy_canvas_stroke_erase_services.h" #include "legacy_canvas_stroke_erase_services.h"
#include "shader.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<LogOnionRangeFailure>(log_onion_range_failure));
if (use_blend) {
composite_blend_cache();
}
}
inline void execute_legacy_canvas_draw_merge_plane_setup( inline void execute_legacy_canvas_draw_merge_plane_setup(
const LegacyCanvasDrawMergePlaneSetupUniforms& uniforms, const LegacyCanvasDrawMergePlaneSetupUniforms& uniforms,
const LegacyCanvasDrawMergePlaneSetupExecution& execution) const LegacyCanvasDrawMergePlaneSetupExecution& execution)

View File

@@ -21,10 +21,6 @@
#include "wacom.h" #include "wacom.h"
#include "abr.h" #include "abr.h"
#include <iomanip>
#include <ctime>
#include <sstream>
namespace pp::platform::windows { namespace pp::platform::windows {
void set_async_render_context(HDC hdc, HGLRC hrc); void set_async_render_context(HDC hdc, HGLRC hrc);
void lock_async_render_context(); void lock_async_render_context();
@@ -323,62 +319,6 @@ int read_WMI_info()
return 0; 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 // create a reverse map from kKey to VK_XXX
void init_vk_map() void init_vk_map()
{ {
@@ -439,8 +379,7 @@ int main(int argc, char** argv)
init_vk_map(); init_vk_map();
SetupExceptionHandler(); pp::platform::windows::setup_exception_handler();
BT_SetTerminate();
read_WMI_info(); read_WMI_info();

View File

@@ -667,11 +667,15 @@ void NodeCanvas::draw()
m_canvas->m_current_stroke ? m_canvas->m_current_stroke->m_brush.get() : nullptr); m_canvas->m_current_stroke ? m_canvas->m_current_stroke->m_brush.get() : nullptr);
const bool use_blend = blend_gate.shader_blend; const bool use_blend = blend_gate.shader_blend;
const bool copy_blend_destination = use_blend && !blend_gate.reads_destination_color; 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; 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, 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()); apply_node_canvas_viewport(0, 0, m_cache_rtt.getWidth(), m_cache_rtt.getHeight());
m_cache_rtt.bindFramebuffer(); m_cache_rtt.bindFramebuffer();
@@ -703,33 +707,8 @@ void NodeCanvas::draw()
[&] { [&] {
apply_node_canvas_capability(pp::renderer::gl::depth_test_state(), false); apply_node_canvas_capability(pp::renderer::gl::depth_test_state(), false);
}, },
[&](size_t layer_index) { [&](size_t layer_index, int plane_index, const glm::mat4& plane_mvp_z) {
return pp::app::plan_animation_onion_frame_range( return make_node_canvas_layer_path_execution(
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(
*this, *this,
layer_index, layer_index,
plane_index, plane_index,
@@ -737,17 +716,6 @@ void NodeCanvas::draw()
b.get(), b.get(),
copy_blend_destination, copy_blend_destination,
m_canvas->m_cam_fov < 20.f); 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) { [&](const char* message) {
LOG("NodeCanvas onion frame range failed: %s", message); LOG("NodeCanvas onion frame range failed: %s", message);

View File

@@ -4,10 +4,16 @@
#include "platform_windows/windows_window_shell.h" #include "platform_windows/windows_window_shell.h"
#include "app.h" #include "app.h"
#include "canvas.h"
#include "legacy_gl_runtime_dispatch.h" #include "legacy_gl_runtime_dispatch.h"
#include "legacy_preference_storage.h" #include "legacy_preference_storage.h"
#include "log.h" #include "log.h"
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <shellscalingapi.h> #include <shellscalingapi.h>
#include <string> #include <string>
@@ -105,6 +111,57 @@ void ensure_runtime_data_directory()
LOG("data files ok"); 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() MainWindowStartupState initialize_main_window_startup_state()
{ {
auto startup = MainWindowStartupState {}; auto startup = MainWindowStartupState {};

View File

@@ -46,6 +46,7 @@ enum class MainStartupResult
}; };
void ensure_runtime_data_directory(); void ensure_runtime_data_directory();
void setup_exception_handler();
MainWindowStartupState initialize_main_window_startup_state(); MainWindowStartupState initialize_main_window_startup_state();
void create_main_window(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title); void create_main_window(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title);
void initialize_pixel_format_descriptor(PIXELFORMATDESCRIPTOR& pixel_format); void initialize_pixel_format_descriptor(PIXELFORMATDESCRIPTOR& pixel_format);