Thin node loader, Win32 wrappers, and canvas mode shells

This commit is contained in:
2026-06-17 00:10:39 +02:00
parent acee4db356
commit 371095770d
9 changed files with 302 additions and 289 deletions

View File

@@ -81,9 +81,9 @@ Current hotspot files:
- `src/canvas.cpp`: 17 lines - `src/canvas.cpp`: 17 lines
- `src/app_layout.cpp`: 125 lines - `src/app_layout.cpp`: 125 lines
- `src/canvas_modes.cpp`: 191 lines - `src/canvas_modes.cpp`: 1 line
- `src/node.cpp`: 257 lines - `src/node.cpp`: 231 lines
- `src/main.cpp`: 156 lines - `src/main.cpp`: 87 lines
- `src/node_panel_brush.cpp`: 2 lines - `src/node_panel_brush.cpp`: 2 lines
- `src/node_stroke_preview.cpp`: 160 lines - `src/node_stroke_preview.cpp`: 160 lines
- `src/node_canvas.cpp`: 85 lines - `src/node_canvas.cpp`: 85 lines
@@ -131,6 +131,16 @@ Latest slice:
`src/legacy_brush_preset_list_services.*`, and `src/legacy_brush_preset_list_services.*`, and
`src/legacy_brush_preset_services.*`), leaving `src/legacy_brush_preset_services.*`), leaving
`src/node_panel_brush.cpp` as a thin translation unit. `src/node_panel_brush.cpp` as a thin translation unit.
- `Node::load_internal(...)` now routes through
`load_legacy_ui_node(...)` in `src/legacy_ui_node_loader.*`, which moves the
init/attribute-parse/create/child-load/loaded shell out of `src/node.cpp`.
- The remaining Win32 shell wrappers for close, async lock/swap, stylus/FPS
updates, VR start/stop, window-state save, and the window-handle accessor now
live in `src/platform_windows/windows_platform_services.cpp` instead of
`src/main.cpp`, leaving `main.cpp` as a thinner entry/runtime dispatcher.
- The entire `CanvasModeGrid` implementation plus `ActionModeGrid` undo/redo
glue now live in `src/legacy_canvas_mode_helpers.cpp` instead of
`src/canvas_modes.cpp`, leaving `src/canvas_modes.cpp` as a minimal shell.
Current architecture mismatches that must be treated as real blockers: Current architecture mismatches that must be treated as real blockers:

View File

@@ -391,6 +391,10 @@ Current slice:
render-target validation, viewport/clear-color save-restore, and immediate render-target validation, viewport/clear-color save-restore, and immediate
runtime request assembly out of the live node file and leaves runtime request assembly out of the live node file and leaves
`src/node_stroke_preview.cpp` at 160 lines. `src/node_stroke_preview.cpp` at 160 lines.
- `CanvasModeGrid` plus `ActionModeGrid` undo/redo now also live in
`src/legacy_canvas_mode_helpers.cpp` instead of staying inline in
`src/canvas_modes.cpp`, which leaves the live canvas-modes file as a
minimal shell.
- `NodeCanvas::init()` plus the remaining `NodeCanvas::draw()` outer shell now - `NodeCanvas::init()` plus the remaining `NodeCanvas::draw()` outer shell now
also live in `src/legacy_node_canvas_draw_services.*` instead of staying also live in `src/legacy_node_canvas_draw_services.*` instead of staying
inline in `src/node_canvas.cpp`, which materially reduces the live node to a inline in `src/node_canvas.cpp`, which materially reduces the live node to a
@@ -908,6 +912,10 @@ Current slice:
base clone plumbing now also lives in `src/legacy_ui_node_lifecycle.*` base clone plumbing now also lives in `src/legacy_ui_node_lifecycle.*`
instead of staying inline in `src/node.cpp`, which materially thins another instead of staying inline in `src/node.cpp`, which materially thins another
coherent generic scene-graph shell without changing the public surface. coherent generic scene-graph shell without changing the public surface.
- `Node::load_internal(...)` now also routes through
`load_legacy_ui_node(...)` in `src/legacy_ui_node_loader.*`, which moves the
init/attribute-parse/create/child-load/loaded shell out of `src/node.cpp`
and leaves the remaining live node file thinner.
Write scope: Write scope:
- `src/node.cpp` - `src/node.cpp`
@@ -1090,6 +1098,12 @@ Current slice:
directly in those method bodies directly in those method bodies
- retained Apple callback injection and broader `platform_legacy` singleton - retained Apple callback injection and broader `platform_legacy` singleton
reach are still open reach are still open
- The remaining Win32 shell wrappers for close, async lock/swap,
stylus/FPS updates, VR start/stop, window-state save, and the
window-handle accessor now live in
`src/platform_windows/windows_platform_services.cpp` instead of
`src/main.cpp`, which leaves the live entry file as a thinner
startup/runtime dispatcher.
Write scope: Write scope:
- `src/platform_apple/*` - `src/platform_apple/*`

