Merge pull request #94609 from bruvzg/pixel_font_detect

[Font Import] Detect pixel fonts and disable subpixel positioning.
This commit is contained in:
Rémi Verschelde 2024-08-16 14:32:14 +02:00
commit 7865266f24
No known key found for this signature in database
GPG Key ID: C3336907360768E1
13 changed files with 128 additions and 3 deletions

View File

@ -69,12 +69,13 @@
<member name="script_support" type="Dictionary" setter="" getter="" default="{}"> <member name="script_support" type="Dictionary" setter="" getter="" default="{}">
Override the list of language scripts 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 language_support]. Override the list of language scripts 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 language_support].
</member> </member>
<member name="subpixel_positioning" type="int" setter="" getter="" default="1"> <member name="subpixel_positioning" type="int" setter="" getter="" default="4">
Subpixel positioning improves font rendering appearance, especially at smaller font sizes. The downside is that it takes more time to initially render the font, which can cause stuttering during gameplay, especially if used with large font sizes. This should be set to [b]Disabled[/b] for fonts with a pixel art appearance. Subpixel positioning improves font rendering appearance, especially at smaller font sizes. The downside is that it takes more time to initially render the font, which can cause stuttering during gameplay, especially if used with large font sizes. This should be set to [b]Disabled[/b] for fonts with a pixel art appearance.
[b]Disabled:[/b] No subpixel positioning. Lowest quality, fastest rendering. [b]Disabled:[/b] No subpixel positioning. Lowest quality, fastest rendering.
[b]Auto:[/b] Use subpixel positioning at small font sizes (the chosen quality varies depending on font size). Large fonts will not use subpixel positioning. This is a good tradeoff between performance and quality. [b]Auto:[/b] Use subpixel positioning at small font sizes (the chosen quality varies depending on font size). Large fonts will not use subpixel positioning. This is a good tradeoff between performance and quality.
[b]One Half of a Pixel:[/b] Always perform intermediate subpixel positioning regardless of font size. High quality, slow rendering. [b]One Half of a Pixel:[/b] Always perform intermediate subpixel positioning regardless of font size. High quality, slow rendering.
[b]One Quarter of a Pixel:[/b] Always perform precise subpixel positioning regardless of font size. Highest quality, slowest rendering. [b]One Quarter of a Pixel:[/b] Always perform precise subpixel positioning regardless of font size. Highest quality, slowest rendering.
[b]Auto (Except Pixel Fonts):[/b] [b]Disabled[/b] for the pixel style fonts (each glyph contours contain only straight horizontal and vertical lines), [b]Auto[/b] for the other fonts.
</member> </member>
</members> </members>
</class> </class>

View File

@ -459,6 +459,13 @@
Returns a string containing all the characters available in the font. Returns a string containing all the characters available in the font.
</description> </description>
</method> </method>
<method name="font_get_supported_glyphs" qualifiers="const">
<return type="PackedInt32Array" />
<param index="0" name="font_rid" type="RID" />
<description>
Returns an array containing all glyph indices in the font.
</description>
</method>
<method name="font_get_texture_count" qualifiers="const"> <method name="font_get_texture_count" qualifiers="const">
<return type="int" /> <return type="int" />
<param index="0" name="font_rid" type="RID" /> <param index="0" name="font_rid" type="RID" />

View File

@ -496,6 +496,14 @@
Returns a string containing all the characters available in the font. Returns a string containing all the characters available in the font.
</description> </description>
</method> </method>
<method name="_font_get_supported_glyphs" qualifiers="virtual const">
<return type="PackedInt32Array" />
<param index="0" name="font_rid" type="RID" />
<description>
[b]Required.[/b]
Returns an array containing all glyph indices in the font.
</description>
</method>
<method name="_font_get_texture_count" qualifiers="virtual const"> <method name="_font_get_texture_count" qualifiers="virtual const">
<return type="int" /> <return type="int" />
<param index="0" name="font_rid" type="RID" /> <param index="0" name="font_rid" type="RID" />

