#pragma once #include "foundation/result.h" #include #include namespace pp::app { struct AppStartupPlan { int previous_run_counter = 0; int next_run_counter = 1; bool save_preferences = true; bool start_timelapse = false; bool vr_controllers_enabled = true; bool show_license_warning = false; }; struct AppStartupResourcePlan { int ui_render_target_width = 0; int ui_render_target_height = 0; bool initialize_shaders = true; bool initialize_assets = true; bool initialize_layout = true; bool update_title = true; bool create_ui_render_target = true; }; class AppStartupServices { public: virtual ~AppStartupServices() = default; virtual void store_run_counter(int value) = 0; virtual void save_preferences() = 0; virtual void start_timelapse_recording() = 0; virtual void apply_vr_controllers_enabled(bool enabled) = 0; virtual void show_license_warning() = 0; }; class AppStartupResourceServices { public: virtual ~AppStartupResourceServices() = default; virtual void initialize_shaders() = 0; virtual void initialize_assets() = 0; virtual void initialize_layout() = 0; virtual void update_title() = 0; virtual void create_ui_render_target(int width, int height) = 0; }; [[nodiscard]] inline pp::foundation::Result plan_app_startup( int current_run_counter, bool auto_timelapse_enabled, bool stored_vr_controllers_enabled, bool license_valid) { if (current_run_counter < 0) { return pp::foundation::Result::failure( pp::foundation::Status::invalid_argument("run counter must not be negative")); } if (current_run_counter == std::numeric_limits::max()) { return pp::foundation::Result::failure( pp::foundation::Status::out_of_range("run counter would overflow")); } AppStartupPlan plan; plan.previous_run_counter = current_run_counter; plan.next_run_counter = current_run_counter + 1; plan.start_timelapse = auto_timelapse_enabled; plan.vr_controllers_enabled = stored_vr_controllers_enabled; plan.show_license_warning = !license_valid; return pp::foundation::Result::success(plan); } [[nodiscard]] inline pp::foundation::Result plan_app_startup_resources( float ui_width, float ui_height) { if (!std::isfinite(ui_width) || !std::isfinite(ui_height)) { return pp::foundation::Result::failure( pp::foundation::Status::invalid_argument("startup resource dimensions must be finite")); } if (ui_width < 1.0F || ui_height < 1.0F) { return pp::foundation::Result::failure( pp::foundation::Status::invalid_argument("startup resource dimensions must be positive")); } if (ui_width > static_cast(std::numeric_limits::max()) || ui_height > static_cast(std::numeric_limits::max())) { return pp::foundation::Result::failure( pp::foundation::Status::out_of_range("startup resource dimensions exceed integer range")); } AppStartupResourcePlan plan; plan.ui_render_target_width = static_cast(ui_width); plan.ui_render_target_height = static_cast(ui_height); return pp::foundation::Result::success(plan); } [[nodiscard]] inline pp::foundation::Status execute_app_startup_plan( const AppStartupPlan& plan, AppStartupServices& services) { if (plan.previous_run_counter < 0 || plan.next_run_counter <= plan.previous_run_counter) { return pp::foundation::Status::invalid_argument("startup plan has invalid run counter state"); } services.store_run_counter(plan.next_run_counter); if (plan.save_preferences) { services.save_preferences(); } if (plan.start_timelapse) { services.start_timelapse_recording(); } services.apply_vr_controllers_enabled(plan.vr_controllers_enabled); if (plan.show_license_warning) { services.show_license_warning(); } return pp::foundation::Status::success(); } [[nodiscard]] inline pp::foundation::Status execute_app_startup_persistence_plan( const AppStartupPlan& plan, AppStartupServices& services) { if (plan.previous_run_counter < 0 || plan.next_run_counter <= plan.previous_run_counter) { return pp::foundation::Status::invalid_argument("startup plan has invalid run counter state"); } services.store_run_counter(plan.next_run_counter); if (plan.save_preferences) { services.save_preferences(); } return pp::foundation::Status::success(); } [[nodiscard]] inline pp::foundation::Status execute_app_startup_runtime_plan( const AppStartupPlan& plan, AppStartupServices& services) { if (plan.previous_run_counter < 0 || plan.next_run_counter <= plan.previous_run_counter) { return pp::foundation::Status::invalid_argument("startup plan has invalid run counter state"); } if (plan.start_timelapse) { services.start_timelapse_recording(); } services.apply_vr_controllers_enabled(plan.vr_controllers_enabled); if (plan.show_license_warning) { services.show_license_warning(); } return pp::foundation::Status::success(); } [[nodiscard]] inline pp::foundation::Status execute_app_startup_resources( const AppStartupResourcePlan& plan, AppStartupResourceServices& services) { if (plan.create_ui_render_target && (plan.ui_render_target_width <= 0 || plan.ui_render_target_height <= 0)) { return pp::foundation::Status::invalid_argument("startup resource plan has invalid UI render target size"); } if (plan.initialize_shaders) { services.initialize_shaders(); } if (plan.initialize_assets) { services.initialize_assets(); } if (plan.initialize_layout) { services.initialize_layout(); } if (plan.update_title) { services.update_title(); } if (plan.create_ui_render_target) { services.create_ui_render_target(plan.ui_render_target_width, plan.ui_render_target_height); } return pp::foundation::Status::success(); } } // namespace pp::app