View File

@@ -1,191 +1 @@
#include "pch.h" #include "pch.h"
#include <cstdint>
#include "canvas_modes.h"
#include "layout.h"
#include "canvas.h"
#include "node_canvas.h"
#include "legacy_canvas_draw_merge_services.h"
#include "legacy_canvas_mode_helpers.h"
#include "legacy_ui_overlay_services.h"
#include "app.h"
#include "util.h"
NodeCanvas* CanvasMode::node;
using pp::legacy_canvas_mode::apply_canvas_mode_viewport;
using pp::legacy_canvas_mode::query_canvas_mode_read_framebuffer;
////////////////////////////////////////////////////////////////////
void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
return;
switch (me->m_type)
{
case kEventType::MouseDownL:
{
node->mouse_capture();
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 fb_pos;
if (Canvas::I->point_trace(loc, ro, rd, hit_o, fb_pos, hit_d, m_plane_id))
{
m_action = std::make_unique<ActionModeGrid>();
m_action->m_mode = this;
m_action->m_highlight = m_highlight;
m_action->m_selected_index = m_selected_index;
m_action->m_lines = m_lines;
int select = -1;
for (int i = 0; i < m_lines.size(); i++)
{
auto const& l = m_lines[i];
float d = lines_distance(ro, ro+rd*10.f, l.o-l.d*10.f, l.o+l.d*10.f);
if (d < 0.03f)
select = i;
}
if (select == -1)
{
m_lines.push_back({ hit_o, hit_d });
m_selected_index = (int)m_lines.size() - 1;
m_highlight = false;
m_added = true;
}
else
{
m_selected_index = select;
m_highlight = true;
m_added = false;
}
origin = hit_o;
dir = hit_d;
m_dragging = true;
}
break;
}
case kEventType::MouseUpL:
pp::panopainter::release_legacy_mouse_capture(*node);
m_dragging = false;
ActionManager::add(m_action.release());
//commit();
break;
case kEventType::MouseMove:
{
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 hit_fb;
if (m_dragging && Canvas::I->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, m_plane_id))
{
m_lines[m_selected_index] = { hit_o, hit_d };
origin = hit_o;
dir = hit_d;
m_dragging = true;
}
break;
}
case kEventType::MouseCancel:
if (m_dragging && m_selected_index == m_lines.size() - 1)
m_lines.pop_back();
m_dragging = false;
pp::panopainter::release_legacy_mouse_capture(*node);
break;
default:
break;
}
}
void CanvasModeGrid::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
const glm::vec4 blue(0, 0, 1, 1);
const glm::vec4 red(1, 0, 0, 1);
for (int i = 0; i < m_lines.size(); i++)
{
auto const& l = m_lines[i];
auto origin = l.o;
auto dir = l.d;
pp::panopainter::setup_legacy_vr_color_shader({
.color = m_highlight && i == m_selected_index ? blue : red,
.mvp = proj * camera,
});
static glm::vec4 AB[2];
AB[0] = {origin - dir * 10.f, 1};
AB[1] = {origin + dir * 10.f, 1 };
m_line.update_vertices(AB);
m_line.draw_stroke();
}
}
void CanvasModeGrid::init()
{
m_line.create();
}
void CanvasModeGrid::commit()
{
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj){
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 1, 0, 0, 1 },
.mvp = proj * camera,
});
static glm::vec4 AB[2];
AB[0] = {origin - dir * 10.f, 1};
AB[1] = {origin + dir * 10.f, 1 };
m_line.update_vertices(AB);
m_line.draw_stroke();
};
Canvas::I->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->layer().m_frame_index, true);
}
void CanvasModeGrid::clear()
{
auto a = new ActionModeGrid;
a->m_mode = this;
a->m_highlight = m_highlight;
a->m_selected_index = m_selected_index;
a->m_lines = m_lines;
ActionManager::add(a);
m_lines.clear();
}
void CanvasModeGrid::leave(kCanvasMode next)
{
m_selected_index = -1;
}
void CanvasModeGrid::on_KeyEvent(KeyEvent* ke)
{
if ((ke->m_key == kKey::KeyBackspace || ke->m_key == kKey::KeyDel)
&& ke->m_type == kEventType::KeyUp)
{
if (m_highlight)
{
auto a = new ActionModeGrid;
a->m_mode = this;
a->m_highlight = m_highlight;
a->m_selected_index = m_selected_index;
a->m_lines = m_lines;
ActionManager::add(a);
m_lines.erase(m_lines.begin() + m_selected_index);
m_highlight = false;
}
}
}
Action* ActionModeGrid::get_redo()
{
auto a = new ActionModeGrid;
a->m_mode = m_mode;
a->m_highlight = m_mode->m_highlight;
a->m_selected_index = m_mode->m_selected_index;
a->m_lines = m_mode->m_lines;
return a;
}
void ActionModeGrid::undo()
{
m_mode->m_highlight = m_highlight;
m_mode->m_selected_index = m_selected_index;
m_mode->m_lines = m_lines;
}

