Browse Source

Add font import flag to toggle modulation of colored glyphs.

Pāvels Nadtočajevs 4 months ago
parent
commit
19f360d65a

+ 3 - 0
doc/classes/FontFile.xml

@@ -634,6 +634,9 @@
 		<member name="keep_rounding_remainders" type="bool" setter="set_keep_rounding_remainders" getter="get_keep_rounding_remainders" default="true">
 			If set to [code]true[/code], when aligning glyphs to the pixel boundaries rounding remainders are accumulated to ensure more uniform glyph distribution. This setting has no effect if subpixel positioning is enabled.
 		</member>
+		<member name="modulate_color_glyphs" type="bool" setter="set_modulate_color_glyphs" getter="is_modulate_color_glyphs" default="false">
+			If set to [code]true[/code], color modulation is applied when drawing colored glyphs, otherwise it's applied to the monochrome glyphs only.
+		</member>
 		<member name="msdf_pixel_range" type="int" setter="set_msdf_pixel_range" getter="get_msdf_pixel_range" default="16">
 			The width of the range around the shape between the minimum and maximum representable signed distance. If using font outlines, [member msdf_pixel_range] must be set to at least [i]twice[/i] the size of the largest font outline. The default [member msdf_pixel_range] value of [code]16[/code] allows outline sizes up to [code]8[/code] to look correct.
 		</member>

+ 3 - 0
doc/classes/ResourceImporterDynamicFont.xml

@@ -50,6 +50,9 @@
 		<member name="language_support" type="Dictionary" setter="" getter="" default="{}">
 			Override the list of languages supported by this font. If left empty, this is supplied by the font metadata. There is usually no need to change this. See also [member script_support].
 		</member>
+		<member name="modulate_color_glyphs" type="bool" setter="" getter="" default="false">
+			If set to [code]true[/code], color modulation is applied when drawing colored glyphs, otherwise it's applied to the monochrome glyphs only.
+		</member>
 		<member name="msdf_pixel_range" type="int" setter="" getter="" default="8">
 			The width of the range around the shape between the minimum and maximum representable signed distance. If using font outlines, [member msdf_pixel_range] must be set to at least [i]twice[/i] the size of the largest font outline. The default [member msdf_pixel_range] value of [code]8[/code] allows outline sizes up to [code]4[/code] to look correct.
 		</member>

+ 3 - 0
doc/classes/SystemFont.xml

@@ -46,6 +46,9 @@
 		<member name="keep_rounding_remainders" type="bool" setter="set_keep_rounding_remainders" getter="get_keep_rounding_remainders" default="true">
 			If set to [code]true[/code], when aligning glyphs to the pixel boundaries rounding remainders are accumulated to ensure more uniform glyph distribution. This setting has no effect if subpixel positioning is enabled.
 		</member>
+		<member name="modulate_color_glyphs" type="bool" setter="set_modulate_color_glyphs" getter="is_modulate_color_glyphs" default="false">
+			If set to [code]true[/code], color modulation is applied when drawing colored glyphs, otherwise it's applied to the monochrome glyphs only.
+		</member>
 		<member name="msdf_pixel_range" type="int" setter="set_msdf_pixel_range" getter="get_msdf_pixel_range" default="16">
 			The width of the range around the shape between the minimum and maximum representable signed distance. If using font outlines, [member msdf_pixel_range] must be set to at least [i]twice[/i] the size of the largest font outline. The default [member msdf_pixel_range] value of [code]16[/code] allows outline sizes up to [code]8[/code] to look correct.
 		</member>

+ 15 - 0
doc/classes/TextServer.xml

