Fix text shadow outline draw batching.

This commit is contained in:
Pāvels Nadtočajevs
2025-03-02 18:38:19 +02:00
parent 15ff450680
commit 7397e33cc9
4 changed files with 40 additions and 28 deletions

View File

@ -392,14 +392,15 @@ inline void draw_glyph(const Glyph &p_gl, const RID &p_canvas, const Color &p_fo
} }
} }
inline void draw_glyph_shadow(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_shadow_color, int p_shadow_outline_size, const Vector2 &p_ofs, const Vector2 &shadow_ofs) { inline void draw_glyph_shadow(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_shadow_color, const Vector2 &p_ofs, const Vector2 &shadow_ofs) {
if (p_gl.font_rid != RID()) { if (p_gl.font_rid != RID()) {
if (p_font_shadow_color.a > 0) { TS->font_draw_glyph(p_gl.font_rid, p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off) + shadow_ofs, p_gl.index, p_font_shadow_color);
TS->font_draw_glyph(p_gl.font_rid, p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off) + shadow_ofs, p_gl.index, p_font_shadow_color); }
} }
if (p_font_shadow_color.a > 0 && p_shadow_outline_size > 0) {
TS->font_draw_glyph_outline(p_gl.font_rid, p_canvas, p_gl.font_size, p_shadow_outline_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off) + shadow_ofs, p_gl.index, p_font_shadow_color); inline void draw_glyph_shadow_outline(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_shadow_color, int p_shadow_outline_size, const Vector2 &p_ofs, const Vector2 &shadow_ofs) {
} if (p_gl.font_rid != RID()) {
TS->font_draw_glyph_outline(p_gl.font_rid, p_canvas, p_gl.font_size, p_shadow_outline_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off) + shadow_ofs, p_gl.index, p_font_shadow_color);
} }
} }
@ -768,7 +769,10 @@ void Label::_notification(int p_what) {
// Draw shadow, outline and text. Note: Do not merge this into the single loop iteration, to prevent overlaps. // Draw shadow, outline and text. Note: Do not merge this into the single loop iteration, to prevent overlaps.
int processed_glyphs_step = 0; int processed_glyphs_step = 0;
for (int step = DRAW_STEP_SHADOW; step < DRAW_STEP_MAX; step++) { for (int step = DRAW_STEP_SHADOW_OUTLINE; step < DRAW_STEP_MAX; step++) {
if (step == DRAW_STEP_SHADOW_OUTLINE && (font_shadow_color.a == 0 || shadow_outline_size <= 0)) {
continue;
}
if (step == DRAW_STEP_SHADOW && (font_shadow_color.a == 0)) { if (step == DRAW_STEP_SHADOW && (font_shadow_color.a == 0)) {
continue; continue;
} }
@ -784,8 +788,10 @@ void Label::_notification(int p_what) {
for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) { for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end + para.start > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_step >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_step < total_glyphs - visible_glyphs)); bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end + para.start > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_step >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_step < total_glyphs - visible_glyphs));
if (!skip) { if (!skip) {
if (step == DRAW_STEP_SHADOW) { if (step == DRAW_STEP_SHADOW_OUTLINE) {
draw_glyph_shadow(ellipsis_glyphs[gl_idx], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs); draw_glyph_shadow_outline(ellipsis_glyphs[gl_idx], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs);
} else if (step == DRAW_STEP_SHADOW) {
draw_glyph_shadow(ellipsis_glyphs[gl_idx], ci, font_shadow_color, offset_step, shadow_ofs);
} else if (step == DRAW_STEP_OUTLINE) { } else if (step == DRAW_STEP_OUTLINE) {
draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_outline_color, outline_size, offset_step); draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_outline_color, outline_size, offset_step);
} else if (step == DRAW_STEP_TEXT) { } else if (step == DRAW_STEP_TEXT) {
@ -814,8 +820,10 @@ void Label::_notification(int p_what) {
for (int k = 0; k < glyphs[j].repeat; k++) { for (int k = 0; k < glyphs[j].repeat; k++) {
bool skip = (trim_chars && glyphs[j].end + para.start > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_step >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_step < total_glyphs - visible_glyphs)); bool skip = (trim_chars && glyphs[j].end + para.start > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_step >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_step < total_glyphs - visible_glyphs));
if (!skip) { if (!skip) {
if (step == DRAW_STEP_SHADOW) { if (step == DRAW_STEP_SHADOW_OUTLINE) {
draw_glyph_shadow(glyphs[j], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs); draw_glyph_shadow_outline(glyphs[j], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs);
} else if (step == DRAW_STEP_SHADOW) {
draw_glyph_shadow(glyphs[j], ci, font_shadow_color, offset_step, shadow_ofs);
} else if (step == DRAW_STEP_OUTLINE) { } else if (step == DRAW_STEP_OUTLINE) {
draw_glyph_outline(glyphs[j], ci, font_outline_color, outline_size, offset_step); draw_glyph_outline(glyphs[j], ci, font_outline_color, outline_size, offset_step);
} else if (step == DRAW_STEP_TEXT) { } else if (step == DRAW_STEP_TEXT) {
@ -832,8 +840,10 @@ void Label::_notification(int p_what) {
for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) { for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end + para.start > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_step >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_step < total_glyphs - visible_glyphs)); bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end + para.start > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_step >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_step < total_glyphs - visible_glyphs));
if (!skip) { if (!skip) {
if (step == DRAW_STEP_SHADOW) { if (step == DRAW_STEP_SHADOW_OUTLINE) {
draw_glyph_shadow(ellipsis_glyphs[gl_idx], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs); draw_glyph_shadow_outline(ellipsis_glyphs[gl_idx], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs);
} else if (step == DRAW_STEP_SHADOW) {
draw_glyph_shadow(ellipsis_glyphs[gl_idx], ci, font_shadow_color, offset_step, shadow_ofs);
} else if (step == DRAW_STEP_OUTLINE) { } else if (step == DRAW_STEP_OUTLINE) {
draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_outline_color, outline_size, offset_step); draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_outline_color, outline_size, offset_step);
} else if (step == DRAW_STEP_TEXT) { } else if (step == DRAW_STEP_TEXT) {

View File

@ -39,6 +39,7 @@ class Label : public Control {
private: private:
enum LabelDrawStep { enum LabelDrawStep {
DRAW_STEP_SHADOW_OUTLINE,
DRAW_STEP_SHADOW, DRAW_STEP_SHADOW,
DRAW_STEP_OUTLINE, DRAW_STEP_OUTLINE,
DRAW_STEP_TEXT, DRAW_STEP_TEXT,

View File

@ -1051,17 +1051,18 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} }
} }
Color font_color = (step == DRAW_STEP_SHADOW || step == DRAW_STEP_OUTLINE || step == DRAW_STEP_TEXT) ? _find_color(it, p_base_color) : Color(); Color font_color = (step == DRAW_STEP_SHADOW_OUTLINE || step == DRAW_STEP_SHADOW || step == DRAW_STEP_OUTLINE || step == DRAW_STEP_TEXT) ? _find_color(it, p_base_color) : Color();
int outline_size = (step == DRAW_STEP_OUTLINE) ? _find_outline_size(it, p_outline_size) : 0; int outline_size = (step == DRAW_STEP_OUTLINE) ? _find_outline_size(it, p_outline_size) : 0;
Color font_outline_color = (step == DRAW_STEP_OUTLINE) ? _find_outline_color(it, p_outline_color) : Color(); Color font_outline_color = (step == DRAW_STEP_OUTLINE) ? _find_outline_color(it, p_outline_color) : Color();
Color font_shadow_color = p_font_shadow_color; Color font_shadow_color = p_font_shadow_color;
bool txt_visible = false; bool txt_visible = (font_color.a != 0);
if (step == DRAW_STEP_OUTLINE) { if (step == DRAW_STEP_OUTLINE && (outline_size <= 0 || font_outline_color.a == 0)) {
txt_visible = (font_outline_color.a != 0 && outline_size > 0); continue;
} else if (step == DRAW_STEP_SHADOW) { } else if (step == DRAW_STEP_SHADOW_OUTLINE && (font_shadow_color.a == 0 || p_shadow_outline_size <= 0)) {
txt_visible = (font_shadow_color.a != 0); continue;
} else if (step == DRAW_STEP_SHADOW && (font_shadow_color.a == 0)) {
continue;
} else if (step == DRAW_STEP_TEXT) { } else if (step == DRAW_STEP_TEXT) {
txt_visible = (font_color.a != 0);
bool has_ul = _find_underline(it); bool has_ul = _find_underline(it);
if (!has_ul && underline_meta) { if (!has_ul && underline_meta) {
ItemMeta *meta = nullptr; ItemMeta *meta = nullptr;
@ -1146,7 +1147,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), st_color, underline_width); draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), st_color, underline_width);
} }
} }
if (step == DRAW_STEP_SHADOW || step == DRAW_STEP_OUTLINE || step == DRAW_STEP_TEXT) { if (step == DRAW_STEP_SHADOW_OUTLINE || step == DRAW_STEP_SHADOW || step == DRAW_STEP_OUTLINE || step == DRAW_STEP_TEXT) {
ItemFade *fade = nullptr; ItemFade *fade = nullptr;
Item *fade_item = it; Item *fade_item = it;
while (fade_item) { while (fade_item) {
@ -1209,7 +1210,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
charfx->range = Vector2i(l.char_offset + glyphs[i].start, l.char_offset + glyphs[i].end); charfx->range = Vector2i(l.char_offset + glyphs[i].start, l.char_offset + glyphs[i].end);
charfx->relative_index = l.char_offset + glyphs[i].start - item_fx->char_ofs; charfx->relative_index = l.char_offset + glyphs[i].start - item_fx->char_ofs;
charfx->visibility = txt_visible; charfx->visibility = txt_visible;
charfx->outline = (step == DRAW_STEP_SHADOW) || (step == DRAW_STEP_OUTLINE); charfx->outline = (step == DRAW_STEP_SHADOW_OUTLINE) || (step == DRAW_STEP_SHADOW) || (step == DRAW_STEP_OUTLINE);
charfx->font = frid; charfx->font = frid;
charfx->glyph_index = gl; charfx->glyph_index = gl;
charfx->glyph_flags = gl_fl; charfx->glyph_flags = gl_fl;
@ -1284,7 +1285,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
char_reverse_xform.set_origin(-char_off); char_reverse_xform.set_origin(-char_off);
Transform2D char_final_xform = char_xform * char_reverse_xform; Transform2D char_final_xform = char_xform * char_reverse_xform;
draw_set_transform_matrix(char_final_xform); draw_set_transform_matrix(char_final_xform);
} else if (step == DRAW_STEP_SHADOW) { } else if (step == DRAW_STEP_SHADOW_OUTLINE || step == DRAW_STEP_SHADOW) {
font_color = font_shadow_color * Color(1, 1, 1, font_color.a); font_color = font_shadow_color * Color(1, 1, 1, font_color.a);
char_reverse_xform.set_origin(-char_off - p_shadow_ofs); char_reverse_xform.set_origin(-char_off - p_shadow_ofs);
@ -1311,12 +1312,11 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) && ((glyphs[i].flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) != TextServer::GRAPHEME_IS_EMBEDDED_OBJECT)) { } else if (((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) && ((glyphs[i].flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) != TextServer::GRAPHEME_IS_EMBEDDED_OBJECT)) {
TS->draw_hex_code_box(ci, glyphs[i].font_size, fx_offset + char_off, gl, font_color); TS->draw_hex_code_box(ci, glyphs[i].font_size, fx_offset + char_off, gl, font_color);
} }
} else if (step == DRAW_STEP_SHADOW_OUTLINE && frid != RID()) {
TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, p_shadow_outline_size, fx_offset + char_off + p_shadow_ofs, gl, font_color);
} else if (step == DRAW_STEP_SHADOW && frid != RID()) { } else if (step == DRAW_STEP_SHADOW && frid != RID()) {
TS->font_draw_glyph(frid, ci, glyphs[i].font_size, fx_offset + char_off + p_shadow_ofs, gl, font_color); TS->font_draw_glyph(frid, ci, glyphs[i].font_size, fx_offset + char_off + p_shadow_ofs, gl, font_color);
if (p_shadow_outline_size > 0) { } else if (step == DRAW_STEP_OUTLINE && frid != RID()) {
TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, p_shadow_outline_size, fx_offset + char_off + p_shadow_ofs, gl, font_color);
}
} else if (step == DRAW_STEP_OUTLINE && frid != RID() && outline_size > 0) {
TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, outline_size, fx_offset + char_off, gl, font_color); TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, outline_size, fx_offset + char_off, gl, font_color);
} }
} }

View File

@ -45,6 +45,7 @@ class RichTextLabel : public Control {
enum RTLDrawStep { enum RTLDrawStep {
DRAW_STEP_BACKGROUND, DRAW_STEP_BACKGROUND,
DRAW_STEP_SHADOW_OUTLINE,
DRAW_STEP_SHADOW, DRAW_STEP_SHADOW,
DRAW_STEP_OUTLINE, DRAW_STEP_OUTLINE,
DRAW_STEP_TEXT, DRAW_STEP_TEXT,