View File

@ -118,7 +118,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, "allow_system_fallback"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), 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, "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"), 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::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), 0.0)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), 0.0));
r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Fallbacks", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Fallbacks", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant()));
@ -176,11 +176,44 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str
font->set_fixed_size(0); font->set_fixed_size(0);
font->set_force_autohinter(autohinter); font->set_force_autohinter(autohinter);
font->set_allow_system_fallback(allow_system_fallback); font->set_allow_system_fallback(allow_system_fallback);
font->set_subpixel_positioning((TextServer::SubpixelPositioning)subpixel_positioning);
font->set_hinting((TextServer::Hinting)hinting); font->set_hinting((TextServer::Hinting)hinting);
font->set_oversampling(oversampling); font->set_oversampling(oversampling);
font->set_fallbacks(fallbacks); font->set_fallbacks(fallbacks);
if (subpixel_positioning == 4 /* Auto (Except Pixel Fonts) */) {
PackedInt32Array glyphs = TS->font_get_supported_glyphs(font->get_rids()[0]);
bool is_pixel = true;
for (int32_t gl : glyphs) {
Dictionary ct = TS->font_get_glyph_contours(font->get_rids()[0], 16, gl);
PackedInt32Array contours = ct["contours"];
PackedVector3Array points = ct["points"];
int prev_start = 0;
for (int i = 0; i < contours.size(); i++) {
for (int j = prev_start; j <= contours[i]; j++) {
int next_point = (j < contours[i]) ? (j + 1) : prev_start;
if ((points[j].z != TextServer::CONTOUR_CURVE_TAG_ON) || (!Math::is_equal_approx(points[j].x, points[next_point].x) && !Math::is_equal_approx(points[j].y, points[next_point].y))) {
is_pixel = false;
break;
}
}
prev_start = contours[i] + 1;
if (!is_pixel) {
break;
}
}
if (!is_pixel) {
break;
}
}
if (is_pixel && !glyphs.is_empty()) {
print_line(vformat("%s: Pixel font detected, disabling subpixel positioning.", p_source_file));
subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
} else {
subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
}
}
font->set_subpixel_positioning((TextServer::SubpixelPositioning)subpixel_positioning);
Dictionary langs = p_options["language_support"]; Dictionary langs = p_options["language_support"];
for (int i = 0; i < langs.size(); i++) { for (int i = 0; i < langs.size(); i++) {
String key = langs.get_key_at_index(i); String key = langs.get_key_at_index(i);

View File

@ -3528,6 +3528,37 @@ String TextServerAdvanced::_font_get_supported_chars(const RID &p_font_rid) cons
return chars; return chars;
} }
PackedInt32Array TextServerAdvanced::_font_get_supported_glyphs(const RID &p_font_rid) const {
FontAdvanced *fd = _get_font_data(p_font_rid);
ERR_FAIL_NULL_V(fd, PackedInt32Array());
MutexLock lock(fd->mutex);
if (fd->cache.is_empty()) {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), PackedInt32Array());
}
FontForSizeAdvanced *at_size = fd->cache.begin()->value;
PackedInt32Array glyphs;
#ifdef MODULE_FREETYPE_ENABLED
if (at_size && at_size->face) {
FT_UInt gindex;
FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex);
while (gindex != 0) {
glyphs.push_back(gindex);
charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex);
}
return glyphs;
}
#endif
if (at_size) {
const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;
for (const KeyValue<int32_t, FontGlyph> &E : gl) {
glyphs.push_back(E.key);
}
}
return glyphs;
}
void TextServerAdvanced::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) { void TextServerAdvanced::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {
FontAdvanced *fd = _get_font_data(p_font_rid); FontAdvanced *fd = _get_font_data(p_font_rid);
ERR_FAIL_NULL(fd); ERR_FAIL_NULL(fd);

View File

@ -871,6 +871,7 @@ public:
MODBIND2RC(bool, font_has_char, const RID &, int64_t); MODBIND2RC(bool, font_has_char, const RID &, int64_t);
MODBIND1RC(String, font_get_supported_chars, const RID &); MODBIND1RC(String, font_get_supported_chars, const RID &);
MODBIND1RC(PackedInt32Array, font_get_supported_glyphs, const RID &);
MODBIND4(font_render_range, const RID &, const Vector2i &, int64_t, int64_t); MODBIND4(font_render_range, const RID &, const Vector2i &, int64_t, int64_t);
MODBIND3(font_render_glyph, const RID &, const Vector2i &, int64_t); MODBIND3(font_render_glyph, const RID &, const Vector2i &, int64_t);

View File

@ -2477,6 +2477,37 @@ String TextServerFallback::_font_get_supported_chars(const RID &p_font_rid) cons
return chars; return chars;
} }
PackedInt32Array TextServerFallback::_font_get_supported_glyphs(const RID &p_font_rid) const {
FontFallback *fd = _get_font_data(p_font_rid);
ERR_FAIL_NULL_V(fd, PackedInt32Array());
MutexLock lock(fd->mutex);
if (fd->cache.is_empty()) {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), PackedInt32Array());
}
FontForSizeFallback *at_size = fd->cache.begin()->value;
PackedInt32Array glyphs;
#ifdef MODULE_FREETYPE_ENABLED
if (at_size && at_size->face) {
FT_UInt gindex;
FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex);
while (gindex != 0) {
glyphs.push_back(gindex);
charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex);
}
return glyphs;
}
#endif
if (at_size) {
const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;
for (const KeyValue<int32_t, FontGlyph> &E : gl) {
glyphs.push_back(E.key);
}
}
return glyphs;
}
void TextServerFallback::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) { void TextServerFallback::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {
FontFallback *fd = _get_font_data(p_font_rid); FontFallback *fd = _get_font_data(p_font_rid);
ERR_FAIL_NULL(fd); ERR_FAIL_NULL(fd);

View File

@ -739,6 +739,7 @@ public:
MODBIND2RC(bool, font_has_char, const RID &, int64_t); MODBIND2RC(bool, font_has_char, const RID &, int64_t);
MODBIND1RC(String, font_get_supported_chars, const RID &); MODBIND1RC(String, font_get_supported_chars, const RID &);
MODBIND1RC(PackedInt32Array, font_get_supported_glyphs, const RID &);
MODBIND4(font_render_range, const RID &, const Vector2i &, int64_t, int64_t); MODBIND4(font_render_range, const RID &, const Vector2i &, int64_t, int64_t);
MODBIND3(font_render_glyph, const RID &, const Vector2i &, int64_t); MODBIND3(font_render_glyph, const RID &, const Vector2i &, int64_t);

View File

@ -88,6 +88,7 @@ public:
virtual int64_t font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const override { return 0; } virtual int64_t font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const override { return 0; }
virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override { return false; } virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override { return false; }
virtual String font_get_supported_chars(const RID &p_font_rid) const override { return String(); } virtual String font_get_supported_chars(const RID &p_font_rid) const override { return String(); }
virtual PackedInt32Array font_get_supported_glyphs(const RID &p_font_rid) const override { return PackedInt32Array(); };
virtual void font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const override {} virtual void font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const override {}
virtual void font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const override {} virtual void font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const override {}

View File

@ -196,6 +196,7 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(_font_has_char, "font_rid", "char"); GDVIRTUAL_BIND(_font_has_char, "font_rid", "char");
GDVIRTUAL_BIND(_font_get_supported_chars, "font_rid"); GDVIRTUAL_BIND(_font_get_supported_chars, "font_rid");
GDVIRTUAL_BIND(_font_get_supported_glyphs, "font_rid");
GDVIRTUAL_BIND(_font_render_range, "font_rid", "size", "start", "end"); GDVIRTUAL_BIND(_font_render_range, "font_rid", "size", "start", "end");
GDVIRTUAL_BIND(_font_render_glyph, "font_rid", "size", "index"); GDVIRTUAL_BIND(_font_render_glyph, "font_rid", "size", "index");
@ -927,6 +928,12 @@ String TextServerExtension::font_get_supported_chars(const RID &p_font_rid) cons
return ret; return ret;
} }
PackedInt32Array TextServerExtension::font_get_supported_glyphs(const RID &p_font_rid) const {
PackedInt32Array ret;
GDVIRTUAL_REQUIRED_CALL(_font_get_supported_glyphs, p_font_rid, ret);
return ret;
}
void TextServerExtension::font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) { void TextServerExtension::font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {
GDVIRTUAL_CALL(_font_render_range, p_font_rid, p_size, p_start, p_end); GDVIRTUAL_CALL(_font_render_range, p_font_rid, p_size, p_start, p_end);
} }

