Extract app runtime shell, canvas render shell, and node tree services

This commit is contained in:
2026-06-16 20:36:47 +02:00
parent a05afb24f3
commit c25af6f493
10 changed files with 1450 additions and 1251 deletions

View File

@@ -0,0 +1,239 @@
#include "pch.h"
#include "app.h"
#include "app_core/app_frame.h"
#include "app_core/app_shutdown.h"
#include "app_core/app_status.h"
#include "legacy_recording_services.h"
#include "legacy_ui_gl_dispatch.h"
#include "renderer_gl/opengl_capabilities.h"
namespace {
void apply_app_viewport(pp::renderer::gl::OpenGlViewportRect viewport)
{
const auto status = pp::renderer::gl::apply_opengl_viewport(
viewport,
pp::renderer::gl::OpenGlViewportDispatch {
.viewport = pp::legacy::ui_gl::set_opengl_viewport,
});
if (!status.ok())
LOG("OpenGL viewport failed: %s", status.message);
}
void apply_app_scissor_test(bool enabled)
{
const auto status = pp::renderer::gl::apply_opengl_scissor_test(
enabled,
pp::renderer::gl::OpenGlScissorTestDispatch {
.enable = pp::legacy::ui_gl::enable_opengl_state,
.disable = pp::legacy::ui_gl::disable_opengl_state,
});
if (!status.ok())
LOG("OpenGL scissor test failed: %s", status.message);
}
} // namespace
namespace pp::panopainter {
bool process_legacy_recording_worker_iteration(App& app);
void update_legacy_recording_frame_label(App& app);
bool update_legacy_app_ui_observer(App& app, Node* n);
void watch_legacy_app_ui_children(App& app, const std::function<bool(Node*)>& observer, bool skip_first_main_child);
void update_legacy_canvas_toolbar(App& app);
} // namespace pp::panopainter
void App::draw(float dt)
{
const auto draw_plan = pp::app::plan_app_frame_draw(
canvas != nullptr,
canvas && canvas->m_canvas,
vr_active,
ui_visible,
vr_only);
// update offscreen stuff
if (draw_plan.draw_canvas_stroke)
canvas->m_canvas->stroke_draw();
auto observer = std::bind(&App::update_ui_observer, this, std::placeholders::_1);
if (draw_plan.draw_vr_ui)
{
uirtt.bindFramebuffer();
uirtt.clear();
apply_app_viewport(pp::renderer::gl::OpenGlViewportRect {
.width = static_cast<std::int32_t>(uirtt.getWidth()),
.height = static_cast<std::int32_t>(uirtt.getHeight()),
});
apply_app_scissor_test(true);
pp::panopainter::watch_legacy_app_ui_children(*this, observer, true);
apply_app_scissor_test(false);
uirtt.unbindFramebuffer();
}
if (draw_plan.draw_main_ui)
{
bind_main_render_target();
apply_app_viewport(pp::renderer::gl::OpenGlViewportRect {
.x = static_cast<std::int32_t>(off_x),
.y = static_cast<std::int32_t>(off_y),
.width = static_cast<std::int32_t>(width),
.height = static_cast<std::int32_t>(height),
});
apply_app_scissor_test(true);
pp::panopainter::watch_legacy_app_ui_children(*this, observer, false);
apply_app_scissor_test(false);
}
if (draw_plan.reset_redraw)
redraw = false;
}
void App::update(float dt)
{
const auto update_plan = pp::app::plan_app_frame_update(redraw, animate);
if (!update_plan.update_frame)
return;
if (auto* main = layout[main_id]; update_plan.update_layouts && main)
main->update(width, height, zoom);
if (auto* main = layout_designer[main_id]; update_plan.update_layouts && main)
main->update(width, height, zoom);
if (!update_plan.refresh_canvas_toolbar)
return;
pp::panopainter::update_legacy_canvas_toolbar(*this);
}
void App::terminate()
{
LOG("App::terminate");
const auto shutdown_plan = pp::app::plan_app_shutdown();
if (shutdown_plan.save_ui_state)
ui_save();
if (shutdown_plan.terminate_stroke_preview_renderer)
NodeStrokePreview::terminate_renderer();
if (shutdown_plan.stop_recording)
rec_stop();
if (shutdown_plan.invalidate_textures)
TextureManager::invalidate();
if (shutdown_plan.invalidate_shaders)
ShaderManager::invalidate();
if (shutdown_plan.unload_layouts) {
layout.unload();
layout_designer.unload();
}
if (shutdown_plan.destroy_ui_render_target)
uirtt.destroy();
if (shutdown_plan.destroy_face_plane)
m_face_plane.destroy();
if (shutdown_plan.release_panel_nodes) {
layers.reset();
color.reset();
stroke.reset();
grid.reset();
presets.reset();
floating_presets.reset();
floating_color.reset();
floating_layers.reset();
floating_picker.reset();
}
if (shutdown_plan.clear_quick_mode_state)
quick_mode_state.clear();
}
void App::update_memory_usage(size_t bytes)
{
if (auto txt = layout[main_id]->find<NodeText>("txt-memory"))
{
const auto label = pp::app::make_history_memory_label(bytes);
txt->set_text(label.c_str());
}
}
void App::update_rec_frames()
{
pp::panopainter::update_legacy_recording_frame_label(*this);
}
int App::res_from_index(int i)
{
const auto resolution = pp::app::display_resolution_from_index(i);
return resolution ? resolution.value() : pp::app::document_resolution_values.front();
}
int App::res_to_index(int res)
{
const auto index = pp::app::document_resolution_to_index(res);
return index ? static_cast<int>(index.value()) : static_cast<int>(pp::app::document_resolution_values.size());
}
std::string App::res_to_string(int res)
{
const auto label = pp::app::document_resolution_label(res);
return label ? std::string(label.value()) : std::string("unknown");
}
void App::rec_clear()
{
const auto plan = pp::app::plan_recording_clear(
rec_running,
platform_deletes_recorded_files_on_clear()
);
const auto status = pp::panopainter::execute_legacy_recording_clear_plan(*this, plan);
if (!status.ok())
LOG("Recording clear action failed: %s", status.message);
}
void App::rec_start()
{
const auto plan = pp::app::plan_recording_start(rec_running);
const auto status = pp::panopainter::execute_legacy_recording_start_action(*this, plan);
if (!status.ok())
LOG("Recording start action failed: %s", status.message);
}
void App::rec_stop()
{
const auto plan = pp::app::plan_recording_stop(rec_running);
const auto status = pp::panopainter::execute_legacy_recording_stop_action(*this, plan);
if (!status.ok())
LOG("Recording stop action failed: %s", status.message);
}
void App::rec_export(std::string path)
{
const auto plan = pp::app::plan_recording_export(static_cast<std::size_t>(rec_count));
/*
#if defined(__IOS__) || defined(__OSX__)
export_mp4(rec_path, width, height, rec_count, ^(float) {
pb->increment();
});
#endif
*/
const auto status = pp::panopainter::execute_legacy_recording_export_plan(*this, plan, path);
if (!status.ok())
LOG("Recording export action failed: %s", status.message);
}
void App::rec_loop()
{
BT_SetTerminate();
rec_running = true;
while (rec_running)
{
if (!pp::panopainter::process_legacy_recording_worker_iteration(*this))
break;
}
}
void App::render_thread_tick()
{
runtime_.render_thread_tick(*this);
}