|
@@ -92,7 +92,8 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
|
|
String _get_linker_flags();
|
|
String _get_linker_flags();
|
|
String _get_cpp_code();
|
|
String _get_cpp_code();
|
|
void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug);
|
|
void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug);
|
|
- Error _export_loading_screens(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
|
|
|
|
|
|
+ Error _export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
|
|
|
|
+ Error _export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
|
|
Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir);
|
|
Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir);
|
|
|
|
|
|
Vector<ExportArchitecture> _get_supported_architectures();
|
|
Vector<ExportArchitecture> _get_supported_architectures();
|
|
@@ -255,6 +256,13 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
|
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight
|
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight
|
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with retina display
|
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with retina display
|
|
|
|
|
|
|
|
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false));
|
|
|
|
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale To Fit,Scale To Fill,Scale"), 0));
|
|
|
|
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png"), ""));
|
|
|
|
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png"), ""));
|
|
|
|
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false));
|
|
|
|
+ r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color()));
|
|
|
|
+
|
|
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "launch_screens/generate_missing"), false));
|
|
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "launch_screens/generate_missing"), false));
|
|
|
|
|
|
for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) {
|
|
for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) {
|
|
@@ -274,6 +282,12 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
|
|
"ad-hoc",
|
|
"ad-hoc",
|
|
"enterprise"
|
|
"enterprise"
|
|
};
|
|
};
|
|
|
|
+ static const String storyboard_image_scale_mode[] = {
|
|
|
|
+ "center",
|
|
|
|
+ "scaleAspectFit",
|
|
|
|
+ "scaleAspectFill",
|
|
|
|
+ "scaleToFill"
|
|
|
|
+ };
|
|
String str;
|
|
String str;
|
|
String strnew;
|
|
String strnew;
|
|
str.parse_utf8((const char *)pfile.ptr(), pfile.size());
|
|
str.parse_utf8((const char *)pfile.ptr(), pfile.size());
|
|
@@ -390,6 +404,60 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
|
|
} else if (lines[i].find("$photolibrary_usage_description") != -1) {
|
|
} else if (lines[i].find("$photolibrary_usage_description") != -1) {
|
|
String description = p_preset->get("privacy/photolibrary_usage_description");
|
|
String description = p_preset->get("privacy/photolibrary_usage_description");
|
|
strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n";
|
|
strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n";
|
|
|
|
+ } else if (lines[i].find("$plist_launch_screen_name") != -1) {
|
|
|
|
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
|
|
|
|
+ String value = is_on ? "<key>UILaunchStoryboardName</key>\n<string>Launch Screen</string>" : "";
|
|
|
|
+ strnew += lines[i].replace("$plist_launch_screen_name", value) + "\n";
|
|
|
|
+ } else if (lines[i].find("$pbx_launch_screen_file_reference") != -1) {
|
|
|
|
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
|
|
|
|
+ String value = is_on ? "90DD2D9D24B36E8000717FE1 = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = \"Launch Screen.storyboard\"; sourceTree = \"<group>\"; };" : "";
|
|
|
|
+ strnew += lines[i].replace("$pbx_launch_screen_file_reference", value) + "\n";
|
|
|
|
+ } else if (lines[i].find("$pbx_launch_screen_copy_files") != -1) {
|
|
|
|
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
|
|
|
|
+ String value = is_on ? "90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */," : "";
|
|
|
|
+ strnew += lines[i].replace("$pbx_launch_screen_copy_files", value) + "\n";
|
|
|
|
+ } else if (lines[i].find("$pbx_launch_screen_build_phase") != -1) {
|
|
|
|
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
|
|
|
|
+ String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */," : "";
|
|
|
|
+ strnew += lines[i].replace("$pbx_launch_screen_build_phase", value) + "\n";
|
|
|
|
+ } else if (lines[i].find("$pbx_launch_screen_build_reference") != -1) {
|
|
|
|
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
|
|
|
|
+ String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };" : "";
|
|
|
|
+ strnew += lines[i].replace("$pbx_launch_screen_build_reference", value) + "\n";
|
|
|
|
+ } else if (lines[i].find("$pbx_launch_image_usage_setting") != -1) {
|
|
|
|
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
|
|
|
|
+ String value = is_on ? "" : "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;";
|
|
|
|
+ strnew += lines[i].replace("$pbx_launch_image_usage_setting", value) + "\n";
|
|
|
|
+ } else if (lines[i].find("$launch_screen_image_mode") != -1) {
|
|
|
|
+ int image_scale_mode = p_preset->get("storyboard/image_scale_mode");
|
|
|
|
+ String value;
|
|
|
|
+
|
|
|
|
+ switch (image_scale_mode) {
|
|
|
|
+ case 0: {
|
|
|
|
+ String logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
|
|
|
|
+ bool is_on = ProjectSettings::get_singleton()->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];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ strnew += lines[i].replace("$launch_screen_image_mode", value) + "\n";
|
|
|
|
+ } else if (lines[i].find("$launch_screen_background_color") != -1) {
|
|
|
|
+ bool use_custom = p_preset->get("storyboard/use_custom_bg_color");
|
|
|
|
+ Color color = use_custom ? p_preset->get("storyboard/custom_bg_color") : ProjectSettings::get_singleton()->get("application/boot_splash/bg_color");
|
|
|
|
+ const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
|
|
|
|
+
|
|
|
|
+ Dictionary value_dictionary;
|
|
|
|
+ value_dictionary["red"] = color.r;
|
|
|
|
+ value_dictionary["green"] = color.g;
|
|
|
|
+ value_dictionary["blue"] = color.b;
|
|
|
|
+ value_dictionary["alpha"] = color.a;
|
|
|
|
+ String value = value_format.format(value_dictionary, "$_");
|
|
|
|
+
|
|
|
|
+ strnew += lines[i].replace("$launch_screen_background_color", value) + "\n";
|
|
} else {
|
|
} else {
|
|
strnew += lines[i] + "\n";
|
|
strnew += lines[i] + "\n";
|
|
}
|
|
}
|
|
@@ -591,7 +659,75 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
|
|
return OK;
|
|
return OK;
|
|
}
|
|
}
|
|
|
|
|
|
-Error EditorExportPlatformIOS::_export_loading_screens(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) {
|
|
|
|
|
|
+Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) {
|
|
|
|
+ const String custom_launch_image_2x = p_preset->get("storyboard/custom_image@2x");
|
|
|
|
+ const String custom_launch_image_3x = p_preset->get("storyboard/custom_image@3x");
|
|
|
|
+
|
|
|
|
+ if (custom_launch_image_2x.length() > 0 && custom_launch_image_3x.length() > 0) {
|
|
|
|
+ Ref<Image> image;
|
|
|
|
+ String image_path = p_dest_dir.plus_file("[email protected]");
|
|
|
|
+ image.instance();
|
|
|
|
+ Error err = image->load(custom_launch_image_2x);
|
|
|
|
+
|
|
|
|
+ if (err) {
|
|
|
|
+ image.unref();
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (image->save_png(image_path) != OK) {
|
|
|
|
+ return ERR_FILE_CANT_WRITE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ image.unref();
|
|
|
|
+ image_path = p_dest_dir.plus_file("[email protected]");
|
|
|
|
+ image.instance();
|
|
|
|
+ err = image->load(custom_launch_image_3x);
|
|
|
|
+
|
|
|
|
+ if (err) {
|
|
|
|
+ image.unref();
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (image->save_png(image_path) != OK) {
|
|
|
|
+ return ERR_FILE_CANT_WRITE;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ Ref<Image> splash;
|
|
|
|
+
|
|
|
|
+ const String splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
|
|
|
|
+
|
|
|
|
+ if (!splash_path.empty()) {
|
|
|
|
+ splash.instance();
|
|
|
|
+ const Error err = splash->load(splash_path);
|
|
|
|
+ if (err) {
|
|
|
|
+ splash.unref();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (splash.is_null()) {
|
|
|
|
+ splash = Ref<Image>(memnew(Image(boot_splash_png)));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Using same image for both @2x and @3x
|
|
|
|
+ // because Godot's own boot logo uses single image for all resolutions.
|
|
|
|
+ // Also not using @1x image, because devices using this image variant
|
|
|
|
+ // are not supported by iOS 9, which is minimal target.
|
|
|
|
+ const String splash_png_path_2x = p_dest_dir.plus_file("[email protected]");
|
|
|
|
+ const String splash_png_path_3x = p_dest_dir.plus_file("[email protected]");
|
|
|
|
+
|
|
|
|
+ if (splash->save_png(splash_png_path_2x) != OK) {
|
|
|
|
+ return ERR_FILE_CANT_WRITE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (splash->save_png(splash_png_path_3x) != OK) {
|
|
|
|
+ return ERR_FILE_CANT_WRITE;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return OK;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) {
|
|
DirAccess *da = DirAccess::open(p_dest_dir);
|
|
DirAccess *da = DirAccess::open(p_dest_dir);
|
|
ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_dest_dir + "'.");
|
|
ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_dest_dir + "'.");
|
|
|
|
|
|
@@ -1177,6 +1313,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
|
|
files_to_parse.insert("godot_ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata");
|
|
files_to_parse.insert("godot_ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata");
|
|
files_to_parse.insert("godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme");
|
|
files_to_parse.insert("godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme");
|
|
files_to_parse.insert("godot_ios/godot_ios.entitlements");
|
|
files_to_parse.insert("godot_ios/godot_ios.entitlements");
|
|
|
|
+ files_to_parse.insert("godot_ios/Launch Screen.storyboard");
|
|
|
|
|
|
IOSConfigData config_data = {
|
|
IOSConfigData config_data = {
|
|
pkg_name,
|
|
pkg_name,
|
|
@@ -1352,7 +1489,43 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
- err = _export_loading_screens(p_preset, dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/");
|
|
|
|
|
|
+ bool use_storyboard = p_preset->get("storyboard/use_launch_screen_storyboard");
|
|
|
|
+
|
|
|
|
+ String launch_image_path = dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/";
|
|
|
|
+ String splash_image_path = dest_dir + binary_name + "/Images.xcassets/SplashImage.imageset/";
|
|
|
|
+
|
|
|
|
+ DirAccess *launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
|
|
|
+
|
|
|
|
+ if (!launch_screen_da) {
|
|
|
|
+ return ERR_CANT_CREATE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (use_storyboard) {
|
|
|
|
+ print_line("Using Launch Storyboard");
|
|
|
|
+
|
|
|
|
+ if (launch_screen_da->change_dir(launch_image_path) == OK) {
|
|
|
|
+ launch_screen_da->erase_contents_recursive();
|
|
|
|
+ launch_screen_da->remove(launch_image_path);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = _export_loading_screen_file(p_preset, splash_image_path);
|
|
|
|
+ } else {
|
|
|
|
+ print_line("Using Launch Images");
|
|
|
|
+
|
|
|
|
+ const String launch_screen_path = dest_dir + binary_name + "/Launch Screen.storyboard";
|
|
|
|
+
|
|
|
|
+ launch_screen_da->remove(launch_screen_path);
|
|
|
|
+
|
|
|
|
+ if (launch_screen_da->change_dir(splash_image_path) == OK) {
|
|
|
|
+ launch_screen_da->erase_contents_recursive();
|
|
|
|
+ launch_screen_da->remove(splash_image_path);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = _export_loading_screen_images(p_preset, launch_image_path);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memdelete(launch_screen_da);
|
|
|
|
+
|
|
if (err) {
|
|
if (err) {
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|