Skip to content

Commit

Permalink
Fix signed distance field font rendering
Browse files Browse the repository at this point in the history
This fix works in both GLES3 and GLES2.

The rendering formula in the shader was adjusted to further improve the
sharpness/antialiasing quality balance.

Co-authored-by: Hugo Locurcio <hugo.locurcio@hugo.pro>
  • Loading branch information
lawnjelly and Calinou committed Feb 5, 2024
1 parent a81d96c commit bc607fb
Show file tree
Hide file tree
Showing 19 changed files with 80 additions and 22 deletions.
1 change: 1 addition & 0 deletions drivers/gles2/rasterizer_canvas_base_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ void RasterizerCanvasBaseGLES2::canvas_begin() {
state.using_large_vertex = false;
state.using_modulate = false;

state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_DISTANCE_FIELD, false);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_ATTRIB_LIGHT_ANGLE, false);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_ATTRIB_MODULATE, false);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_ATTRIB_LARGE_VERTEX, false);
Expand Down
19 changes: 19 additions & 0 deletions drivers/gles2/rasterizer_canvas_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,7 @@ void RasterizerCanvasGLES2::canvas_render_items_implementation(Item *p_item_list
ris.item_group_modulate = p_modulate;
ris.item_group_light = p_light;
ris.item_group_base_transform = p_base_transform;
ris.prev_distance_field = false;

state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SKELETON, false);

Expand Down Expand Up @@ -1558,6 +1559,12 @@ bool RasterizerCanvasGLES2::try_join_item(Item *p_ci, RenderItemState &r_ris, bo
join = false;
}

if (r_ris.prev_distance_field != p_ci->distance_field) {
r_ris.prev_distance_field = p_ci->distance_field;
join = false;
r_batch_break = true;
}

// non rects will break the batching anyway, we don't want to record item changes, detect this
if (!r_batch_break && _detect_item_batch_break(r_ris, p_ci, r_batch_break)) {
join = false;
Expand All @@ -1573,6 +1580,12 @@ bool RasterizerCanvasGLES2::try_join_item(Item *p_ci, RenderItemState &r_ris, bo
void RasterizerCanvasGLES2::_legacy_canvas_render_item(Item *p_ci, RenderItemState &r_ris) {
storage->info.render._2d_item_count++;

if (r_ris.prev_distance_field != p_ci->distance_field) {
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_DISTANCE_FIELD, p_ci->distance_field);
r_ris.prev_distance_field = p_ci->distance_field;
r_ris.rebind_shader = true;
}

if (r_ris.current_clip != p_ci->final_clip_owner) {
r_ris.current_clip = p_ci->final_clip_owner;

Expand Down Expand Up @@ -1936,6 +1949,12 @@ void RasterizerCanvasGLES2::render_joined_item(const BItemJoined &p_bij, RenderI
// all the joined items will share the same state with the first item
Item *ci = bdata.item_refs[p_bij.first_item_ref].item;

if (r_ris.prev_distance_field != ci->distance_field) {
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_DISTANCE_FIELD, ci->distance_field);
r_ris.prev_distance_field = ci->distance_field;
r_ris.rebind_shader = true;
}

if (r_ris.current_clip != ci->final_clip_owner) {
r_ris.current_clip = ci->final_clip_owner;

Expand Down
10 changes: 9 additions & 1 deletion drivers/gles2/shaders/canvas.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -443,10 +443,18 @@ void main() {
uv = mod(uv, vec2(1.0, 1.0));
#endif

#ifdef USE_DISTANCE_FIELD
// Higher is smoother, but also more blurry. Lower is crisper, but also more aliased.
// TODO: Adjust automatically based on screen resolution/font size ratio.
const float smoothing = 0.125;
float dist = texture2D(color_texture, uv).a;
color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, dist);
#else
#if !defined(COLOR_USED)
//default behavior, texture by color
// Default behavior, texture by color.
color *= texture2D(color_texture, uv);
#endif
#endif

#ifdef SCREEN_UV_USED
vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
Expand Down
1 change: 1 addition & 0 deletions drivers/gles3/rasterizer_canvas_base_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ void RasterizerCanvasBaseGLES3::canvas_begin() {
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, false);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_NINEPATCH, false);

state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, false);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_LIGHT_ANGLE, false);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_MODULATE, false);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_LARGE_VERTEX, false);
Expand Down
6 changes: 6 additions & 0 deletions drivers/gles3/rasterizer_canvas_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1878,6 +1878,12 @@ bool RasterizerCanvasGLES3::try_join_item(Item *p_ci, RenderItemState &r_ris, bo
join = false;
}