View File

@@ -9,6 +9,8 @@
#include "legacy_ui_gl_dispatch.h" #include "legacy_ui_gl_dispatch.h"
#include "renderer_gl/opengl_capabilities.h" #include "renderer_gl/opengl_capabilities.h"
NodeCanvas* CanvasMode::node;
namespace pp::legacy_canvas_mode { namespace pp::legacy_canvas_mode {
void set_canvas_mode_active_texture_unit(std::uint32_t unit_index) void set_canvas_mode_active_texture_unit(std::uint32_t unit_index)
@@ -188,3 +190,174 @@ void CanvasModeCamera::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
break; break;
} }
} }
void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
return;
switch (me->m_type)
{
case kEventType::MouseDownL:
{
node->mouse_capture();
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 fb_pos;
if (Canvas::I->point_trace(loc, ro, rd, hit_o, fb_pos, hit_d, m_plane_id))
{
m_action = std::make_unique<ActionModeGrid>();
m_action->m_mode = this;
m_action->m_highlight = m_highlight;
m_action->m_selected_index = m_selected_index;
m_action->m_lines = m_lines;
int select = -1;
for (int i = 0; i < m_lines.size(); i++)
{
auto const& l = m_lines[i];
float d = lines_distance(ro, ro + rd * 10.f, l.o - l.d * 10.f, l.o + l.d * 10.f);
if (d < 0.03f)
select = i;
}
if (select == -1)
{
m_lines.push_back({ hit_o, hit_d });
m_selected_index = (int)m_lines.size() - 1;
m_highlight = false;
m_added = true;
}
else
{
m_selected_index = select;
m_highlight = true;
m_added = false;
}
origin = hit_o;
dir = hit_d;
m_dragging = true;
}
break;
}
case kEventType::MouseUpL:
pp::panopainter::release_legacy_mouse_capture(*node);
m_dragging = false;
ActionManager::add(m_action.release());
//commit();
break;
case kEventType::MouseMove:
{
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 hit_fb;
if (m_dragging && Canvas::I->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, m_plane_id))
{
m_lines[m_selected_index] = { hit_o, hit_d };
origin = hit_o;
dir = hit_d;
m_dragging = true;
}
break;
}
case kEventType::MouseCancel:
if (m_dragging && m_selected_index == m_lines.size() - 1)
m_lines.pop_back();
m_dragging = false;
pp::panopainter::release_legacy_mouse_capture(*node);
break;
default:
break;
}
}
void CanvasModeGrid::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
const glm::vec4 blue(0, 0, 1, 1);
const glm::vec4 red(1, 0, 0, 1);
for (int i = 0; i < m_lines.size(); i++)
{
auto const& l = m_lines[i];
auto origin = l.o;
auto dir = l.d;
pp::panopainter::setup_legacy_vr_color_shader({
.color = m_highlight && i == m_selected_index ? blue : red,
.mvp = proj * camera,
});
static glm::vec4 AB[2];
AB[0] = { origin - dir * 10.f, 1 };
AB[1] = { origin + dir * 10.f, 1 };
m_line.update_vertices(AB);
m_line.draw_stroke();
}
}
void CanvasModeGrid::init()
{
m_line.create();
}
void CanvasModeGrid::commit()
{
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 1, 0, 0, 1 },
.mvp = proj * camera,
});
static glm::vec4 AB[2];
AB[0] = { origin - dir * 10.f, 1 };
AB[1] = { origin + dir * 10.f, 1 };
m_line.update_vertices(AB);
m_line.draw_stroke();
};
Canvas::I->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->layer().m_frame_index, true);
}
void CanvasModeGrid::clear()
{
auto a = new ActionModeGrid;
a->m_mode = this;
a->m_highlight = m_highlight;
a->m_selected_index = m_selected_index;
a->m_lines = m_lines;
ActionManager::add(a);
m_lines.clear();
}
void CanvasModeGrid::leave(kCanvasMode next)
{
m_selected_index = -1;
}
void CanvasModeGrid::on_KeyEvent(KeyEvent* ke)
{
if ((ke->m_key == kKey::KeyBackspace || ke->m_key == kKey::KeyDel)
&& ke->m_type == kEventType::KeyUp)
{
if (m_highlight)
{
auto a = new ActionModeGrid;
a->m_mode = this;
a->m_highlight = m_highlight;
a->m_selected_index = m_selected_index;
a->m_lines = m_lines;
ActionManager::add(a);
m_lines.erase(m_lines.begin() + m_selected_index);
m_highlight = false;
}
}
}
Action* ActionModeGrid::get_redo()
{
auto a = new ActionModeGrid;
a->m_mode = m_mode;
a->m_highlight = m_mode->m_highlight;
a->m_selected_index = m_mode->m_selected_index;
a->m_lines = m_mode->m_lines;
return a;
}
void ActionModeGrid::undo()
{
m_mode->m_highlight = m_highlight;
m_mode->m_selected_index = m_selected_index;
m_mode->m_lines = m_lines;
}

