From 90a55b86fe815e2a14cfe05ab3dc01bc5ba0387e Mon Sep 17 00:00:00 2001 From: omigamedev Date: Wed, 17 Jun 2026 01:03:01 +0200 Subject: [PATCH] Split Apple platform target and move platform state ownership --- CMakeLists.txt | 17 +++- cmake/PanoPainterSources.cmake | 5 ++ docs/modernization/roadmap.md | 25 +++++- docs/modernization/tasks.md | 33 +++++++- src/app.h | 13 ++- src/app_events.cpp | 15 +++- src/app_layout_tools_menu.cpp | 2 +- src/app_vr.cpp | 16 ++-- src/legacy_app_runtime_shell_services.cpp | 3 +- src/legacy_canvas_mode_helpers.cpp | 3 +- .../legacy_platform_services.cpp | 80 ++----------------- src/platform_legacy/legacy_platform_state.cpp | 48 +++++++++++ src/platform_legacy/legacy_platform_state.h | 44 ++++++++++ .../windows_lifecycle_shell.cpp | 2 +- .../windows_platform_services.cpp | 5 ++ .../windows_platform_services.h | 3 + src/platform_windows/windows_vr_shell.h | 45 +++++++++-- tests/CMakeLists.txt | 3 + 18 files changed, 258 insertions(+), 104 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bebee5ba..882c43d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,8 +239,6 @@ add_library(pp_platform_api STATIC src/platform_api/asset_file_load_policy.h src/platform_api/network_tls_policy.cpp src/platform_api/network_tls_policy.h - src/platform_apple/apple_platform_services.cpp - src/platform_apple/apple_platform_services.h src/platform_api/platform_policy.cpp src/platform_api/platform_policy.h src/platform_api/platform_services.cpp @@ -255,6 +253,18 @@ target_link_libraries(pp_platform_api PRIVATE pp_project_warnings) +add_library(pp_platform_apple STATIC + ${PP_PLATFORM_APPLE_SOURCES}) +target_include_directories(pp_platform_apple + PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/src") +target_link_libraries(pp_platform_apple + PUBLIC + pp_platform_api + pp_project_options + PRIVATE + pp_project_warnings) + add_library(pp_app_core STATIC src/app_core/about_menu.h src/app_core/app_dialog.h @@ -608,6 +618,9 @@ if(PP_BUILD_APP) pp_project_options PRIVATE pp_project_warnings) + if(APPLE) + target_link_libraries(panopainter_app PRIVATE pp_platform_apple) + endif() pp_add_version_generation(panopainter_app "$,debug,release>") add_library(pp_platform_windows OBJECT diff --git a/cmake/PanoPainterSources.cmake b/cmake/PanoPainterSources.cmake index 5bb1d322..9f4f5d37 100644 --- a/cmake/PanoPainterSources.cmake +++ b/cmake/PanoPainterSources.cmake @@ -117,6 +117,11 @@ set(PP_PLATFORM_LINUX_SOURCES src/platform_linux/linux_platform_services.h ) +set(PP_PLATFORM_APPLE_SOURCES + src/platform_apple/apple_platform_services.cpp + src/platform_apple/apple_platform_services.h +) + set(PP_PANOPAINTER_APP_SOURCES src/app.cpp src/app_runtime.cpp diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 43326112..e6390e1e 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -92,6 +92,20 @@ Current hotspot files: Latest slice: +- `pp_platform_api` no longer compiles + `src/platform_apple/apple_platform_services.*`; Apple concrete platform + code now lives in the new `pp_platform_apple` target, and + `panopainter_app` plus `pp_platform_api_tests` link that concrete target + where needed. +- Retained GLFW window hooks/state and retained Apple UI/app handle snapshots + now live in `src/platform_legacy/legacy_platform_state.*` instead of staying + inline in `src/platform_legacy/legacy_platform_services.cpp`, which trims + another process-global platform-state pocket out of the legacy platform + shell and removes more direct `App::I` reads from touched platform paths. +- Windows VR session snapshot ownership now lives in + `src/platform_windows/windows_vr_shell.h` and + `src/platform_windows/windows_platform_services.*` instead of on `App`, + with app-side reads now routed through `App::vr_session_snapshot()`. - The live Windows entry shell now routes through `run_main_application(...)` in `src/platform_windows/windows_runtime_shell.*`, leaving `src/main.cpp` as a @@ -172,8 +186,9 @@ Latest slice: Current architecture mismatches that must be treated as real blockers: -- `pp_platform_api` still compiles Apple implementation files instead of only - platform-neutral policy and interface code. +- `pp_platform_api` no longer compiles Apple implementation files, but it + still owns concrete Linux platform sources instead of only platform-neutral + policy and interface code. - `src/platform_apple/apple_platform_services.cpp` no longer reaches `App::I` directly, and Linux FPS title reporting now uses an injected callback, but retained Apple bridging in `platform_legacy` and other platform/app coupling @@ -185,8 +200,10 @@ Current architecture mismatches that must be treated as real blockers: route through retained local GLFW callback hooks, and retained Apple ObjC handles plus storage paths now sit behind one local `platform_legacy` helper instead of being re-read through `App::I` in each touched path, with - the retained GLFW window hooks and fallback storage-path return now also - using local retained-state helpers instead of direct method-body reads. + the retained GLFW window hooks, Apple handle snapshots, and fallback + storage-path return now also using local retained-state helpers instead of + direct method-body reads, while Windows VR session snapshot state now also + lives behind platform-owned helpers instead of on `App`. - `src/platform_legacy/legacy_platform_services.*` is still part of the live app shell. - `pp_panopainter_ui` still depends on `pp_legacy_app`. diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index edae76a2..97146718 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -41,7 +41,8 @@ Completed, blocked, and superseded task history moved to `src/node_stroke_preview.cpp`, `src/app.cpp`, `src/app_dialogs.cpp`, and the extracted canvas/platform containment files. - The platform boundary is not finished: - - `pp_platform_api` still compiles Apple implementation files + - `pp_platform_api` no longer compiles Apple implementation files, but it + still compiles concrete Linux platform sources - `platform_apple` no longer reaches `App::I` directly, and Linux FPS title reporting now uses an injected callback, but retained Apple bridging and broader platform-to-app singleton reach are still open in @@ -1063,11 +1064,21 @@ layer. #### ARC-PLT-001 - Split `pp_platform_api` From Concrete Platform Code -Status: Ready +Status: In Progress Why now: `pp_platform_api` is supposed to be the SDK-free policy and interface layer, -but it still compiles `src/platform_apple/apple_platform_services.*`. +and while Apple implementation has now moved out, it still compiles concrete +Linux platform sources. + +Current slice: +- `pp_platform_api` no longer compiles + `src/platform_apple/apple_platform_services.*`. +- Apple concrete platform code now lives in the new `pp_platform_apple` + target, and `panopainter_app` plus `pp_platform_api_tests` now link that + concrete target where needed. +- The dependency direction is cleaner for Apple, but the same split is still + incomplete for Linux and the broader concrete platform family. Write scope: - `CMakeLists.txt` @@ -1128,6 +1139,10 @@ Current slice: - retained storage-path state now also lives in `src/platform_legacy/legacy_platform_state.*` instead of staying inline in `src/platform_legacy/legacy_platform_services.cpp` +- retained GLFW window hooks/state and retained Apple UI/app handle state now + also live in `src/platform_legacy/legacy_platform_state.*`, and + `src/platform_legacy/legacy_platform_services.cpp` now consumes those + snapshots without direct `App::I` reads in the touched paths - retained Apple callback injection and broader `platform_legacy` singleton reach are still open - The remaining Win32 shell wrappers for close, async lock/swap, @@ -1160,12 +1175,22 @@ Mini-model packet: #### ARC-PLT-003 - Remove App-Owned Cross-Platform Handle Storage -Status: Ready +Status: In Progress Why now: `src/platform_legacy/legacy_platform_services.cpp` and `src/app.h` still keep platform-handle state on `App`, which blocks a real `pp_platform_*` shell split. +Current slice: +- Windows VR session snapshot ownership no longer lives on `App`. +- `VrSessionSnapshot` now lives behind + `src/platform_windows/windows_vr_shell.h` and + `read_platform_vr_session_snapshot()` in + `src/platform_windows/windows_platform_services.*`, with app-side reads now + routed through `App::vr_session_snapshot()`. +- `App` still owns other platform-facing handles and retained legacy platform + state is not fully removed, so this remains a live ownership task. + Write scope: - `src/platform_legacy/legacy_platform_services.*` - `src/app.h` diff --git a/src/app.h b/src/app.h index 093099c9..ef2cd32e 100644 --- a/src/app.h +++ b/src/app.h @@ -77,6 +77,14 @@ struct VRController virtual float get_trigger_value() const { return 1.f; } }; +struct VrSessionSnapshot +{ + bool has_vr = false; + bool vr_active = false; + std::array vr_controllers{}; + glm::mat4 vr_head{1.0f}; +}; + class App { public: @@ -125,7 +133,6 @@ public: std::string doc_dir; std::string doc_filename; bool has_stylus = false; - bool has_vr = false; bool vr_controllers_enabled = true; float off_x = 0; float off_y = 0; @@ -136,10 +143,7 @@ public: bool animate = false; bool ui_visible = true; bool ui_rtl = false; - bool vr_active = false; bool vr_only = false; - VRController vr_controllers[2]; - glm::mat4 vr_head; float vr_pressure = 1.f; glm::mat4 vr_rot{ 0 }; glm::mat4 vr_uirot{ 0 }; @@ -209,6 +213,7 @@ public: [[nodiscard]] bool platform_enables_live_asset_reloading(); void update_platform_frame(float delta_time_seconds); void report_rendered_frames(int frames); + [[nodiscard]] VrSessionSnapshot vr_session_snapshot() const; void save_prepared_file( std::string path, std::string suggested_name, diff --git a/src/app_events.cpp b/src/app_events.cpp index a919d723..0390c633 100644 --- a/src/app_events.cpp +++ b/src/app_events.cpp @@ -12,6 +12,9 @@ #include #include "platform_linux/linux_platform_services.h" #endif +#ifdef _WIN32 +#include "platform_windows/windows_platform_services.h" +#endif #include "platform_legacy/legacy_platform_services.h" #include "renderer_gl/opengl_capabilities.h" @@ -435,6 +438,15 @@ void App::report_rendered_frames(int frames) active_platform_services().report_rendered_frames(frames); } +VrSessionSnapshot App::vr_session_snapshot() const +{ +#ifdef _WIN32 + return pp::platform::windows::read_platform_vr_session_snapshot(); +#else + return {}; +#endif +} + void App::save_prepared_file( std::string path, std::string suggested_name, @@ -655,10 +667,11 @@ bool App::touch_tap(const glm::vec2& pos, int fingers, int tap_count) } bool App::key_down(kKey key) { + const auto vr_session = vr_session_snapshot(); const auto plan = pp::app::plan_app_key_down_dispatch( layout.get(main_id) != nullptr, key == kKey::KeySpacebar, - vr_active); + vr_session.vr_active); if (plan.sync_vr_camera_rotation) canvas->m_canvas->m_cam_rot = vr_rot; redraw = plan.request_redraw; diff --git a/src/app_layout_tools_menu.cpp b/src/app_layout_tools_menu.cpp index 0dbfce8b..a69e37d0 100644 --- a/src/app_layout_tools_menu.cpp +++ b/src/app_layout_tools_menu.cpp @@ -357,7 +357,7 @@ void bind_legacy_tools_menu(App& app) if (auto vr_btn = popup_time->find("tools-vr")) { NodeCheckBox* cb = vr_btn->find("tools-vr-check"); - cb->set_value(app.has_vr); + cb->set_value(app.vr_session_snapshot().has_vr); vr_btn->on_click = [vr_btn](Node*) { diff --git a/src/app_vr.cpp b/src/app_vr.cpp index 49635fc6..ff9933ee 100644 --- a/src/app_vr.cpp +++ b/src/app_vr.cpp @@ -128,6 +128,8 @@ void App::vr_update(float dt) { if (!vr_controllers_enabled) return; + + const auto vr_session = vr_session_snapshot(); canvas->m_canvas->m_cam_fov = 60; float tan_fov = glm::tan(glm::radians(canvas->m_canvas->m_cam_fov / 2.f)); glm::vec3 aspect = { (float)uirtt.getWidth() / (float)uirtt.getHeight(), 1.f, 1.f }; @@ -142,8 +144,8 @@ void App::vr_update(float dt) auto r = glm::normalize(glm::vec3(glm::vec4(1, 0, 0, 0) * mm)); auto n = glm::normalize(glm::vec3(glm::vec4(0, 0, 1, 0) * mm)); auto u = glm::normalize(glm::vec3(glm::vec4(0, 1, 0, 0) * mm)); - auto co = vr_controllers[0].get_pos(); - auto cd = glm::mat3(vr_controllers[0].m_mat) * glm::mat3(glm::eulerAngleX(glm::radians(-30.f))) * glm::vec3(0, 0, -1); + auto co = vr_session.vr_controllers[0].get_pos(); + auto cd = glm::mat3(vr_session.vr_controllers[0].m_mat) * glm::mat3(glm::eulerAngleX(glm::radians(-30.f))) * glm::vec3(0, 0, -1); ui_inside = false; glm::vec3 hit; float t; @@ -167,7 +169,7 @@ void App::vr_update(float dt) if (down_controller) { - glm::vec3 head_position = vr_head[3]; + glm::vec3 head_position = vr_session.vr_head[3]; glm::vec3 c_pos = glm::normalize(down_controller->get_pos() - head_position) * 800.f; controller_points.add(c_pos); auto p = controller_points.average(); @@ -210,7 +212,7 @@ void App::vr_analog(const VRController& c, VRController::kButton b, VRController { if (a == VRController::kAction::Press) { - glm::vec3 head_position = vr_head[3]; + glm::vec3 head_position = vr_session_snapshot().vr_head[3]; glm::vec3 c_pos = glm::normalize(c.get_pos() - head_position) * 800.f; render_task_async([=] { Canvas::I->stroke_start(c_pos, force.x); @@ -517,7 +519,8 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat // draw the motion controller sphere if (vr_controllers_enabled && ui_visible && ui_inside) { - auto mvp = proj * camera * vr_controllers[0].m_mat * glm::eulerAngleX(glm::radians(-30.f)); + const auto vr_session = vr_session_snapshot(); + auto mvp = proj * camera * vr_session.vr_controllers[0].m_mat * glm::eulerAngleX(glm::radians(-30.f)); pp::panopainter::setup_legacy_vr_color_shader( pp::panopainter::LegacyVrColorUniforms { .color = { 1, 0, 1, 1 }, @@ -530,7 +533,8 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat // draw the motion controller brush if (vr_controllers_enabled && (!ui_visible || !ui_inside)) { - glm::vec3 cpos = vr_controllers[0].get_pos() - xyz(pose[3]); + const auto vr_session = vr_session_snapshot(); + glm::vec3 cpos = vr_session.vr_controllers[0].get_pos() - xyz(pose[3]); auto pos = glm::translate(glm::normalize(cpos) * 100.f); auto tip_color = glm::vec4(glm::vec3(canvas->m_canvas->m_current_brush->m_tip_color), 1); pp::panopainter::setup_legacy_vr_stroke_preview_shader( diff --git a/src/legacy_app_runtime_shell_services.cpp b/src/legacy_app_runtime_shell_services.cpp index 0cd4c2e5..f590a3a0 100644 --- a/src/legacy_app_runtime_shell_services.cpp +++ b/src/legacy_app_runtime_shell_services.cpp @@ -110,10 +110,11 @@ void execute_legacy_app_ui_thread_stop(App& app) 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_active, + vr_session.vr_active, ui_visible, vr_only); diff --git a/src/legacy_canvas_mode_helpers.cpp b/src/legacy_canvas_mode_helpers.cpp index 3a6ed961..885c4b1f 100644 --- a/src/legacy_canvas_mode_helpers.cpp +++ b/src/legacy_canvas_mode_helpers.cpp @@ -106,7 +106,8 @@ void CanvasModeBasicCamera::on_MouseEvent(MouseEvent* me, glm::vec2& loc) } else { - auto dir = (App::I->has_vr && App::I->vr_active) ? glm::vec2(1, 1) : glm::vec2(-1, -1); + const auto vr_session = App::I->vr_session_snapshot(); + auto dir = (vr_session.has_vr && vr_session.vr_active) ? glm::vec2(1, 1) : glm::vec2(-1, -1); Canvas::I->m_pan = m_pan_start + (me->m_pos - m_dragR_start) * dir * (Canvas::I->m_cam_fov / 85.f); auto angle = Canvas::I->m_pan * 0.003f; Canvas::I->m_cam_rot = glm::eulerAngleXY(angle.y, angle.x); diff --git a/src/platform_legacy/legacy_platform_services.cpp b/src/platform_legacy/legacy_platform_services.cpp index 559caf04..717fc624 100644 --- a/src/platform_legacy/legacy_platform_services.cpp +++ b/src/platform_legacy/legacy_platform_services.cpp @@ -2,7 +2,6 @@ #include "platform_legacy/legacy_platform_services.h" #include "platform_legacy/legacy_platform_state.h" -#include "app.h" #include "legacy_ui_gl_dispatch.h" #include "log.h" #include "platform_apple/apple_platform_services.h" @@ -36,13 +35,11 @@ void delete_all_files_in_path(const std::string& source_path); void save_image_library(const std::string& path); #endif #elif __LINUX__ -#include #include #include "platform_linux/linux_platform_services.h" std::string linux_home_path(); int mkpath(const std::string& dir, mode_t mode = DEFFILEMODE); #elif __WEB__ -#include void webgl_pick_file(std::function callback); void webgl_pick_file_save( const std::string& path, @@ -95,43 +92,6 @@ public: #endif } -#if defined(__LINUX__) || defined(__WEB__) -struct RetainedLegacyGlfwWindowHooks final { - std::function acquire_render_context; - std::function present_render_context; - std::function request_app_close; -}; - -struct RetainedLegacyGlfwWindowState final { - decltype(App::I->glfw_window) window = nullptr; - RetainedLegacyGlfwWindowHooks hooks; -}; - -[[nodiscard]] RetainedLegacyGlfwWindowState& active_legacy_glfw_window_state() -{ - static RetainedLegacyGlfwWindowState state = [] { - RetainedLegacyGlfwWindowState retained; - retained.window = App::I->glfw_window; - retained.hooks.acquire_render_context = [window = retained.window] { - glfwMakeContextCurrent(window); - }; - retained.hooks.present_render_context = [window = retained.window] { - glfwSwapBuffers(window); - }; - retained.hooks.request_app_close = [window = retained.window] { - glfwSetWindowShouldClose(window, GLFW_TRUE); - }; - return retained; - }(); - return state; -} - -[[nodiscard]] RetainedLegacyGlfwWindowHooks& active_legacy_glfw_window_hooks() -{ - return active_legacy_glfw_window_state().hooks; -} -#endif - #if defined(__IOS__) || defined(__OSX__) [[nodiscard]] NSMutableArray* apple_file_types_array(const std::vector& file_types) { @@ -143,47 +103,21 @@ struct RetainedLegacyGlfwWindowState final { return types; } -struct RetainedLegacyAppleState final { -#ifdef __IOS__ - decltype(App::I->ios_view) ios_view = nullptr; - decltype(App::I->ios_app) ios_app = nullptr; -#elif defined(__OSX__) - decltype(App::I->osx_view) osx_view = nullptr; - decltype(App::I->osx_app) osx_app = nullptr; -#endif -}; - -[[nodiscard]] RetainedLegacyAppleState& active_legacy_apple_state() -{ - static RetainedLegacyAppleState state = [] { - RetainedLegacyAppleState retained; -#ifdef __IOS__ - retained.ios_view = App::I->ios_view; - retained.ios_app = App::I->ios_app; -#elif defined(__OSX__) - retained.osx_view = App::I->osx_view; - retained.osx_app = App::I->osx_app; -#endif - return retained; - }(); - return state; -} - [[nodiscard]] pp::platform::PlatformStoragePaths prepare_legacy_apple_storage_paths() { - const auto& apple_state = active_legacy_apple_state(); + const auto& apple_state = pp::platform::legacy::active_legacy_apple_state(); #ifdef __IOS__ [apple_state.ios_view init_dirs]; #elif defined(__OSX__) [apple_state.osx_app init_dirs]; #endif - return active_legacy_storage_paths(); + return pp::platform::legacy::active_legacy_storage_paths(); } [[nodiscard]] pp::platform::apple::AppleDocumentPlatformServices& active_apple_document_platform_services() { #ifdef __IOS__ - const auto& apple_state = active_legacy_apple_state(); + const auto& apple_state = pp::platform::legacy::active_legacy_apple_state(); auto* const ios_view = apple_state.ios_view; auto* const ios_app = apple_state.ios_app; static pp::platform::apple::AppleDocumentPlatformServices services( @@ -259,7 +193,7 @@ struct RetainedLegacyAppleState final { }()); return services; #else - const auto& apple_state = active_legacy_apple_state(); + const auto& apple_state = pp::platform::legacy::active_legacy_apple_state(); auto* const osx_view = apple_state.osx_view; auto* const osx_app = apple_state.osx_app; static pp::platform::apple::AppleDocumentPlatformServices services( @@ -470,7 +404,7 @@ public: #elif __ANDROID__ android_async_lock(); #elif __LINUX__ || __WEB__ - active_legacy_glfw_window_hooks().acquire_render_context(); + pp::platform::legacy::active_legacy_glfw_window_hooks().acquire_render_context(); #endif } @@ -490,7 +424,7 @@ public: #elif __ANDROID__ android_async_swap(); #elif __LINUX__ || __WEB__ - active_legacy_glfw_window_hooks().present_render_context(); + pp::platform::legacy::active_legacy_glfw_window_hooks().present_render_context(); #endif } @@ -801,7 +735,7 @@ public: #ifdef __OSX__ active_apple_document_platform_services().request_app_close(); #elif __LINUX__ - active_legacy_glfw_window_hooks().request_app_close(); + pp::platform::legacy::active_legacy_glfw_window_hooks().request_app_close(); #endif } diff --git a/src/platform_legacy/legacy_platform_state.cpp b/src/platform_legacy/legacy_platform_state.cpp index 6a62d66b..4b4604c6 100644 --- a/src/platform_legacy/legacy_platform_state.cpp +++ b/src/platform_legacy/legacy_platform_state.cpp @@ -3,6 +3,10 @@ #include "app.h" +#if defined(__LINUX__) || defined(__WEB__) +#include +#endif + namespace pp::platform::legacy { namespace { @@ -12,6 +16,50 @@ struct RetainedLegacyStoragePaths final { } +#if defined(__LINUX__) || defined(__WEB__) +[[nodiscard]] RetainedLegacyGlfwWindowState& active_legacy_glfw_window_state() +{ + static RetainedLegacyGlfwWindowState state = [] { + RetainedLegacyGlfwWindowState retained; + retained.window = App::I->glfw_window; + retained.hooks.acquire_render_context = [window = retained.window] { + glfwMakeContextCurrent(window); + }; + retained.hooks.present_render_context = [window = retained.window] { + glfwSwapBuffers(window); + }; + retained.hooks.request_app_close = [window = retained.window] { + glfwSetWindowShouldClose(window, GLFW_TRUE); + }; + return retained; + }(); + return state; +} + +[[nodiscard]] RetainedLegacyGlfwWindowHooks& active_legacy_glfw_window_hooks() +{ + return active_legacy_glfw_window_state().hooks; +} +#endif + +#if defined(__IOS__) || defined(__OSX__) +[[nodiscard]] RetainedLegacyAppleState& active_legacy_apple_state() +{ + static RetainedLegacyAppleState state = [] { + RetainedLegacyAppleState retained; +#ifdef __IOS__ + retained.ios_view = App::I->ios_view; + retained.ios_app = App::I->ios_app; +#elif defined(__OSX__) + retained.osx_view = App::I->osx_view; + retained.osx_app = App::I->osx_app; +#endif + return retained; + }(); + return state; +} +#endif + [[nodiscard]] const pp::platform::PlatformStoragePaths& active_legacy_storage_paths() { static RetainedLegacyStoragePaths state = [] { diff --git a/src/platform_legacy/legacy_platform_state.h b/src/platform_legacy/legacy_platform_state.h index 5cc7fa6a..0b644022 100644 --- a/src/platform_legacy/legacy_platform_state.h +++ b/src/platform_legacy/legacy_platform_state.h @@ -2,8 +2,52 @@ #include "platform_api/platform_services.h" +#if __LINUX__ || __WEB__ +struct GLFWwindow; +#endif + +#if defined(__OBJC__) && defined(__IOS__) +@class GameViewController; +@class AppDelegate; +#endif + +#if defined(__OBJC__) && defined(__OSX__) +@class View; +@class AppOSX; +#endif + namespace pp::platform::legacy { +#if defined(__LINUX__) || defined(__WEB__) +struct RetainedLegacyGlfwWindowHooks final { + std::function acquire_render_context; + std::function present_render_context; + std::function request_app_close; +}; + +struct RetainedLegacyGlfwWindowState final { + GLFWwindow* window = nullptr; + RetainedLegacyGlfwWindowHooks hooks; +}; + +[[nodiscard]] RetainedLegacyGlfwWindowState& active_legacy_glfw_window_state(); +[[nodiscard]] RetainedLegacyGlfwWindowHooks& active_legacy_glfw_window_hooks(); +#endif + +#if defined(__IOS__) || defined(__OSX__) +struct RetainedLegacyAppleState final { +#ifdef __IOS__ + GameViewController* ios_view = nullptr; + AppDelegate* ios_app = nullptr; +#elif defined(__OSX__) + View* osx_view = nullptr; + AppOSX* osx_app = nullptr; +#endif +}; + +[[nodiscard]] RetainedLegacyAppleState& active_legacy_apple_state(); +#endif + [[nodiscard]] const pp::platform::PlatformStoragePaths& active_legacy_storage_paths(); } diff --git a/src/platform_windows/windows_lifecycle_shell.cpp b/src/platform_windows/windows_lifecycle_shell.cpp index 1a25db29..6945ca20 100644 --- a/src/platform_windows/windows_lifecycle_shell.cpp +++ b/src/platform_windows/windows_lifecycle_shell.cpp @@ -63,7 +63,7 @@ void update_window_fps(HWND hWnd, const wchar_t* window_title, VrShellState& vr, { static wchar_t title_fps[512]; const int vr_fps = current_vr_fps(vr); - if (App::I->vr_active) + if (read_vr_session_snapshot(vr).vr_active) swprintf_s(title_fps, L"%s - %d fps - %d vr fps", window_title, frames, vr_fps); else swprintf_s(title_fps, L"%s - %d fps", window_title, frames); diff --git a/src/platform_windows/windows_platform_services.cpp b/src/platform_windows/windows_platform_services.cpp index dc498f31..c2bd796b 100644 --- a/src/platform_windows/windows_platform_services.cpp +++ b/src/platform_windows/windows_platform_services.cpp @@ -793,4 +793,9 @@ PlatformServices& platform_services() return services; } +VrSessionSnapshot read_platform_vr_session_snapshot() noexcept +{ + return read_vr_session_snapshot(retained_state().vr); +} + } diff --git a/src/platform_windows/windows_platform_services.h b/src/platform_windows/windows_platform_services.h index f705726e..9c86f8b5 100644 --- a/src/platform_windows/windows_platform_services.h +++ b/src/platform_windows/windows_platform_services.h @@ -4,9 +4,12 @@ #include +struct VrSessionSnapshot; + namespace pp::platform::windows { [[nodiscard]] PlatformServices& platform_services(); +[[nodiscard]] VrSessionSnapshot read_platform_vr_session_snapshot() noexcept; void enqueue_main_thread_task(std::packaged_task task); void drain_main_thread_tasks(); diff --git a/src/platform_windows/windows_vr_shell.h b/src/platform_windows/windows_vr_shell.h index f8d2cfaa..61dd501b 100644 --- a/src/platform_windows/windows_vr_shell.h +++ b/src/platform_windows/windows_vr_shell.h @@ -14,6 +14,8 @@ namespace pp::platform::windows { struct VrShellState final { + std::mutex snapshot_mutex; + VrSessionSnapshot session; std::jthread hmd_renderer; std::mutex hmd_render_mutex; std::condition_variable hmd_render_cv; @@ -27,6 +29,35 @@ inline int current_vr_fps(const VrShellState& state) return state.vr_frames.load(std::memory_order_relaxed); } +inline VrSessionSnapshot read_vr_session_snapshot(VrShellState& state) +{ + std::lock_guard lock(state.snapshot_mutex); + return state.session; +} + +inline void write_vr_session_snapshot( + VrShellState& state, + bool has_vr, + bool vr_active, + const VRController& primary_controller, + const glm::mat4& vr_head) +{ + std::lock_guard lock(state.snapshot_mutex); + state.session.has_vr = has_vr; + state.session.vr_active = vr_active; + state.session.vr_controllers[0] = primary_controller; + state.session.vr_head = vr_head; +} + +inline void clear_vr_session_snapshot(VrShellState& state, bool has_vr) +{ + std::lock_guard lock(state.snapshot_mutex); + state.session.has_vr = has_vr; + state.session.vr_active = false; + state.session.vr_controllers[0] = {}; + state.session.vr_head = glm::mat4(1.0f); +} + inline void request_stop_and_join_vr_thread(VrShellState& state) { if (state.hmd_renderer.joinable()) @@ -64,7 +95,7 @@ inline bool start_vr_shell(VrShellState& state, bool sandboxed, std::atomic BT_SetTerminate(); LOG("start hmd render thread"); - App::I->has_vr = true; + clear_vr_session_snapshot(state, true); state.vr_running.store(true, std::memory_order_relaxed); state.vive->on_analog_button = std::bind(&App::vr_analog, App::I, std::placeholders::_1, @@ -99,9 +130,12 @@ inline bool start_vr_shell(VrShellState& state, bool sandboxed, std::atomic frames++; state.vive->Update(); - App::I->vr_active = state.vive->m_active; - App::I->vr_controllers[0] = state.vive->m_controllers[0]; - App::I->vr_head = state.vive->m_pose; + write_vr_session_snapshot( + state, + true, + state.vive->m_active, + state.vive->m_controllers[0], + state.vive->m_pose); App::I->vr_update(dt); if (state.vr_running.load(std::memory_order_relaxed) && state.vive->m_active) @@ -118,8 +152,7 @@ inline bool start_vr_shell(VrShellState& state, bool sandboxed, std::atomic t0 = t1; } - App::I->vr_active = false; - App::I->has_vr = false; + clear_vr_session_snapshot(state, false); state.vr_running.store(false, std::memory_order_relaxed); state.vive->Terminate(); LOG("hmd renderer terminated"); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 880b3067..d799cdc9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -352,6 +352,9 @@ add_executable(pp_platform_api_tests target_link_libraries(pp_platform_api_tests PRIVATE pp_platform_api pp_test_harness) +if(TARGET pp_platform_apple) + target_link_libraries(pp_platform_api_tests PRIVATE pp_platform_apple) +endif() add_test(NAME pp_platform_api_tests COMMAND pp_platform_api_tests) set_tests_properties(pp_platform_api_tests PROPERTIES