if (r_ris.prev_distance_field != p_ci->distance_field) {
r_ris.prev_distance_field = p_ci->distance_field;
join = false;
r_batch_break = true;
}

// non rects will break the batching anyway, we don't want to record item changes, detect this
if (!r_batch_break && _detect_item_batch_break(r_ris, p_ci, r_batch_break)) {
join = false;
Expand Down
15 changes: 7 additions & 8 deletions drivers/gles3/shaders/canvas.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -581,18 +581,17 @@ void main() {

#endif

#if !defined(COLOR_USED)
//default behavior, texture by color

#ifdef USE_DISTANCE_FIELD
const float smoothing = 1.0 / 32.0;
float distance = textureLod(color_texture, uv, 0.0).a;
color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance) * color.a;
// Higher is smoother, but also more blurry. Lower is crisper, but also more aliased.
// TODO: Adjust automatically based on screen resolution/font size ratio.
const float smoothing = 0.125;
float dist = texture(color_texture, uv, 0.0).a;
color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, dist);
#else
#if !defined(COLOR_USED)
// Default behavior, texture by color.
color *= texture(color_texture, uv);

#endif

#endif

vec3 normal;
Expand Down
12 changes: 12 additions & 0 deletions scene/2d/canvas_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,17 @@ void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Tex
VisualServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid, normal_map_rid);
}

void CanvasItem::select_font(const Ref<Font> &p_font) {
// Purely to keep canvas item SDF state up to date for now.
bool new_font_sdf_selected = p_font.is_valid() && p_font->is_distance_field_hint();

if (font_sdf_selected != new_font_sdf_selected) {
ERR_FAIL_COND(!get_canvas_item().is_valid());
font_sdf_selected = new_font_sdf_selected;
VisualServer::get_singleton()->canvas_item_set_distance_field_mode(get_canvas_item(), font_sdf_selected);
}
}

void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");

Expand Down Expand Up @@ -1351,6 +1362,7 @@ CanvasItem::CanvasItem() :
global_invalid = true;
notify_local_transform = false;
notify_transform = false;
font_sdf_selected = false;
light_mask = 1;

C = nullptr;
Expand Down
24 changes: 13 additions & 11 deletions scene/2d/canvas_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,21 +191,22 @@ class CanvasItem : public Node {

int light_mask;

bool first_draw;
bool visible;
bool pending_update;
bool toplevel;
bool drawing;
bool block_transform_notify;
bool behind;
bool use_parent_material;
bool notify_local_transform;
bool notify_transform;
bool first_draw : 1;
bool visible : 1;
bool pending_update : 1;
bool toplevel : 1;
bool drawing : 1;
bool block_transform_notify : 1;
bool behind : 1;
bool use_parent_material : 1;
bool notify_local_transform : 1;
bool notify_transform : 1;
bool font_sdf_selected : 1;
mutable bool global_invalid : 1;

Ref<Material> material;

mutable Transform2D global_transform;
mutable bool global_invalid;

void _toplevel_raise_self();
void _toplevel_visibility_changed(bool p_visible);
Expand Down Expand Up @@ -335,6 +336,7 @@ class CanvasItem : public Node {
void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1));
void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map);

void select_font(const Ref<Font> &p_font);
void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", const Color &p_modulate = Color(1, 1, 1));

Expand Down
1 change: 1 addition & 0 deletions scene/gui/button.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ void Button::_notification(int p_what) {

text_ofs.y += font->get_ascent();
text_ofs.y += line_height * (((float)i) - (((float)(num_lines - 1)) / 2.0));
select_font(font);
font->draw(ci, text_ofs.floor(), line_text, color, clip_text ? text_clip : -1);
}
} break;
Expand Down
1 change: 1 addition & 0 deletions scene/gui/dialogs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ void WindowDialog::_notification(int p_what) {
int font_height = title_font->get_height() - title_font->get_descent() * 2;
int x = (size.x - title_font->get_string_size(xl_title).x) / 2;
int y = (-title_height + font_height) / 2;
select_font(title_font);
title_font->draw(canvas, Point2(x, y), xl_title, title_color, size.x - panel->get_minimum_size().x);
} break;

