Browse Source

Windows icon export improvements.

Regenerate Windows icon on export to ensure correct icon size order.
Add support for using PNG/WebP/SVG files as an icon for Windows exports.
Allow using WebP/SVG files as icon for macOS exports.
Add option to select generated icons interpolation, and set default interpolation to Lanczos.
bruvzg 2 years ago
parent
commit
ac0ed9ce67

+ 13 - 10
platform/ios/export/export_plugin.cpp

@@ -137,6 +137,9 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
 
 
+	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
+	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/launch_screens_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
+
 	Vector<PluginConfigIOS> found_plugins = get_plugins();
 	Vector<PluginConfigIOS> found_plugins = get_plugins();
 	for (int i = 0; i < found_plugins.size(); i++) {
 	for (int i = 0; i < found_plugins.size(); i++) {
 		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("plugins"), found_plugins[i].name)), false));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("plugins"), found_plugins[i].name)), false));
@@ -589,13 +592,13 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
 				return ERR_UNCONFIGURED;
 				return ERR_UNCONFIGURED;
 			} else if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) {
 			} else if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) {
 				add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key));
 				add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key));
-				img->resize(side_size, side_size);
+				img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
 				Ref<Image> new_img = Image::create_empty(side_size, side_size, false, Image::FORMAT_RGBA8);
 				Ref<Image> new_img = Image::create_empty(side_size, side_size, false, Image::FORMAT_RGBA8);
 				new_img->fill(boot_bg_color);
 				new_img->fill(boot_bg_color);
 				_blend_and_rotate(new_img, img, false);
 				_blend_and_rotate(new_img, img, false);
 				err = new_img->save_png(p_iconset_dir + info.export_name);
 				err = new_img->save_png(p_iconset_dir + info.export_name);
 			} else {
 			} else {
-				img->resize(side_size, side_size);
+				img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
 				err = img->save_png(p_iconset_dir + info.export_name);
 				err = img->save_png(p_iconset_dir + info.export_name);
 			}
 			}
 			if (err) {
 			if (err) {
@@ -611,14 +614,14 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
 				return ERR_UNCONFIGURED;
 				return ERR_UNCONFIGURED;
 			} else if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) {
 			} else if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) {
 				add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key));
 				add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key));
-				img->resize(side_size, side_size);
+				img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
 				Ref<Image> new_img = Image::create_empty(side_size, side_size, false, Image::FORMAT_RGBA8);
 				Ref<Image> new_img = Image::create_empty(side_size, side_size, false, Image::FORMAT_RGBA8);
 				new_img->fill(boot_bg_color);
 				new_img->fill(boot_bg_color);
 				_blend_and_rotate(new_img, img, false);
 				_blend_and_rotate(new_img, img, false);
 				err = new_img->save_png(p_iconset_dir + info.export_name);
 				err = new_img->save_png(p_iconset_dir + info.export_name);
 			} else if (img->get_width() != side_size || img->get_height() != side_size) {
 			} else if (img->get_width() != side_size || img->get_height() != side_size) {
 				add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s): '%s' has incorrect size %s and was automatically resized to %s.", info.preset_key, icon_path, img->get_size(), Vector2i(side_size, side_size)));
 				add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s): '%s' has incorrect size %s and was automatically resized to %s.", info.preset_key, icon_path, img->get_size(), Vector2i(side_size, side_size)));