@@ -571,6 +571,13 @@
 				Returns [code]true[/code], if font supports given language ([url=https://en.wikipedia.org/wiki/ISO_639-1]ISO 639[/url] code).
 			</description>
 		</method>
+		<method name="font_is_modulate_color_glyphs" qualifiers="const">
+			<return type="bool" />
+			<param index="0" name="font_rid" type="RID" />
+			<description>
+				Returns [code]true[/code], if color modulation is applied when drawing colored glyphs.
+			</description>
+		</method>
 		<method name="font_is_multichannel_signed_distance_field" qualifiers="const">
 			<return type="bool" />
 			<param index="0" name="font_rid" type="RID" />
@@ -858,6 +865,14 @@
 				Adds override for [method font_is_language_supported].
 			</description>
 		</method>
+		<method name="font_set_modulate_color_glyphs">
+			<return type="void" />
+			<param index="0" name="font_rid" type="RID" />
+			<param index="1" name="force_autohinter" type="bool" />
+			<description>
+				If set to [code]true[/code], color modulation is applied when drawing colored glyphs, otherwise it's applied to the monochrome glyphs only.
+			</description>
+		</method>
 		<method name="font_set_msdf_pixel_range">
 			<return type="void" />
 			<param index="0" name="font_rid" type="RID" />

+ 17 - 0
doc/classes/TextServerExtension.xml

@@ -617,6 +617,14 @@
 				Returns [code]true[/code], if font supports given language ([url=https://en.wikipedia.org/wiki/ISO_639-1]ISO 639[/url] code).
 			</description>
 		</method>
+		<method name="_font_is_modulate_color_glyphs" qualifiers="virtual const">
+			<return type="bool" />
+			<param index="0" name="font_rid" type="RID" />
+			<description>
+				[b]Optional.[/b]
+				Returns [code]true[/code], if color modulation is applied when drawing colored glyphs.
+			</description>
+		</method>
 		<method name="_font_is_multichannel_signed_distance_field" qualifiers="virtual const">
 			<return type="bool" />
 			<param index="0" name="font_rid" type="RID" />
@@ -942,6 +950,15 @@
 				Adds override for [method _font_is_language_supported].
 			</description>
 		</method>
+		<method name="_font_set_modulate_color_glyphs" qualifiers="virtual">
+			<return type="void" />
+			<param index="0" name="font_rid" type="RID" />
+			<param index="1" name="modulate" type="bool" />
+			<description>
+				[b]Optional.[/b]
+				If set to [code]true[/code], color modulation is applied when drawing colored glyphs, otherwise it's applied to the monochrome glyphs only.
+			</description>
+		</method>
 		<method name="_font_set_msdf_pixel_range" qualifiers="virtual">
 			<return type="void" />
 			<param index="0" name="font_rid" type="RID" />

+ 5 - 0
editor/import/dynamic_font_import_settings.cpp

@@ -490,6 +490,8 @@ void DynamicFontImportSettingsDialog::_main_prop_changed(const String &p_edited_
 			font_preview->set_allow_system_fallback(import_settings_data->get("allow_system_fallback"));
 		} else if (p_edited_property == "force_autohinter") {
 			font_preview->set_force_autohinter(import_settings_data->get("force_autohinter"));
+		} else if (p_edited_property == "modulate_color_glyphs") {
+			font_preview->set_modulate_color_glyphs(import_settings_data->get("modulate_color_glyphs"));
 		} else if (p_edited_property == "hinting") {
 			font_preview->set_hinting((TextServer::Hinting)import_settings_data->get("hinting").operator int());
 		} else if (p_edited_property == "subpixel_positioning") {
@@ -977,6 +979,7 @@ void DynamicFontImportSettingsDialog::_re_import() {
 	main_settings["msdf_size"] = import_settings_data->get("msdf_size");
 	main_settings["allow_system_fallback"] = import_settings_data->get("allow_system_fallback");
 	main_settings["force_autohinter"] = import_settings_data->get("force_autohinter");
+	main_settings["modulate_color_glyphs"] = import_settings_data->get("modulate_color_glyphs");
 	main_settings["hinting"] = import_settings_data->get("hinting");
 	main_settings["subpixel_positioning"] = import_settings_data->get("subpixel_positioning");
 	main_settings["keep_rounding_remainders"] = import_settings_data->get("keep_rounding_remainders");
@@ -1281,6 +1284,7 @@ void DynamicFontImportSettingsDialog::open_settings(const String &p_path) {
 		font_preview->set_msdf_size(import_settings_data->get("msdf_size"));
 		font_preview->set_allow_system_fallback(import_settings_data->get("allow_system_fallback"));
 		font_preview->set_force_autohinter(import_settings_data->get("force_autohinter"));
+		font_preview->set_modulate_color_glyphs(import_settings_data->get("modulate_color_glyphs"));
 		font_preview->set_hinting((TextServer::Hinting)import_settings_data->get("hinting").operator int());
 		int font_subpixel_positioning = import_settings_data->get("subpixel_positioning").operator int();
 		if (font_subpixel_positioning == 4 /* Auto (Except Pixel Fonts) */) {
@@ -1322,6 +1326,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() {
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_RANGE, "1,250,1"), 48));
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "allow_system_fallback"), true));
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false));
+	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "modulate_color_glyphs"), false));
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), 1));
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel,Auto (Except Pixel Fonts)"), 4));
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "keep_rounding_remainders"), true));