View File

@@ -1,6 +1,7 @@
#include "pch.h" #include "pch.h"
#include "legacy_ui_node_loader.h" #include "legacy_ui_node_loader.h"
#include "legacy_ui_node_attributes.h"
#include "log.h" #include "log.h"
#include "node.h" #include "node.h"
#include "layout.h" #include "layout.h"
@@ -154,6 +155,32 @@ void load_typed_child(Node& parent, const tinyxml2::XMLElement& x_child, std::st
} // namespace } // namespace
void load_legacy_ui_node(Node& node, const tinyxml2::XMLElement& x_node, bool skip_children)
{
node.m_name = x_node.Name();
//LOG("load_internal node %s", node.m_name.c_str());
node.init();
auto attr = x_node.FirstAttribute();
while (attr)
{
parse_legacy_ui_node_attribute(node, (kAttribute)const_hash(attr->Name()), attr);
attr = attr->Next();
}
node.create();
if (skip_children)
{
node.loaded();
return;
}
load_legacy_ui_children(node, x_node);
node.loaded();
}
void load_legacy_ui_children(Node& parent, const tinyxml2::XMLElement& x_node) void load_legacy_ui_children(Node& parent, const tinyxml2::XMLElement& x_node)
{ {
auto x_child = x_node.FirstChildElement(); auto x_child = x_node.FirstChildElement();

View File

@@ -8,6 +8,7 @@ class Node;
namespace pp::panopainter { namespace pp::panopainter {
void load_legacy_ui_node(Node& node, const tinyxml2::XMLElement& x_node, bool skip_children = false);
void load_legacy_ui_children(Node& parent, const tinyxml2::XMLElement& x_node); void load_legacy_ui_children(Node& parent, const tinyxml2::XMLElement& x_node);
} // namespace pp::panopainter } // namespace pp::panopainter

View File

@@ -19,76 +19,7 @@
#include "wacom.h" #include "wacom.h"
#include "abr.h" #include "abr.h"
namespace pp::platform::windows {
void set_async_render_context(HDC hdc, HGLRC hrc);
void lock_async_render_context();
bool try_lock_async_render_context();
void unlock_async_render_context();
void swap_async_render_context();
RetainedState& retained_state();
}
using pp::platform::windows::retained_state; using pp::platform::windows::retained_state;
HWND pp_windows_main_window_handle()
{
return retained_state().hWnd;
}
void destroy_window()
{
pp::platform::windows::enqueue_main_thread_task(std::packaged_task<void()>([hWnd = retained_state().hWnd] {
pp::platform::windows::request_window_close(hWnd);
}));
}
void async_lock()
{
pp::platform::windows::lock_async_render_context();
}
bool async_lock_try()
{
return pp::platform::windows::try_lock_async_render_context();
}
void win32_async_swap()
{
pp::platform::windows::swap_async_render_context();
}
void async_unlock()
{
pp::platform::windows::unlock_async_render_context();
}
void win32_update_stylus(float dt)
{
pp::platform::windows::update_stylus_frame(dt);
}
void win32_update_fps(int frames)
{
auto& state = retained_state();
pp::platform::windows::enqueue_main_thread_task(std::packaged_task<void()>([hWnd = state.hWnd, window_title = state.window_title, &vr = state.vr, frames] {
pp::platform::windows::update_window_fps(hWnd, window_title, vr, frames);
}));
}
bool win32_vr_start()
{
auto& state = retained_state();
return pp::platform::windows::start_window_vr(state.vr, state.sandboxed);
}
void win32_vr_stop()
{
pp::platform::windows::stop_window_vr(retained_state().vr);
}
void win32_save_window_state()
{
pp::platform::windows::save_window_preferences(retained_state().hWnd);
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
auto& state = retained_state(); auto& state = retained_state();

View File

@@ -1,14 +1,9 @@
#include "pch.h" #include "pch.h"
#include "app.h"
#include "log.h"
#include "legacy_ui_node_attributes.h" #include "legacy_ui_node_attributes.h"
#include "legacy_ui_node_event.h" #include "legacy_ui_node_event.h"
#include "legacy_ui_node_loader.h" #include "legacy_ui_node_loader.h"
#include "legacy_ui_node_style.h" #include "legacy_ui_node_style.h"
#include "node.h" #include "node.h"
#include "layout.h"
#include "util.h"
#include "asset.h"
kEventResult Node::on_event(Event* e) kEventResult Node::on_event(Event* e)
{ {
@@ -232,26 +227,5 @@ void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
void Node::load_internal(const tinyxml2::XMLElement* x_node, bool skip_children /*= false*/) void Node::load_internal(const tinyxml2::XMLElement* x_node, bool skip_children /*= false*/)
{ {
m_name = x_node->Name(); pp::panopainter::load_legacy_ui_node(*this, *x_node, skip_children);
//LOG("load_internal node %s", m_name.c_str());
init();
auto attr = x_node->FirstAttribute();
while (attr)
{
parse_attributes((kAttribute)const_hash(attr->Name()), attr);
attr = attr->Next();
}
create();
if (skip_children)
{
loaded();
return;
}
pp::panopainter::load_legacy_ui_children(*this, *x_node);
loaded();
} }

View File

@@ -1,6 +1,9 @@
#include "pch.h" #include "pch.h"
#include "platform_windows/windows_bootstrap_helpers.h" #include "platform_windows/windows_bootstrap_helpers.h"
#include "platform_windows/windows_lifecycle_shell.h"
#include "platform_windows/windows_platform_services.h" #include "platform_windows/windows_platform_services.h"
#include "platform_windows/windows_stylus_input.h"
#include "platform_windows/windows_window_shell.h"
#include "log.h" #include "log.h"
#include "legacy_gl_runtime_dispatch.h" #include "legacy_gl_runtime_dispatch.h"
@@ -12,6 +15,15 @@
#include <deque> #include <deque>
#include <map> #include <map>
namespace pp::platform::windows {
void set_async_render_context(HDC hdc, HGLRC hrc);
void lock_async_render_context();
bool try_lock_async_render_context();
void unlock_async_render_context();
void swap_async_render_context();
RetainedState& retained_state();
}
void destroy_window(); void destroy_window();
void async_lock(); void async_lock();
void async_unlock(); void async_unlock();
@@ -23,6 +35,67 @@ bool win32_vr_start();
void win32_vr_stop(); void win32_vr_stop();
HWND pp_windows_main_window_handle(); HWND pp_windows_main_window_handle();
HWND pp_windows_main_window_handle()
{
return pp::platform::windows::retained_state().hWnd;
}
void destroy_window()
{
pp::platform::windows::enqueue_main_thread_task(std::packaged_task<void()>([hWnd = pp::platform::windows::retained_state().hWnd] {
pp::platform::windows::request_window_close(hWnd);
}));
}
void async_lock()
{
pp::platform::windows::lock_async_render_context();
}
bool async_lock_try()
{
return pp::platform::windows::try_lock_async_render_context();
}
void win32_async_swap()
{
pp::platform::windows::swap_async_render_context();
}
void async_unlock()
{
pp::platform::windows::unlock_async_render_context();
}
void win32_update_stylus(float dt)
{
pp::platform::windows::update_stylus_frame(dt);
}
void win32_update_fps(int frames)
{
auto& state = pp::platform::windows::retained_state();
pp::platform::windows::enqueue_main_thread_task(std::packaged_task<void()>([hWnd = state.hWnd, window_title = state.window_title, &vr = state.vr, frames] {
pp::platform::windows::update_window_fps(hWnd, window_title, vr, frames);
}));
}
bool win32_vr_start()
{
auto& state = pp::platform::windows::retained_state();
return pp::platform::windows::start_window_vr(state.vr, state.sandboxed);
}
void win32_vr_stop()
{
pp::platform::windows::stop_window_vr(pp::platform::windows::retained_state().vr);
}
void win32_save_window_state()
{
pp::platform::windows::save_window_preferences(pp::platform::windows::retained_state().hWnd);
}
namespace pp::platform::windows { namespace pp::platform::windows {
namespace { namespace {