-				img->resize(side_size, side_size);
+				img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
 				err = img->save_png(p_iconset_dir + info.export_name);
 				err = img->save_png(p_iconset_dir + info.export_name);
 			} else {
 			} else {
 				err = da->copy(icon_path, p_iconset_dir + info.export_name);
 				err = da->copy(icon_path, p_iconset_dir + info.export_name);
@@ -748,9 +751,9 @@ Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExp
 				float aspect_ratio = (float)img->get_width() / (float)img->get_height();
 				float aspect_ratio = (float)img->get_width() / (float)img->get_height();
 				if (boot_logo_scale) {
 				if (boot_logo_scale) {
 					if (info.height * aspect_ratio <= info.width) {
 					if (info.height * aspect_ratio <= info.width) {
-						img->resize(info.height * aspect_ratio, info.height);
+						img->resize(info.height * aspect_ratio, info.height, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
 					} else {
 					} else {
-						img->resize(info.width, info.width / aspect_ratio);
+						img->resize(info.width, info.width / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
 					}
 					}
 				}
 				}
 				Ref<Image> new_img = Image::create_empty(info.width, info.height, false, Image::FORMAT_RGBA8);
 				Ref<Image> new_img = Image::create_empty(info.width, info.height, false, Image::FORMAT_RGBA8);
@@ -784,17 +787,17 @@ Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExp
 				if (info.rotate) {
 				if (info.rotate) {
 					if (boot_logo_scale) {
 					if (boot_logo_scale) {
 						if (info.width * aspect_ratio <= info.height) {
 						if (info.width * aspect_ratio <= info.height) {
-							img_bs->resize(info.width * aspect_ratio, info.width);
+							img_bs->resize(info.width * aspect_ratio, info.width, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
 						} else {
 						} else {
-							img_bs->resize(info.height, info.height / aspect_ratio);
+							img_bs->resize(info.height, info.height / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
 						}
 						}
 					}
 					}
 				} else {
 				} else {
 					if (boot_logo_scale) {
 					if (boot_logo_scale) {
 						if (info.height * aspect_ratio <= info.width) {
 						if (info.height * aspect_ratio <= info.width) {
-							img_bs->resize(info.height * aspect_ratio, info.height);
+							img_bs->resize(info.height * aspect_ratio, info.height, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
 						} else {
 						} else {
-							img_bs->resize(info.width, info.width / aspect_ratio);
+							img_bs->resize(info.width, info.width / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
 						}
 						}
 					}
 					}
 				}
 				}

+ 7 - 8
platform/macos/export/export_plugin.cpp

@@ -116,7 +116,8 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
 
 
 	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "debug/export_console_script", PROPERTY_HINT_ENUM, "No,Debug Only,Debug and Release"), 1));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "debug/export_console_script", PROPERTY_HINT_ENUM, "No,Debug Only,Debug and Release"), 1));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), ""));
+	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.icns,*.png,*.webp,*.svg"), ""));
+	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games"));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games"));
@@ -268,7 +269,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source,
 	memcpy(&p_dest.write[ofs], result.ptr(), res_size);
 	memcpy(&p_dest.write[ofs], result.ptr(), res_size);
 }
 }
 
 
-void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
+void EditorExportPlatformMacOS::_make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
 	Ref<ImageTexture> it = memnew(ImageTexture);
 	Ref<ImageTexture> it = memnew(ImageTexture);
 
 
 	Vector<uint8_t> data;
 	Vector<uint8_t> data;
@@ -302,7 +303,7 @@ void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint
 	for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
 	for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
 		Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy?
 		Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy?
 		copy->convert(Image::FORMAT_RGBA8);
 		copy->convert(Image::FORMAT_RGBA8);
-		copy->resize(icon_infos[i].size, icon_infos[i].size);
+		copy->resize(icon_infos[i].size, icon_infos[i].size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
 
 
 		if (icon_infos[i].is_png) {
 		if (icon_infos[i].is_png) {
 			// Encode PNG icon.
 			// Encode PNG icon.
@@ -1268,11 +1269,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
 						icon->get_buffer(&data.write[0], icon->get_length());
 						icon->get_buffer(&data.write[0], icon->get_length());
 					}
 					}
 				} else {
 				} else {
-					Ref<Image> icon;
-					icon.instantiate();
-					icon->load(iconpath);
-					if (!icon->is_empty()) {
-						_make_icon(icon, data);
+					Ref<Image> icon = Image::load_from_file(iconpath);
+					if (icon.is_valid() && !icon->is_empty()) {
+						_make_icon(p_preset, icon, data);
 					}
 					}
 				}
 				}
 			}
 			}