Expand Down
1 change: 1 addition & 0 deletions scene/gui/item_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,7 @@ void ItemList::_notification(int p_what) {
Ref<StyleBox> cursor = has_focus() ? get_stylebox("cursor") : get_stylebox("cursor_unfocused");

Ref<Font> font = get_font("font");
select_font(font);
Color guide_color = get_color("guide_color");
Color font_color = get_color("font_color");
Color font_color_selected = get_color("font_color_selected");
Expand Down
3 changes: 1 addition & 2 deletions scene/gui/label.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ void Label::_notification(int p_what) {
Size2 size = get_size();
Ref<StyleBox> style = get_stylebox("normal");
Ref<Font> font = get_font("font");
select_font(font);
Color font_color = get_color("font_color");
Color font_color_shadow = get_color("font_color_shadow");
bool use_outline = get_constant("shadow_as_outline");
Expand All @@ -99,8 +100,6 @@ void Label::_notification(int p_what) {

style->draw(ci, Rect2(Point2(0, 0), get_size()));

VisualServer::get_singleton()->canvas_item_set_distance_field_mode(get_canvas_item(), font.is_valid() && font->is_distance_field_hint());

int font_h = font->get_height() + line_spacing;

int lines_visible = (size.y + line_spacing) / font_h;
Expand Down
1 change: 1 addition & 0 deletions scene/gui/line_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,7 @@ void LineEdit::_notification(int p_what) {
}

Ref<Font> font = get_font("font");
select_font(font);

style->draw(ci, Rect2(Point2(), size));

Expand Down
1 change: 1 addition & 0 deletions scene/gui/link_button.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ void LinkButton::_notification(int p_what) {
}

Ref<Font> font = get_font("font");
select_font(font);

draw_string(font, Vector2(0, font->get_ascent()), xl_text, color);

Expand Down
2 changes: 2 additions & 0 deletions scene/gui/popup_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,8 @@ void PopupMenu::_draw_items() {
Ref<StyleBox> style = get_stylebox("panel");
Ref<StyleBox> hover = get_stylebox("hover");
Ref<Font> font = get_font("font");
select_font(font);

// In Item::checkable_type enum order (less the non-checkable member)
Ref<Texture> check[] = { get_icon("checked"), get_icon("radio_checked") };
Ref<Texture> uncheck[] = { get_icon("unchecked"), get_icon("radio_unchecked") };
Expand Down
1 change: 1 addition & 0 deletions scene/gui/progress_bar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ void ProgressBar::_notification(int p_what) {
Ref<StyleBox> bg = get_stylebox("bg");
Ref<StyleBox> fg = get_stylebox("fg");
Ref<Font> font = get_font("font");
select_font(font);
Color font_color = get_color("font_color");

draw_style_box(bg, Rect2(Point2(), get_size()));
Expand Down
1 change: 1 addition & 0 deletions scene/gui/rich_text_label.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,7 @@ void RichTextLabel::_notification(int p_what) {
}
int y = (main->lines[from_line].height_accum_cache - main->lines[from_line].height_cache) - ofs;
Ref<Font> base_font = get_font("normal_font");
select_font(base_font);
Color base_color = get_color("default_color");
Color font_color_shadow = get_color("font_color_shadow");
bool use_outline = get_constant("shadow_as_outline");
Expand Down
1 change: 1 addition & 0 deletions scene/gui/tab_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ void TabContainer::_notification(int p_what) {
Ref<Texture> menu = get_icon("menu");
Ref<Texture> menu_hl = get_icon("menu_highlight");
Ref<Font> font = get_font("font");
select_font(font);
Color font_color_fg = get_color("font_color_fg");
Color font_color_bg = get_color("font_color_bg");
Color font_color_disabled = get_color("font_color_disabled");
Expand Down
1 change: 1 addition & 0 deletions scene/gui/tabs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ void Tabs::_notification(int p_what) {
Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
Ref<Font> font = get_font("font");
select_font(font);
Color color_fg = get_color("font_color_fg");
Color color_bg = get_color("font_color_bg");
Color color_disabled = get_color("font_color_disabled");
Expand Down

0 comments on commit bc607fb

Please sign in to comment.