+ 3 - 0
editor/import/resource_importer_dynamic_font.cpp

@@ -116,6 +116,7 @@ void ResourceImporterDynamicFont::get_import_options(const String &p_path, List<
 
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "allow_system_fallback"), true));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false));
+	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "modulate_color_glyphs"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), 1));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel,Auto (Except Pixel Fonts)"), 4));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "keep_rounding_remainders"), true));
@@ -153,6 +154,7 @@ Error ResourceImporterDynamicFont::import(ResourceUID::ID p_source_id, const Str
 	Dictionary ot_ov = p_options["opentype_features"];
 
 	bool autohinter = p_options["force_autohinter"];
+	bool modulate_color_glyphs = p_options["modulate_color_glyphs"];
 	bool allow_system_fallback = p_options["allow_system_fallback"];
 	int hinting = p_options["hinting"];
 	int subpixel_positioning = p_options["subpixel_positioning"];
@@ -176,6 +178,7 @@ Error ResourceImporterDynamicFont::import(ResourceUID::ID p_source_id, const Str
 	font->set_opentype_feature_overrides(ot_ov);
 	font->set_fixed_size(0);
 	font->set_force_autohinter(autohinter);
+	font->set_modulate_color_glyphs(modulate_color_glyphs);
 	font->set_allow_system_fallback(allow_system_fallback);
 	font->set_hinting((TextServer::Hinting)hinting);
 	font->set_oversampling(oversampling);

+ 1 - 0
editor/import/resource_importer_imagefont.cpp

@@ -114,6 +114,7 @@ Error ResourceImporterImageFont::import(ResourceUID::ID p_source_id, const Strin
 	font->set_subpixel_positioning(TextServer::SUBPIXEL_POSITIONING_DISABLED);
 	font->set_keep_rounding_remainders(true);
 	font->set_force_autohinter(false);
+	font->set_modulate_color_glyphs(false);
 	font->set_allow_system_fallback(false);
 	font->set_hinting(TextServer::HINTING_NONE);
 	font->set_oversampling(1.0f);

+ 19 - 1
modules/text_server_adv/text_server_adv.cpp

@@ -2440,6 +2440,24 @@ bool TextServerAdvanced::_font_is_force_autohinter(const RID &p_font_rid) const
 	return fd->force_autohinter;
 }
 
+void TextServerAdvanced::_font_set_modulate_color_glyphs(const RID &p_font_rid, bool p_modulate) {
+	FontAdvanced *fd = _get_font_data(p_font_rid);
+	ERR_FAIL_NULL(fd);
+
+	MutexLock lock(fd->mutex);
+	if (fd->modulate_color_glyphs != p_modulate) {
+		fd->modulate_color_glyphs = p_modulate;
+	}
+}
+
+bool TextServerAdvanced::_font_is_modulate_color_glyphs(const RID &p_font_rid) const {
+	FontAdvanced *fd = _get_font_data(p_font_rid);
+	ERR_FAIL_NULL_V(fd, false);
+
+	MutexLock lock(fd->mutex);
+	return fd->modulate_color_glyphs;
+}
+
 void TextServerAdvanced::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {
 	FontAdvanced *fd = _get_font_data(p_font_rid);
 	ERR_FAIL_NULL(fd);
@@ -3800,7 +3818,7 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
 		if (fgl.texture_idx != -1) {
 			Color modulate = p_color;
 #ifdef MODULE_FREETYPE_ENABLED
-			if (!fgl.from_svg && ffsd->face && ffsd->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
+			if (!fd->modulate_color_glyphs && ffsd->face && ffsd->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
 				modulate.r = modulate.g = modulate.b = 1.0;
 			}
 #endif

+ 4 - 0
modules/text_server_adv/text_server_adv.h

@@ -330,6 +330,7 @@ class TextServerAdvanced : public TextServerExtension {
 		int fixed_size = 0;
 		bool allow_system_fallback = true;
 		bool force_autohinter = false;
+		bool modulate_color_glyphs = false;
 		TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
 		TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
 		bool keep_rounding_remainders = true;
@@ -807,6 +808,9 @@ public:
 	MODBIND2(font_set_force_autohinter, const RID &, bool);
 	MODBIND1RC(bool, font_is_force_autohinter, const RID &);
 
+	MODBIND2(font_set_modulate_color_glyphs, const RID &, bool);
+	MODBIND1RC(bool, font_is_modulate_color_glyphs, const RID &);
+
 	MODBIND2(font_set_subpixel_positioning, const RID &, SubpixelPositioning);
 	MODBIND1RC(SubpixelPositioning, font_get_subpixel_positioning, const RID &);
 

+ 19 - 1
modules/text_server_fb/text_server_fb.cpp

@@ -1442,6 +1442,24 @@ bool TextServerFallback::_font_is_force_autohinter(const RID &p_font_rid) const
 	return fd->force_autohinter;
 }
 
+void TextServerFallback::_font_set_modulate_color_glyphs(const RID &p_font_rid, bool p_modulate) {
+	FontFallback *fd = _get_font_data(p_font_rid);
+	ERR_FAIL_NULL(fd);
+
+	MutexLock lock(fd->mutex);
+	if (fd->modulate_color_glyphs != p_modulate) {
+		fd->modulate_color_glyphs = p_modulate;
+	}
+}
+
+bool TextServerFallback::_font_is_modulate_color_glyphs(const RID &p_font_rid) const {
+	FontFallback *fd = _get_font_data(p_font_rid);
+	ERR_FAIL_NULL_V(fd, false);
+
+	MutexLock lock(fd->mutex);
+	return fd->modulate_color_glyphs;
+}
+
 void TextServerFallback::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {
 	FontFallback *fd = _get_font_data(p_font_rid);
 	ERR_FAIL_NULL(fd);
@@ -2741,7 +2759,7 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
 		if (fgl.texture_idx != -1) {
 			Color modulate = p_color;
 #ifdef MODULE_FREETYPE_ENABLED
-			if (!fgl.from_svg && ffsd->face && ffsd->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
+			if (!fd->modulate_color_glyphs && ffsd->face && ffsd->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
 				modulate.r = modulate.g = modulate.b = 1.0;
 			}
 #endif

+ 4 - 0
modules/text_server_fb/text_server_fb.h

@@ -268,6 +268,7 @@ class TextServerFallback : public TextServerExtension {
 		int fixed_size = 0;
 		bool force_autohinter = false;
 		bool allow_system_fallback = true;
+		bool modulate_color_glyphs = false;
 		TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
 		TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
 		bool keep_rounding_remainders = true;
@@ -662,6 +663,9 @@ public:
 	MODBIND2(font_set_force_autohinter, const RID &, bool);
 	MODBIND1RC(bool, font_is_force_autohinter, const RID &);
 
+	MODBIND2(font_set_modulate_color_glyphs, const RID &, bool);
+	MODBIND1RC(bool, font_is_modulate_color_glyphs, const RID &);
+
 	MODBIND2(font_set_subpixel_positioning, const RID &, SubpixelPositioning);
 	MODBIND1RC(SubpixelPositioning, font_get_subpixel_positioning, const RID &);
 

+ 42 - 0
scene/resources/font.cpp

@@ -602,6 +602,7 @@ _FORCE_INLINE_ void FontFile::_ensure_rid(int p_cache_index, int p_make_linked_f
 			TS->font_set_fixed_size(cache[p_cache_index], fixed_size);
 			TS->font_set_fixed_size_scale_mode(cache[p_cache_index], fixed_size_scale_mode);
 			TS->font_set_force_autohinter(cache[p_cache_index], force_autohinter);
+			TS->font_set_modulate_color_glyphs(cache[p_cache_index], modulate_color_glyphs);
 			TS->font_set_allow_system_fallback(cache[p_cache_index], allow_system_fallback);
 			TS->font_set_hinting(cache[p_cache_index], hinting);
 			TS->font_set_subpixel_positioning(cache[p_cache_index], subpixel_positioning);
@@ -929,6 +930,9 @@ void FontFile::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &FontFile::set_force_autohinter);
 	ClassDB::bind_method(D_METHOD("is_force_autohinter"), &FontFile::is_force_autohinter);
 
+	ClassDB::bind_method(D_METHOD("set_modulate_color_glyphs", "modulate"), &FontFile::set_modulate_color_glyphs);
+	ClassDB::bind_method(D_METHOD("is_modulate_color_glyphs"), &FontFile::is_modulate_color_glyphs);
+
 	ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &FontFile::set_hinting);
 	ClassDB::bind_method(D_METHOD("get_hinting"), &FontFile::get_hinting);
 
@@ -1054,6 +1058,7 @@ void FontFile::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_size", "get_msdf_size");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_system_fallback", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_allow_system_fallback", "is_allow_system_fallback");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_force_autohinter", "is_force_autohinter");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "modulate_color_glyphs", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_modulate_color_glyphs", "is_modulate_color_glyphs");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_STORAGE), "set_hinting", "get_hinting");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_oversampling", "get_oversampling");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_fixed_size", "get_fixed_size");
@@ -1413,6 +1418,7 @@ void FontFile::reset_state() {
 	disable_embedded_bitmaps = true;
 	msdf = false;
 	force_autohinter = false;
+	modulate_color_glyphs = false;
 	allow_system_fallback = true;
 	hinting = TextServer::HINTING_LIGHT;
 	subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
@@ -1453,6 +1459,7 @@ Error FontFile::_load_bitmap_font(const String &p_path, List<String> *r_image_fi
 	disable_embedded_bitmaps = true;
 	msdf = false;
 	force_autohinter = false;
+	modulate_color_glyphs = false;
 	allow_system_fallback = true;
 	hinting = TextServer::HINTING_NONE;
 	oversampling = 1.0f;
@@ -2271,6 +2278,21 @@ bool FontFile::is_force_autohinter() const {
 	return force_autohinter;
 }
 
+void FontFile::set_modulate_color_glyphs(bool p_modulate) {
+	if (modulate_color_glyphs != p_modulate) {
+		modulate_color_glyphs = p_modulate;
+		for (int i = 0; i < cache.size(); i++) {
+			_ensure_rid(i);
+			TS->font_set_modulate_color_glyphs(cache[i], modulate_color_glyphs);
+		}
+		emit_changed();
+	}
+}
+
+bool FontFile::is_modulate_color_glyphs() const {
+	return modulate_color_glyphs;
+}
+
 void FontFile::set_hinting(TextServer::Hinting p_hinting) {
 	if (hinting != p_hinting) {
 		hinting = p_hinting;
@@ -3100,6 +3122,9 @@ void SystemFont::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &SystemFont::set_force_autohinter);
 	ClassDB::bind_method(D_METHOD("is_force_autohinter"), &SystemFont::is_force_autohinter);
 
+	ClassDB::bind_method(D_METHOD("set_modulate_color_glyphs", "modulate"), &SystemFont::set_modulate_color_glyphs);
+	ClassDB::bind_method(D_METHOD("is_modulate_color_glyphs"), &SystemFont::is_modulate_color_glyphs);
+
 	ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &SystemFont::set_hinting);
 	ClassDB::bind_method(D_METHOD("get_hinting"), &SystemFont::get_hinting);
 
@@ -3138,6 +3163,7 @@ void SystemFont::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_embedded_bitmaps"), "set_disable_embedded_bitmaps", "get_disable_embedded_bitmaps");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_system_fallback"), "set_allow_system_fallback", "is_allow_system_fallback");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter"), "set_force_autohinter", "is_force_autohinter");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "modulate_color_glyphs"), "set_modulate_color_glyphs", "is_modulate_color_glyphs");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel"), "set_subpixel_positioning", "get_subpixel_positioning");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_rounding_remainders"), "set_keep_rounding_remainders", "get_keep_rounding_remainders");
@@ -3243,6 +3269,7 @@ void SystemFont::_update_base_font() {
 		file->set_generate_mipmaps(mipmaps);
 		file->set_disable_embedded_bitmaps(disable_embedded_bitmaps);
 		file->set_force_autohinter(force_autohinter);
+		file->set_modulate_color_glyphs(modulate_color_glyphs);
 		file->set_allow_system_fallback(allow_system_fallback);
 		file->set_hinting(hinting);
 		file->set_subpixel_positioning(subpixel_positioning);
@@ -3287,6 +3314,7 @@ void SystemFont::reset_state() {
 	mipmaps = false;
 	disable_embedded_bitmaps = true;
 	force_autohinter = false;
+	modulate_color_glyphs = false;
 	allow_system_fallback = true;
 	hinting = TextServer::HINTING_LIGHT;
 	subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
@@ -3416,6 +3444,20 @@ bool SystemFont::is_force_autohinter() const {
 	return force_autohinter;
 }
 
+void SystemFont::set_modulate_color_glyphs(bool p_modulate) {
+	if (modulate_color_glyphs != p_modulate) {
+		modulate_color_glyphs = p_modulate;
+		if (base_font.is_valid()) {
+			base_font->set_modulate_color_glyphs(modulate_color_glyphs);
+		}
+		emit_changed();
+	}
+}
+
+bool SystemFont::is_modulate_color_glyphs() const {
+	return modulate_color_glyphs;
+}
+
 void SystemFont::set_hinting(TextServer::Hinting p_hinting) {
 	if (hinting != p_hinting) {
 		hinting = p_hinting;

+ 8 - 0
scene/resources/font.h

@@ -192,6 +192,7 @@ class FontFile : public Font {
 	int fixed_size = 0;
 	TextServer::FixedSizeScaleMode fixed_size_scale_mode = TextServer::FIXED_SIZE_SCALE_DISABLE;
 	bool force_autohinter = false;
+	bool modulate_color_glyphs = false;
 	bool allow_system_fallback = true;
 	TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
 	TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
@@ -273,6 +274,9 @@ public:
 	virtual void set_force_autohinter(bool p_force_autohinter);
 	virtual bool is_force_autohinter() const;
 
+	virtual void set_modulate_color_glyphs(bool p_modulate);
+	virtual bool is_modulate_color_glyphs() const;
+
 	virtual void set_hinting(TextServer::Hinting p_hinting);
 	virtual TextServer::Hinting get_hinting() const;
 
@@ -479,6 +483,7 @@ class SystemFont : public Font {
 	bool mipmaps = false;
 	bool disable_embedded_bitmaps = true;
 	bool force_autohinter = false;
+	bool modulate_color_glyphs = false;
 	bool allow_system_fallback = true;
 	TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
 	TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
@@ -515,6 +520,9 @@ public:
 	virtual void set_force_autohinter(bool p_force_autohinter);
 	virtual bool is_force_autohinter() const;
 
+	virtual void set_modulate_color_glyphs(bool p_modulate);
+	virtual bool is_modulate_color_glyphs() const;
+
 	virtual void set_hinting(TextServer::Hinting p_hinting);
 	virtual TextServer::Hinting get_hinting() const;
 

+ 13 - 0
servers/text/text_server_extension.cpp

@@ -108,6 +108,9 @@ void TextServerExtension::_bind_methods() {
 	GDVIRTUAL_BIND(_font_set_force_autohinter, "font_rid", "force_autohinter");
 	GDVIRTUAL_BIND(_font_is_force_autohinter, "font_rid");
 
+	GDVIRTUAL_BIND(_font_set_modulate_color_glyphs, "font_rid", "modulate");
+	GDVIRTUAL_BIND(_font_is_modulate_color_glyphs, "font_rid");
+
 	GDVIRTUAL_BIND(_font_set_hinting, "font_rid", "hinting");
 	GDVIRTUAL_BIND(_font_get_hinting, "font_rid");
 
@@ -631,6 +634,16 @@ bool TextServerExtension::font_is_force_autohinter(const RID &p_font_rid) const
 	return ret;
 }
 
+void TextServerExtension::font_set_modulate_color_glyphs(const RID &p_font_rid, bool p_modulate) {
+	GDVIRTUAL_CALL(_font_set_modulate_color_glyphs, p_font_rid, p_modulate);
+}
+
+bool TextServerExtension::font_is_modulate_color_glyphs(const RID &p_font_rid) const {
+	bool ret = false;
+	GDVIRTUAL_CALL(_font_is_modulate_color_glyphs, p_font_rid, ret);
+	return ret;
+}
+
 void TextServerExtension::font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {
 	GDVIRTUAL_CALL(_font_set_hinting, p_font_rid, p_hinting);
 }

+ 5 - 0
servers/text/text_server_extension.h

@@ -204,6 +204,11 @@ public:
 	GDVIRTUAL2(_font_set_force_autohinter, RID, bool);
 	GDVIRTUAL1RC(bool, _font_is_force_autohinter, RID);
 
+	virtual void font_set_modulate_color_glyphs(const RID &p_font_rid, bool p_modulate) override;
+	virtual bool font_is_modulate_color_glyphs(const RID &p_font_rid) const override;
+	GDVIRTUAL2(_font_set_modulate_color_glyphs, RID, bool);
+	GDVIRTUAL1RC(bool, _font_is_modulate_color_glyphs, RID);
+
 	virtual void font_set_hinting(const RID &p_font_rid, Hinting p_hinting) override;
 	virtual Hinting font_get_hinting(const RID &p_font_rid) const override;
 	GDVIRTUAL2(_font_set_hinting, RID, Hinting);

+ 3 - 0
servers/text_server.cpp

@@ -264,6 +264,9 @@ void TextServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("font_set_force_autohinter", "font_rid", "force_autohinter"), &TextServer::font_set_force_autohinter);
 	ClassDB::bind_method(D_METHOD("font_is_force_autohinter", "font_rid"), &TextServer::font_is_force_autohinter);
 
+	ClassDB::bind_method(D_METHOD("font_set_modulate_color_glyphs", "font_rid", "force_autohinter"), &TextServer::font_set_modulate_color_glyphs);
+	ClassDB::bind_method(D_METHOD("font_is_modulate_color_glyphs", "font_rid"), &TextServer::font_is_modulate_color_glyphs);
+
 	ClassDB::bind_method(D_METHOD("font_set_hinting", "font_rid", "hinting"), &TextServer::font_set_hinting);
 	ClassDB::bind_method(D_METHOD("font_get_hinting", "font_rid"), &TextServer::font_get_hinting);
 

+ 3 - 0
servers/text_server.h

@@ -318,6 +318,9 @@ public:
 	virtual void font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) = 0;
 	virtual bool font_is_force_autohinter(const RID &p_font_rid) const = 0;
 
+	virtual void font_set_modulate_color_glyphs(const RID &p_font_rid, bool p_modulate) = 0;
+	virtual bool font_is_modulate_color_glyphs(const RID &p_font_rid) const = 0;
+
 	virtual void font_set_hinting(const RID &p_font_rid, Hinting p_hinting) = 0;
 	virtual Hinting font_get_hinting(const RID &p_font_rid) const = 0;