diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 3cf96b01449d..677d46a9cd6f 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -1053,7 +1053,7 @@
- Set a custom draw callback for the gutter at the given index. [param draw_callback] must take the following arguments: A line index [int], a gutter index [int], and an area [Rect2]. This callback only works when the gutter type is [constant GUTTER_TYPE_CUSTOM] (see [method set_gutter_type]).
+ Set a custom draw callback for the gutter at the given index. [param draw_callback] must take the following arguments: A canvas item [RID], a line index [int], a gutter index [int], and an area [Rect2]. This callback only works when the gutter type is [constant GUTTER_TYPE_CUSTOM] (see [method set_gutter_type]).
diff --git a/doc/classes/TextLine.xml b/doc/classes/TextLine.xml
index c52552f71d80..05e93afc443b 100644
--- a/doc/classes/TextLine.xml
+++ b/doc/classes/TextLine.xml
@@ -20,6 +20,19 @@
Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
+
+
+
+
+
+
+
+
+
+
+ Adds draw calls for glyph outlines to the draw list [param list].
+
+
@@ -31,6 +44,18 @@
Adds text span and font to draw it.
+
+
+
+
+
+
+
+
+
+ Adds draw calls for glyphs to the draw list [param list].
+
+
diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml
index 756efa0529f5..01a65a6ed52f 100644
--- a/doc/classes/TextParagraph.xml
+++ b/doc/classes/TextParagraph.xml
@@ -9,6 +9,58 @@
+
+
+
+
+
+
+
+
+
+
+ Adds draw calls for dropcap glyph outlines to the draw list [param list].
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw calls for dropcap glyphs to the draw list [param list].
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw calls for line [param line] glyph outlines to the draw list [param list].
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw calls for line [param line] glyphs to the draw list [param list].
+
+
@@ -20,6 +72,20 @@
Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw calls for paragraph glyph outlines to the draw list [param list].
+
+
@@ -31,6 +97,19 @@
Adds text span and font to draw it.
+
+
+
+
+
+
+
+
+
+
+ Adds draw calls for paragraph glyphs to the draw list [param list].
+
+
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 6ec7bf77ffca..cdd2dfedcc25 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -19,6 +19,12 @@
+
+
+
+ Creates a new, empty draw list resource.
+
+
@@ -53,6 +59,122 @@
Draws box displaying character hexadecimal code. Used for replacing missing characters.
+
+
+
+
+
+
+
+ Adds custom draw call to a draw list [param list]. [param callback] is called with one argument, [RID] of canvas item to draw it to.
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for box displaying character hexadecimal code to a draw list [param list].
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for a line to a draw list [param list].
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for a rectangle to a draw list [param list].
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for a texture to a draw list [param list].
+
+
+
+
+
+
+
+
+ Processes all draw calls in the draw list [param list] to the canvas item [param ci]. If [param free] is [code]true[/code], the draw list is also deleted.
+
+
+
+
+
+
+
+ Reserves additional space in the draw list [param list] for a [param count] draw calls.
+
+
+
+
+
+
+ Sorts draw calls in the draw list using to layer index and texture id.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for a single glyph outline to a draw list [param list].
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for a single glyph to a draw list [param list].
+
+
@@ -1363,6 +1485,22 @@
Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw calls for text buffer glyph outlines to the draw list [param list].
+
+
@@ -1376,6 +1514,21 @@
Adds text span and font to draw it to the text buffer.
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw calls for text buffer glyphs to the draw list [param list].
+
+
@@ -2216,6 +2369,33 @@
Maximum font size which will use "one quarter of the pixel" subpixel positioning in [constant SUBPIXEL_POSITIONING_AUTO] mode.
+
+ Draw call that does nothing. This is used to initialize new [code]TextServer::DrawCallType[/code] native structures.
+
+
+ Draw call for a normal glyph or glyph outline.
+
+
+ Draw call for a MSDF glyph or glyph outline.
+
+
+ Draw call for a LCD anti-aliased glyph or glyph outline using.
+
+
+ Draw call for a box displaying character hexadecimal code.
+
+
+ Draw call for a line.
+
+
+ Draw call for a rectangle.
+
+
+ Draw call for a texture.
+
+
+ Draw call using a custom draw callback.
+
TextServer supports simple text layouts.
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index 5ceb3a194838..8c13aa54dd6d 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -15,6 +15,12 @@
This method is called before text server is unregistered.
+
+
+
+ Creates a new, empty draw list resource.
+
+
@@ -48,6 +54,122 @@
Draws box displaying character hexadecimal code.
+
+
+
+
+
+
+
+ Adds custom draw call to the draw list [param list]. [param callback] is called with one argument, [RID] of canvas item to draw it to.
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for box displaying character hexadecimal code to a draw list [param list].
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for a line to a draw list [param list].
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for a rectangle to a draw list [param list].
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for a texture to a draw list [param list].
+
+
+
+
+
+
+
+
+ Processes all draw calls in the draw list [param list] to the canvas item [param ci]. If [param free] is [code]true[/code], the draw list is also deleted.
+
+
+
+
+
+
+
+ Reserves additional space in the draw list [param list] for a [param count] draw calls.
+
+
+
+
+
+
+ Sorts draw calls in the draw list using to layer index and texture id.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for a single glyph outline to a draw list [param list].
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw call for a single glyph to a draw list [param list].
+
+
@@ -1335,6 +1457,22 @@
Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw calls for text buffer glyph outlines to the draw list [param list].
+
+
@@ -1348,6 +1486,21 @@
Adds text span and font to draw it to the text buffer.
+
+
+
+
+
+
+
+
+
+
+
+
+ Adds draw calls for text buffer glyphs to the draw list [param list].
+
+
diff --git a/editor/script/script_text_editor.cpp b/editor/script/script_text_editor.cpp
index 48a49ebaa68d..ad0e3426a3bb 100644
--- a/editor/script/script_text_editor.cpp
+++ b/editor/script/script_text_editor.cpp
@@ -526,16 +526,15 @@ Array ScriptTextEditor::_inline_object_parse(const String &p_text) {
return result;
}
-void ScriptTextEditor::_inline_object_draw(const Dictionary &p_info, const Rect2 &p_rect) {
+void ScriptTextEditor::_inline_object_draw(RID p_ci, const Dictionary &p_info, const Rect2 &p_rect) {
if (_is_valid_color_info(p_info)) {
Rect2 col_rect = p_rect.grow(-4);
if (color_alpha_texture.is_null()) {
color_alpha_texture = inline_color_picker->get_theme_icon("sample_bg", "ColorPicker");
}
- RID text_ci = code_editor->get_text_editor()->get_text_canvas_item();
- RS::get_singleton()->canvas_item_add_rect(text_ci, p_rect.grow(-3), Color(1, 1, 1));
- color_alpha_texture->draw_rect(text_ci, col_rect);
- RS::get_singleton()->canvas_item_add_rect(text_ci, col_rect, Color(p_info["color"]));
+ RS::get_singleton()->canvas_item_add_rect(p_ci, p_rect.grow(-3), Color(1, 1, 1));
+ color_alpha_texture->draw_rect(p_ci, col_rect);
+ RS::get_singleton()->canvas_item_add_rect(p_ci, col_rect, Color(p_info["color"]));
}
}
diff --git a/editor/script/script_text_editor.h b/editor/script/script_text_editor.h
index 24b73d6deb69..bf3f2e3b2357 100644
--- a/editor/script/script_text_editor.h
+++ b/editor/script/script_text_editor.h
@@ -218,7 +218,7 @@ class ScriptTextEditor : public ScriptEditorBase {
bool _is_valid_color_info(const Dictionary &p_info);
Array _inline_object_parse(const String &p_text);
- void _inline_object_draw(const Dictionary &p_info, const Rect2 &p_rect);
+ void _inline_object_draw(RID p_ci, const Dictionary &p_info, const Rect2 &p_rect);
void _inline_object_handle_click(const Dictionary &p_info, const Rect2 &p_rect);
String _picker_color_stringify(const Color &p_color, COLOR_MODE p_mode);
void _picker_color_changed(const Color &p_color);
diff --git a/misc/extension_api_validation/4.5-stable.expected b/misc/extension_api_validation/4.5-stable.expected
index 3cb31355e7fd..16ceeae84fc2 100644
--- a/misc/extension_api_validation/4.5-stable.expected
+++ b/misc/extension_api_validation/4.5-stable.expected
@@ -99,3 +99,11 @@ Validate extension JSON: Error: Field 'builtin_classes/PackedVector3Array/method
Validate extension JSON: Error: Field 'builtin_classes/PackedVector4Array/methods/duplicate': is_const changed value in new API, from false to true.
Duplicate method made const. Compatibility methods registered.
+
+
+GH-108369
+---------
+Validate extension JSON: Error: Field 'native_structures/CaretInfo': format changed value in new API, from "Rect2 leading_caret;Rect2 trailing_caret;TextServer::Direction leading_direction;TextServer::Direction trailing_direction" to "Rect2 leading_caret;Rect2 trailing_caret;TextServer::Direction leading_direction = TextServer::DIRECTION_AUTO;TextServer::Direction trailing_direction = TextServer::DIRECTION_AUTO".
+Validate extension JSON: Error: Field 'native_structures/Glyph': format changed value in new API, from "int start = -1;int end = -1;uint8_t count = 0;uint8_t repeat = 1;uint16_t flags = 0;float x_off = 0.f;float y_off = 0.f;float advance = 0.f;RID font_rid;int font_size = 0;int32_t index = 0" to "int start = -1;int end = -1;uint8_t count = 0;uint8_t repeat = 1;uint16_t flags = 0;float x_off = 0.f;float y_off = 0.f;float advance = 0.f;RID font_rid;int font_size = 0;int32_t index = 0;int span_index = -1".
+
+Updated existing native structures to match actual definitions.
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 4c211dc64cf7..788be590ead6 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -431,6 +431,10 @@ void TextServerAdvanced::_free_rid(const RID &p_rid) {
shaped_owner.free(p_rid);
}
memdelete(sd);
+ } else if (list_owner.owns(p_rid)) {
+ DrawList *dc = list_owner.get_or_null(p_rid);
+ list_owner.free(p_rid);
+ memdelete(dc);
}
}
@@ -3928,11 +3932,18 @@ void TextServerAdvanced::_font_render_glyph(const RID &p_font_rid, const Vector2
#endif
}
-void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+void TextServerAdvanced::_font_add_glyph_to_draw_list(const RID &p_font, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+ DrawList *list = list_owner.get_or_null(p_list);
+ ERR_FAIL_NULL(list);
+
+ _imp_font_add_glyph_to_draw_list(p_font, p_layer, list, p_transform, p_size, p_pos, p_index, p_color, p_oversampling);
+}
+
+void TextServerAdvanced::_imp_font_add_glyph_to_draw_list(const RID &p_font, int64_t p_layer, TextServerAdvanced::DrawList *p_list, const Transform2D &p_transform, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
if (p_index == 0) {
return; // Non visual character, skip.
}
- FontAdvanced *fd = _get_font_data(p_font_rid);
+ FontAdvanced *fd = _get_font_data(p_font);
ERR_FAIL_NULL(fd);
MutexLock lock(fd->mutex);
@@ -4031,10 +4042,19 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
Point2 cpos = p_pos;
cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;
Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;
- RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
+ GlyphDrawCall ret;
+ ret.layer = p_layer;
+ ret.texture = texture;
+ ret.dst_rect = Rect2(cpos, csize);
+ ret.src_rect = fgl.uv_rect;
+ ret.modulate = modulate;
+ ret.transform = p_transform;
+ ret.data = Vector3i(0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
+ ret.draw_type = DRAW_CALL_MSDF;
+ p_list->calls.push_back(ret);
} else {
Point2 cpos = p_pos;
- double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;
+ double scale = _font_get_scale(p_font, p_size) / oversampling_factor;
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {
cpos.x = cpos.x + 0.125;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {
@@ -4063,22 +4083,33 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
csize /= oversampling_factor;
}
cpos += gpos;
- if (lcd_aa) {
- RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);
- } else {
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);
- }
+ GlyphDrawCall ret;
+ ret.layer = p_layer;
+ ret.texture = texture;
+ ret.dst_rect = Rect2(cpos, csize);
+ ret.src_rect = fgl.uv_rect;
+ ret.modulate = modulate;
+ ret.transform = p_transform;
+ ret.draw_type = lcd_aa ? DRAW_CALL_LCD : DRAW_CALL_NORMAL;
+ p_list->calls.push_back(ret);
}
}
}
}
}
-void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+void TextServerAdvanced::_font_add_glyph_outline_to_draw_list(const RID &p_font, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+ DrawList *list = list_owner.get_or_null(p_list);
+ ERR_FAIL_NULL(list);
+
+ _imp_font_add_glyph_outline_to_draw_list(p_font, p_layer, list, p_transform, p_size, p_outline_size, p_pos, p_index, p_color, p_oversampling);
+}
+
+void TextServerAdvanced::_imp_font_add_glyph_outline_to_draw_list(const RID &p_font, int64_t p_layer, TextServerAdvanced::DrawList *p_list, const Transform2D &p_transform, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
if (p_index == 0) {
return; // Non visual character, skip.
}
- FontAdvanced *fd = _get_font_data(p_font_rid);
+ FontAdvanced *fd = _get_font_data(p_font);
ERR_FAIL_NULL(fd);
MutexLock lock(fd->mutex);
@@ -4173,10 +4204,19 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R
Point2 cpos = p_pos;
cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;
Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;
- RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
+ GlyphDrawCall ret;
+ ret.layer = p_layer;
+ ret.texture = texture;
+ ret.dst_rect = Rect2(cpos, csize);
+ ret.src_rect = fgl.uv_rect;
+ ret.modulate = modulate;
+ ret.transform = p_transform;
+ ret.data = Vector3i(p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
+ ret.draw_type = DRAW_CALL_MSDF;
+ p_list->calls.push_back(ret);
} else {
Point2 cpos = p_pos;
- double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;
+ double scale = _font_get_scale(p_font, p_size) / oversampling_factor;
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {
cpos.x = cpos.x + 0.125;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {
@@ -4205,17 +4245,37 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R
csize /= oversampling_factor;
}
cpos += gpos;
- if (lcd_aa) {
- RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);
- } else {
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);
- }
+ GlyphDrawCall ret;
+ ret.layer = p_layer;
+ ret.texture = texture;
+ ret.dst_rect = Rect2(cpos, csize);
+ ret.src_rect = fgl.uv_rect;
+ ret.modulate = modulate;
+ ret.transform = p_transform;
+ ret.draw_type = lcd_aa ? DRAW_CALL_LCD : DRAW_CALL_NORMAL;
+ p_list->calls.push_back(ret);
}
}
}
}
}
+void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+ if (RenderingServer::get_singleton() != nullptr) {
+ DrawList dl;
+ _imp_font_add_glyph_to_draw_list(p_font_rid, 0, &dl, Transform2D(), p_size, p_pos, p_index, p_color, p_oversampling);
+ _imp_draw_list_draw(&dl, p_canvas);
+ }
+}
+
+void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+ if (RenderingServer::get_singleton() != nullptr) {
+ DrawList dl;
+ _imp_font_add_glyph_outline_to_draw_list(p_font_rid, 0, &dl, Transform2D(), p_size, p_outline_size, p_pos, p_index, p_color, p_oversampling);
+ _imp_draw_list_draw(&dl, p_canvas);
+ }
+}
+
bool TextServerAdvanced::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const {
FontAdvanced *fd = _get_font_data(p_font_rid);
ERR_FAIL_NULL_V(fd, false);
@@ -4362,6 +4422,187 @@ Dictionary TextServerAdvanced::_font_supported_variation_list(const RID &p_font_
return fd->supported_varaitions;
}
+/*************************************************************************/
+/* Draw list interface */
+/*************************************************************************/
+
+RID TextServerAdvanced::_create_draw_list() {
+ _THREAD_SAFE_METHOD_
+ DrawList *list = memnew(DrawList);
+ return list_owner.make_rid(list);
+}
+
+void TextServerAdvanced::_draw_list_sort(const RID &p_dc) {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+ list->calls.sort_custom();
+}
+
+void TextServerAdvanced::_draw_list_reserve(const RID &p_dc, int64_t p_new_items) {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+ list->calls.reserve(list->calls.size() + p_new_items);
+}
+
+void TextServerAdvanced::_draw_list_add_hexbox(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Vector2 &p_pos, int64_t p_index, int64_t p_size, const Color &p_modulate) const {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+
+ GlyphDrawCall dc;
+ dc.draw_type = TextServer::DRAW_CALL_HEX;
+ dc.layer = p_layer;
+ dc.transform = p_transform;
+ dc.data = Vector2i(p_index, p_size);
+ dc.modulate = p_modulate;
+ dc.dst_rect.position = p_pos;
+
+ list->calls.push_back(dc);
+}
+
+void TextServerAdvanced::_draw_list_add_rect(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Rect2 &p_rect, bool p_filled, const Color &p_modulate) const {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+
+ GlyphDrawCall dc;
+ dc.draw_type = TextServer::DRAW_CALL_RECT;
+ dc.layer = p_layer;
+ dc.transform = p_transform;
+ dc.data = p_filled;
+ dc.modulate = p_modulate;
+ dc.dst_rect = p_rect;
+
+ list->calls.push_back(dc);
+}
+
+void TextServerAdvanced::_draw_list_add_line(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Point2 &p_start, const Point2 &p_end, float p_width, float p_dash, const Color &p_modulate) const {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+
+ GlyphDrawCall dc;
+ dc.draw_type = TextServer::DRAW_CALL_LINE;
+ dc.layer = p_layer;
+ dc.transform = p_transform;
+ dc.data = Vector2(p_dash, p_width);
+ dc.modulate = p_modulate;
+ dc.dst_rect.position = p_start;
+ dc.src_rect.position = p_end;
+
+ list->calls.push_back(dc);
+}
+
+void TextServerAdvanced::_draw_list_add_texture(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, RID p_texture, const Rect2 &p_dst_rect, const Color &p_modulate) const {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+
+ GlyphDrawCall dc;
+ dc.draw_type = TextServer::DRAW_CALL_IMAGE;
+ dc.layer = p_layer;
+ dc.texture = p_texture;
+ dc.transform = p_transform;
+ dc.modulate = p_modulate;
+ dc.dst_rect = p_dst_rect;
+
+ list->calls.push_back(dc);
+}
+
+void TextServerAdvanced::_draw_list_add_custom(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Callable &p_callback) const {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+
+ GlyphDrawCall dc;
+ dc.draw_type = TextServer::DRAW_CALL_CUSTOM;
+ dc.layer = p_layer;
+ dc.data = p_callback;
+ dc.transform = p_transform;
+
+ list->calls.push_back(dc);
+}
+
+void TextServerAdvanced::_imp_draw_list_draw(TextServerAdvanced::DrawList *p_list, const RID &p_ci) const {
+ for (const GlyphDrawCall &dc : p_list->calls) {
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_ci, dc.transform);
+ if (dc.draw_type == TextServer::DRAW_CALL_MSDF) {
+ RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_ci, dc.dst_rect, dc.texture, dc.src_rect, dc.modulate, dc.data.operator Vector3().x, dc.data.operator Vector3().y, dc.data.operator Vector3().z);
+ } else if (dc.draw_type == TextServer::DRAW_CALL_LCD) {
+ RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_ci, dc.dst_rect, dc.texture, dc.src_rect, dc.modulate);
+ } else if (dc.draw_type == TextServer::DRAW_CALL_NORMAL) {
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_ci, dc.dst_rect, dc.texture, dc.src_rect, dc.modulate, false, false);
+ } else if (dc.draw_type == TextServer::DRAW_CALL_CUSTOM) {
+ const Callable &cb = dc.data.operator Callable();
+ if (cb.is_valid()) {
+ if (cb.get_argument_count() == 1) {
+ cb.call(p_ci);
+#ifndef DISABLE_DEPRECATED
+ } else if (cb.get_argument_count() == 0) {
+ cb.call();
+#endif
+ }
+ }
+ } else if (dc.draw_type == TextServer::DRAW_CALL_IMAGE) {
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_ci, dc.dst_rect, dc.texture, false, dc.modulate, false);
+ } else if (dc.draw_type == TextServer::DRAW_CALL_HEX) {
+ TS->draw_hex_code_box(p_ci, dc.data.operator Vector2i().y, dc.dst_rect.position, dc.data.operator Vector2i().x, dc.modulate);
+ } else if (dc.draw_type == TextServer::DRAW_CALL_RECT) {
+ if (dc.data.operator bool()) {
+ RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, dc.dst_rect, dc.modulate, false);
+ } else {
+ Vector points;
+ points.resize(5);
+ points.write[0] = dc.dst_rect.position;
+ points.write[1] = dc.dst_rect.position + Vector2(dc.dst_rect.size.x, 0);
+ points.write[2] = dc.dst_rect.position + dc.dst_rect.size;
+ points.write[3] = dc.dst_rect.position + Vector2(0, dc.dst_rect.size.y);
+ points.write[4] = dc.dst_rect.position;
+
+ Vector colors = { dc.modulate };
+
+ RenderingServer::get_singleton()->canvas_item_add_polyline(p_ci, points, colors, -1.0, false);
+ }
+ } else if (dc.draw_type == TextServer::DRAW_CALL_LINE) {
+ float dash = dc.data.operator Vector2().x;
+ if (dash <= 0.0) {
+ RenderingServer::get_singleton()->canvas_item_add_line(p_ci, dc.dst_rect.position, dc.src_rect.position, dc.modulate, dc.data.operator Vector2().y, false);
+ } else {
+ float length = (dc.src_rect.position - dc.dst_rect.position).length();
+ Vector2 step = dash * (dc.src_rect.position - dc.dst_rect.position).normalized();
+
+ if (length < dash || step == Vector2()) {
+ RenderingServer::get_singleton()->canvas_item_add_line(p_ci, dc.dst_rect.position, dc.src_rect.position, dc.modulate, dc.data.operator Vector2().y, false);
+ return;
+ }
+
+ int steps = Math::ceil(length / dash);
+ if (steps % 2 == 0) {
+ steps--;
+ }
+
+ Point2 off = dc.dst_rect.position + (dc.src_rect.position - dc.dst_rect.position).normalized() * (length - steps * dash) / 2.0;
+
+ Vector points;
+ points.resize(steps + 1);
+ for (int i = 0; i < steps; i += 2) {
+ points.write[i] = (i == 0) ? dc.dst_rect.position : off;
+ points.write[i + 1] = (i == steps - 1) ? dc.src_rect.position : (off + step);
+ off += step * 2;
+ }
+
+ Vector colors = { dc.modulate };
+
+ RenderingServer::get_singleton()->canvas_item_add_multiline(p_ci, points, colors, dc.data.operator Vector2().y, false);
+ }
+ }
+ }
+}
+
+void TextServerAdvanced::_draw_list_draw(const RID &p_dc, const RID &p_ci, bool p_free) {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+ _imp_draw_list_draw(list, p_ci);
+ if (p_free) {
+ _free_rid(p_dc);
+ }
+}
+
/*************************************************************************/
/* Shaped text buffer interface */
/*************************************************************************/
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 49a0e2512cb6..e0fd70dd3c35 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -584,11 +584,16 @@ class TextServerAdvanced : public TextServerExtension {
}
};
+ struct DrawList {
+ LocalVector calls;
+ };
+
// Common data.
mutable RID_PtrOwner font_var_owner;
mutable RID_PtrOwner font_owner;
mutable RID_PtrOwner shaped_owner;
+ mutable RID_PtrOwner list_owner;
_FORCE_INLINE_ FontAdvanced *_get_font_data(const RID &p_font_rid) const {
RID rid = p_font_rid;
@@ -768,6 +773,10 @@ class TextServerAdvanced : public TextServerExtension {
_FORCE_INLINE_ void _add_features(const Dictionary &p_source, Vector &r_ftrs);
+ void _imp_font_add_glyph_to_draw_list(const RID &p_font, int64_t p_layer, TextServerAdvanced::DrawList *p_list, const Transform2D &p_transform, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const;
+ void _imp_font_add_glyph_outline_to_draw_list(const RID &p_font, int64_t p_layer, TextServerAdvanced::DrawList *p_list, const Transform2D &p_transform, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const;
+ void _imp_draw_list_draw(TextServerAdvanced::DrawList *p_list, const RID &p_ci) const;
+
Mutex ft_mutex;
// HarfBuzz bitmap font interface.
@@ -997,6 +1006,9 @@ class TextServerAdvanced : public TextServerExtension {
MODBIND7C(font_draw_glyph, const RID &, const RID &, int64_t, const Vector2 &, int64_t, const Color &, float);
MODBIND8C(font_draw_glyph_outline, const RID &, const RID &, int64_t, int64_t, const Vector2 &, int64_t, const Color &, float);
+ MODBIND9C(font_add_glyph_to_draw_list, const RID &, int64_t, const RID &, const Transform2D &, int64_t, const Vector2 &, int64_t, const Color &, float);
+ MODBIND10C(font_add_glyph_outline_to_draw_list, const RID &, int64_t, const RID &, const Transform2D &, int64_t, int64_t, const Vector2 &, int64_t, const Color &, float);
+
MODBIND2RC(bool, font_is_language_supported, const RID &, const String &);
MODBIND3(font_set_language_support_override, const RID &, const String &, bool);
MODBIND2R(bool, font_get_language_support_override, const RID &, const String &);
@@ -1018,6 +1030,18 @@ class TextServerAdvanced : public TextServerExtension {
MODBIND1(reference_oversampling_level, double);
MODBIND1(unreference_oversampling_level, double);
+ /* Draw list interface */
+
+ MODBIND0R(RID, create_draw_list);
+ MODBIND1(draw_list_sort, const RID &);
+ MODBIND2(draw_list_reserve, const RID &, int64_t);
+ MODBIND7C(draw_list_add_hexbox, const RID &, int64_t, const Transform2D &, const Vector2 &, int64_t, int64_t, const Color &);
+ MODBIND6C(draw_list_add_rect, const RID &, int64_t, const Transform2D &, const Rect2 &, bool, const Color &);
+ MODBIND8C(draw_list_add_line, const RID &, int64_t, const Transform2D &, const Point2 &, const Point2 &, float, float, const Color &);
+ MODBIND6C(draw_list_add_texture, const RID &, int64_t, const Transform2D &, RID, const Rect2 &, const Color &);
+ MODBIND4C(draw_list_add_custom, const RID &, int64_t, const Transform2D &, const Callable &);
+ MODBIND3(draw_list_draw, const RID &, const RID &, bool);
+
/* Shaped text buffer interface */
MODBIND2R(RID, create_shaped_text, Direction, Orientation);
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 554108faf1ce..f64b0b69d143 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -155,6 +155,10 @@ void TextServerFallback::_free_rid(const RID &p_rid) {
shaped_owner.free(p_rid);
}
memdelete(sd);
+ } else if (list_owner.owns(p_rid)) {
+ DrawList *dc = list_owner.get_or_null(p_rid);
+ list_owner.free(p_rid);
+ memdelete(dc);
}
}
@@ -2835,11 +2839,18 @@ void TextServerFallback::_font_render_glyph(const RID &p_font_rid, const Vector2
#endif
}
-void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+void TextServerFallback::_font_add_glyph_to_draw_list(const RID &p_font, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+ DrawList *list = list_owner.get_or_null(p_list);
+ ERR_FAIL_NULL(list);
+
+ _imp_font_add_glyph_to_draw_list(p_font, p_layer, list, p_transform, p_size, p_pos, p_index, p_color, p_oversampling);
+}
+
+void TextServerFallback::_imp_font_add_glyph_to_draw_list(const RID &p_font, int64_t p_layer, TextServerFallback::DrawList *p_list, const Transform2D &p_transform, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
if (p_index == 0) {
return; // Non visual character, skip.
}
- FontFallback *fd = _get_font_data(p_font_rid);
+ FontFallback *fd = _get_font_data(p_font);
ERR_FAIL_NULL(fd);
MutexLock lock(fd->mutex);
@@ -2938,10 +2949,19 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
Point2 cpos = p_pos;
cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;
Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;
- RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
+ GlyphDrawCall ret;
+ ret.layer = p_layer;
+ ret.texture = texture;
+ ret.dst_rect = Rect2(cpos, csize);
+ ret.src_rect = fgl.uv_rect;
+ ret.modulate = modulate;
+ ret.transform = p_transform;
+ ret.data = Vector3i(0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
+ ret.draw_type = DRAW_CALL_MSDF;
+ p_list->calls.push_back(ret);
} else {
Point2 cpos = p_pos;
- double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;
+ double scale = _font_get_scale(p_font, p_size) / oversampling_factor;
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
cpos.x = cpos.x + 0.125;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
@@ -2970,22 +2990,33 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
csize /= oversampling_factor;
}
cpos += gpos;
- if (lcd_aa) {
- RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);
- } else {
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);
- }
+ GlyphDrawCall ret;
+ ret.layer = p_layer;
+ ret.texture = texture;
+ ret.dst_rect = Rect2(cpos, csize);
+ ret.src_rect = fgl.uv_rect;
+ ret.modulate = modulate;
+ ret.transform = p_transform;
+ ret.draw_type = lcd_aa ? DRAW_CALL_LCD : DRAW_CALL_NORMAL;
+ p_list->calls.push_back(ret);
}
}
}
}
}
-void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+void TextServerFallback::_font_add_glyph_outline_to_draw_list(const RID &p_font, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+ DrawList *list = list_owner.get_or_null(p_list);
+ ERR_FAIL_NULL(list);
+
+ _imp_font_add_glyph_outline_to_draw_list(p_font, p_layer, list, p_transform, p_size, p_outline_size, p_pos, p_index, p_color, p_oversampling);
+}
+
+void TextServerFallback::_imp_font_add_glyph_outline_to_draw_list(const RID &p_font, int64_t p_layer, TextServerFallback::DrawList *p_list, const Transform2D &p_transform, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
if (p_index == 0) {
return; // Non visual character, skip.
}
- FontFallback *fd = _get_font_data(p_font_rid);
+ FontFallback *fd = _get_font_data(p_font);
ERR_FAIL_NULL(fd);
MutexLock lock(fd->mutex);
@@ -3080,10 +3111,19 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R
Point2 cpos = p_pos;
cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;
Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;
- RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
+ GlyphDrawCall ret;
+ ret.layer = p_layer;
+ ret.texture = texture;
+ ret.dst_rect = Rect2(cpos, csize);
+ ret.src_rect = fgl.uv_rect;
+ ret.modulate = modulate;
+ ret.transform = p_transform;
+ ret.data = Vector3i(p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
+ ret.draw_type = DRAW_CALL_MSDF;
+ p_list->calls.push_back(ret);
} else {
Point2 cpos = p_pos;
- double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;
+ double scale = _font_get_scale(p_font, p_size) / oversampling_factor;
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
cpos.x = cpos.x + 0.125;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
@@ -3112,17 +3152,37 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R
csize /= oversampling_factor;
}
cpos += gpos;
- if (lcd_aa) {
- RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);
- } else {
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);
- }
+ GlyphDrawCall ret;
+ ret.layer = p_layer;
+ ret.texture = texture;
+ ret.dst_rect = Rect2(cpos, csize);
+ ret.src_rect = fgl.uv_rect;
+ ret.modulate = modulate;
+ ret.transform = p_transform;
+ ret.draw_type = lcd_aa ? DRAW_CALL_LCD : DRAW_CALL_NORMAL;
+ p_list->calls.push_back(ret);
}
}
}
}
}
+void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+ if (RenderingServer::get_singleton() != nullptr) {
+ DrawList dl;
+ _imp_font_add_glyph_to_draw_list(p_font_rid, 0, &dl, Transform2D(), p_size, p_pos, p_index, p_color, p_oversampling);
+ _imp_draw_list_draw(&dl, p_canvas);
+ }
+}
+
+void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+ if (RenderingServer::get_singleton() != nullptr) {
+ DrawList dl;
+ _imp_font_add_glyph_outline_to_draw_list(p_font_rid, 0, &dl, Transform2D(), p_size, p_outline_size, p_pos, p_index, p_color, p_oversampling);
+ _imp_draw_list_draw(&dl, p_canvas);
+ }
+}
+
bool TextServerFallback::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const {
FontFallback *fd = _get_font_data(p_font_rid);
ERR_FAIL_NULL_V(fd, false);
@@ -3256,6 +3316,187 @@ Dictionary TextServerFallback::_font_supported_variation_list(const RID &p_font_
return fd->supported_varaitions;
}
+/*************************************************************************/
+/* Draw list interface */
+/*************************************************************************/
+
+RID TextServerFallback::_create_draw_list() {
+ _THREAD_SAFE_METHOD_
+ DrawList *list = memnew(DrawList);
+ return list_owner.make_rid(list);
+}
+
+void TextServerFallback::_draw_list_sort(const RID &p_dc) {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+ list->calls.sort_custom();
+}
+
+void TextServerFallback::_draw_list_reserve(const RID &p_dc, int64_t p_new_items) {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+ list->calls.reserve(list->calls.size() + p_new_items);
+}
+
+void TextServerFallback::_draw_list_add_hexbox(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Vector2 &p_pos, int64_t p_index, int64_t p_size, const Color &p_modulate) const {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+
+ GlyphDrawCall dc;
+ dc.draw_type = TextServer::DRAW_CALL_HEX;
+ dc.layer = p_layer;
+ dc.transform = p_transform;
+ dc.data = Vector2i(p_index, p_size);
+ dc.modulate = p_modulate;
+ dc.dst_rect.position = p_pos;
+
+ list->calls.push_back(dc);
+}
+
+void TextServerFallback::_draw_list_add_rect(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Rect2 &p_rect, bool p_filled, const Color &p_modulate) const {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+
+ GlyphDrawCall dc;
+ dc.draw_type = TextServer::DRAW_CALL_RECT;
+ dc.layer = p_layer;
+ dc.transform = p_transform;
+ dc.data = p_filled;
+ dc.modulate = p_modulate;
+ dc.dst_rect = p_rect;
+
+ list->calls.push_back(dc);
+}
+
+void TextServerFallback::_draw_list_add_line(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Point2 &p_start, const Point2 &p_end, float p_width, float p_dash, const Color &p_modulate) const {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+
+ GlyphDrawCall dc;
+ dc.draw_type = TextServer::DRAW_CALL_LINE;
+ dc.layer = p_layer;
+ dc.transform = p_transform;
+ dc.data = Vector2(p_dash, p_width);
+ dc.modulate = p_modulate;
+ dc.dst_rect.position = p_start;
+ dc.src_rect.position = p_end;
+
+ list->calls.push_back(dc);
+}
+
+void TextServerFallback::_draw_list_add_texture(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, RID p_texture, const Rect2 &p_dst_rect, const Color &p_modulate) const {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+
+ GlyphDrawCall dc;
+ dc.draw_type = TextServer::DRAW_CALL_IMAGE;
+ dc.layer = p_layer;
+ dc.texture = p_texture;
+ dc.transform = p_transform;
+ dc.modulate = p_modulate;
+ dc.dst_rect = p_dst_rect;
+
+ list->calls.push_back(dc);
+}
+
+void TextServerFallback::_draw_list_add_custom(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Callable &p_callback) const {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+
+ GlyphDrawCall dc;
+ dc.draw_type = TextServer::DRAW_CALL_CUSTOM;
+ dc.layer = p_layer;
+ dc.data = p_callback;
+ dc.transform = p_transform;
+
+ list->calls.push_back(dc);
+}
+
+void TextServerFallback::_imp_draw_list_draw(TextServerFallback::DrawList *p_list, const RID &p_ci) const {
+ for (const GlyphDrawCall &dc : p_list->calls) {
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_ci, dc.transform);
+ if (dc.draw_type == TextServer::DRAW_CALL_MSDF) {
+ RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_ci, dc.dst_rect, dc.texture, dc.src_rect, dc.modulate, dc.data.operator Vector3().x, dc.data.operator Vector3().y, dc.data.operator Vector3().z);
+ } else if (dc.draw_type == TextServer::DRAW_CALL_LCD) {
+ RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_ci, dc.dst_rect, dc.texture, dc.src_rect, dc.modulate);
+ } else if (dc.draw_type == TextServer::DRAW_CALL_NORMAL) {
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_ci, dc.dst_rect, dc.texture, dc.src_rect, dc.modulate, false, false);
+ } else if (dc.draw_type == TextServer::DRAW_CALL_CUSTOM) {
+ const Callable &cb = dc.data.operator Callable();
+ if (cb.is_valid()) {
+ if (cb.get_argument_count() == 1) {
+ cb.call(p_ci);
+#ifndef DISABLE_DEPRECATED
+ } else if (cb.get_argument_count() == 0) {
+ cb.call();
+#endif
+ }
+ }
+ } else if (dc.draw_type == TextServer::DRAW_CALL_IMAGE) {
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_ci, dc.dst_rect, dc.texture, false, dc.modulate, false);
+ } else if (dc.draw_type == TextServer::DRAW_CALL_HEX) {
+ TS->draw_hex_code_box(p_ci, dc.data.operator Vector2i().y, dc.dst_rect.position, dc.data.operator Vector2i().x, dc.modulate);
+ } else if (dc.draw_type == TextServer::DRAW_CALL_RECT) {
+ if (dc.data.operator bool()) {
+ RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, dc.dst_rect, dc.modulate, false);
+ } else {
+ Vector points;
+ points.resize(5);
+ points.write[0] = dc.dst_rect.position;
+ points.write[1] = dc.dst_rect.position + Vector2(dc.dst_rect.size.x, 0);
+ points.write[2] = dc.dst_rect.position + dc.dst_rect.size;
+ points.write[3] = dc.dst_rect.position + Vector2(0, dc.dst_rect.size.y);
+ points.write[4] = dc.dst_rect.position;
+
+ Vector colors = { dc.modulate };
+
+ RenderingServer::get_singleton()->canvas_item_add_polyline(p_ci, points, colors, -1.0, false);
+ }
+ } else if (dc.draw_type == TextServer::DRAW_CALL_LINE) {
+ float dash = dc.data.operator Vector2().x;
+ if (dash <= 0.0) {
+ RenderingServer::get_singleton()->canvas_item_add_line(p_ci, dc.dst_rect.position, dc.src_rect.position, dc.modulate, dc.data.operator Vector2().y, false);
+ } else {
+ float length = (dc.src_rect.position - dc.dst_rect.position).length();
+ Vector2 step = dash * (dc.src_rect.position - dc.dst_rect.position).normalized();
+
+ if (length < dash || step == Vector2()) {
+ RenderingServer::get_singleton()->canvas_item_add_line(p_ci, dc.dst_rect.position, dc.src_rect.position, dc.modulate, dc.data.operator Vector2().y, false);
+ return;
+ }
+
+ int steps = Math::ceil(length / dash);
+ if (steps % 2 == 0) {
+ steps--;
+ }
+
+ Point2 off = dc.dst_rect.position + (dc.src_rect.position - dc.dst_rect.position).normalized() * (length - steps * dash) / 2.0;
+
+ Vector points;
+ points.resize(steps + 1);
+ for (int i = 0; i < steps; i += 2) {
+ points.write[i] = (i == 0) ? dc.dst_rect.position : off;
+ points.write[i + 1] = (i == steps - 1) ? dc.src_rect.position : (off + step);
+ off += step * 2;
+ }
+
+ Vector colors = { dc.modulate };
+
+ RenderingServer::get_singleton()->canvas_item_add_multiline(p_ci, points, colors, dc.data.operator Vector2().y, false);
+ }
+ }
+ }
+}
+
+void TextServerFallback::_draw_list_draw(const RID &p_dc, const RID &p_ci, bool p_free) {
+ DrawList *list = list_owner.get_or_null(p_dc);
+ ERR_FAIL_NULL(list);
+ _imp_draw_list_draw(list, p_ci);
+ if (p_free) {
+ _free_rid(p_dc);
+ }
+}
+
/*************************************************************************/
/* Shaped text buffer interface */
/*************************************************************************/
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 7cc029853305..84f72d3f31bf 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -488,11 +488,16 @@ class TextServerFallback : public TextServerExtension {
Vector glyphs_logical;
};
+ struct DrawList {
+ LocalVector calls;
+ };
+
// Common data.
mutable RID_PtrOwner font_var_owner;
mutable RID_PtrOwner font_owner;
mutable RID_PtrOwner shaped_owner;
+ mutable RID_PtrOwner list_owner;
_FORCE_INLINE_ FontFallback *_get_font_data(const RID &p_font_rid) const {
RID rid = p_font_rid;
@@ -595,6 +600,10 @@ class TextServerFallback : public TextServerExtension {
void _realign(ShapedTextDataFallback *p_sd) const;
_FORCE_INLINE_ RID _find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text);
+ void _imp_font_add_glyph_to_draw_list(const RID &p_font, int64_t p_layer, TextServerFallback::DrawList *p_list, const Transform2D &p_transform, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const;
+ void _imp_font_add_glyph_outline_to_draw_list(const RID &p_font, int64_t p_layer, TextServerFallback::DrawList *p_list, const Transform2D &p_transform, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const;
+ void _imp_draw_list_draw(TextServerFallback::DrawList *p_list, const RID &p_ci) const;
+
Mutex ft_mutex;
protected:
@@ -785,6 +794,9 @@ class TextServerFallback : public TextServerExtension {
MODBIND7C(font_draw_glyph, const RID &, const RID &, int64_t, const Vector2 &, int64_t, const Color &, float);
MODBIND8C(font_draw_glyph_outline, const RID &, const RID &, int64_t, int64_t, const Vector2 &, int64_t, const Color &, float);
+ MODBIND9C(font_add_glyph_to_draw_list, const RID &, int64_t, const RID &, const Transform2D &, int64_t, const Vector2 &, int64_t, const Color &, float);
+ MODBIND10C(font_add_glyph_outline_to_draw_list, const RID &, int64_t, const RID &, const Transform2D &, int64_t, int64_t, const Vector2 &, int64_t, const Color &, float);
+
MODBIND2RC(bool, font_is_language_supported, const RID &, const String &);
MODBIND3(font_set_language_support_override, const RID &, const String &, bool);
MODBIND2R(bool, font_get_language_support_override, const RID &, const String &);
@@ -806,6 +818,18 @@ class TextServerFallback : public TextServerExtension {
MODBIND1(reference_oversampling_level, double);
MODBIND1(unreference_oversampling_level, double);
+ /* Draw list interface */
+
+ MODBIND0R(RID, create_draw_list);
+ MODBIND1(draw_list_sort, const RID &);
+ MODBIND2(draw_list_reserve, const RID &, int64_t);
+ MODBIND7C(draw_list_add_hexbox, const RID &, int64_t, const Transform2D &, const Vector2 &, int64_t, int64_t, const Color &);
+ MODBIND6C(draw_list_add_rect, const RID &, int64_t, const Transform2D &, const Rect2 &, bool, const Color &);
+ MODBIND8C(draw_list_add_line, const RID &, int64_t, const Transform2D &, const Point2 &, const Point2 &, float, float, const Color &);
+ MODBIND6C(draw_list_add_texture, const RID &, int64_t, const Transform2D &, RID, const Rect2 &, const Color &);
+ MODBIND4C(draw_list_add_custom, const RID &, int64_t, const Transform2D &, const Callable &);
+ MODBIND3(draw_list_draw, const RID &, const RID &, bool);
+
/* Shaped text buffer interface */
MODBIND2R(RID, create_shaped_text, Direction, Orientation);
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index de5173d0ea19..32d9d561b6c3 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -1342,9 +1342,8 @@ bool CodeEdit::is_drawing_executing_lines_gutter() const {
return draw_executing_lines;
}
-void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) {
+void CodeEdit::_main_gutter_draw_callback(RID p_ci, int p_line, int p_gutter, const Rect2 &p_region) {
bool hovering = get_hovered_gutter() == Vector2i(main_gutter, p_line);
- RID ci = get_text_canvas_item();
if (draw_breakpoints && theme_cache.breakpoint_icon.is_valid()) {
bool breakpointed = is_line_breakpointed(p_line);
bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
@@ -1359,7 +1358,7 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2
Rect2 icon_region = p_region;
icon_region.position += Point2(padding, padding);
icon_region.size -= Point2(padding, padding) * 2;
- theme_cache.breakpoint_icon->draw_rect(ci, icon_region, false, use_color);
+ theme_cache.breakpoint_icon->draw_rect(p_ci, icon_region, false, use_color);
}
}
@@ -1378,7 +1377,7 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2
Rect2 icon_region = p_region;
icon_region.position += Point2(horizontal_padding, 0);
icon_region.size -= Point2(horizontal_padding * 1.1, vertical_padding);
- theme_cache.bookmark_icon->draw_rect(ci, icon_region, false, use_color);
+ theme_cache.bookmark_icon->draw_rect(p_ci, icon_region, false, use_color);
}
}
@@ -1389,7 +1388,7 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2
Rect2 icon_region = p_region;
icon_region.position += Point2(horizontal_padding, vertical_padding);
icon_region.size -= Point2(horizontal_padding, vertical_padding) * 2;
- theme_cache.executing_line_icon->draw_rect(ci, icon_region, false, theme_cache.executing_line_color);
+ theme_cache.executing_line_icon->draw_rect(p_ci, icon_region, false, theme_cache.executing_line_color);
}
}
@@ -1532,7 +1531,7 @@ int CodeEdit::get_line_numbers_min_digits() const {
return line_numbers_min_digits;
}
-void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) {
+void CodeEdit::_line_number_draw_callback(RID p_ci, int p_line, int p_gutter, const Rect2 &p_region) {
if (!Rect2(Vector2(0, 0), get_size()).intersects(p_region)) {
return;
}
@@ -1571,7 +1570,7 @@ void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2
number_color = theme_cache.line_number_color;
}
- TS->shaped_text_draw(text_rid, get_text_canvas_item(), ofs, -1, -1, number_color);
+ TS->shaped_text_draw(text_rid, p_ci, ofs, -1, -1, number_color);
}
void CodeEdit::_clear_line_number_text_cache() {
@@ -1594,13 +1593,12 @@ bool CodeEdit::is_drawing_fold_gutter() const {
return is_gutter_drawn(fold_gutter);
}
-void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_region) {
+void CodeEdit::_fold_gutter_draw_callback(RID p_ci, int p_line, int p_gutter, Rect2 p_region) {
if (!can_fold_line(p_line) && !is_line_folded(p_line)) {
set_line_gutter_clickable(p_line, fold_gutter, false);
return;
}
set_line_gutter_clickable(p_line, fold_gutter, true);
- RID ci = get_text_canvas_item();
int horizontal_padding = p_region.size.x / 10;
int vertical_padding = p_region.size.y / 6;
@@ -1614,17 +1612,17 @@ void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_regi
Color region_icon_color = theme_cache.folded_code_region_color;
region_icon_color.a = MAX(region_icon_color.a, 0.4f);
if (can_fold) {
- theme_cache.can_fold_code_region_icon->draw_rect(ci, p_region, false, region_icon_color);
+ theme_cache.can_fold_code_region_icon->draw_rect(p_ci, p_region, false, region_icon_color);
} else {
- theme_cache.folded_code_region_icon->draw_rect(ci, p_region, false, region_icon_color);
+ theme_cache.folded_code_region_icon->draw_rect(p_ci, p_region, false, region_icon_color);
}
return;
}
if (can_fold) {
- theme_cache.can_fold_icon->draw_rect(ci, p_region, false, theme_cache.code_folding_color);
+ theme_cache.can_fold_icon->draw_rect(p_ci, p_region, false, theme_cache.code_folding_color);
return;
}
- theme_cache.folded_icon->draw_rect(ci, p_region, false, theme_cache.code_folding_color);
+ theme_cache.folded_icon->draw_rect(p_ci, p_region, false, theme_cache.code_folding_color);
}
/* Line Folding */
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index bda57af261c0..c9fee6b57442 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -96,7 +96,7 @@ class CodeEdit : public TextEdit {
int main_gutter = -1;
void _update_draw_main_gutter();
- void _main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region);
+ void _main_gutter_draw_callback(RID p_ci, int p_line, int p_gutter, const Rect2 &p_region);
// breakpoints
HashMap breakpointed_lines;
@@ -116,12 +116,12 @@ class CodeEdit : public TextEdit {
HashMap line_number_text_cache;
void _clear_line_number_text_cache();
void _update_line_number_gutter_width();
- void _line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region);
+ void _line_number_draw_callback(RID p_ci, int p_line, int p_gutter, const Rect2 &p_region);
/* Fold Gutter */
int fold_gutter = -1;
bool draw_fold_gutter = false;
- void _fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_region);
+ void _fold_gutter_draw_callback(RID p_ci, int p_line, int p_gutter, Rect2 p_region);
void _gutter_clicked(int p_line, int p_gutter);
void _update_gutter_indexes();
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 04387dcc99dd..625a19080ad7 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -388,30 +388,30 @@ void Label::_update_visible() const {
}
}
-inline void draw_glyph(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_color, const Vector2 &p_ofs) {
+inline void draw_glyph(const Glyph &p_gl, int p_layer, RID p_list, const Color &p_font_color, const Vector2 &p_ofs) {
if (p_gl.font_rid != RID()) {
- 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), p_gl.index, p_font_color);
+ TS->font_add_glyph_to_draw_list(p_gl.font_rid, p_layer, p_list, Transform2D(), p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_color);
} else if (((p_gl.flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) && ((p_gl.flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) != TextServer::GRAPHEME_IS_EMBEDDED_OBJECT)) {
- TS->draw_hex_code_box(p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_color);
+ TS->draw_list_add_hexbox(p_list, -1, Transform2D(), p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_gl.font_size, p_font_color);
}
}
-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) {
+inline void draw_glyph_shadow(const Glyph &p_gl, int p_layer, RID p_list, const Color &p_font_shadow_color, const Vector2 &p_ofs, const Vector2 &shadow_ofs) {
if (p_gl.font_rid != RID()) {
- 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_add_glyph_to_draw_list(p_gl.font_rid, p_layer, p_list, Transform2D(), p_gl.font_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, const Vector2 &p_ofs, int p_shadow_outline_size, const Vector2 &shadow_ofs) {
+inline void draw_glyph_shadow_outline(const Glyph &p_gl, int p_layer, RID p_list, const Color &p_font_shadow_color, const Vector2 &p_ofs, int p_shadow_outline_size, 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);
+ TS->font_add_glyph_outline_to_draw_list(p_gl.font_rid, p_layer, p_list, Transform2D(), 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_outline(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_outline_color, const Vector2 &p_ofs, int p_outline_size) {
+inline void draw_glyph_outline(const Glyph &p_gl, int p_layer, RID p_list, const Color &p_font_outline_color, const Vector2 &p_ofs, int p_outline_size) {
if (p_gl.font_rid != RID()) {
if (p_font_outline_color.a != 0.0 && p_outline_size > 0) {
- TS->font_draw_glyph_outline(p_gl.font_rid, p_canvas, p_gl.font_size, p_outline_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_outline_color);
+ TS->font_add_glyph_outline_to_draw_list(p_gl.font_rid, p_layer, p_list, Transform2D(), p_gl.font_size, p_outline_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_outline_color);
}
}
}
@@ -787,6 +787,38 @@ void Label::_notification(int p_what) {
int visible_glyphs = total_glyphs * visible_ratio;
int line_index = 0;
+ int dc_call_count = 1;
+ if (font_shadow_color.a != 0 && shadow_outline_size > 0) {
+ dc_call_count++;
+ }
+ if (font_shadow_color.a > 0) {
+ dc_call_count++;
+ }
+ if (stacked_outline_datas.size() != 0) {
+ int draw_iterations = stacked_shadow_datas.size();
+ for (int draw_iteration_index = draw_iterations - 1; draw_iteration_index >= 0; --draw_iteration_index) {
+ LabelSettings::StackedShadowData stacked_shadow_data = stacked_shadow_datas[draw_iteration_index];
+ if (stacked_shadow_data.outline_size > 0) {
+ dc_call_count++;
+ }
+ dc_call_count++;
+ }
+ }
+ if (stacked_outline_datas.size() != 0) {
+ int draw_iterations = stacked_outline_datas.size();
+ for (int draw_iteration_index = draw_iterations - 1; draw_iteration_index >= 0; --draw_iteration_index) {
+ LabelSettings::StackedOutlineData stacked_outline_data = stacked_outline_datas[draw_iteration_index];
+ if (stacked_outline_data.size <= 0) {
+ continue;
+ }
+ dc_call_count++;
+ }
+ }
+ if (outline_size > 0 && font_outline_color.a != 0) {
+ dc_call_count++;
+ }
+
+ RID draw_list = TS->create_draw_list();
for (int p = 0; p < paragraphs.size(); p++) {
const Paragraph ¶ = paragraphs[p];
if (line_index + para.lines_rid.size() <= lines_skipped) {
@@ -799,6 +831,8 @@ void Label::_notification(int p_what) {
}
bool rtl = (TS->shaped_text_get_inferred_direction(para.text_rid) == TextServer::DIRECTION_RTL);
for (int i = start; i < end; i++) {
+ TS->draw_list_reserve(draw_list, +dc_call_count * (end - start));
+ int priority = 0;
RID line_rid = para.lines_rid[i];
Vector2 line_offset = _get_line_rect(p, i).position;
ofs.x = line_offset.x;
@@ -827,12 +861,12 @@ void Label::_notification(int p_what) {
// Draw shadow outline.
if (font_shadow_color.a != 0 && shadow_outline_size > 0) {
- draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, font_shadow_color, draw_glyph_shadow_outline, shadow_outline_size, shadow_ofs);
+ draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, priority++, draw_list, ofs, gl_size, trim_pos, glyphs, font_shadow_color, draw_glyph_shadow_outline, shadow_outline_size, shadow_ofs);
}
// Draw shadow.
if (font_shadow_color.a > 0) {
- draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, font_shadow_color, draw_glyph_shadow, shadow_ofs);
+ draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, priority++, draw_list, ofs, gl_size, trim_pos, glyphs, font_shadow_color, draw_glyph_shadow, shadow_ofs);
}
// Draw stacked shadow.
@@ -842,10 +876,10 @@ void Label::_notification(int p_what) {
for (int draw_iteration_index = draw_iterations - 1; draw_iteration_index >= 0; --draw_iteration_index) {
LabelSettings::StackedShadowData stacked_shadow_data = stacked_shadow_datas[draw_iteration_index];
if (stacked_shadow_data.outline_size > 0) {
- draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, stacked_shadow_data.color, draw_glyph_shadow_outline, stacked_shadow_data.outline_size, stacked_shadow_data.offset);
+ draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, priority++, draw_list, ofs, gl_size, trim_pos, glyphs, stacked_shadow_data.color, draw_glyph_shadow_outline, stacked_shadow_data.outline_size, stacked_shadow_data.offset);
}
- draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, stacked_shadow_data.color, draw_glyph_shadow, stacked_shadow_data.offset);
+ draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, priority++, draw_list, ofs, gl_size, trim_pos, glyphs, stacked_shadow_data.color, draw_glyph_shadow, stacked_shadow_data.offset);
}
}
@@ -868,19 +902,19 @@ void Label::_notification(int p_what) {
if (stacked_outline_data.size <= 0) {
continue;
}
- draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, stacked_outline_data.color, draw_glyph_outline, stacked_outline_draw_size);
+ draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, priority++, draw_list, ofs, gl_size, trim_pos, glyphs, stacked_outline_data.color, draw_glyph_outline, stacked_outline_draw_size);
stacked_outline_draw_size -= stacked_outline_data.size;
}
}
// Draw outline.
if (outline_size > 0 && font_outline_color.a != 0) {
- draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, font_outline_color, draw_glyph_outline, outline_size);
+ draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, priority++, draw_list, ofs, gl_size, trim_pos, glyphs, font_outline_color, draw_glyph_outline, outline_size);
}
// Draw text.
{
- draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, font_color, draw_glyph);
+ draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, priority++, draw_list, ofs, gl_size, trim_pos, glyphs, font_color, draw_glyph);
}
processed_glyphs = processed_glyphs_step;
@@ -890,6 +924,8 @@ void Label::_notification(int p_what) {
line_index += para.lines_rid.size();
}
}
+ TS->draw_list_sort(draw_list);
+ TS->draw_list_draw(draw_list, ci, true);
} break;
case NOTIFICATION_THEME_CHANGED: {
diff --git a/scene/gui/label.h b/scene/gui/label.h
index be05c98e0eaa..950ebd02b29d 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -194,7 +194,7 @@ class Label : public Control {
~Label();
template
- void draw_text(bool p_rtl, int p_ellipsis_pos, int p_ellipsis_gl_size, const Glyph *p_ellipsis_glyphs, bool p_trim_chars, int p_para_start, int p_visible_chars, bool p_trim_glyphs_ltr, int &p_processed_glyphs_step, int p_processed_glyphs, int p_visible_glyphs, bool p_trim_glyphs_rtl, int p_total_glyphs, const RID &p_ci, const Vector2 &p_ofs, int p_gl_size, int p_trim_pos, const Glyph *p_glyphs, const Color &p_color, void (*p_draw_func)(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_outline_color, const Vector2 &p_ofs, VarArgsFunc... p_args), VarArgs &&...p_args) {
+ void draw_text(bool p_rtl, int p_ellipsis_pos, int p_ellipsis_gl_size, const Glyph *p_ellipsis_glyphs, bool p_trim_chars, int p_para_start, int p_visible_chars, bool p_trim_glyphs_ltr, int &p_processed_glyphs_step, int p_processed_glyphs, int p_visible_glyphs, bool p_trim_glyphs_rtl, int p_total_glyphs, int p_layer, RID p_list, const Vector2 &p_ofs, int p_gl_size, int p_trim_pos, const Glyph *p_glyphs, const Color &p_color, void (*p_draw_func)(const Glyph &p_gl, int p_layer, RID p_list, const Color &p_font_outline_color, const Vector2 &p_ofs, VarArgsFunc... p_args), VarArgs &&...p_args) {
p_processed_glyphs_step = p_processed_glyphs;
Vector2 offset_step = p_ofs; /* Draw RTL ellipsis string when necessary. */
if (p_rtl && p_ellipsis_pos >= 0) {
@@ -202,7 +202,7 @@ class Label : public Control {
for (int j = 0; j < p_ellipsis_glyphs[gl_idx].repeat; j++) {
bool skip = (p_trim_chars && p_ellipsis_glyphs[gl_idx].end + p_para_start > p_visible_chars) || (p_trim_glyphs_ltr && (p_processed_glyphs_step >= p_visible_glyphs)) || (p_trim_glyphs_rtl && (p_processed_glyphs_step < p_total_glyphs - p_visible_glyphs));
if (!skip) {
- p_draw_func(p_ellipsis_glyphs[gl_idx], p_ci, p_color, offset_step, std::forward(p_args)...);
+ p_draw_func(p_ellipsis_glyphs[gl_idx], p_layer, p_list, p_color, offset_step, std::forward(p_args)...);
}
p_processed_glyphs_step++;
offset_step.x += p_ellipsis_glyphs[gl_idx].advance;
@@ -224,7 +224,7 @@ class Label : public Control {
for (int k = 0; k < p_glyphs[j].repeat; k++) {
bool skip = (p_trim_chars && p_glyphs[j].end + p_para_start > p_visible_chars) || (p_trim_glyphs_ltr && (p_processed_glyphs_step >= p_visible_glyphs)) || (p_trim_glyphs_rtl && (p_processed_glyphs_step < p_total_glyphs - p_visible_glyphs));
if (!skip) {
- p_draw_func(p_glyphs[j], p_ci, p_color, offset_step, std::forward(p_args)...);
+ p_draw_func(p_glyphs[j], p_layer, p_list, p_color, offset_step, std::forward(p_args)...);
}
p_processed_glyphs_step++;
offset_step.x += p_glyphs[j].advance;
@@ -235,7 +235,7 @@ class Label : public Control {
for (int j = 0; j < p_ellipsis_glyphs[gl_idx].repeat; j++) {
bool skip = (p_trim_chars && p_ellipsis_glyphs[gl_idx].end + p_para_start > p_visible_chars) || (p_trim_glyphs_ltr && (p_processed_glyphs_step >= p_visible_glyphs)) || (p_trim_glyphs_rtl && (p_processed_glyphs_step < p_total_glyphs - p_visible_glyphs));
if (!skip) {
- p_draw_func(p_ellipsis_glyphs[gl_idx], p_ci, p_color, offset_step, std::forward(p_args)...);
+ p_draw_func(p_ellipsis_glyphs[gl_idx], p_layer, p_list, p_color, offset_step, std::forward(p_args)...);
}
p_processed_glyphs_step++;
offset_step.x += p_ellipsis_glyphs[gl_idx].advance;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 69ef0bde1e45..e3989c2032c1 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -1470,33 +1470,24 @@ void LineEdit::_notification(int p_what) {
int gl_size = TS->shaped_text_get_glyph_count(text_rid);
// Draw text.
+ RID draw_list = TS->create_draw_list();
+
ofs.y += TS->shaped_text_get_ascent(text_rid);
Color font_outline_color = theme_cache.font_outline_color;
int outline_size = theme_cache.font_outline_size;
- if (outline_size > 0 && font_outline_color.a > 0) {
- Vector2 oofs = ofs;
- for (int i = 0; i < gl_size; i++) {
- for (int j = 0; j < glyphs[i].repeat; j++) {
- if (std::ceil(oofs.x) >= x_ofs && (oofs.x + glyphs[i].advance) <= ofs_max) {
- if (glyphs[i].font_rid != RID()) {
- TS->font_draw_glyph_outline(glyphs[i].font_rid, ci, glyphs[i].font_size, outline_size, oofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, font_outline_color);
- }
- }
- oofs.x += glyphs[i].advance;
- }
- if (oofs.x >= ofs_max) {
- break;
- }
- }
- }
+
+ TS->draw_list_reserve(draw_list, gl_size * (outline_size > 0 && font_outline_color.a > 0 ? 2 : 1));
for (int i = 0; i < gl_size; i++) {
bool selected = selection.enabled && glyphs[i].start >= selection.begin && glyphs[i].end <= selection.end;
for (int j = 0; j < glyphs[i].repeat; j++) {
if (std::ceil(ofs.x) >= x_ofs && (ofs.x + glyphs[i].advance) <= ofs_max) {
if (glyphs[i].font_rid != RID()) {
- TS->font_draw_glyph(glyphs[i].font_rid, ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_selected_color : font_color);
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ TS->font_add_glyph_outline_to_draw_list(glyphs[i].font_rid, DRAW_STEP_OUTLINE, draw_list, Transform2D(), glyphs[i].font_size, outline_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, font_outline_color);
+ }
+ TS->font_add_glyph_to_draw_list(glyphs[i].font_rid, DRAW_STEP_TEXT, draw_list, Transform2D(), glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_selected_color : 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, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_selected_color : font_color);
+ TS->draw_list_add_hexbox(draw_list, DRAW_STEP_TEXT, Transform2D(), ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, glyphs[i].font_size, selected ? font_selected_color : font_color);
}
}
ofs.x += glyphs[i].advance;
@@ -1505,6 +1496,8 @@ void LineEdit::_notification(int p_what) {
break;
}
}
+ TS->draw_list_sort(draw_list);
+ TS->draw_list_draw(draw_list, ci, true);
// Draw carets.
ofs.x = x_ofs + scroll_offset;
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index c8ca6c7e3bbf..1018acf9e502 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -84,6 +84,11 @@ class LineEdit : public Control {
};
private:
+ enum LEDrawStep {
+ DRAW_STEP_OUTLINE,
+ DRAW_STEP_TEXT,
+ };
+
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
bool editing = false;
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index dd66583459d3..d7d7864b9cfd 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -919,10 +919,12 @@ void RichTextLabel::_set_table_size(ItemTable *p_table, int p_available_width) {
}
}
-int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, float p_vsep, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs) {
+int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, float p_vsep, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs, RID p_list, int p_layer) {
ERR_FAIL_NULL_V(p_frame, 0);
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)p_frame->lines.size(), 0);
+ int first_layer = DRAW_STEP_MAX * p_layer;
+
Vector2 off;
Line &l = p_frame->lines[p_line];
@@ -934,7 +936,6 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
return 0;
}
- RID ci = get_canvas_item();
bool rtl = (l.text_buf->get_direction() == TextServer::DIRECTION_RTL);
bool lrtl = is_layout_rtl();
@@ -950,9 +951,9 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
bool skip_dc = (trim_chars && l.char_offset > visible_characters) || (trim_glyphs_ltr && (r_processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (r_processed_glyphs < total_glyphs - visible_glyphs));
if (!skip_dc) {
if (l.dc_ol_size > 0) {
- l.text_buf->draw_dropcap_outline(ci, p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_ol_size, l.dc_ol_color);
+ l.text_buf->add_dropcap_outline_to_draw_list(DRAW_STEP_OUTLINE, p_list, Transform2D(), p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_ol_size, l.dc_ol_color);
}
- l.text_buf->draw_dropcap(ci, p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_color);
+ l.text_buf->add_dropcap_to_draw_list(DRAW_STEP_TEXT, p_list, Transform2D(), p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_color);
}
const Ref &text_buf = l.text_buf_disp.is_valid() ? l.text_buf_disp : l.text_buf;
@@ -1020,20 +1021,20 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
Color font_shadow_color = p_font_shadow_color * Color(1, 1, 1, font_color.a);
if (rtl) {
if (p_shadow_outline_size > 0 && font_shadow_color.a != 0.0) {
- l.text_prefix->draw_outline(ci, p_ofs + Vector2(off.x + length, 0) + p_shadow_ofs, p_shadow_outline_size, font_shadow_color);
+ l.text_prefix->add_outline_to_draw_list(DRAW_STEP_SHADOW_OUTLINE, p_list, Transform2D(), p_ofs + Vector2(off.x + length, 0) + p_shadow_ofs, p_shadow_outline_size, font_shadow_color);
}
if (outline_size > 0 && font_outline_color.a != 0.0) {
- l.text_prefix->draw_outline(ci, p_ofs + Vector2(off.x + length, 0), outline_size, font_outline_color);
+ l.text_prefix->add_outline_to_draw_list(DRAW_STEP_OUTLINE, p_list, Transform2D(), p_ofs + Vector2(off.x + length, 0), outline_size, font_outline_color);
}
- l.text_prefix->draw(ci, p_ofs + Vector2(off.x + length, 0), font_color);
+ l.text_prefix->add_to_draw_list(DRAW_STEP_TEXT, p_list, Transform2D(), p_ofs + Vector2(off.x + length, 0), font_color);
} else {
if (p_shadow_outline_size > 0 && font_shadow_color.a != 0.0) {
- l.text_prefix->draw_outline(ci, p_ofs + Vector2(off.x - l.text_prefix->get_size().x, 0) + p_shadow_ofs, p_shadow_outline_size, font_shadow_color);
+ l.text_prefix->add_outline_to_draw_list(DRAW_STEP_SHADOW_OUTLINE, p_list, Transform2D(), p_ofs + Vector2(off.x - l.text_prefix->get_size().x, 0) + p_shadow_ofs, p_shadow_outline_size, font_shadow_color);
}
if (outline_size > 0 && font_outline_color.a != 0.0) {
- l.text_prefix->draw_outline(ci, p_ofs + Vector2(off.x - l.text_prefix->get_size().x, 0), outline_size, font_outline_color);
+ l.text_prefix->add_outline_to_draw_list(DRAW_STEP_OUTLINE, p_list, Transform2D(), p_ofs + Vector2(off.x - l.text_prefix->get_size().x, 0), outline_size, font_outline_color);
}
- l.text_prefix->draw(ci, p_ofs + Vector2(off.x - l.text_prefix->get_size().x, 0), font_color);
+ l.text_prefix->add_to_draw_list(DRAW_STEP_TEXT, p_list, Transform2D(), p_ofs + Vector2(off.x - l.text_prefix->get_size().x, 0), font_color);
}
}
@@ -1090,10 +1091,10 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (img->pad) {
Size2 pad_size = rect.size.min(img->image->get_size());
Vector2 pad_off = (rect.size - pad_size) / 2;
- img->image->draw_rect(ci, Rect2(p_ofs + rect.position + off + pad_off, pad_size), false, img->color);
+ TS->draw_list_add_texture(p_list, first_layer + DRAW_STEP_TEXT, Transform2D(), img->image->get_rid(), Rect2(p_ofs + rect.position + off + pad_off, pad_size), img->color);
visible_rect = _merge_or_copy_rect(visible_rect, Rect2(p_ofs + rect.position + off + pad_off, pad_size));
} else {
- img->image->draw_rect(ci, Rect2(p_ofs + rect.position + off, rect.size), false, img->color);
+ TS->draw_list_add_texture(p_list, first_layer + DRAW_STEP_TEXT, Transform2D(), img->image->get_rid(), Rect2(p_ofs + rect.position + off, rect.size), img->color);
visible_rect = _merge_or_copy_rect(visible_rect, Rect2(p_ofs + rect.position + off, rect.size));
}
} break;
@@ -1124,22 +1125,22 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (row % 2 == 0) {
Color c = frame->odd_row_bg != Color(0, 0, 0, 0) ? frame->odd_row_bg : odd_row_bg;
if (c.a > 0.0) {
- draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position - Vector2(h_separation * 0.5, v_separation * 0.5).floor(), Size2(table->columns[col].width + h_separation + frame->padding.position.x + frame->padding.size.x, table->rows_no_padding[row] + frame->padding.position.y + frame->padding.size.y)), c, true);
+ TS->draw_list_add_rect(p_list, first_layer + DRAW_STEP_BACKGROUND, Transform2D(), Rect2(p_ofs + rect.position + off + coff - frame->padding.position - Vector2(h_separation * 0.5, v_separation * 0.5).floor(), Size2(table->columns[col].width + h_separation + frame->padding.position.x + frame->padding.size.x, table->rows_no_padding[row] + frame->padding.position.y + frame->padding.size.y)), true, c);
}
} else {
Color c = frame->even_row_bg != Color(0, 0, 0, 0) ? frame->even_row_bg : even_row_bg;
if (c.a > 0.0) {
- draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position - Vector2(h_separation * 0.5, v_separation * 0.5).floor(), Size2(table->columns[col].width + h_separation + frame->padding.position.x + frame->padding.size.x, table->rows_no_padding[row] + frame->padding.position.y + frame->padding.size.y)), c, true);
+ TS->draw_list_add_rect(p_list, first_layer + DRAW_STEP_BACKGROUND, Transform2D(), Rect2(p_ofs + rect.position + off + coff - frame->padding.position - Vector2(h_separation * 0.5, v_separation * 0.5).floor(), Size2(table->columns[col].width + h_separation + frame->padding.position.x + frame->padding.size.x, table->rows_no_padding[row] + frame->padding.position.y + frame->padding.size.y)), true, c);
}
}
Color bc = frame->border != Color(0, 0, 0, 0) ? frame->border : border;
if (bc.a > 0.0) {
- draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position - Vector2(h_separation * 0.5, v_separation * 0.5).floor(), Size2(table->columns[col].width + h_separation + frame->padding.position.x + frame->padding.size.x, table->rows_no_padding[row] + frame->padding.position.y + frame->padding.size.y)), bc, false);
+ TS->draw_list_add_rect(p_list, first_layer + DRAW_STEP_BACKGROUND, Transform2D(), Rect2(p_ofs + rect.position + off + coff - frame->padding.position - Vector2(h_separation * 0.5, v_separation * 0.5).floor(), Size2(table->columns[col].width + h_separation + frame->padding.position.x + frame->padding.size.x, table->rows_no_padding[row] + frame->padding.position.y + frame->padding.size.y)), false, bc);
}
}
for (int j = 0; j < (int)frame->lines.size(); j++) {
- _draw_line(frame, j, p_ofs + rect.position + off + Vector2(0, frame->lines[j].offset.y), rect.size.x, 0, p_base_color, p_outline_size, p_outline_color, p_font_shadow_color, p_shadow_outline_size, p_shadow_ofs, r_processed_glyphs);
+ _draw_line(frame, j, p_ofs + rect.position + off + Vector2(0, frame->lines[j].offset.y), rect.size.x, 0, p_base_color, p_outline_size, p_outline_color, p_font_shadow_color, p_shadow_outline_size, p_shadow_ofs, r_processed_glyphs, p_list, p_layer + 1);
}
idx++;
}
@@ -1239,7 +1240,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (ul_started && new_ul_color != ul_color_prev) {
float y_off = upos;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), ul_color, underline_width);
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_BACKGROUND, Transform2D(), ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, 0.0, ul_color);
ul_start = p_ofs + Vector2(off_step.x, off_step.y);
ul_color = new_ul_color;
ul_color_prev = new_ul_color;
@@ -1253,13 +1254,13 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
ul_started = false;
float y_off = upos;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), ul_color, underline_width);
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_BACKGROUND, Transform2D(), ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, 0.0, ul_color);
}
if (_find_hint(it, nullptr) && underline_hint) {
if (dot_ul_started && font_color != dot_ul_color_prev) {
float y_off = upos;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), dot_ul_color, underline_width, MAX(2.0, underline_width * 2));
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_BACKGROUND, Transform2D(), dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, MAX(2.0, underline_width * 2), dot_ul_color);
dot_ul_start = p_ofs + Vector2(off_step.x, off_step.y);
dot_ul_color_prev = font_color;
dot_ul_color = font_color;
@@ -1275,7 +1276,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
dot_ul_started = false;
float y_off = upos;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), dot_ul_color, underline_width, MAX(2.0, underline_width * 2));
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_BACKGROUND, Transform2D(), dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, MAX(2.0, underline_width * 2), dot_ul_color);
}
Color user_st_color = Color(0, 0, 0, 0);
if (_find_strikethrough(it, &user_st_color)) {
@@ -1289,7 +1290,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (st_started && new_st_color != st_color_prev) {
float y_off = -l_ascent + l_size.y / 2;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), st_color, underline_width);
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_FOREGROUND, Transform2D(), st_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, 0.0, st_color);
st_start = p_ofs + Vector2(off_step.x, off_step.y);
st_color = new_st_color;
st_color_prev = new_st_color;
@@ -1303,7 +1304,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
st_started = false;
float y_off = -l_ascent + l_size.y / 2;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), st_color, underline_width);
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_FOREGROUND, Transform2D(), st_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, 0.0, st_color);
}
}
if (step == DRAW_STEP_SHADOW_OUTLINE || step == DRAW_STEP_SHADOW || step == DRAW_STEP_OUTLINE || step == DRAW_STEP_TEXT) {
@@ -1436,27 +1437,25 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
Vector2 char_off = char_xform.get_origin();
Transform2D char_reverse_xform;
+ Transform2D char_final_xform;
if (step == DRAW_STEP_TEXT) {
if (selected && use_selected_font_color) {
font_color = theme_cache.font_selected_color;
}
char_reverse_xform.set_origin(-char_off);
- Transform2D char_final_xform = char_xform * char_reverse_xform;
- draw_set_transform_matrix(char_final_xform);
+ char_final_xform = char_xform * char_reverse_xform;
} else if (step == DRAW_STEP_SHADOW_OUTLINE || step == DRAW_STEP_SHADOW) {
font_color = font_shadow_color * Color(1, 1, 1, font_color.a);
char_reverse_xform.set_origin(-char_off - p_shadow_ofs);
- Transform2D char_final_xform = char_xform * char_reverse_xform;
+ char_final_xform = char_xform * char_reverse_xform;
char_final_xform.columns[2] += p_shadow_ofs;
- draw_set_transform_matrix(char_final_xform);
} else if (step == DRAW_STEP_OUTLINE) {
font_color = font_outline_color * Color(1, 1, 1, font_color.a);
char_reverse_xform.set_origin(-char_off);
- Transform2D char_final_xform = char_xform * char_reverse_xform;
- draw_set_transform_matrix(char_final_xform);
+ char_final_xform = char_xform * char_reverse_xform;
}
// Draw glyphs.
@@ -1468,16 +1467,16 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
visible_rect = _merge_or_copy_rect(visible_rect, Rect2i(fx_offset + char_off - Vector2i(0, l_ascent), Point2i(glyphs[i].advance, l_size.y)));
if (step == DRAW_STEP_TEXT) {
if (frid != RID()) {
- TS->font_draw_glyph(frid, ci, glyphs[i].font_size, fx_offset + char_off, gl, font_color);
+ TS->font_add_glyph_to_draw_list(frid, step, p_list, char_final_xform, 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, fx_offset + char_off, gl, font_color);
+ TS->draw_list_add_hexbox(p_list, first_layer + DRAW_STEP_TEXT, char_final_xform, fx_offset + char_off, gl, glyphs[i].font_size, 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);
+ TS->font_add_glyph_outline_to_draw_list(frid, step, p_list, char_final_xform, 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()) {
- TS->font_draw_glyph(frid, ci, glyphs[i].font_size, fx_offset + char_off + p_shadow_ofs, gl, font_color);
+ TS->font_add_glyph_to_draw_list(frid, step, p_list, char_final_xform, glyphs[i].font_size, fx_offset + char_off + p_shadow_ofs, gl, font_color);
} else if (step == DRAW_STEP_OUTLINE && frid != RID()) {
- TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, outline_size, fx_offset + char_off, gl, font_color);
+ TS->font_add_glyph_outline_to_draw_list(frid, step, p_list, char_final_xform, glyphs[i].font_size, outline_size, fx_offset + char_off, gl, font_color);
}
}
}
@@ -1488,24 +1487,23 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
ul_started = false;
float y_off = upos;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), ul_color, underline_width);
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_BACKGROUND, Transform2D(), ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, 0.0, ul_color);
}
if (dot_ul_started) {
dot_ul_started = false;
float y_off = upos;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), dot_ul_color, underline_width, MAX(2.0, underline_width * 2));
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_BACKGROUND, Transform2D(), dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, MAX(2.0, underline_width * 2), dot_ul_color);
}
if (st_started) {
st_started = false;
float y_off = -l_ascent + l_size.y / 2;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), st_color, underline_width);
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_FOREGROUND, Transform2D(), st_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, 0.0, st_color);
}
}
off_step.x += glyphs[i].advance;
}
- draw_set_transform_matrix(Transform2D());
}
// Draw boxes.
if (step == DRAW_STEP_BACKGROUND || step == DRAW_STEP_FOREGROUND) {
@@ -1522,7 +1520,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (last_color.a > 0.0) {
Vector2 rect_off = p_ofs + Vector2(box_start - theme_cache.text_highlight_h_padding, off_step.y - l_ascent - theme_cache.text_highlight_v_padding);
Vector2 rect_size = Vector2(off_step.x - box_start + 2 * theme_cache.text_highlight_h_padding, l_size.y + 2 * theme_cache.text_highlight_v_padding);
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(rect_off, rect_size), last_color);
+ TS->draw_list_add_rect(p_list, first_layer + step, Transform2D(), Rect2(rect_off, rect_size), true, last_color);
}
if (color.a > 0.0) {
box_start = off_step.x;
@@ -1534,7 +1532,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (last_color.a > 0.0) {
Vector2 rect_off = p_ofs + Vector2(box_start - theme_cache.text_highlight_h_padding, off_step.y - l_ascent - theme_cache.text_highlight_v_padding);
Vector2 rect_size = Vector2(off_step.x - box_start + 2 * theme_cache.text_highlight_h_padding, l_size.y + 2 * theme_cache.text_highlight_v_padding);
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(rect_off, rect_size), last_color);
+ TS->draw_list_add_rect(p_list, first_layer + step, Transform2D(), Rect2(rect_off, rect_size), true, last_color);
}
last_color = Color(0, 0, 0, 0);
}
@@ -1548,7 +1546,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (last_color.a > 0.0) {
Vector2 rect_off = p_ofs + Vector2(box_start - theme_cache.text_highlight_h_padding, off_step.y - l_ascent - theme_cache.text_highlight_v_padding);
Vector2 rect_size = Vector2(off_step.x - box_start + 2 * theme_cache.text_highlight_h_padding, l_size.y + 2 * theme_cache.text_highlight_v_padding);
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(rect_off, rect_size), last_color);
+ TS->draw_list_add_rect(p_list, first_layer + step, Transform2D(), Rect2(rect_off, rect_size), true, last_color);
}
}
if (step == DRAW_STEP_BACKGROUND) {
@@ -1557,7 +1555,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
Vector sel = TS->shaped_text_get_selection(rid, sel_start, sel_end);
for (int i = 0; i < sel.size(); i++) {
Rect2 rect = Rect2(sel[i].x + p_ofs.x + off.x, p_ofs.y + off.y - l_ascent, sel[i].y - sel[i].x, l_size.y); // Note: use "off" not "off_step", selection is relative to the line start.
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_bg);
+ TS->draw_list_add_rect(p_list, first_layer + step, Transform2D(), rect, true, selection_bg);
}
}
}
@@ -1566,19 +1564,19 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
ul_started = false;
float y_off = upos;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), ul_color, underline_width);
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_BACKGROUND, Transform2D(), ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, 0.0, ul_color);
}
if (dot_ul_started) {
dot_ul_started = false;
float y_off = upos;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), dot_ul_color, underline_width, MAX(2.0, underline_width * 2));
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_BACKGROUND, Transform2D(), dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, MAX(2.0, underline_width * 2), dot_ul_color);
}
if (st_started) {
st_started = false;
float y_off = -l_ascent + l_size.y / 2;
float underline_width = MAX(1.0, uth * theme_cache.base_scale);
- draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), st_color, underline_width);
+ TS->draw_list_add_line(p_list, first_layer + DRAW_STEP_FOREGROUND, Transform2D(), st_start + Vector2(0, y_off), p_ofs + Vector2(off_step.x, off_step.y + y_off), underline_width, 0.0, st_color);
}
}
}
@@ -2647,10 +2645,11 @@ void RichTextLabel::_notification(int p_what) {
// New cache draw.
Point2 ofs = text_rect.get_position() + Vector2(0, vbegin + main->lines[from_line].offset.y - vofs);
int processed_glyphs = 0;
+ RID draw_list = TS->create_draw_list();
while (ofs.y < size.height - v_limit && from_line < to_line) {
MutexLock lock(main->lines[from_line].text_buf->get_mutex());
- int drawn_lines = _draw_line(main, from_line, ofs, text_rect.size.x, vsep, theme_cache.default_color, theme_cache.outline_size, theme_cache.font_outline_color, theme_cache.font_shadow_color, theme_cache.shadow_outline_size, shadow_ofs, processed_glyphs);
+ int drawn_lines = _draw_line(main, from_line, ofs, text_rect.size.x, vsep, theme_cache.default_color, theme_cache.outline_size, theme_cache.font_outline_color, theme_cache.font_shadow_color, theme_cache.shadow_outline_size, shadow_ofs, processed_glyphs, draw_list, 0);
visible_line_count += drawn_lines;
if (drawn_lines > 0) {
visible_paragraph_count++;
@@ -2662,6 +2661,9 @@ void RichTextLabel::_notification(int p_what) {
scroll_visible = follow_vc_pos > 0;
vscroll->set_visible(follow_vc_pos > 0);
}
+ TS->draw_list_sort(draw_list);
+ TS->draw_list_draw(draw_list, ci, true);
+
if (has_focus() && get_tree()->is_accessibility_enabled()) {
RID ae;
if (keyboard_focus_frame && keyboard_focus_item) {
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 07fc3961da98..88ba3932e7a0 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -674,7 +674,7 @@ class RichTextLabel : public Control {
void _set_table_size(ItemTable *p_table, int p_available_width);
void _update_line_font(ItemFrame *p_frame, int p_line, const Ref &p_base_font, int p_base_font_size);
- int _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, float p_vsep, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs);
+ int _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, float p_vsep, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs, RID p_list, int p_layer);
float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, float p_vsep, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool p_table = false, bool p_meta = false);
void _accessibility_update_line(RID p_id, ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, float p_vsep);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 5d247e2f9c4c..810280bf7c86 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1324,6 +1324,8 @@ void TextEdit::_notification(int p_what) {
_draw_guidelines();
// Draw main text.
+ RID draw_list = TS->create_draw_list();
+
line_drawing_cache.clear();
int row_height = draw_placeholder ? placeholder_line_height + theme_cache.line_spacing : get_line_height();
int line = first_vis_line;
@@ -1398,18 +1400,18 @@ void TextEdit::_notification(int p_what) {
if (text.get_line_background_color(line).a > 0.0) {
if (rtl) {
- RS::get_singleton()->canvas_item_add_rect(text_ci, Rect2(size.width - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), text.get_line_background_color(line));
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_BACKGROUND, Transform2D(), Rect2(size.width - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), true, text.get_line_background_color(line));
} else {
- RS::get_singleton()->canvas_item_add_rect(text_ci, Rect2(xmargin_beg, ofs_y, xmargin_end - xmargin_beg, row_height), text.get_line_background_color(line));
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_BACKGROUND, Transform2D(), Rect2(xmargin_beg, ofs_y, xmargin_end - xmargin_beg, row_height), true, text.get_line_background_color(line));
}
}
// Draw current line highlight.
if (highlight_current_line && highlighted_lines.has(Pair(line, line_wrap_index))) {
if (rtl) {
- RS::get_singleton()->canvas_item_add_rect(text_ci, Rect2(size.width - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), theme_cache.current_line_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_BACKGROUND, Transform2D(), Rect2(size.width - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), true, theme_cache.current_line_color);
} else {
- RS::get_singleton()->canvas_item_add_rect(text_ci, Rect2(xmargin_beg, ofs_y, xmargin_end - xmargin_beg, row_height), theme_cache.current_line_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_BACKGROUND, Transform2D(), Rect2(xmargin_beg, ofs_y, xmargin_end - xmargin_beg, row_height), true, theme_cache.current_line_color);
}
}
@@ -1439,9 +1441,9 @@ void TextEdit::_notification(int p_what) {
int yofs = ofs_y + (row_height - tl->get_size().y) / 2;
if (theme_cache.outline_size > 0 && theme_cache.outline_color.a > 0) {
- tl->draw_outline(text_ci, Point2(gutter_offset, yofs), theme_cache.outline_size, theme_cache.outline_color);
+ tl->add_outline_to_draw_list(DRAW_STEP_TEXT_OUTLINE, draw_list, Transform2D(), Point2(gutter_offset, yofs), theme_cache.outline_size, theme_cache.outline_color);
}
- tl->draw(text_ci, Point2(gutter_offset, yofs), get_line_gutter_item_color(line, g));
+ tl->add_to_draw_list(DRAW_STEP_TEXT, draw_list, Transform2D(), Point2(gutter_offset, yofs), get_line_gutter_item_color(line, g));
} break;
case GUTTER_TYPE_ICON: {
const Ref icon = get_line_gutter_icon(line, g);
@@ -1469,7 +1471,7 @@ void TextEdit::_notification(int p_what) {
gutter_rect.position.x = size.width - gutter_rect.position.x - gutter_rect.size.x;
}
- icon->draw_rect(text_ci, gutter_rect, false, get_line_gutter_item_color(line, g));
+ TS->draw_list_add_texture(draw_list, DRAW_STEP_TEXT, Transform2D(), icon->get_rid(), gutter_rect, get_line_gutter_item_color(line, g));
} break;
case GUTTER_TYPE_CUSTOM: {
if (gutter.custom_draw_callback.is_valid()) {
@@ -1477,7 +1479,7 @@ void TextEdit::_notification(int p_what) {
if (rtl) {
gutter_rect.position.x = size.width - gutter_rect.position.x - gutter_rect.size.x;
}
- gutter.custom_draw_callback.call(line, g, Rect2(gutter_rect));
+ TS->draw_list_add_custom(draw_list, DRAW_STEP_TEXT, Transform2D(), gutter.custom_draw_callback.bind(line, g, Rect2(gutter_rect)));
}
} break;
}
@@ -1546,7 +1548,7 @@ void TextEdit::_notification(int p_what) {
if (rect.position.x + rect.size.x > xmargin_end) {
rect.size.x = xmargin_end - rect.position.x;
}
- RS::get_singleton()->canvas_item_add_rect(text_ci, rect, theme_cache.selection_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_BACKGROUND, Transform2D(), rect, true, theme_cache.selection_color);
}
}
}
@@ -1568,8 +1570,8 @@ void TextEdit::_notification(int p_what) {
} else if (rect.position.x + rect.size.x > xmargin_end) {
rect.size.x = xmargin_end - rect.position.x;
}
- RS::get_singleton()->canvas_item_add_rect(text_ci, rect, theme_cache.search_result_color);
- _draw_rect_unfilled(text_ci, rect, theme_cache.search_result_border_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_BACKGROUND, Transform2D(), rect, true, theme_cache.search_result_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_BACKGROUND_BORDER, Transform2D(), rect, false, theme_cache.search_result_border_color);
}
search_text_col = _get_column_pos_of_word(search_text, str, search_flags, search_text_col + search_text_len);
@@ -1592,7 +1594,7 @@ void TextEdit::_notification(int p_what) {
} else if (rect.position.x + rect.size.x > xmargin_end) {
rect.size.x = xmargin_end - rect.position.x;
}
- RS::get_singleton()->canvas_item_add_rect(text_ci, rect, theme_cache.word_highlighted_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_BACKGROUND, Transform2D(), rect, true, theme_cache.word_highlighted_color);
}
highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, highlighted_text_col + highlighted_text_len);
@@ -1619,7 +1621,7 @@ void TextEdit::_notification(int p_what) {
}
rect.position.y += std::ceil(TS->shaped_text_get_ascent(rid)) + std::ceil(theme_cache.font->get_underline_position(theme_cache.font_size));
rect.size.y = MAX(1, theme_cache.font->get_underline_thickness(theme_cache.font_size));
- RS::get_singleton()->canvas_item_add_rect(text_ci, rect, highlight_underline_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_BACKGROUND, Transform2D(), rect, true, highlight_underline_color);
}
lookup_symbol_word_col = _get_column_pos_of_word(lookup_symbol_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, lookup_symbol_word_col + lookup_symbol_word_len);
@@ -1637,33 +1639,16 @@ void TextEdit::_notification(int p_what) {
int first_visible_char = TS->shaped_text_get_range(rid).y;
int last_visible_char = TS->shaped_text_get_range(rid).x;
- float char_ofs = 0;
- if (theme_cache.outline_size > 0 && theme_cache.outline_color.a > 0) {
- for (int j = 0; j < gl_size; j++) {
- for (int k = 0; k < glyphs[j].repeat; k++) {
- if ((char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
- if (glyphs[j].font_rid != RID()) {
- TS->font_draw_glyph_outline(glyphs[j].font_rid, text_ci, glyphs[j].font_size, theme_cache.outline_size, Vector2(char_margin + char_ofs + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, theme_cache.outline_color);
- }
- }
- char_ofs += glyphs[j].advance;
- }
- if ((char_ofs + char_margin) >= xmargin_end) {
- break;
- }
- }
- char_ofs = 0;
- }
-
// Draw inline objects.
for (Dictionary k : object_keys) {
Rect2 col_rect = TS->shaped_text_get_object_rect(rid, k);
col_rect.position += Vector2(char_margin, ofs_y);
if (!clipped && (col_rect.position.x) >= xmargin_beg && (col_rect.position.x + col_rect.size.x) <= xmargin_end) {
- inline_object_drawer.call(k, col_rect);
+ TS->draw_list_add_custom(draw_list, DRAW_STEP_TEXT, Transform2D(), inline_object_drawer.bind(k, col_rect));
}
}
+ float char_ofs = 0;
for (int j = 0; j < gl_size; j++) {
for (const Pair &color_data : color_map) {
if (color_data.first <= glyphs[j].start) {
@@ -1699,7 +1684,7 @@ void TextEdit::_notification(int p_what) {
gl_color = _get_brace_mismatch_color();
}
Rect2 rect = Rect2(char_pos, ofs_y + theme_cache.font->get_underline_position(theme_cache.font_size), glyphs[j].advance * glyphs[j].repeat, MAX(theme_cache.font->get_underline_thickness(theme_cache.font_size) * theme_cache.base_scale, 1));
- RS::get_singleton()->canvas_item_add_rect(text_ci, rect, gl_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_BACKGROUND, Transform2D(), rect, true, gl_color);
}
if ((brace_match.close_match_line == line && brace_match.close_match_column == glyphs[j].start) ||
@@ -1708,18 +1693,18 @@ void TextEdit::_notification(int p_what) {
gl_color = _get_brace_mismatch_color();
}
Rect2 rect = Rect2(char_pos, ofs_y + theme_cache.font->get_underline_position(theme_cache.font_size), glyphs[j].advance * glyphs[j].repeat, MAX(theme_cache.font->get_underline_thickness(theme_cache.font_size) * theme_cache.base_scale, 1));
- RS::get_singleton()->canvas_item_add_rect(text_ci, rect, gl_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_BACKGROUND, Transform2D(), rect, true, gl_color);
}
}
}
if (draw_tabs && ((glyphs[j].flags & TextServer::GRAPHEME_IS_TAB) == TextServer::GRAPHEME_IS_TAB)) {
int yofs = (text_height - theme_cache.tab_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
- theme_cache.tab_icon->draw(text_ci, Point2(char_pos, ofs_y + yofs), gl_color);
+ TS->draw_list_add_texture(draw_list, DRAW_STEP_TEXT, Transform2D(), theme_cache.tab_icon->get_rid(), Rect2(Point2(char_pos, ofs_y + yofs), theme_cache.tab_icon->get_size()), gl_color);
} else if (draw_spaces && ((glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE) && ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL)) {
int yofs = (text_height - theme_cache.space_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
int xofs = (glyphs[j].advance * glyphs[j].repeat - theme_cache.space_icon->get_width()) / 2;
- theme_cache.space_icon->draw(text_ci, Point2(char_pos + xofs, ofs_y + yofs), gl_color);
+ TS->draw_list_add_texture(draw_list, DRAW_STEP_TEXT, Transform2D(), theme_cache.space_icon->get_rid(), Rect2(Point2(char_pos + xofs, ofs_y + yofs), theme_cache.space_icon->get_size()), gl_color);
}
}
@@ -1727,10 +1712,13 @@ void TextEdit::_notification(int p_what) {
for (int k = 0; k < glyphs[j].repeat; k++) {
if (!clipped && (char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
if (glyphs[j].font_rid != RID()) {
- TS->font_draw_glyph(glyphs[j].font_rid, text_ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color);
+ if (theme_cache.outline_size > 0 && theme_cache.outline_color.a > 0) {
+ TS->font_add_glyph_outline_to_draw_list(glyphs[j].font_rid, DRAW_STEP_TEXT_OUTLINE, draw_list, Transform2D(), glyphs[j].font_size, theme_cache.outline_size, Vector2(char_margin + char_ofs + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, theme_cache.outline_color);
+ }
+ TS->font_add_glyph_to_draw_list(glyphs[j].font_rid, DRAW_STEP_TEXT, draw_list, Transform2D(), glyphs[j].font_size, Vector2(char_margin + char_ofs + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color);
had_glyphs_drawn = true;
} else if (((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) && ((glyphs[j].flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) != TextServer::GRAPHEME_IS_EMBEDDED_OBJECT)) {
- TS->draw_hex_code_box(text_ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color);
+ TS->draw_list_add_hexbox(draw_list, DRAW_STEP_TEXT, Transform2D(), Vector2(char_margin + char_ofs + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, glyphs[j].font_size, gl_color);
had_glyphs_drawn = true;
}
}
@@ -1761,7 +1749,7 @@ void TextEdit::_notification(int p_what) {
int yofs = (text_height - _get_folded_eol_icon()->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
Color eol_color = _get_code_folding_color();
eol_color.a = 1;
- _get_folded_eol_icon()->draw(text_ci, Point2(xofs, ofs_y + yofs), eol_color);
+ TS->draw_list_add_texture(draw_list, DRAW_STEP_TEXT, Transform2D(), _get_folded_eol_icon()->get_rid(), Rect2(Point2(xofs, ofs_y + yofs), _get_folded_eol_icon()->get_size()), eol_color);
}
}
@@ -1814,20 +1802,21 @@ void TextEdit::_notification(int p_what) {
}
ts_caret.t_caret.position += Vector2(char_margin, ofs_y);
if (overtype_mode) {
- RS::get_singleton()->canvas_item_add_rect(text_ci, ts_caret.t_caret, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), ts_caret.t_caret, true, theme_cache.caret_color);
+
} else {
- _draw_rect_unfilled(text_ci, ts_caret.t_caret, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), ts_caret.t_caret, false, theme_cache.caret_color);
}
if (ts_caret.l_caret != Rect2() && ts_caret.l_dir != ts_caret.t_dir) {
// Draw split caret (leading part).
ts_caret.l_caret.position += Vector2(char_margin, ofs_y);
ts_caret.l_caret.size.x = caret_width;
- RS::get_singleton()->canvas_item_add_rect(text_ci, ts_caret.l_caret, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), ts_caret.l_caret, true, theme_cache.caret_color);
// Draw extra direction marker on top of split caret.
float d = (ts_caret.l_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3;
Rect2 trect = Rect2(ts_caret.l_caret.position.x + d * caret_width, ts_caret.l_caret.position.y + ts_caret.l_caret.size.y - caret_width, 3 * caret_width, caret_width);
- RS::get_singleton()->canvas_item_add_rect(text_ci, trect, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), trect, true, theme_cache.caret_color);
}
} else { // End of the line.
if (gl_size > 0) {
@@ -1853,9 +1842,9 @@ void TextEdit::_notification(int p_what) {
ts_caret.l_caret.position.x -= ts_caret.l_caret.size.x;
}
if (overtype_mode) {
- RS::get_singleton()->canvas_item_add_rect(text_ci, ts_caret.l_caret, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), ts_caret.l_caret, true, theme_cache.caret_color);
} else {
- _draw_rect_unfilled(text_ci, ts_caret.l_caret, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), ts_caret.l_caret, false, theme_cache.caret_color);
}
}
} else {
@@ -1864,28 +1853,28 @@ void TextEdit::_notification(int p_what) {
// Draw extra marker on top of mid caret.
Rect2 trect = Rect2(ts_caret.l_caret.position.x - 2.5 * caret_width, ts_caret.l_caret.position.y, 6 * caret_width, caret_width);
trect.position += Vector2(char_margin, ofs_y);
- RS::get_singleton()->canvas_item_add_rect(text_ci, trect, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), trect, true, theme_cache.caret_color);
} else if (ts_caret.l_caret != Rect2() && ts_caret.t_caret != Rect2() && ts_caret.l_dir != ts_caret.t_dir) {
// Draw extra direction marker on top of split caret.
float d = (ts_caret.l_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3;
Rect2 trect = Rect2(ts_caret.l_caret.position.x + d * caret_width, ts_caret.l_caret.position.y + ts_caret.l_caret.size.y - caret_width, 3 * caret_width, caret_width);
trect.position += Vector2(char_margin, ofs_y);
- RS::get_singleton()->canvas_item_add_rect(text_ci, trect, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), trect, true, theme_cache.caret_color);
d = (ts_caret.t_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3;
trect = Rect2(ts_caret.t_caret.position.x + d * caret_width, ts_caret.t_caret.position.y, 3 * caret_width, caret_width);
trect.position += Vector2(char_margin, ofs_y);
- RS::get_singleton()->canvas_item_add_rect(text_ci, trect, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), trect, true, theme_cache.caret_color);
}
ts_caret.l_caret.position += Vector2(char_margin, ofs_y);
ts_caret.l_caret.size.x = caret_width;
- RS::get_singleton()->canvas_item_add_rect(text_ci, ts_caret.l_caret, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), ts_caret.l_caret, true, theme_cache.caret_color);
ts_caret.t_caret.position += Vector2(char_margin, ofs_y);
ts_caret.t_caret.size.x = caret_width;
- RS::get_singleton()->canvas_item_add_rect(text_ci, ts_caret.t_caret, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), ts_caret.t_caret, true, theme_cache.caret_color);
}
}
}
@@ -1906,7 +1895,7 @@ void TextEdit::_notification(int p_what) {
rect.size.x = xmargin_end - rect.position.x;
}
rect.size.y = caret_width;
- RS::get_singleton()->canvas_item_add_rect(text_ci, rect, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), rect, true, theme_cache.caret_color);
carets.write[c].draw_pos.x = rect.position.x;
}
}
@@ -1925,7 +1914,7 @@ void TextEdit::_notification(int p_what) {
rect.size.x = xmargin_end - rect.position.x;
}
rect.size.y = caret_width * 3;
- RS::get_singleton()->canvas_item_add_rect(text_ci, rect, theme_cache.caret_color);
+ TS->draw_list_add_rect(draw_list, DRAW_STEP_FOREGROUND, Transform2D(), rect, true, theme_cache.caret_color);
carets.write[c].draw_pos.x = rect.position.x;
}
}
@@ -1938,6 +1927,8 @@ void TextEdit::_notification(int p_what) {
line_drawing_cache[line] = cache_entry;
}
}
+ TS->draw_list_sort(draw_list);
+ TS->draw_list_draw(draw_list, text_ci, true);
if (has_focus()) {
_update_ime_window_position();
@@ -9242,26 +9233,6 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
emit_signal(SNAME("lines_edited_from"), p_to_line, p_from_line);
}
-void TextEdit::_draw_rect_unfilled(RID p_canvas_item, const Rect2 &p_rect, const Color &p_color, real_t p_width, bool p_antialiased) const {
- Rect2 rect = p_rect.abs();
-
- if (p_width >= rect.size.width || p_width >= rect.size.height) {
- RS::get_singleton()->canvas_item_add_rect(p_canvas_item, rect.grow(0.5f * p_width), p_color, p_antialiased);
- } else {
- Vector points;
- points.resize(5);
- points.write[0] = rect.position;
- points.write[1] = rect.position + Vector2(rect.size.x, 0);
- points.write[2] = rect.position + rect.size;
- points.write[3] = rect.position + Vector2(0, rect.size.y);
- points.write[4] = rect.position;
-
- Vector colors = { p_color };
-
- RS::get_singleton()->canvas_item_add_polyline(p_canvas_item, points, colors, p_width, p_antialiased);
- }
-}
-
TextEdit::TextEdit(const String &p_placeholder) {
placeholder_data_buf.instantiate();
carets.push_back(Caret());
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 5517290224c7..12902e43e2e5 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -122,6 +122,15 @@ class TextEdit : public Control {
};
private:
+ enum TEDrawStep {
+ DRAW_STEP_BACKGROUND,
+ DRAW_STEP_BACKGROUND_BORDER,
+ DRAW_STEP_TEXT_OUTLINE,
+ DRAW_STEP_TEXT,
+ DRAW_STEP_FOREGROUND,
+ DRAW_STEP_MAX,
+ };
+
struct GutterInfo {
GutterType type = GutterType::GUTTER_TYPE_STRING;
String name = "";
@@ -658,9 +667,6 @@ class TextEdit : public Control {
RID accessibility_text_root_element_nl;
- // FIXME: Helper method to draw unfilled rects, should be moved to RenderingServer.
- void _draw_rect_unfilled(RID p_canvas_item, const Rect2 &p_rect, const Color &p_color, real_t p_width = -1.0, bool p_antialiased = false) const;
-
/* Theme. */
Ref _get_current_stylebox() const;
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index a74359e25fd4..a7dc2b416023 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -109,6 +109,9 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw", "canvas", "pos", "color", "oversampling"), &TextLine::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("draw_outline", "canvas", "pos", "outline_size", "color", "oversampling"), &TextLine::draw_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("add_to_draw_list", "layer", "list", "transform", "pos", "color", "oversampling"), &TextLine::add_to_draw_list, DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("add_outline_to_draw_list", "layer", "list", "transform", "pos", "outline_size", "color", "oversampling"), &TextLine::add_outline_to_draw_list, DEFVAL(1), DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+
ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextLine::hit_test);
}
@@ -432,7 +435,7 @@ void TextLine::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color, fl
ofs.x += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.y - ofs.y);
}
- return TS->shaped_text_draw(rid, p_canvas, ofs, clip_l, clip_l + width, p_color, p_oversampling);
+ TS->shaped_text_draw(rid, p_canvas, ofs, clip_l, clip_l + width, p_color, p_oversampling);
}
void TextLine::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color, float p_oversampling) const {
@@ -479,7 +482,101 @@ void TextLine::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_si
ofs.x += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.y - ofs.y);
}
- return TS->shaped_text_draw_outline(rid, p_canvas, ofs, clip_l, clip_l + width, p_outline_size, p_color, p_oversampling);
+ TS->shaped_text_draw_outline(rid, p_canvas, ofs, clip_l, clip_l + width, p_outline_size, p_color, p_oversampling);
+}
+
+void TextLine::add_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, const Color &p_color, float p_oversampling) const {
+ _shape();
+
+ Vector2 ofs = p_pos;
+
+ float length = TS->shaped_text_get_width(rid);
+ if (width > 0) {
+ switch (alignment) {
+ case HORIZONTAL_ALIGNMENT_FILL:
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ break;
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ if (length <= width) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(rid) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
+ }
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
+ } break;
+ }
+ }
+
+ float clip_l;
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y += TS->shaped_text_get_ascent(rid);
+ clip_l = MAX(0, p_pos.x - ofs.x);
+ } else {
+ ofs.x += TS->shaped_text_get_ascent(rid);
+ clip_l = MAX(0, p_pos.y - ofs.y);
+ }
+ TS->shaped_text_add_to_draw_list(rid, p_layer, p_list, p_transform, ofs, clip_l, clip_l + width, p_color, p_oversampling);
+}
+
+void TextLine::add_outline_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, int p_outline_size, const Color &p_color, float p_oversampling) const {
+ _shape();
+
+ Vector2 ofs = p_pos;
+
+ float length = TS->shaped_text_get_width(rid);
+ if (width > 0) {
+ switch (alignment) {
+ case HORIZONTAL_ALIGNMENT_FILL:
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ break;
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ if (length <= width) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(rid) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
+ }
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
+ } break;
+ }
+ }
+
+ float clip_l;
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y += TS->shaped_text_get_ascent(rid);
+ clip_l = MAX(0, p_pos.x - ofs.x);
+ } else {
+ ofs.x += TS->shaped_text_get_ascent(rid);
+ clip_l = MAX(0, p_pos.y - ofs.y);
+ }
+ TS->shaped_text_add_outline_to_draw_list(rid, p_layer, p_list, p_transform, ofs, clip_l, clip_l + width, p_outline_size, p_color, p_oversampling);
}
int TextLine::hit_test(float p_coords) const {
diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h
index 6c9f548d9ddb..3dec85eac8ff 100644
--- a/scene/resources/text_line.h
+++ b/scene/resources/text_line.h
@@ -119,6 +119,9 @@ class TextLine : public RefCounted {
void draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
void draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+ void add_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+ void add_outline_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+
int hit_test(float p_coords) const;
TextLine(const String &p_text, const Ref &p_font, int p_font_size, const String &p_language = "", TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 35d8af36cb3e..f22bbe8eabbf 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -149,6 +149,15 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_dropcap", "canvas", "pos", "color", "oversampling"), &TextParagraph::draw_dropcap, DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("draw_dropcap_outline", "canvas", "pos", "outline_size", "color", "oversampling"), &TextParagraph::draw_dropcap_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("add_to_draw_list", "layer", "list", "transform", "pos", "color", "dc_color", "oversampling"), &TextParagraph::add_to_draw_list, DEFVAL(Color(1, 1, 1)), DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("add_outline_to_draw_list", "layer", "list", "transform", "pos", "outline_size", "color", "dc_color", "oversampling"), &TextParagraph::add_outline_to_draw_list, DEFVAL(1), DEFVAL(Color(1, 1, 1)), DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+
+ ClassDB::bind_method(D_METHOD("add_line_to_draw_list", "layer", "list", "transform", "pos", "line", "color", "oversampling"), &TextParagraph::add_line_to_draw_list, DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("add_line_outline_to_draw_list", "layer", "list", "transform", "pos", "line", "outline_size", "color", "oversampling"), &TextParagraph::add_line_outline_to_draw_list, DEFVAL(1), DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+
+ ClassDB::bind_method(D_METHOD("add_dropcap_to_draw_list", "layer", "list", "transform", "pos", "color", "oversampling"), &TextParagraph::add_dropcap_to_draw_list, DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("add_dropcap_outline_to_draw_list", "layer", "list", "transform", "pos", "outline_size", "color", "oversampling"), &TextParagraph::add_dropcap_outline_to_draw_list, DEFVAL(1), DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+
ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextParagraph::hit_test);
}
@@ -1039,6 +1048,211 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
}
}
+void TextParagraph::add_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, const Color &p_color, const Color &p_dc_color, float p_oversampling) const {
+ _THREAD_SAFE_METHOD_
+
+ _shape_lines();
+ Vector2 ofs = p_pos;
+ float h_offset = 0.f;
+ if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x;
+ } else {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y;
+ }
+
+ if (h_offset > 0) {
+ // Draw dropcap.
+ Vector2 dc_off = ofs;
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ dc_off.x += width - h_offset;
+ } else {
+ dc_off.y += width - h_offset;
+ }
+ }
+ TS->shaped_text_add_to_draw_list(dropcap_rid, p_layer, p_list, p_transform, dc_off + Vector2(0, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.size.y + dropcap_margins.position.y / 2), -1, -1, p_dc_color, p_oversampling);
+ }
+
+ int lines_visible = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
+
+ for (int i = 0; i < lines_visible; i++) {
+ float l_width = width;
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x = p_pos.x;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[i]);
+ if (i <= dropcap_lines) {
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
+ ofs.x -= h_offset;
+ }
+ l_width -= h_offset;
+ }
+ } else {
+ ofs.y = p_pos.y;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[i]);
+ if (i <= dropcap_lines) {
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
+ ofs.y -= h_offset;
+ }
+ l_width -= h_offset;
+ }
+ }
+ float line_width = TS->shaped_text_get_width(lines_rid[i]);
+ if (width > 0) {
+ switch (alignment) {
+ case HORIZONTAL_ALIGNMENT_FILL:
+ if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - line_width;
+ } else {
+ ofs.y += l_width - line_width;
+ }
+ }
+ break;
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ break;
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ if (line_width <= l_width) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((l_width - line_width) / 2.0);
+ } else {
+ ofs.y += Math::floor((l_width - line_width) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - line_width;
+ } else {
+ ofs.y += l_width - line_width;
+ }
+ }
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - line_width;
+ } else {
+ ofs.y += l_width - line_width;
+ }
+ } break;
+ }
+ }
+ float clip_l;
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ clip_l = MAX(0, p_pos.x - ofs.x);
+ } else {
+ clip_l = MAX(0, p_pos.y - ofs.y);
+ }
+ TS->shaped_text_add_to_draw_list(lines_rid[i], p_layer, p_list, p_transform, ofs, clip_l, clip_l + l_width, p_color, p_oversampling);
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x = p_pos.x;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
+ } else {
+ ofs.y = p_pos.y;
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
+ }
+ }
+}
+
+void TextParagraph::add_outline_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, int p_outline_size, const Color &p_color, const Color &p_dc_color, float p_oversampling) const {
+ _THREAD_SAFE_METHOD_
+
+ _shape_lines();
+ Vector2 ofs = p_pos;
+
+ float h_offset = 0.f;
+ if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x;
+ } else {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y;
+ }
+
+ if (h_offset > 0) {
+ // Draw dropcap.
+ Vector2 dc_off = ofs;
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ dc_off.x += width - h_offset;
+ } else {
+ dc_off.y += width - h_offset;
+ }
+ }
+ TS->shaped_text_add_outline_to_draw_list(dropcap_rid, p_layer, p_list, p_transform, dc_off + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_dc_color, p_oversampling);
+ }
+
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
+ float l_width = width;
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x = p_pos.x;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[i]);
+ if (i <= dropcap_lines) {
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
+ ofs.x -= h_offset;
+ }
+ l_width -= h_offset;
+ }
+ } else {
+ ofs.y = p_pos.y;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[i]);
+ if (i <= dropcap_lines) {
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
+ ofs.y -= h_offset;
+ }
+ l_width -= h_offset;
+ }
+ }
+ float length = TS->shaped_text_get_width(lines_rid[i]);
+ if (width > 0) {
+ switch (alignment) {
+ case HORIZONTAL_ALIGNMENT_FILL:
+ if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ }
+ break;
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ break;
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ if (length <= l_width) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((l_width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((l_width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ }
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ } break;
+ }
+ }
+ float clip_l;
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ clip_l = MAX(0, p_pos.x - ofs.x);
+ } else {
+ clip_l = MAX(0, p_pos.y - ofs.y);
+ }
+ TS->shaped_text_add_outline_to_draw_list(lines_rid[i], p_layer, p_list, p_transform, ofs, clip_l, clip_l + l_width, p_outline_size, p_color, p_oversampling);
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x = p_pos.x;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
+ } else {
+ ofs.y = p_pos.y;
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
+ }
+ }
+}
+
int TextParagraph::hit_test(const Point2 &p_coords) const {
_THREAD_SAFE_METHOD_
@@ -1121,6 +1335,54 @@ void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int
}
}
+void TextParagraph::add_dropcap_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, const Color &p_color, float p_oversampling) const {
+ _THREAD_SAFE_METHOD_
+
+ Vector2 ofs = p_pos;
+ float h_offset = 0.f;
+ if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x;
+ } else {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y;
+ }
+
+ if (h_offset > 0) {
+ // Draw dropcap.
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - h_offset;
+ } else {
+ ofs.y += width - h_offset;
+ }
+ }
+ TS->shaped_text_add_to_draw_list(dropcap_rid, p_layer, p_list, p_transform, ofs + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_color, p_oversampling);
+ }
+}
+
+void TextParagraph::add_dropcap_outline_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, int p_outline_size, const Color &p_color, float p_oversampling) const {
+ _THREAD_SAFE_METHOD_
+
+ Vector2 ofs = p_pos;
+ float h_offset = 0.f;
+ if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x;
+ } else {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y;
+ }
+
+ if (h_offset > 0) {
+ // Draw dropcap.
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - h_offset;
+ } else {
+ ofs.y += width - h_offset;
+ }
+ }
+ TS->shaped_text_add_outline_to_draw_list(dropcap_rid, p_layer, p_list, p_transform, ofs + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_color, p_oversampling);
+ }
+}
+
void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, const Color &p_color, float p_oversampling) const {
_THREAD_SAFE_METHOD_
@@ -1152,6 +1414,37 @@ void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_
return TS->shaped_text_draw_outline(lines_rid[p_line], p_canvas, ofs, -1, -1, p_outline_size, p_color, p_oversampling);
}
+void TextParagraph::add_line_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, int p_line, const Color &p_color, float p_oversampling) const {
+ _THREAD_SAFE_METHOD_
+
+ _shape_lines();
+ ERR_FAIL_COND(p_line < 0 || p_line >= (int)lines_rid.size());
+
+ Vector2 ofs = p_pos;
+
+ if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]);
+ } else {
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]);
+ }
+ return TS->shaped_text_add_to_draw_list(lines_rid[p_line], p_layer, p_list, p_transform, ofs, -1, -1, p_color, p_oversampling);
+}
+
+void TextParagraph::add_line_outline_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, int p_line, int p_outline_size, const Color &p_color, float p_oversampling) const {
+ _THREAD_SAFE_METHOD_
+
+ _shape_lines();
+ ERR_FAIL_COND(p_line < 0 || p_line >= (int)lines_rid.size());
+
+ Vector2 ofs = p_pos;
+ if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]);
+ } else {
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]);
+ }
+ return TS->shaped_text_add_outline_to_draw_list(lines_rid[p_line], p_layer, p_list, p_transform, ofs, -1, -1, p_outline_size, p_color, p_oversampling);
+}
+
TextParagraph::TextParagraph(const String &p_text, const Ref &p_font, int p_font_size, const String &p_language, float p_width, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
rid = TS->create_shaped_text(p_direction, p_orientation);
if (p_font.is_valid()) {
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index 5a5a2c6d2e79..e4425f4f62be 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -169,6 +169,15 @@ class TextParagraph : public RefCounted {
void draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
void draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+ void add_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, const Color &p_color = Color(1, 1, 1), const Color &p_dc_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+ void add_outline_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1), const Color &p_dc_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+
+ void add_line_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, int p_line, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+ void add_line_outline_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, int p_line, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+
+ void add_dropcap_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+ void add_dropcap_outline_to_draw_list(int p_layer, RID p_list, const Transform2D &p_transform, const Vector2 &p_pos, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+
int hit_test(const Point2 &p_coords) const;
bool is_dirty();
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index bee17012578f..af660f0f515b 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -146,8 +146,9 @@ void register_server_types() {
GDREGISTER_CLASS(TextServerExtension);
GDREGISTER_CLASS(TextServerDummy);
- GDREGISTER_NATIVE_STRUCT(Glyph, "int start = -1;int end = -1;uint8_t count = 0;uint8_t repeat = 1;uint16_t flags = 0;float x_off = 0.f;float y_off = 0.f;float advance = 0.f;RID font_rid;int font_size = 0;int32_t index = 0");
- GDREGISTER_NATIVE_STRUCT(CaretInfo, "Rect2 leading_caret;Rect2 trailing_caret;TextServer::Direction leading_direction;TextServer::Direction trailing_direction");
+ GDREGISTER_NATIVE_STRUCT(Glyph, "int start = -1;int end = -1;uint8_t count = 0;uint8_t repeat = 1;uint16_t flags = 0;float x_off = 0.f;float y_off = 0.f;float advance = 0.f;RID font_rid;int font_size = 0;int32_t index = 0;int span_index = -1");
+ GDREGISTER_NATIVE_STRUCT(CaretInfo, "Rect2 leading_caret;Rect2 trailing_caret;TextServer::Direction leading_direction = TextServer::DIRECTION_AUTO;TextServer::Direction trailing_direction = TextServer::DIRECTION_AUTO");
+ GDREGISTER_NATIVE_STRUCT(GlyphDrawCall, "TextServer::DrawCallType draw_type = TextServer::DRAW_CALL_NULL;int16_t layer = 0;Transform2D transform;RID texture;Rect2 dst_rect;Rect2 src_rect;Color modulate;Variant data;");
Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton(), "TextServerManager"));
diff --git a/servers/text/text_server.cpp b/servers/text/text_server.cpp
index 117dc5073fe0..194fd8d0cb3a 100644
--- a/servers/text/text_server.cpp
+++ b/servers/text/text_server.cpp
@@ -375,6 +375,9 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("font_draw_glyph", "font_rid", "canvas", "size", "pos", "index", "color", "oversampling"), &TextServer::font_draw_glyph, DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("font_draw_glyph_outline", "font_rid", "canvas", "size", "outline_size", "pos", "index", "color", "oversampling"), &TextServer::font_draw_glyph_outline, DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("font_add_glyph_to_draw_list", "font_rid", "layer", "list", "transform", "size", "pos", "index", "color", "oversampling"), &TextServer::font_add_glyph_to_draw_list, DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("font_add_glyph_outline_to_draw_list", "font_rid", "layer", "list", "transform", "size", "outline_size", "pos", "index", "color", "oversampling"), &TextServer::font_add_glyph_outline_to_draw_list, DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+
ClassDB::bind_method(D_METHOD("font_is_language_supported", "font_rid", "language"), &TextServer::font_is_language_supported);
ClassDB::bind_method(D_METHOD("font_set_language_support_override", "font_rid", "language", "supported"), &TextServer::font_set_language_support_override);
ClassDB::bind_method(D_METHOD("font_get_language_support_override", "font_rid", "language"), &TextServer::font_get_language_support_override);
@@ -401,6 +404,20 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_hex_code_box_size", "size", "index"), &TextServer::get_hex_code_box_size);
ClassDB::bind_method(D_METHOD("draw_hex_code_box", "canvas", "size", "pos", "index", "color"), &TextServer::draw_hex_code_box);
+ /* Draw list interface */
+
+ ClassDB::bind_method(D_METHOD("create_draw_list"), &TextServer::create_draw_list);
+ ClassDB::bind_method(D_METHOD("draw_list_sort", "list"), &TextServer::draw_list_sort);
+ ClassDB::bind_method(D_METHOD("draw_list_reserve", "list", "count"), &TextServer::draw_list_reserve);
+
+ ClassDB::bind_method(D_METHOD("draw_list_add_hexbox", "list", "layer", "transform", "pos", "index", "size", "modulate"), &TextServer::draw_list_add_hexbox);
+ ClassDB::bind_method(D_METHOD("draw_list_add_rect", "list", "layer", "transform", "rect", "filled", "modulate"), &TextServer::draw_list_add_rect);
+ ClassDB::bind_method(D_METHOD("draw_list_add_line", "list", "layer", "transform", "start", "end", "width", "dash", "modulate"), &TextServer::draw_list_add_line);
+ ClassDB::bind_method(D_METHOD("draw_list_add_texture", "list", "layer", "transform", "texture", "rect", "modulate"), &TextServer::draw_list_add_texture);
+ ClassDB::bind_method(D_METHOD("draw_list_add_custom", "list", "layer", "transform", "callback"), &TextServer::draw_list_add_custom);
+
+ ClassDB::bind_method(D_METHOD("draw_list_draw", "list", "ci", "free"), &TextServer::draw_list_draw, DEFVAL(false));
+
/* Shaped text buffer interface */
ClassDB::bind_method(D_METHOD("create_shaped_text", "direction", "orientation"), &TextServer::create_shaped_text, DEFVAL(DIRECTION_AUTO), DEFVAL(ORIENTATION_HORIZONTAL));
@@ -509,6 +526,9 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("shaped_text_draw", "shaped", "canvas", "pos", "clip_l", "clip_r", "color", "oversampling"), &TextServer::shaped_text_draw, DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("shaped_text_draw_outline", "shaped", "canvas", "pos", "clip_l", "clip_r", "outline_size", "color", "oversampling"), &TextServer::shaped_text_draw_outline, DEFVAL(-1), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("shaped_text_add_to_draw_list", "shaped", "layer", "list", "transform", "pos", "clip_l", "clip_r", "color", "oversampling"), &TextServer::shaped_text_add_to_draw_list, DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("shaped_text_add_outline_to_draw_list", "shaped", "layer", "list", "transform", "pos", "clip_l", "clip_r", "outline_size", "color", "oversampling"), &TextServer::shaped_text_add_outline_to_draw_list, DEFVAL(-1), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1, 1, 1)), DEFVAL(0.0));
+
ClassDB::bind_method(D_METHOD("shaped_text_get_dominant_direction_in_range", "shaped", "start", "end"), &TextServer::shaped_text_get_dominant_direction_in_range);
#ifndef DISABLE_DEPRECATED
@@ -638,6 +658,17 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE);
+ /* DrawCallType */
+ BIND_ENUM_CONSTANT(DRAW_CALL_NULL);
+ BIND_ENUM_CONSTANT(DRAW_CALL_NORMAL);
+ BIND_ENUM_CONSTANT(DRAW_CALL_MSDF);
+ BIND_ENUM_CONSTANT(DRAW_CALL_LCD);
+ BIND_ENUM_CONSTANT(DRAW_CALL_HEX);
+ BIND_ENUM_CONSTANT(DRAW_CALL_LINE);
+ BIND_ENUM_CONSTANT(DRAW_CALL_RECT);
+ BIND_ENUM_CONSTANT(DRAW_CALL_IMAGE);
+ BIND_ENUM_CONSTANT(DRAW_CALL_CUSTOM);
+
/* Feature */
BIND_ENUM_CONSTANT(FEATURE_SIMPLE_LAYOUT);
BIND_ENUM_CONSTANT(FEATURE_BIDI_LAYOUT);
@@ -1922,6 +1953,196 @@ void TextServer::shaped_text_draw_outline(const RID &p_shaped, const RID &p_canv
}
}
+void TextServer::shaped_text_add_to_draw_list(const RID &p_shaped, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, const Vector2 &p_pos, double p_clip_l, double p_clip_r, const Color &p_color, float p_oversampling) const {
+ TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
+ bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped);
+
+ bool rtl = shaped_text_get_direction(p_shaped) == DIRECTION_RTL;
+
+ int ellipsis_pos = shaped_text_get_ellipsis_pos(p_shaped);
+ int trim_pos = shaped_text_get_trim_pos(p_shaped);
+
+ const Glyph *ellipsis_glyphs = shaped_text_get_ellipsis_glyphs(p_shaped);
+ int ellipsis_gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped);
+
+ int v_size = shaped_text_get_glyph_count(p_shaped);
+ const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
+
+ Vector2 ofs;
+ // Draw RTL ellipsis string when needed.
+ if (rtl && ellipsis_pos >= 0) {
+ for (int i = ellipsis_gl_size - 1; i >= 0; i--) {
+ for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) {
+ font_add_glyph_to_draw_list(ellipsis_glyphs[i].font_rid, p_layer, p_list, p_transform, ellipsis_glyphs[i].font_size, ofs + p_pos + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color, p_oversampling);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += ellipsis_glyphs[i].advance;
+ } else {
+ ofs.y += ellipsis_glyphs[i].advance;
+ }
+ }
+ }
+ }
+ // Draw at the baseline.
+ for (int i = 0; i < v_size; i++) {
+ if (trim_pos >= 0) {
+ if (rtl) {
+ if (i < trim_pos) {
+ continue;
+ }
+ } else {
+ if (i >= trim_pos) {
+ break;
+ }
+ }
+ }
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ if (p_clip_r > 0) {
+ // Clip right / bottom.
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ if (ofs.x + glyphs[i].advance > p_clip_r) {
+ return;
+ }
+ } else {
+ if (ofs.y + glyphs[i].advance > p_clip_r) {
+ return;
+ }
+ }
+ }
+ if (p_clip_l > 0) {
+ // Clip left / top.
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ if (ofs.x < p_clip_l) {
+ ofs.x += glyphs[i].advance;
+ continue;
+ }
+ } else {
+ if (ofs.y < p_clip_l) {
+ ofs.y += glyphs[i].advance;
+ continue;
+ }
+ }
+ }
+
+ if (glyphs[i].font_rid != RID()) {
+ font_add_glyph_to_draw_list(glyphs[i].font_rid, p_layer, p_list, p_transform, glyphs[i].font_size, ofs + p_pos + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color, p_oversampling);
+ } else if (hex_codes && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL) && ((glyphs[i].flags & GRAPHEME_IS_EMBEDDED_OBJECT) != GRAPHEME_IS_EMBEDDED_OBJECT)) {
+ draw_list_add_hexbox(p_list, p_layer, p_transform, ofs + p_pos + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, glyphs[i].font_size, p_color);
+ }
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += glyphs[i].advance;
+ } else {
+ ofs.y += glyphs[i].advance;
+ }
+ }
+ }
+ // Draw LTR ellipsis string when needed.
+ if (!rtl && ellipsis_pos >= 0) {
+ for (int i = 0; i < ellipsis_gl_size; i++) {
+ for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) {
+ font_add_glyph_to_draw_list(ellipsis_glyphs[i].font_rid, p_layer, p_list, p_transform, ellipsis_glyphs[i].font_size, ofs + p_pos + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color, p_oversampling);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += ellipsis_glyphs[i].advance;
+ } else {
+ ofs.y += ellipsis_glyphs[i].advance;
+ }
+ }
+ }
+ }
+}
+
+void TextServer::shaped_text_add_outline_to_draw_list(const RID &p_shaped, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, const Vector2 &p_pos, double p_clip_l, double p_clip_r, int64_t p_outline_size, const Color &p_color, float p_oversampling) const {
+ TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
+
+ bool rtl = (shaped_text_get_inferred_direction(p_shaped) == DIRECTION_RTL);
+
+ int ellipsis_pos = shaped_text_get_ellipsis_pos(p_shaped);
+ int trim_pos = shaped_text_get_trim_pos(p_shaped);
+
+ const Glyph *ellipsis_glyphs = shaped_text_get_ellipsis_glyphs(p_shaped);
+ int ellipsis_gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped);
+
+ int v_size = shaped_text_get_glyph_count(p_shaped);
+ const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
+
+ Vector2 ofs;
+ // Draw RTL ellipsis string when needed.
+ if (rtl && ellipsis_pos >= 0) {
+ for (int i = ellipsis_gl_size - 1; i >= 0; i--) {
+ for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) {
+ font_add_glyph_outline_to_draw_list(ellipsis_glyphs[i].font_rid, p_layer, p_list, p_transform, ellipsis_glyphs[i].font_size, p_outline_size, ofs + p_pos + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color, p_oversampling);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += ellipsis_glyphs[i].advance;
+ } else {
+ ofs.y += ellipsis_glyphs[i].advance;
+ }
+ }
+ }
+ }
+ // Draw at the baseline.
+ for (int i = 0; i < v_size; i++) {
+ if (trim_pos >= 0) {
+ if (rtl) {
+ if (i < trim_pos) {
+ continue;
+ }
+ } else {
+ if (i >= trim_pos) {
+ break;
+ }
+ }
+ }
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ if (p_clip_r > 0) {
+ // Clip right / bottom.
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ if (ofs.x + glyphs[i].advance > p_clip_r) {
+ return;
+ }
+ } else {
+ if (ofs.y + glyphs[i].advance > p_clip_r) {
+ return;
+ }
+ }
+ }
+ if (p_clip_l > 0) {
+ // Clip left / top.
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ if (ofs.x < p_clip_l) {
+ ofs.x += glyphs[i].advance;
+ continue;
+ }
+ } else {
+ if (ofs.y < p_clip_l) {
+ ofs.y += glyphs[i].advance;
+ continue;
+ }
+ }
+ }
+ if (glyphs[i].font_rid != RID()) {
+ font_add_glyph_outline_to_draw_list(glyphs[i].font_rid, p_layer, p_list, p_transform, glyphs[i].font_size, p_outline_size, ofs + p_pos + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color, p_oversampling);
+ }
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += glyphs[i].advance;
+ } else {
+ ofs.y += glyphs[i].advance;
+ }
+ }
+ }
+ // Draw LTR ellipsis string when needed.
+ if (!rtl && ellipsis_pos >= 0) {
+ for (int i = 0; i < ellipsis_gl_size; i++) {
+ for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) {
+ font_add_glyph_outline_to_draw_list(ellipsis_glyphs[i].font_rid, p_layer, p_list, p_transform, ellipsis_glyphs[i].font_size, p_outline_size, ofs + p_pos + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color, p_oversampling);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += ellipsis_glyphs[i].advance;
+ } else {
+ ofs.y += ellipsis_glyphs[i].advance;
+ }
+ }
+ }
+ }
+}
+
#ifdef DEBUG_ENABLED
void TextServer::debug_print_glyph(int p_idx, const Glyph &p_glyph) const {
diff --git a/servers/text/text_server.h b/servers/text/text_server.h
index 64e8a6bc80f5..4a0fa7675976 100644
--- a/servers/text/text_server.h
+++ b/servers/text/text_server.h
@@ -41,6 +41,7 @@ class TypedArray;
struct Glyph;
struct CaretInfo;
+struct GlyphDrawCall;
#define OT_TAG(m_c1, m_c2, m_c3, m_c4) ((int32_t)((((uint32_t)(m_c1) & 0xff) << 24) | (((uint32_t)(m_c2) & 0xff) << 16) | (((uint32_t)(m_c3) & 0xff) << 8) | ((uint32_t)(m_c4) & 0xff)))
@@ -172,6 +173,18 @@ class TextServer : public RefCounted {
SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE = 16,
};
+ enum DrawCallType {
+ DRAW_CALL_NULL,
+ DRAW_CALL_NORMAL,
+ DRAW_CALL_MSDF,
+ DRAW_CALL_LCD,
+ DRAW_CALL_HEX,
+ DRAW_CALL_LINE,
+ DRAW_CALL_RECT,
+ DRAW_CALL_IMAGE,
+ DRAW_CALL_CUSTOM,
+ };
+
enum Feature {
FEATURE_SIMPLE_LAYOUT = 1 << 0,
FEATURE_BIDI_LAYOUT = 1 << 1,
@@ -430,6 +443,9 @@ class TextServer : public RefCounted {
virtual void font_draw_glyph(const RID &p_font, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const = 0;
virtual void font_draw_glyph_outline(const RID &p_font, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const = 0;
+ virtual void font_add_glyph_to_draw_list(const RID &p_font, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const = 0;
+ virtual void font_add_glyph_outline_to_draw_list(const RID &p_font, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const = 0;
+
virtual bool font_is_language_supported(const RID &p_font_rid, const String &p_language) const = 0;
virtual void font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) = 0;
virtual bool font_get_language_support_override(const RID &p_font_rid, const String &p_language) = 0;
@@ -458,6 +474,20 @@ class TextServer : public RefCounted {
virtual Vector2 get_hex_code_box_size(int64_t p_size, int64_t p_index) const;
virtual void draw_hex_code_box(const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const;
+ /* Draw list interface */
+
+ virtual RID create_draw_list() = 0;
+ virtual void draw_list_sort(const RID &p_dc) = 0;
+ virtual void draw_list_reserve(const RID &p_dc, int64_t p_new_items) = 0;
+
+ virtual void draw_list_add_hexbox(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Vector2 &p_pos, int64_t p_index, int64_t p_size, const Color &p_modulate) const = 0;
+ virtual void draw_list_add_rect(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Rect2 &p_rect, bool p_filled, const Color &p_modulate) const = 0;
+ virtual void draw_list_add_line(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Point2 &p_start, const Point2 &p_end, float p_width, float p_dash, const Color &p_modulate) const = 0;
+ virtual void draw_list_add_texture(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, RID p_texture, const Rect2 &p_dst_rect, const Color &p_modulate) const = 0;
+ virtual void draw_list_add_custom(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Callable &p_callback) const = 0;
+
+ virtual void draw_list_draw(const RID &p_dc, const RID &p_ci, bool p_free = true) = 0;
+
/* Shaped text buffer interface */
virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) = 0;
@@ -579,6 +609,9 @@ class TextServer : public RefCounted {
virtual void shaped_text_draw(const RID &p_shaped, const RID &p_canvas, const Vector2 &p_pos, double p_clip_l = -1.0, double p_clip_r = -1.0, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
virtual void shaped_text_draw_outline(const RID &p_shaped, const RID &p_canvas, const Vector2 &p_pos, double p_clip_l = -1.0, double p_clip_r = -1.0, int64_t p_outline_size = 1, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+ virtual void shaped_text_add_to_draw_list(const RID &p_shaped, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, const Vector2 &p_pos, double p_clip_l = -1.0, double p_clip_r = -1.0, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+ virtual void shaped_text_add_outline_to_draw_list(const RID &p_shaped, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, const Vector2 &p_pos, double p_clip_l = -1.0, double p_clip_r = -1.0, int64_t p_outline_size = 1, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const;
+
#ifdef DEBUG_ENABLED
void debug_print_glyph(int p_idx, const Glyph &p_glyph) const;
void shaped_text_debug_print(const RID &p_shaped) const;
@@ -619,6 +652,8 @@ class TextServer : public RefCounted {
/*************************************************************************/
+// Native structures, sync with `register_server_types()` if definition is changed.
+
struct Glyph {
int start = -1; // Start offset in the source string.
int end = -1; // End offset in the source string.
@@ -647,8 +682,30 @@ struct Glyph {
struct CaretInfo {
Rect2 l_caret;
Rect2 t_caret;
- TextServer::Direction l_dir;
- TextServer::Direction t_dir;
+ TextServer::Direction l_dir = TextServer::DIRECTION_AUTO;
+ TextServer::Direction t_dir = TextServer::DIRECTION_AUTO;
+};
+
+struct GlyphDrawCall {
+ TextServer::DrawCallType draw_type = TextServer::DRAW_CALL_NULL;
+ int16_t layer = 0;
+ Transform2D transform;
+
+ RID texture;
+ Rect2 dst_rect;
+ Rect2 src_rect;
+ Color modulate;
+ Variant data;
+};
+
+struct GlyphDrawCallCompare {
+ _FORCE_INLINE_ bool operator()(const GlyphDrawCall &l, const GlyphDrawCall &r) const {
+ if (l.layer == r.layer) {
+ return l.texture.get_id() < r.texture.get_id();
+ } else {
+ return l.layer < r.layer;
+ }
+ }
};
/*************************************************************************/
@@ -709,6 +766,8 @@ VARIANT_ENUM_CAST(TextServer::StructuredTextParser);
VARIANT_ENUM_CAST(TextServer::FontAntialiasing);
VARIANT_ENUM_CAST(TextServer::FontLCDSubpixelLayout);
VARIANT_ENUM_CAST(TextServer::FixedSizeScaleMode);
+VARIANT_ENUM_CAST(TextServer::DrawCallType);
GDVIRTUAL_NATIVE_PTR(Glyph);
GDVIRTUAL_NATIVE_PTR(CaretInfo);
+GDVIRTUAL_NATIVE_PTR(GlyphDrawCall);
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index 9882800f9a25..292312840b60 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -218,6 +218,8 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND_COMPAT(_font_draw_glyph_bind_compat_104872, "font_rid", "canvas", "size", "pos", "index", "color");
GDVIRTUAL_BIND_COMPAT(_font_draw_glyph_outline_bind_compat_104872, "font_rid", "canvas", "size", "outline_size", "pos", "index", "color");
#endif
+ GDVIRTUAL_BIND(_font_add_glyph_to_draw_list, "font_rid", "layer", "list", "transform", "size", "pos", "index", "color", "oversampling");
+ GDVIRTUAL_BIND(_font_add_glyph_outline_to_draw_list, "font_rid", "layer", "list", "transform", "size", "outline_size", "pos", "index", "color", "oversampling");
GDVIRTUAL_BIND(_font_is_language_supported, "font_rid", "language");
GDVIRTUAL_BIND(_font_set_language_support_override, "font_rid", "language", "supported");
@@ -247,6 +249,18 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_hex_code_box_size, "size", "index");
GDVIRTUAL_BIND(_draw_hex_code_box, "canvas", "size", "pos", "index", "color");
+ /* Draw list interface */
+
+ GDVIRTUAL_BIND(_create_draw_list);
+ GDVIRTUAL_BIND(_draw_list_sort, "list");
+ GDVIRTUAL_BIND(_draw_list_reserve, "list", "count");
+ GDVIRTUAL_BIND(_draw_list_add_hexbox, "list", "layer", "transform", "pos", "index", "size", "modulate");
+ GDVIRTUAL_BIND(_draw_list_add_rect, "list", "layer", "transform", "rect", "filled", "modulate");
+ GDVIRTUAL_BIND(_draw_list_add_line, "list", "layer", "transform", "start", "end", "width", "dash", "modulate");
+ GDVIRTUAL_BIND(_draw_list_add_texture, "list", "layer", "transform", "texture", "rect", "modulate");
+ GDVIRTUAL_BIND(_draw_list_add_custom, "list", "layer", "transform", "callback");
+ GDVIRTUAL_BIND(_draw_list_draw, "list", "ci", "free");
+
/* Shaped text buffer interface */
GDVIRTUAL_BIND(_create_shaped_text, "direction", "orientation");
@@ -355,6 +369,8 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND_COMPAT(_shaped_text_draw_bind_compat_104872, "shaped", "canvas", "pos", "clip_l", "clip_r", "color");
GDVIRTUAL_BIND_COMPAT(_shaped_text_draw_outline_bind_compat_104872, "shaped", "canvas", "pos", "clip_l", "clip_r", "outline_size", "color");
#endif
+ GDVIRTUAL_BIND(_shaped_text_add_to_draw_list, "shaped", "layer", "list", "transform", "pos", "clip_l", "clip_r", "color", "oversampling");
+ GDVIRTUAL_BIND(_shaped_text_add_outline_to_draw_list, "shaped", "layer", "list", "transform", "pos", "clip_l", "clip_r", "outline_size", "color", "oversampling");
GDVIRTUAL_BIND(_shaped_text_get_grapheme_bounds, "shaped", "pos");
GDVIRTUAL_BIND(_shaped_text_next_grapheme_pos, "shaped", "pos");
@@ -1032,6 +1048,14 @@ void TextServerExtension::font_draw_glyph_outline(const RID &p_font_rid, const R
#endif
}
+void TextServerExtension::font_add_glyph_to_draw_list(const RID &p_font_rid, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+ GDVIRTUAL_CALL(_font_add_glyph_to_draw_list, p_font_rid, p_layer, p_list, p_transform, p_size, p_pos, p_index, p_color, p_oversampling);
+}
+
+void TextServerExtension::font_add_glyph_outline_to_draw_list(const RID &p_font_rid, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
+ GDVIRTUAL_CALL(_font_add_glyph_outline_to_draw_list, p_font_rid, p_layer, p_list, p_transform, p_size, p_outline_size, p_pos, p_index, p_color, p_oversampling);
+}
+
bool TextServerExtension::font_is_language_supported(const RID &p_font_rid, const String &p_language) const {
bool ret = false;
GDVIRTUAL_CALL(_font_is_language_supported, p_font_rid, p_language, ret);
@@ -1137,6 +1161,47 @@ void TextServerExtension::draw_hex_code_box(const RID &p_canvas, int64_t p_size,
TextServer::draw_hex_code_box(p_canvas, p_size, p_pos, p_index, p_color);
}
}
+/*************************************************************************/
+/* Draw list interface */
+/*************************************************************************/
+
+RID TextServerExtension::create_draw_list() {
+ RID ret;
+ GDVIRTUAL_CALL(_create_draw_list, ret);
+ return ret;
+}
+
+void TextServerExtension::draw_list_sort(const RID &p_dc) {
+ GDVIRTUAL_CALL(_draw_list_sort, p_dc);
+}
+
+void TextServerExtension::draw_list_reserve(const RID &p_dc, int64_t p_new_items) {
+ GDVIRTUAL_CALL(_draw_list_reserve, p_dc, p_new_items);
+}
+
+void TextServerExtension::draw_list_add_hexbox(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Vector2 &p_pos, int64_t p_index, int64_t p_size, const Color &p_modulate) const {
+ GDVIRTUAL_CALL(_draw_list_add_hexbox, p_dc, p_layer, p_transform, p_pos, p_index, p_size, p_modulate);
+}
+
+void TextServerExtension::draw_list_add_rect(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Rect2 &p_rect, bool p_filled, const Color &p_modulate) const {
+ GDVIRTUAL_CALL(_draw_list_add_rect, p_dc, p_layer, p_transform, p_rect, p_filled, p_modulate);
+}
+
+void TextServerExtension::draw_list_add_line(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Point2 &p_start, const Point2 &p_end, float p_width, float p_dash, const Color &p_modulate) const {
+ GDVIRTUAL_CALL(_draw_list_add_line, p_dc, p_layer, p_transform, p_start, p_end, p_width, p_dash, p_modulate);
+}
+
+void TextServerExtension::draw_list_add_texture(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, RID p_texture, const Rect2 &p_dst_rect, const Color &p_modulate) const {
+ GDVIRTUAL_CALL(_draw_list_add_texture, p_dc, p_layer, p_transform, p_texture, p_dst_rect, p_modulate);
+}
+
+void TextServerExtension::draw_list_add_custom(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Callable &p_callback) const {
+ GDVIRTUAL_CALL(_draw_list_add_custom, p_dc, p_layer, p_transform, p_callback);
+}
+
+void TextServerExtension::draw_list_draw(const RID &p_dc, const RID &p_ci, bool p_free) {
+ GDVIRTUAL_CALL(_draw_list_draw, p_dc, p_ci, p_free);
+}
/*************************************************************************/
/* Shaped text buffer interface */
@@ -1598,6 +1663,20 @@ void TextServerExtension::shaped_text_draw_outline(const RID &p_shaped, const RI
TextServer::shaped_text_draw_outline(p_shaped, p_canvas, p_pos, p_clip_l, p_clip_r, p_outline_size, p_color, p_oversampling);
}
+void TextServerExtension::shaped_text_add_to_draw_list(const RID &p_shaped, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, const Vector2 &p_pos, double p_clip_l, double p_clip_r, const Color &p_color, float p_oversampling) const {
+ if (GDVIRTUAL_CALL(_shaped_text_add_to_draw_list, p_shaped, p_layer, p_list, p_transform, p_pos, p_clip_l, p_clip_r, p_color, p_oversampling)) {
+ return;
+ }
+ TextServer::shaped_text_add_to_draw_list(p_shaped, p_layer, p_list, p_transform, p_pos, p_clip_l, p_clip_r, p_color, p_oversampling);
+}
+
+void TextServerExtension::shaped_text_add_outline_to_draw_list(const RID &p_shaped, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, const Vector2 &p_pos, double p_clip_l, double p_clip_r, int64_t p_outline_size, const Color &p_color, float p_oversampling) const {
+ if (GDVIRTUAL_CALL(_shaped_text_add_outline_to_draw_list, p_shaped, p_layer, p_list, p_transform, p_pos, p_clip_l, p_clip_r, p_outline_size, p_color, p_oversampling)) {
+ return;
+ }
+ TextServer::shaped_text_add_outline_to_draw_list(p_shaped, p_layer, p_list, p_transform, p_pos, p_clip_l, p_clip_r, p_outline_size, p_color, p_oversampling);
+}
+
Vector2 TextServerExtension::shaped_text_get_grapheme_bounds(const RID &p_shaped, int64_t p_pos) const {
Vector2 ret;
if (GDVIRTUAL_CALL(_shaped_text_get_grapheme_bounds, p_shaped, p_pos, ret)) {
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index b764addcf837..a1b066aac605 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -356,6 +356,10 @@ class TextServerExtension : public TextServer {
GDVIRTUAL6C_COMPAT(_font_draw_glyph_bind_compat_104872, _font_draw_glyph, RID, RID, int64_t, const Vector2 &, int64_t, const Color &);
GDVIRTUAL7C_COMPAT(_font_draw_glyph_outline_bind_compat_104872, _font_draw_glyph_outline, RID, RID, int64_t, int64_t, const Vector2 &, int64_t, const Color &);
#endif
+ virtual void font_add_glyph_to_draw_list(const RID &p_font, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const override;
+ virtual void font_add_glyph_outline_to_draw_list(const RID &p_font, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const override;
+ GDVIRTUAL9C_REQUIRED(_font_add_glyph_to_draw_list, const RID &, int64_t, const RID &, const Transform2D &, int64_t, const Vector2 &, int64_t, const Color &, float);
+ GDVIRTUAL10C_REQUIRED(_font_add_glyph_outline_to_draw_list, const RID &, int64_t, const RID &, const Transform2D &, int64_t, int64_t, const Vector2 &, int64_t, const Color &, float);
virtual bool font_is_language_supported(const RID &p_font_rid, const String &p_language) const override;
virtual void font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) override;
@@ -405,6 +409,27 @@ class TextServerExtension : public TextServer {
GDVIRTUAL2RC(Vector2, _get_hex_code_box_size, int64_t, int64_t);
GDVIRTUAL5C(_draw_hex_code_box, RID, int64_t, const Vector2 &, int64_t, const Color &);
+ /* Draw list interface */
+
+ virtual RID create_draw_list() override;
+ virtual void draw_list_sort(const RID &p_dc) override;
+ virtual void draw_list_reserve(const RID &p_dc, int64_t p_new_items) override;
+ virtual void draw_list_add_hexbox(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Vector2 &p_pos, int64_t p_index, int64_t p_size, const Color &p_modulate) const override;
+ virtual void draw_list_add_rect(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Rect2 &p_rect, bool p_filled, const Color &p_modulate) const override;
+ virtual void draw_list_add_line(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Point2 &p_start, const Point2 &p_end, float p_width, float p_dash, const Color &p_modulate) const override;
+ virtual void draw_list_add_texture(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, RID p_texture, const Rect2 &p_dst_rect, const Color &p_modulate) const override;
+ virtual void draw_list_add_custom(const RID &p_dc, int64_t p_layer, const Transform2D &p_transform, const Callable &p_callback) const override;
+ virtual void draw_list_draw(const RID &p_dc, const RID &p_ci, bool p_free = true) override;
+ GDVIRTUAL0R_REQUIRED(RID, _create_draw_list);
+ GDVIRTUAL1_REQUIRED(_draw_list_sort, const RID &);
+ GDVIRTUAL2_REQUIRED(_draw_list_reserve, const RID &, int64_t);
+ GDVIRTUAL7C_REQUIRED(_draw_list_add_hexbox, const RID &, int64_t, const Transform2D &, const Vector2 &, int64_t, int64_t, const Color &);
+ GDVIRTUAL6C_REQUIRED(_draw_list_add_rect, const RID &, int64_t, const Transform2D &, const Rect2 &, bool, const Color &);
+ GDVIRTUAL8C_REQUIRED(_draw_list_add_line, const RID &, int64_t, const Transform2D &, const Point2 &, const Point2 &, float, float, const Color &);
+ GDVIRTUAL6C_REQUIRED(_draw_list_add_texture, const RID &, int64_t, const Transform2D &, RID, const Rect2 &, const Color &);
+ GDVIRTUAL4C_REQUIRED(_draw_list_add_custom, const RID &, int64_t, const Transform2D &, const Callable &);
+ GDVIRTUAL3_REQUIRED(_draw_list_draw, const RID &, const RID &, bool);
+
/* Shaped text buffer interface */
virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
@@ -590,6 +615,10 @@ class TextServerExtension : public TextServer {
GDVIRTUAL6C_COMPAT(_shaped_text_draw_bind_compat_104872, _shaped_text_draw, RID, RID, const Vector2 &, double, double, const Color &);
GDVIRTUAL7C_COMPAT(_shaped_text_draw_outline_bind_compat_104872, _shaped_text_draw_outline, RID, RID, const Vector2 &, double, double, int64_t, const Color &);
#endif
+ virtual void shaped_text_add_to_draw_list(const RID &p_shaped, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, const Vector2 &p_pos, double p_clip_l = -1.0, double p_clip_r = -1.0, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const override;
+ virtual void shaped_text_add_outline_to_draw_list(const RID &p_shaped, int64_t p_layer, const RID &p_list, const Transform2D &p_transform, const Vector2 &p_pos, double p_clip_l = -1.0, double p_clip_r = -1.0, int64_t p_outline_size = 1, const Color &p_color = Color(1, 1, 1), float p_oversampling = 0.0) const override;
+ GDVIRTUAL9C(_shaped_text_add_to_draw_list, RID, int64_t, RID, const Transform2D &, const Vector2 &, double, double, const Color &, float);
+ GDVIRTUAL10C(_shaped_text_add_outline_to_draw_list, RID, int64_t, RID, const Transform2D &, const Vector2 &, double, double, int64_t, const Color &, float);
virtual Vector2 shaped_text_get_grapheme_bounds(const RID &p_shaped, int64_t p_pos) const override;
virtual int64_t shaped_text_next_grapheme_pos(const RID &p_shaped, int64_t p_pos) const override;