+ 1 - 1
platform/macos/export/export_plugin.h

@@ -53,7 +53,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
 	Ref<ImageTexture> logo;
 	Ref<ImageTexture> logo;
 
 
 	void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary);
 	void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary);
-	void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
+	void _make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
 
 
 	Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
 	Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
 	Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true);
 	Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true);

+ 130 - 3
platform/windows/export/export_plugin.cpp

@@ -32,6 +32,118 @@
 
 
 #include "core/config/project_settings.h"
 #include "core/config/project_settings.h"
 #include "editor/editor_node.h"
 #include "editor/editor_node.h"
+#include "editor/editor_paths.h"
+
+Error EditorExportPlatformWindows::_process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path) {
+	static const uint8_t icon_size[] = { 16, 32, 48, 64, 128, 0 /*256*/ };
+
+	struct IconData {
+		Vector<uint8_t> data;
+		uint8_t pal_colors = 0;
+		uint16_t planes = 0;
+		uint16_t bpp = 32;
+	};
+
+	HashMap<uint8_t, IconData> images;
+	Error err;
+
+	if (p_src_path.get_extension() == "ico") {
+		Ref<FileAccess> f = FileAccess::open(p_src_path, FileAccess::READ, &err);
+		if (err != OK) {
+			return err;
+		}
+
+		// Read ICONDIR.
+		f->get_16(); // Reserved.
+		uint16_t icon_type = f->get_16(); // Image type: 1 - ICO.
+		uint16_t icon_count = f->get_16(); // Number of images.
+		ERR_FAIL_COND_V(icon_type != 1, ERR_CANT_OPEN);
+
+		for (uint16_t i = 0; i < icon_count; i++) {
+			// Read ICONDIRENTRY.
+			uint16_t w = f->get_8(); // Width in pixels.
+			uint16_t h = f->get_8(); // Height in pixels.
+			uint8_t pal_colors = f->get_8(); // Number of colors in the palette (0 - no palette).
+			f->get_8(); // Reserved.
+			uint16_t planes = f->get_16(); // Number of color planes.
+			uint16_t bpp = f->get_16(); // Bits per pixel.
+			uint32_t img_size = f->get_32(); // Image data size in bytes.
+			uint32_t img_offset = f->get_32(); // Image data offset.
+			if (w != h) {
+				continue;
+			}
+
+			// Read image data.
+			uint64_t prev_offset = f->get_position();
+			images[w].pal_colors = pal_colors;
+			images[w].planes = planes;
+			images[w].bpp = bpp;
+			images[w].data.resize(img_size);
+			f->seek(img_offset);
+			f->get_buffer(images[w].data.ptrw(), img_size);
+			f->seek(prev_offset);
+		}
+	} else {
+		Ref<Image> src_image = Image::load_from_file(p_src_path);
+		ERR_FAIL_COND_V(src_image.is_null() || src_image->is_empty(), ERR_CANT_OPEN);
+		for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+			int size = (icon_size[i] == 0) ? 256 : icon_size[i];
+
+			Ref<Image> res_image = src_image->duplicate();
+			ERR_FAIL_COND_V(res_image.is_null() || res_image->is_empty(), ERR_CANT_OPEN);
+			res_image->resize(size, size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
+			images[icon_size[i]].data = res_image->save_png_to_buffer();
+		}
+	}
+
+	uint16_t valid_icon_count = 0;
+	for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+		if (images.has(icon_size[i])) {
+			valid_icon_count++;
+		} else {
+			int size = (icon_size[i] == 0) ? 256 : icon_size[i];
+			add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Icon size \"%d\" is missing."), size));
+		}
+	}
+	ERR_FAIL_COND_V(valid_icon_count == 0, ERR_CANT_OPEN);
+
+	Ref<FileAccess> fw = FileAccess::open(p_dst_path, FileAccess::WRITE, &err);
+	if (err != OK) {
+		return err;
+	}
+
+	// Write ICONDIR.
+	fw->store_16(0); // Reserved.
+	fw->store_16(1); // Image type: 1 - ICO.
+	fw->store_16(valid_icon_count); // Number of images.
+
+	// Write ICONDIRENTRY.
+	uint32_t img_offset = 6 + 16 * valid_icon_count;
+	for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+		if (images.has(icon_size[i])) {
+			const IconData &di = images[icon_size[i]];
+			fw->store_8(icon_size[i]); // Width in pixels.
+			fw->store_8(icon_size[i]); // Height in pixels.
+			fw->store_8(di.pal_colors); // Number of colors in the palette (0 - no palette).
+			fw->store_8(0); // Reserved.
+			fw->store_16(di.planes); // Number of color planes.
+			fw->store_16(di.bpp); // Bits per pixel.
+			fw->store_32(di.data.size()); // Image data size in bytes.
+			fw->store_32(img_offset); // Image data offset.
+
+			img_offset += di.data.size();
+		}
+	}
+
+	// Write image data.
+	for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+		if (images.has(icon_size[i])) {
+			const IconData &di = images[icon_size[i]];
+			fw->store_buffer(di.data.ptr(), di.data.size());
+		}
+	}
+	return OK;
+}
 
 
 Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
 Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
 	if (p_preset->get("codesign/enable")) {
 	if (p_preset->get("codesign/enable")) {
@@ -110,8 +222,9 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
 	r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
 
 
 	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/modify_resources"), true));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/modify_resources"), true));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), ""));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico"), ""));
