375 lines
10 KiB
C++
375 lines
10 KiB
C++
#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<bool(Node*)>& 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<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::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<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);
|
|
}
|