#include "pch.h" #include "legacy_app_runtime_shell_services.h" #include "app.h" #include "app_core/app_frame.h" #include "app_core/app_shutdown.h" #include "app_core/app_status.h" #include "app_core/document_session.h" #include "legacy_document_session_services.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& observer, bool skip_first_main_child); void update_legacy_canvas_toolbar(App& app); bool execute_legacy_app_request_close(App& app) { static bool dialog_already_opened = false; const auto close_decision = pp::app::plan_close_request( Canvas::I->m_unsaved, dialog_already_opened); const auto status = pp::panopainter::execute_legacy_close_request_decision( app, close_decision, dialog_already_opened); if (!status.ok()) LOG("Close request action failed: %s", status.message); return close_decision == pp::app::CloseRequestDecision::close_now; } void execute_legacy_app_renderdoc_frame_start(App& app) { app.begin_render_capture_frame(); } void execute_legacy_app_renderdoc_frame_end(App& app) { app.end_render_capture_frame(); } void execute_legacy_app_render_thread_main(App& app) { app.runtime().render_thread_main(app, {}); } void execute_legacy_app_render_thread_start(App& app) { app.runtime().render_thread_start(app); } void execute_legacy_app_render_thread_stop(App& app) { app.runtime().render_thread_stop(); } void execute_legacy_app_ui_thread_tick(App& app) { app.runtime().ui_thread_tick(app); } void execute_legacy_app_ui_thread_main(App& app) { app.runtime().ui_thread_main(app, {}); } void execute_legacy_app_ui_thread_start(App& app) { app.runtime().ui_thread_start(app); } void execute_legacy_app_ui_thread_stop(App& app) { app.runtime().ui_thread_stop(); } } // namespace pp::panopainter void App::draw(float dt) { const auto vr_session = vr_session_snapshot(); const auto draw_plan = pp::app::plan_app_frame_draw( canvas != nullptr, canvas && canvas->m_canvas, vr_session.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(uirtt.getWidth()), .height = static_cast(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(off_x), .y = static_cast(off_y), .width = static_cast(width), .height = static_cast(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::clear() { const auto status = pp::renderer::gl::clear_panopainter_default_target( pp::renderer::gl::OpenGlClearDispatch { .clear_color = pp::legacy::ui_gl::set_opengl_clear_color, .clear = pp::legacy::ui_gl::clear_opengl_buffer, }); if (!status.ok()) LOG("OpenGL clear failed: %s", status.message); } bool App::check_license() { return true; // TODO: for distribuiton only #if WITH_CURL CURL* curl = curl_easy_init(); if (curl) { std::string url = "https://panopainter.com/license/7565D057-ACBE-4721-9A4E-F342D3DDB7D8.php"; //std::string url = "https://panopainter.com/license/E8EDC2FE-E1BD-4AB1-91BD-FCCD926739BD.php"; // wacom //std::string url = "https://panopainter.com/license/A744FBA9-BC6C-43C8-BD24-0CCE24B3D985.php"; // others std::string ret; curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret); //curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_handler); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L); if (disables_network_tls_verification()) curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); const auto err = curl_easy_perform(curl); curl_easy_cleanup(curl); LOG("License check: %s", ret.c_str()); if (err == CURLcode::CURLE_OK && ret == "success") return true; } #endif //CURL return false; } void App::async_start() { acquire_render_context(); } void App::async_redraw() { const auto plan = pp::app::plan_app_async_redraw(); if (plan.set_redraw) redraw = true; if (plan.notify_ui) runtime_.notify_ui_worker(); } void App::async_end() { release_render_context(); } void App::async_swap() { present_render_context(); } 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("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(index.value()) : static_cast(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(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); }