View File

@ -323,8 +323,10 @@ public:
virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override; virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override;
virtual String font_get_supported_chars(const RID &p_font_rid) const override; virtual String font_get_supported_chars(const RID &p_font_rid) const override;
virtual PackedInt32Array font_get_supported_glyphs(const RID &p_font_rid) const override;
GDVIRTUAL2RC(bool, _font_has_char, RID, int64_t); GDVIRTUAL2RC(bool, _font_has_char, RID, int64_t);
GDVIRTUAL1RC(String, _font_get_supported_chars, RID); GDVIRTUAL1RC(String, _font_get_supported_chars, RID);
GDVIRTUAL1RC(PackedInt32Array, _font_get_supported_glyphs, RID);
virtual void font_render_range(const RID &p_font, const Vector2i &p_size, int64_t p_start, int64_t p_end) override; virtual void font_render_range(const RID &p_font, const Vector2i &p_size, int64_t p_start, int64_t p_end) override;
virtual void font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) override; virtual void font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) override;

View File

@ -352,6 +352,7 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("font_has_char", "font_rid", "char"), &TextServer::font_has_char); ClassDB::bind_method(D_METHOD("font_has_char", "font_rid", "char"), &TextServer::font_has_char);
ClassDB::bind_method(D_METHOD("font_get_supported_chars", "font_rid"), &TextServer::font_get_supported_chars); ClassDB::bind_method(D_METHOD("font_get_supported_chars", "font_rid"), &TextServer::font_get_supported_chars);
ClassDB::bind_method(D_METHOD("font_get_supported_glyphs", "font_rid"), &TextServer::font_get_supported_glyphs);
ClassDB::bind_method(D_METHOD("font_render_range", "font_rid", "size", "start", "end"), &TextServer::font_render_range); ClassDB::bind_method(D_METHOD("font_render_range", "font_rid", "size", "start", "end"), &TextServer::font_render_range);
ClassDB::bind_method(D_METHOD("font_render_glyph", "font_rid", "size", "index"), &TextServer::font_render_glyph); ClassDB::bind_method(D_METHOD("font_render_glyph", "font_rid", "size", "index"), &TextServer::font_render_glyph);

View File

@ -396,6 +396,7 @@ public:
virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const = 0; virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const = 0;
virtual String font_get_supported_chars(const RID &p_font_rid) const = 0; virtual String font_get_supported_chars(const RID &p_font_rid) const = 0;
virtual PackedInt32Array font_get_supported_glyphs(const RID &p_font_rid) const = 0;
virtual void font_render_range(const RID &p_font, const Vector2i &p_size, int64_t p_start, int64_t p_end) = 0; virtual void font_render_range(const RID &p_font, const Vector2i &p_size, int64_t p_start, int64_t p_end) = 0;
virtual void font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) = 0; virtual void font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) = 0;