From eee95aff046d46341c0064a01dd6813448efae41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Botero?= <0xafbf@gmail.com> Date: Sat, 3 Jun 2023 09:42:26 -0500 Subject: [PATCH] Add transform support to CharFXTransform Use absolute transforms for CharFX fix formatting --- doc/classes/CharFXTransform.xml | 3 ++ scene/gui/rich_text_effect.cpp | 4 +++ scene/gui/rich_text_effect.h | 4 +++ scene/gui/rich_text_label.cpp | 58 +++++++++++++++++++++++++++++---- scene/gui/rich_text_label.h | 16 +++------ 5 files changed, 67 insertions(+), 18 deletions(-) diff --git a/doc/classes/CharFXTransform.xml b/doc/classes/CharFXTransform.xml index ad41eceff478..ce74227298cc 100644 --- a/doc/classes/CharFXTransform.xml +++ b/doc/classes/CharFXTransform.xml @@ -49,6 +49,9 @@ The character offset of the glyph, relative to the current [RichTextEffect] custom block. Setting this property won't affect drawing. + + The current transform of the current glyph. It can be overridden (for example, by driving the position and rotation from a curve). You can also alter the existing value to apply transforms on top of other effects. + If [code]true[/code], the character will be drawn. If [code]false[/code], the character will be hidden. Characters around hidden characters will reflow to take the space of hidden characters. If this is not desired, set their [member color] to [code]Color(1, 1, 1, 0)[/code] instead. diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp index 6734f34579a9..e96832177774 100644 --- a/scene/gui/rich_text_effect.cpp +++ b/scene/gui/rich_text_effect.cpp @@ -64,6 +64,9 @@ RichTextEffect::RichTextEffect() { } void CharFXTransform::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_transform"), &CharFXTransform::get_transform); + ClassDB::bind_method(D_METHOD("set_transform", "transform"), &CharFXTransform::set_transform); + ClassDB::bind_method(D_METHOD("get_range"), &CharFXTransform::get_range); ClassDB::bind_method(D_METHOD("set_range", "range"), &CharFXTransform::set_range); @@ -100,6 +103,7 @@ void CharFXTransform::_bind_methods() { ClassDB::bind_method(D_METHOD("get_font"), &CharFXTransform::get_font); ClassDB::bind_method(D_METHOD("set_font", "font"), &CharFXTransform::set_font); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "range"), "set_range", "get_range"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "elapsed_time"), "set_elapsed_time", "get_elapsed_time"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visibility", "is_visible"); diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h index 0799abaffce7..39e35b3a3c91 100644 --- a/scene/gui/rich_text_effect.h +++ b/scene/gui/rich_text_effect.h @@ -42,6 +42,7 @@ protected: static void _bind_methods(); public: + Transform2D transform; Vector2i range; bool visibility = true; bool outline = false; @@ -58,6 +59,9 @@ public: CharFXTransform(); ~CharFXTransform(); + void set_transform(const Transform2D &p_transform) { transform = p_transform; } + const Transform2D &get_transform() { return transform; } + Vector2i get_range() { return range; } void set_range(const Vector2i &p_range) { range = p_range; } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 1e7e376fc8f6..53f2ca7d2233 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -36,6 +36,7 @@ #include "core/os/os.h" #include "core/string/translation.h" #include "scene/gui/label.h" +#include "scene/gui/rich_text_effect.h" #include "scene/resources/atlas_texture.h" #include "scene/scene_string_names.h" #include "servers/display_server.h" @@ -45,6 +46,18 @@ #include "modules/regex/regex.h" #endif +RichTextLabel::ItemCustomFX::ItemCustomFX() { + type = ITEM_CUSTOMFX; + char_fx_transform.instantiate(); +} + +RichTextLabel::ItemCustomFX::~ItemCustomFX() { + _clear_children(); + + char_fx_transform.unref(); + custom_effect.unref(); +} + RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) const { if (p_free) { if (p_item->subitems.size()) { @@ -1030,6 +1043,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } bool txt_visible = (font_outline_color.a != 0) || (font_shadow_color.a != 0); + Transform2D char_xform; + char_xform.set_origin(gloff + p_ofs); for (int j = 0; j < fx_stack.size(); j++) { ItemFX *item_fx = fx_stack[j]; @@ -1053,10 +1068,12 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o charfx->glyph_count = gl_cn; charfx->offset = fx_offset; charfx->color = font_color; + charfx->transform = char_xform; bool effect_status = custom_effect->_process_effect_impl(charfx); custom_fx_ok = effect_status; + char_xform = charfx->transform; fx_offset += charfx->offset; font_color = charfx->color; frid = charfx->font; @@ -1110,6 +1127,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o fx_offset = fx_offset.round(); } + Vector2i char_off = char_xform.get_origin(); + // Draw glyph outlines. const Color modulated_outline_color = font_outline_color * Color(1, 1, 1, font_color.a); const Color modulated_shadow_color = font_shadow_color * Color(1, 1, 1, font_color.a); @@ -1118,13 +1137,24 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o bool skip = (trim_chars && l.char_offset + glyphs[i].end > visible_characters) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs)); if (!skip && frid != RID()) { if (modulated_shadow_color.a > 0) { - TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + gloff + p_shadow_ofs, gl, modulated_shadow_color); - } - if (modulated_shadow_color.a > 0 && p_shadow_outline_size > 0) { - TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, p_shadow_outline_size, p_ofs + fx_offset + gloff + p_shadow_ofs, gl, modulated_shadow_color); + Transform2D char_reverse_xform; + char_reverse_xform.set_origin(-char_off - p_shadow_ofs); + Transform2D char_final_xform = char_xform * char_reverse_xform; + char_final_xform.columns[2] += p_shadow_ofs; + draw_set_transform_matrix(char_final_xform); + + TS->font_draw_glyph(frid, ci, glyphs[i].font_size, fx_offset + char_off + p_shadow_ofs, gl, modulated_shadow_color); + if (p_shadow_outline_size > 0) { + TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, p_shadow_outline_size, fx_offset + char_off + p_shadow_ofs, gl, modulated_shadow_color); + } } if (modulated_outline_color.a != 0.0 && size > 0) { - TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff, gl, modulated_outline_color); + Transform2D char_reverse_xform; + char_reverse_xform.set_origin(-char_off); + Transform2D char_final_xform = char_xform * char_reverse_xform; + draw_set_transform_matrix(char_final_xform); + + TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, fx_offset + char_off, gl, modulated_outline_color); } } processed_glyphs_ol++; @@ -1132,6 +1162,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o gloff.x += glyphs[i].advance; } } + draw_set_transform_matrix(Transform2D()); Vector2 fbg_line_off = off + p_ofs; // Draw background color box @@ -1258,6 +1289,9 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o bool txt_visible = (font_color.a != 0); + Transform2D char_xform; + char_xform.set_origin(p_ofs + off); + for (int j = 0; j < fx_stack.size(); j++) { ItemFX *item_fx = fx_stack[j]; bool cn = cprev_cluster || (cprev_conn && item_fx->connected); @@ -1280,10 +1314,12 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o charfx->glyph_count = gl_cn; charfx->offset = fx_offset; charfx->color = font_color; + charfx->transform = char_xform; bool effect_status = custom_effect->_process_effect_impl(charfx); custom_fx_ok = effect_status; + char_xform = charfx->transform; fx_offset += charfx->offset; font_color = charfx->color; frid = charfx->font; @@ -1337,6 +1373,12 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o fx_offset = fx_offset.round(); } + Vector2i char_off = char_xform.get_origin(); + Transform2D char_reverse_xform; + char_reverse_xform.set_origin(-char_off); + char_xform = char_xform * char_reverse_xform; + draw_set_transform_matrix(char_xform); + if (selected && use_selected_font_color) { font_color = theme_cache.font_selected_color; } @@ -1347,9 +1389,9 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o if (txt_visible) { if (!skip) { if (frid != RID()) { - TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, font_color); + TS->font_draw_glyph(frid, ci, glyphs[i].font_size, fx_offset + char_off, gl, font_color); } 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, p_ofs + fx_offset + off, gl, font_color); + TS->draw_hex_code_box(ci, glyphs[i].font_size, fx_offset + char_off, gl, font_color); } } r_processed_glyphs++; @@ -1377,6 +1419,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } off.x += glyphs[i].advance; } + + draw_set_transform_matrix(Transform2D()); } if (ul_started) { ul_started = false; diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 0d0917a9d8c8..1ea3fe27f2a0 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -33,10 +33,12 @@ #include "core/object/worker_thread_pool.h" #include "scene/gui/popup_menu.h" -#include "scene/gui/rich_text_effect.h" #include "scene/gui/scroll_bar.h" #include "scene/resources/text_paragraph.h" +class CharFXTransform; +class RichTextEffect; + class RichTextLabel : public Control { GDCLASS(RichTextLabel, Control); @@ -367,17 +369,9 @@ private: Ref char_fx_transform; Ref custom_effect; - ItemCustomFX() { - type = ITEM_CUSTOMFX; - char_fx_transform.instantiate(); - } + ItemCustomFX(); - virtual ~ItemCustomFX() { - _clear_children(); - - char_fx_transform.unref(); - custom_effect.unref(); - } + virtual ~ItemCustomFX(); }; struct ItemContext : public Item {