From 8814578ceb3470e1c1e5b2f6d5a62274f8b9dc48 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Sat, 15 Jul 2023 13:52:10 +0100 Subject: [PATCH] MultiRect - Fix flushing in TextEdit The FontDrawer used in TextEdit was previously not being flushed before drawing auto-completion boxes. This was causing rendering artifacts. This PR also increases the backward compatibility of the MultiRect OFF mode, by forcing a flush after each character. --- scene/gui/text_edit.cpp | 5 ++++ scene/resources/font.cpp | 9 ++++-- scene/resources/font.h | 1 + .../visual/visual_server_canvas_helper.cpp | 30 +++++++------------ servers/visual/visual_server_canvas_helper.h | 9 +++--- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index c6aae9c4cba..0955070fa85 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1653,6 +1653,11 @@ void TextEdit::_notification(int p_what) { line_drawing_cache[line] = cache_entry; } + // Flush out any text in the drawer BEFORE + // drawing the completion box, as we want the completion + // box to overwrite the underlying text. + drawer.flush(); + bool completion_below = false; if (completion_active && is_cursor_visible && completion_options.size() > 0) { // Completion panel diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 4d2cf7f660c..9118444cd7f 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -542,15 +542,18 @@ FontDrawer::FontDrawer(const Ref &p_font, const Color &p_outline_color) : font(p_font), outline_color(p_outline_color) { has_outline = p_font->has_outline(); - multirect.begin(); } -FontDrawer::~FontDrawer() { +void FontDrawer::flush() { for (int i = 0; i < pending_draws.size(); ++i) { const PendingDraw &draw = pending_draws[i]; font->draw_char_ex(draw.canvas_item, draw.pos, draw.chr, draw.next, draw.modulate, false, &multirect); } - multirect.end(); + multirect.flush(); +} + +FontDrawer::~FontDrawer() { + flush(); } void BitmapFont::set_fallback(const Ref &p_fallback) { diff --git a/scene/resources/font.h b/scene/resources/font.h index 0a6a696607d..5d8f8b08bfd 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -110,6 +110,7 @@ public: return font->draw_char_ex(p_canvas_item, p_pos, p_char, p_next, has_outline ? outline_color : p_modulate, has_outline, &multirect); } MultiRect &get_multirect() { return multirect; } + void flush(); ~FontDrawer(); }; diff --git a/servers/visual/visual_server_canvas_helper.cpp b/servers/visual/visual_server_canvas_helper.cpp index dda6eabb84b..10a55f19f04 100644 --- a/servers/visual/visual_server_canvas_helper.cpp +++ b/servers/visual/visual_server_canvas_helper.cpp @@ -38,22 +38,6 @@ Mutex VisualServerCanvasHelper::_tilemap_mutex; bool VisualServerCanvasHelper::_multirect_enabled = true; -MultiRect::MultiRect() { - begin(); -} -MultiRect::~MultiRect() { - end(); -} - -void MultiRect::begin() { - DEV_CHECK_ONCE(!rects.size()); - rects.clear(); - sources.clear(); - - state.flags = 0; - state_set = false; -} - void MultiRect::add_rect(RID p_canvas_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, RID p_normal_map, bool p_clip_uv) { bool new_common_data = true; @@ -101,7 +85,7 @@ void MultiRect::add_rect(RID p_canvas_item, const Rect2 &p_rect, RID p_texture, if (!is_empty()) { if ((state != s) || (rects.size() >= MAX_RECTS)) { - end(); + flush(); } else { new_common_data = false; } @@ -113,6 +97,11 @@ void MultiRect::add_rect(RID p_canvas_item, const Rect2 &p_rect, RID p_texture, rects.push_back(rect); sources.push_back(source); + + // Legacy path + if (!VisualServerCanvasHelper::_multirect_enabled) { + flush(); + } } void MultiRect::begin(const VisualServerCanvasHelper::State &p_state) { @@ -184,7 +173,7 @@ bool MultiRect::add(const Rect2 &p_rect, const Rect2 &p_src_rect, bool p_commit_ return true; } -void MultiRect::end() { +void MultiRect::flush() { if (!is_empty()) { if (VisualServerCanvasHelper::_multirect_enabled) { VisualServer::get_singleton()->canvas_item_add_texture_multirect_region(state.item, rects, state.texture, sources, state.modulate, state.flags, state.normal_map); @@ -203,6 +192,9 @@ void MultiRect::end() { sources.clear(); } state_set = false; + + // This may not be necessary (if needing to eek out maximum speed). + state.flags = 0; } void VisualServerCanvasHelper::tilemap_begin() { @@ -272,7 +264,7 @@ void VisualServerCanvasHelper::tilemap_end() { } for (uint32_t n = 0; n < _tilemap_multirects.size(); n++) { - _tilemap_multirects[n].end(); + _tilemap_multirects[n].flush(); } _tilemap_multirects.clear(); diff --git a/servers/visual/visual_server_canvas_helper.h b/servers/visual/visual_server_canvas_helper.h index 0a414e2a5f1..b5a0659af4b 100644 --- a/servers/visual/visual_server_canvas_helper.h +++ b/servers/visual/visual_server_canvas_helper.h @@ -97,7 +97,6 @@ private: public: // Simple API - void begin(); void add_rect(RID p_canvas_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), bool p_clip_uv = false); // Efficient API @@ -105,10 +104,12 @@ public: bool add(const Rect2 &p_rect, const Rect2 &p_src_rect, bool p_commit_on_flip_change = true); bool is_empty() const { return rects.is_empty(); } bool is_full() const { return rects.is_full(); } - void end(); - MultiRect(); - ~MultiRect(); + // Always called in destructor, but can be used explicitly + // for multiple draws, or to time the flush. + void flush(); + + ~MultiRect() { flush(); } }; #endif // VISUAL_SERVER_CANVAS_HELPER_H