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.
This commit is contained in:
lawnjelly 2023-07-15 13:52:10 +01:00
parent ac5d7dc821
commit 8814578ceb
5 changed files with 28 additions and 26 deletions

View File

@ -1653,6 +1653,11 @@ void TextEdit::_notification(int p_what) {
line_drawing_cache[line] = cache_entry; 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; bool completion_below = false;
if (completion_active && is_cursor_visible && completion_options.size() > 0) { if (completion_active && is_cursor_visible && completion_options.size() > 0) {
// Completion panel // Completion panel

View File

@ -542,15 +542,18 @@ FontDrawer::FontDrawer(const Ref<Font> &p_font, const Color &p_outline_color) :
font(p_font), font(p_font),
outline_color(p_outline_color) { outline_color(p_outline_color) {
has_outline = p_font->has_outline(); has_outline = p_font->has_outline();
multirect.begin();
} }
FontDrawer::~FontDrawer() { void FontDrawer::flush() {
for (int i = 0; i < pending_draws.size(); ++i) { for (int i = 0; i < pending_draws.size(); ++i) {
const PendingDraw &draw = pending_draws[i]; const PendingDraw &draw = pending_draws[i];
font->draw_char_ex(draw.canvas_item, draw.pos, draw.chr, draw.next, draw.modulate, false, &multirect); 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<BitmapFont> &p_fallback) { void BitmapFont::set_fallback(const Ref<BitmapFont> &p_fallback) {

View File

@ -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); 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; } MultiRect &get_multirect() { return multirect; }
void flush();
~FontDrawer(); ~FontDrawer();
}; };

View File

@ -38,22 +38,6 @@ Mutex VisualServerCanvasHelper::_tilemap_mutex;
bool VisualServerCanvasHelper::_multirect_enabled = true; 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) { 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; 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 (!is_empty()) {
if ((state != s) || if ((state != s) ||
(rects.size() >= MAX_RECTS)) { (rects.size() >= MAX_RECTS)) {
end(); flush();
} else { } else {
new_common_data = false; 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); rects.push_back(rect);
sources.push_back(source); sources.push_back(source);
// Legacy path
if (!VisualServerCanvasHelper::_multirect_enabled) {
flush();
}
} }
void MultiRect::begin(const VisualServerCanvasHelper::State &p_state) { 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; return true;
} }
void MultiRect::end() { void MultiRect::flush() {
if (!is_empty()) { if (!is_empty()) {
if (VisualServerCanvasHelper::_multirect_enabled) { 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); 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(); sources.clear();
} }
state_set = false; state_set = false;
// This may not be necessary (if needing to eek out maximum speed).
state.flags = 0;
} }
void VisualServerCanvasHelper::tilemap_begin() { void VisualServerCanvasHelper::tilemap_begin() {
@ -272,7 +264,7 @@ void VisualServerCanvasHelper::tilemap_end() {
} }
for (uint32_t n = 0; n < _tilemap_multirects.size(); n++) { for (uint32_t n = 0; n < _tilemap_multirects.size(); n++) {
_tilemap_multirects[n].end(); _tilemap_multirects[n].flush();
} }
_tilemap_multirects.clear(); _tilemap_multirects.clear();

View File

@ -97,7 +97,6 @@ private:
public: public:
// Simple API // 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); 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 // 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 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_empty() const { return rects.is_empty(); }
bool is_full() const { return rects.is_full(); } bool is_full() const { return rects.is_full(); }
void end();
MultiRect(); // Always called in destructor, but can be used explicitly
~MultiRect(); // for multiple draws, or to time the flush.
void flush();
~MultiRect() { flush(); }
}; };
#endif // VISUAL_SERVER_CANVAS_HELPER_H #endif // VISUAL_SERVER_CANVAS_HELPER_H