+	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), ""));
+	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico.*.png,*.webp,*.svg"), ""));
+	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
@@ -154,6 +267,15 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
 			icon_path = console_icon_path;
 			icon_path = console_icon_path;
 		}
 		}
 	}
 	}
+
+	String tmp_icon_path = EditorPaths::get_singleton()->get_cache_dir().path_join("_rcedit.ico");
+	if (!icon_path.is_empty()) {
+		if (_process_icon(p_preset, icon_path, tmp_icon_path) != OK) {
+			add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Invalid icon file \"%s\"."), icon_path));
+			icon_path = String();
+		}
+	}
+
 	String file_verion = p_preset->get("application/file_version");
 	String file_verion = p_preset->get("application/file_version");
 	String product_version = p_preset->get("application/product_version");
 	String product_version = p_preset->get("application/product_version");
 	String company_name = p_preset->get("application/company_name");
 	String company_name = p_preset->get("application/company_name");
@@ -167,7 +289,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
 	args.push_back(p_path);
 	args.push_back(p_path);
 	if (!icon_path.is_empty()) {
 	if (!icon_path.is_empty()) {
 		args.push_back("--set-icon");
 		args.push_back("--set-icon");
-		args.push_back(icon_path);
+		args.push_back(tmp_icon_path);
 	}
 	}
 	if (!file_verion.is_empty()) {
 	if (!file_verion.is_empty()) {
 		args.push_back("--set-file-version");
 		args.push_back("--set-file-version");
@@ -211,6 +333,11 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
 
 
 	String str;
 	String str;
 	Error err = OS::get_singleton()->execute(rcedit_path, args, &str, nullptr, true);
 	Error err = OS::get_singleton()->execute(rcedit_path, args, &str, nullptr, true);
+
+	if (FileAccess::exists(tmp_icon_path)) {
+		DirAccess::remove_file_or_error(tmp_icon_path);
+	}
+
 	if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
 	if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
 		add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > rcedit), or disable \"Application > Modify Resources\" in the export preset."));
 		add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > rcedit), or disable \"Application > Modify Resources\" in the export preset."));
 		return err;
 		return err;

+ 1 - 0
platform/windows/export/export_plugin.h

@@ -38,6 +38,7 @@
 #include "platform/windows/logo.gen.h"
 #include "platform/windows/logo.gen.h"
 
 
 class EditorExportPlatformWindows : public EditorExportPlatformPC {
 class EditorExportPlatformWindows : public EditorExportPlatformPC {
+	Error _process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path);
 	Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon);
 	Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon);
 	Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
 	Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);