diff --git a/core/os/os.cpp b/core/os/os.cpp index c161b2212f4..46e519304ef 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -222,6 +222,23 @@ uint64_t OS::get_embedded_pck_offset() const { return 0; } +// Default boot screen rect scale mode is "Keep Aspect Centered" +Rect2 OS::calculate_boot_screen_rect(const Size2 &p_window_size, const Size2 &p_imgrect_size) const { + Rect2 screenrect; + if (p_window_size.width > p_window_size.height) { + // Scale horizontally. + screenrect.size.y = p_window_size.height; + screenrect.size.x = p_imgrect_size.x * p_window_size.height / p_imgrect_size.y; + screenrect.position.x = (p_window_size.width - screenrect.size.x) / 2; + } else { + // Scale vertically. + screenrect.size.x = p_window_size.width; + screenrect.size.y = p_imgrect_size.y * p_window_size.width / p_imgrect_size.x; + screenrect.position.y = (p_window_size.height - screenrect.size.y) / 2; + } + return screenrect; +} + // Helper function to ensure that a dir name/path will be valid on the OS String OS::get_safe_dir_name(const String &p_dir_name, bool p_allow_paths) const { String safe_dir_name = p_dir_name; diff --git a/core/os/os.h b/core/os/os.h index 15c5715dddc..0fe20c1d39c 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -161,6 +161,8 @@ public: virtual void open_midi_inputs(); virtual void close_midi_inputs(); + virtual Rect2 calculate_boot_screen_rect(const Size2 &p_window_size, const Size2 &p_imgrect_size) const; + virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); struct GDExtensionData { diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index f8358dd0728..55c58a10cb7 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -1525,7 +1525,7 @@ Error EditorExportPlatform::export_project_files(const Ref & custom_list.append_array(export_plugins[i]->_get_export_features(Ref(this), p_debug)); } - ProjectSettings::CustomMap custom_map; + ProjectSettings::CustomMap custom_map = get_custom_project_settings(p_preset); if (path_remaps.size()) { if (true) { //new remap mode, use always as it's friendlier with multiple .pck exports for (int i = 0; i < path_remaps.size(); i += 2) { diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h index ed494514335..37cfaac5cb4 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -336,6 +336,7 @@ public: virtual void get_platform_features(List *r_features) const = 0; virtual void resolve_platform_feature_priorities(const Ref &p_preset, HashSet &p_features) {} virtual String get_debug_protocol() const { return "tcp://"; } + virtual HashMap get_custom_project_settings(const Ref &p_preset) const { return HashMap(); } EditorExportPlatform(); }; diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 06f0ba90580..b27453d48ad 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -198,6 +198,19 @@ static const DataCollectionInfo data_collect_purpose_info[] = { { "Other", "NSPrivacyCollectedDataTypePurposeOther" }, }; +static const String export_method_string[] = { + "app-store", + "development", + "ad-hoc", + "enterprise" +}; +static const String storyboard_image_scale_mode[] = { + "center", + "scaleAspectFit", + "scaleAspectFill", + "scaleToFill" +}; + String EditorExportPlatformIOS::get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const { if (p_preset) { if (p_name == "application/app_store_team_id") { @@ -402,19 +415,28 @@ void EditorExportPlatformIOS::get_export_options(List *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color())); } +HashMap EditorExportPlatformIOS::get_custom_project_settings(const Ref &p_preset) const { + HashMap settings; + + int image_scale_mode = p_preset->get("storyboard/image_scale_mode"); + String value; + + switch (image_scale_mode) { + case 0: { + String logo_path = GLOBAL_GET("application/boot_splash/image"); + bool is_on = GLOBAL_GET("application/boot_splash/fullsize"); + // If custom logo is not specified, Godot does not scale default one, so we should do the same. + value = (is_on && logo_path.length() > 0) ? "scaleAspectFit" : "center"; + } break; + default: { + value = storyboard_image_scale_mode[image_scale_mode - 1]; + } + } + settings["ios/launch_screen_image_mode"] = value; + return settings; +} + void EditorExportPlatformIOS::_fix_config_file(const Ref &p_preset, Vector &pfile, const IOSConfigData &p_config, bool p_debug) { - static const String export_method_string[] = { - "app-store", - "development", - "ad-hoc", - "enterprise" - }; - static const String storyboard_image_scale_mode[] = { - "center", - "scaleAspectFit", - "scaleAspectFill", - "scaleToFill" - }; String dbg_sign_id = p_preset->get("application/code_sign_identity_debug").operator String().is_empty() ? "iPhone Developer" : p_preset->get("application/code_sign_identity_debug"); String rel_sign_id = p_preset->get("application/code_sign_identity_release").operator String().is_empty() ? "iPhone Distribution" : p_preset->get("application/code_sign_identity_release"); bool dbg_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG).operator String().is_empty() || (dbg_sign_id != "iPhone Developer" && dbg_sign_id != "iPhone Distribution"); diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h index 3d423ae8d10..d5a8981fa24 100644 --- a/platform/ios/export/export_plugin.h +++ b/platform/ios/export/export_plugin.h @@ -203,6 +203,8 @@ public: return list; } + virtual HashMap get_custom_project_settings(const Ref &p_preset) const override; + virtual Error export_project(const Ref &p_preset, bool p_debug, const String &p_path, BitField p_flags = 0) override; virtual bool has_valid_export_configuration(const Ref &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override; diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h index f2ac1b36628..e9cbfd216cc 100644 --- a/platform/ios/os_ios.h +++ b/platform/ios/os_ios.h @@ -132,6 +132,8 @@ public: void on_enter_background(); void on_exit_background(); + + virtual Rect2 calculate_boot_screen_rect(const Size2 &p_window_size, const Size2 &p_imgrect_size) const override; }; #endif // IOS_ENABLED diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm index 2f75bf9dd5e..e1489f02f13 100644 --- a/platform/ios/os_ios.mm +++ b/platform/ios/os_ios.mm @@ -86,6 +86,46 @@ void register_dynamic_symbol(char *name, void *address) { OS_IOS::dynamic_symbol_lookup_table[String(name)] = address; } +Rect2 fit_keep_aspect_centered(const Vector2 &p_container, const Vector2 &p_rect) { + real_t available_ratio = p_container.width / p_container.height; + real_t fit_ratio = p_rect.width / p_rect.height; + Rect2 result; + if (fit_ratio < available_ratio) { + // Fit height - we'll have horizontal gaps + result.size.height = p_container.height; + result.size.width = p_container.height * fit_ratio; + result.position.y = 0; + result.position.x = (p_container.width - result.size.width) * 0.5f; + } else { + // Fit width - we'll have vertical gaps + result.size.width = p_container.width; + result.size.height = p_container.width / fit_ratio; + result.position.x = 0; + result.position.y = (p_container.height - result.size.height) * 0.5f; + } + return result; +} + +Rect2 fit_keep_aspect_covered(const Vector2 &p_container, const Vector2 &p_rect) { + real_t available_ratio = p_container.width / p_container.height; + real_t fit_ratio = p_rect.width / p_rect.height; + Rect2 result; + if (fit_ratio < available_ratio) { + // Need to scale up to fit width, and crop height + result.size.width = p_container.width; + result.size.height = p_container.width / fit_ratio; + result.position.x = 0; + result.position.y = (p_container.height - result.size.height) * 0.5f; + } else { + // Need to scale up to fit height, and crop width + result.size.width = p_container.height * fit_ratio; + result.size.height = p_container.height; + result.position.x = (p_container.width - result.size.width) * 0.5f; + result.position.y = 0; + } + return result; +} + OS_IOS *OS_IOS::get_singleton() { return (OS_IOS *)OS::get_singleton(); } @@ -660,4 +700,21 @@ void OS_IOS::on_exit_background() { } } +Rect2 OS_IOS::calculate_boot_screen_rect(const Size2 &p_window_size, const Size2 &p_imgrect_size) const { + String scalemodestr = GLOBAL_GET("ios/launch_screen_image_mode"); + + if (scalemodestr == "scaleAspectFit") { + return fit_keep_aspect_centered(p_window_size, p_imgrect_size); + } else if (scalemodestr == "scaleAspectFill") { + return fit_keep_aspect_covered(p_window_size, p_imgrect_size); + } else if (scalemodestr == "scaleToFill") { + return Rect2(Point2(), p_window_size); + } else if (scalemodestr == "center") { + return OS_Unix::calculate_boot_screen_rect(p_window_size, p_imgrect_size); + } else { + WARN_PRINT(vformat("Boot screen scale mode mismatch between iOS and Godot: %s not supported", scalemodestr)); + return OS_Unix::calculate_boot_screen_rect(p_window_size, p_imgrect_size); + } +} + #endif // IOS_ENABLED diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index a7901ac6c03..42780411f70 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -216,18 +216,7 @@ void RendererCompositorRD::set_boot_image(const Ref &p_image, const Color Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height()); Rect2 screenrect; if (p_scale) { - if (window_size.width > window_size.height) { - //scale horizontally - screenrect.size.y = window_size.height; - screenrect.size.x = imgrect.size.x * window_size.height / imgrect.size.y; - screenrect.position.x = (window_size.width - screenrect.size.x) / 2; - - } else { - //scale vertically - screenrect.size.x = window_size.width; - screenrect.size.y = imgrect.size.y * window_size.width / imgrect.size.x; - screenrect.position.y = (window_size.height - screenrect.size.y) / 2; - } + screenrect = OS::get_singleton()->calculate_boot_screen_rect(window_size, imgrect.size); } else { screenrect = imgrect; screenrect.position += ((window_size - screenrect.size) / 2.0).floor();