summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/error/error_macros.cpp7
-rw-r--r--core/register_core_types.cpp2
-rw-r--r--doc/classes/Camera2D.xml14
-rw-r--r--doc/classes/Control.xml1
-rw-r--r--doc/classes/Node.xml3
-rw-r--r--doc/classes/ProjectSettings.xml3
-rw-r--r--doc/classes/ReflectionProbe.xml27
-rw-r--r--doc/classes/Viewport.xml3
-rw-r--r--editor/editor_spin_slider.cpp2
-rw-r--r--editor/editor_toaster.cpp17
-rw-r--r--editor/editor_toaster.h2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp6
-rw-r--r--modules/text_server_adv/text_server_adv.cpp200
-rw-r--r--modules/text_server_adv/text_server_adv.h1
-rw-r--r--modules/text_server_fb/text_server_fb.cpp33
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.cpp11
-rw-r--r--platform/windows/os_windows.cpp3
-rw-r--r--scene/register_scene_types.cpp8
-rw-r--r--scene/resources/material.cpp6
-rw-r--r--servers/rendering/shader_language.cpp20
-rw-r--r--servers/rendering/shader_language.h8
21 files changed, 232 insertions, 145 deletions
diff --git a/core/error/error_macros.cpp b/core/error/error_macros.cpp
index 61bb949ed4..c236f30945 100644
--- a/core/error/error_macros.cpp
+++ b/core/error/error_macros.cpp
@@ -37,9 +37,16 @@
static ErrorHandlerList *error_handler_list = nullptr;
void add_error_handler(ErrorHandlerList *p_handler) {
+ // If p_handler is already in error_handler_list
+ // we'd better remove it first then we can add it.
+ // This prevent cyclic redundancy.
+ remove_error_handler(p_handler);
+
_global_lock();
+
p_handler->next = error_handler_list;
error_handler_list = p_handler;
+
_global_unlock();
}
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index e33c21cc00..5479041b29 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -199,7 +199,7 @@ void register_core_types() {
ResourceLoader::add_resource_format_loader(resource_format_loader_crypto);
GDREGISTER_VIRTUAL_CLASS(MultiplayerPeer);
- GDREGISTER_VIRTUAL_CLASS(MultiplayerPeerExtension);
+ GDREGISTER_CLASS(MultiplayerPeerExtension);
GDREGISTER_VIRTUAL_CLASS(MultiplayerReplicator);
GDREGISTER_CLASS(MultiplayerAPI);
GDREGISTER_CLASS(MainLoop);
diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml
index 6a1782fc52..1bcc9689aa 100644
--- a/doc/classes/Camera2D.xml
+++ b/doc/classes/Camera2D.xml
@@ -30,13 +30,15 @@
<method name="get_camera_position" qualifiers="const">
<return type="Vector2" />
<description>
- Returns the camera position.
+ Returns the camera's [code]position[/code] (the tracked point the camera attempts to follow), relative to the origin.
+ [b]Note:[/b] The returned value is not the same as [member Node2D.position] or [member Node2D.global_position], as it is affected by the [code]drag[/code] properties.
</description>
</method>
<method name="get_camera_screen_center" qualifiers="const">
<return type="Vector2" />
<description>
Returns the location of the [Camera2D]'s screen-center, relative to the origin.
+ [b]Note:[/b] The real [code]position[/code] of the camera may be different, see [method get_camera_position].
</description>
</method>
<method name="get_drag_margin" qualifiers="const">
@@ -57,7 +59,7 @@
<return type="void" />
<description>
Sets the camera's position immediately to its current smoothing destination.
- This has no effect if smoothing is disabled.
+ This method has no effect if [member smoothing_enabled] is [code]false[/code].
</description>
</method>
<method name="set_drag_margin">
@@ -95,7 +97,7 @@
</member>
<member name="drag_horizontal_offset" type="float" setter="set_drag_horizontal_offset" getter="get_drag_horizontal_offset" default="0.0">
The relative horizontal drag offset of the camera between the right ([code]-1[/code]) and left ([code]1[/code]) drag margins.
- [b]Note:[/b] Used to set the initial horizontal drag offset; determine the current offset; or force the current offset. It's not automatically updated when the horizontal drag margin is enabled or the drag margins are changed.
+ [b]Note:[/b] Used to set the initial horizontal drag offset; determine the current offset; or force the current offset. It's not automatically updated when [member drag_horizontal_enabled] is [code]true[/code] or the drag margins are changed.
</member>
<member name="drag_left_margin" type="float" setter="set_drag_margin" getter="get_drag_margin" default="0.2">
Left margin needed to drag the camera. A value of [code]1[/code] makes the camera move only when reaching the left edge of the screen.
@@ -111,7 +113,7 @@
</member>
<member name="drag_vertical_offset" type="float" setter="set_drag_vertical_offset" getter="get_drag_vertical_offset" default="0.0">
The relative vertical drag offset of the camera between the bottom ([code]-1[/code]) and top ([code]1[/code]) drag margins.
- [b]Note:[/b] Used to set the initial vertical drag offset; determine the current offset; or force the current offset. It's not automatically updated when the vertical drag margin is enabled or the drag margins are changed.
+ [b]Note:[/b] Used to set the initial vertical drag offset; determine the current offset; or force the current offset. It's not automatically updated when [member drag_vertical_enabled] is [code]true[/code] or the drag margins are changed.
</member>
<member name="editor_draw_drag_margin" type="bool" setter="set_margin_drawing_enabled" getter="is_margin_drawing_enabled" default="false">
If [code]true[/code], draws the camera's drag margin rectangle in the editor.
@@ -133,7 +135,7 @@
</member>
<member name="limit_smoothed" type="bool" setter="set_limit_smoothing_enabled" getter="is_limit_smoothing_enabled" default="false">
If [code]true[/code], the camera smoothly stops when reaches its limits.
- This has no effect if smoothing is disabled.
+ This property has no effect if [member smoothing_enabled] is [code]false[/code].
[b]Note:[/b] To immediately update the camera's position to be within limits without smoothing, even with this setting enabled, invoke [method reset_smoothing].
</member>
<member name="limit_top" type="int" setter="set_limit" getter="get_limit" default="-10000000">
@@ -146,7 +148,7 @@
The camera's process callback. See [enum Camera2DProcessCallback].
</member>
<member name="rotating" type="bool" setter="set_rotating" getter="is_rotating" default="false">
- If [code]true[/code], the camera rotates with the target.
+ If [code]true[/code], the camera view rotates with the target.
</member>
<member name="smoothing_enabled" type="bool" setter="set_enable_follow_smoothing" getter="is_follow_smoothing_enabled" default="false">
If [code]true[/code], the camera smoothly moves towards the target at [member smoothing_speed].
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index ed6a71d5c3..39f8980b2c 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -102,6 +102,7 @@
<description>
Virtual method to be implemented by the user. Returns the minimum size for this control. Alternative to [member rect_min_size] for controlling minimum size via code. The actual minimum size will be the max value of these two (in each axis separately).
If not overridden, defaults to [constant Vector2.ZERO].
+ [b]Note:[/b] This method will not be called when the script is attached to a [Control] node that already overrides its minimum size (e.g. [Label], [Button], [PanelContainer] etc.). It can only be used with most basic GUI nodes, like [Control], [Container], [Panel] etc.
</description>
</method>
<method name="_gui_input" qualifiers="virtual">
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 81b94c036d..22ebbb87f3 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -571,7 +571,8 @@
<description>
Replaces a node in a scene by the given one. Subscriptions that pass through this node will be lost.
If [code]keep_groups[/code] is [code]true[/code], the [code]node[/code] is added to the same groups that the replaced node is in.
- Note that the replaced node is not automatically freed, so you either need to keep it in a variable for later use or free it using [method Object.free].
+ [b]Note:[/b] The given node will become the new parent of any child nodes that the replaced node had.
+ [b]Note:[/b] The replaced node is not automatically freed, so you either need to keep it in a variable for later use or free it using [method Object.free].
</description>
</method>
<method name="request_ready">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index a6303a8caf..26d519506b 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1721,6 +1721,9 @@
<member name="rendering/limits/time/time_rollover_secs" type="float" setter="" getter="" default="3600">
</member>
<member name="rendering/mesh_lod/lod_change/threshold_pixels" type="float" setter="" getter="" default="1.0">
+ The automatic LOD bias to use for meshes rendered within the [ReflectionProbe]. Higher values will use less detailed versions of meshes that have LOD variations generated. If set to [code]0.0[/code], automatic LOD is disabled. Increase [member rendering/mesh_lod/lod_change/threshold_pixels] to improve performance at the cost of geometry detail.
+ [b]Note:[/b] [member rendering/mesh_lod/lod_change/threshold_pixels] does not affect [GeometryInstance3D] visibility ranges (also known as "manual" LOD or hierarchical LOD).
+ [b]Note:[/b] This property is only read when the project starts. To adjust the automatic LOD threshold at runtime, set [member Viewport.lod_threshold] on the root [Viewport].
</member>
<member name="rendering/occlusion_culling/bvh_build_quality" type="int" setter="" getter="" default="2">
</member>
diff --git a/doc/classes/ReflectionProbe.xml b/doc/classes/ReflectionProbe.xml
index 8bf8534334..ae0eae6454 100644
--- a/doc/classes/ReflectionProbe.xml
+++ b/doc/classes/ReflectionProbe.xml
@@ -1,33 +1,39 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ReflectionProbe" inherits="VisualInstance3D" version="4.0">
<brief_description>
- Captures its surroundings to create reflections.
+ Captures its surroundings to create fast, accurate reflections from a given point.
</brief_description>
<description>
Captures its surroundings as a cubemap, and stores versions of it with increasing levels of blur to simulate different material roughnesses.
- The [ReflectionProbe] is used to create high-quality reflections at the cost of performance. It can be combined with [VoxelGI]s and Screen Space Reflections to achieve high quality reflections. [ReflectionProbe]s render all objects within their [member cull_mask], so updating them can be quite expensive. It is best to update them once with the important static objects and then leave them.
+ The [ReflectionProbe] is used to create high-quality reflections at a low performance cost (when [member update_mode] is [constant UPDATE_ONCE]). [ReflectionProbe]s can be blended together and with the rest of the scene smoothly. [ReflectionProbe]s can also be combined with [VoxelGI], SDFGI ([member Environment.sdfgi_enabled]) and screen-space reflections ([member Environment.ss_reflections_enabled]) to get more accurate reflections in specific areas. [ReflectionProbe]s render all objects within their [member cull_mask], so updating them can be quite expensive. It is best to update them once with the important static objects and then leave them as-is.
+ [b]Note:[/b] Unlike [VoxelGI] and SDFGI, [ReflectionProbe]s only source their environment from a [WorldEnvironment] node. If you specify an [Environment] resource within a [Camera3D] node, it will be ignored by the [ReflectionProbe]. This can lead to incorrect lighting within the [ReflectionProbe].
</description>
<tutorials>
<link title="Reflection probes">$DOCS_URL/tutorials/3d/reflection_probes.html</link>
</tutorials>
<members>
<member name="ambient_color" type="Color" setter="set_ambient_color" getter="get_ambient_color" default="Color(0, 0, 0, 1)">
+ The custom ambient color to use within the [ReflectionProbe]'s [member extents]. Only effective if [member ambient_mode] is [constant AMBIENT_COLOR].
</member>
<member name="ambient_color_energy" type="float" setter="set_ambient_color_energy" getter="get_ambient_color_energy" default="1.0">
+ The custom ambient color energy to use within the [ReflectionProbe]'s [member extents]. Only effective if [member ambient_mode] is [constant AMBIENT_COLOR].
</member>
<member name="ambient_mode" type="int" setter="set_ambient_mode" getter="get_ambient_mode" enum="ReflectionProbe.AmbientMode" default="1">
+ The ambient color to use within the [ReflectionProbe]'s [member extents]. The ambient color will smoothly blend with other [ReflectionProbe]s and the rest of the scene (outside the [ReflectionProbe]'s [member extents]).
</member>
<member name="box_projection" type="bool" setter="set_enable_box_projection" getter="is_box_projection_enabled" default="false">
If [code]true[/code], enables box projection. This makes reflections look more correct in rectangle-shaped rooms by offsetting the reflection center depending on the camera's location.
+ [b]Note:[/b] To better fit rectangle-shaped rooms that are not aligned to the grid, you can rotate the [ReflectionProbe] node.
</member>
<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="1048575">
- Sets the cull mask which determines what objects are drawn by this probe. Every [VisualInstance3D] with a layer included in this cull mask will be rendered by the probe. It is best to only include large objects which are likely to take up a lot of space in the reflection in order to save on rendering cost.
+ Sets the cull mask which determines what objects are drawn by this probe. Every [VisualInstance3D] with a layer included in this cull mask will be rendered by the probe. To improve performance, it is best to only include large objects which are likely to take up a lot of space in the reflection.
</member>
<member name="enable_shadows" type="bool" setter="set_enable_shadows" getter="are_shadows_enabled" default="false">
If [code]true[/code], computes shadows in the reflection probe. This makes the reflection probe slower to render; you may want to disable this if using the [constant UPDATE_ALWAYS] [member update_mode].
</member>
<member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(10, 10, 10)">
The size of the reflection probe. The larger the extents, the more space covered by the probe, which will lower the perceived resolution. It is best to keep the extents only as large as you need them.
+ [b]Note:[/b] To better fit areas that are not aligned to the grid, you can rotate the [ReflectionProbe] node.
</member>
<member name="intensity" type="float" setter="set_intensity" getter="get_intensity" default="1.0">
Defines the reflection intensity. Intensity modulates the strength of the reflection.
@@ -36,29 +42,34 @@
If [code]true[/code], reflections will ignore sky contribution.
</member>
<member name="lod_threshold" type="float" setter="set_lod_threshold" getter="get_lod_threshold" default="1.0">
+ The automatic LOD bias to use for meshes rendered within the [ReflectionProbe] (this is analog to [member Viewport.lod_threshold]). Higher values will use less detailed versions of meshes that have LOD variations generated. If set to [code]0.0[/code], automatic LOD is disabled. Increase [member lod_threshold] to improve performance at the cost of geometry detail, especially when using the [constant UPDATE_ALWAYS] [member update_mode].
+ [b]Note:[/b] [member lod_threshold] does not affect [GeometryInstance3D] visibility ranges (also known as "manual" LOD or hierarchical LOD).
</member>
<member name="max_distance" type="float" setter="set_max_distance" getter="get_max_distance" default="0.0">
- Sets the max distance away from the probe an object can be before it is culled.
+ The maximum distance away from the [ReflectionProbe] an object can be before it is culled. Decrease this to improve performance, especially when using the [constant UPDATE_ALWAYS] [member update_mode].
</member>
<member name="origin_offset" type="Vector3" setter="set_origin_offset" getter="get_origin_offset" default="Vector3(0, 0, 0)">
- Sets the origin offset to be used when this reflection probe is in box project mode.
+ Sets the origin offset to be used when this [ReflectionProbe] is in [member box_projection] mode. This can be set to a non-zero value to ensure a reflection fits a rectangle-shaped room, while reducing the amount of objects that "get in the way" of the reflection.
</member>
<member name="update_mode" type="int" setter="set_update_mode" getter="get_update_mode" enum="ReflectionProbe.UpdateMode" default="0">
- Sets how frequently the probe is updated. Can be [constant UPDATE_ONCE] or [constant UPDATE_ALWAYS].
+ Sets how frequently the [ReflectionProbe] is updated. Can be [constant UPDATE_ONCE] or [constant UPDATE_ALWAYS].
</member>
</members>
<constants>
<constant name="UPDATE_ONCE" value="0" enum="UpdateMode">
- Update the probe once on the next frame. The corresponding radiance map will be generated over the following six frames. This is slower to update than [constant UPDATE_ALWAYS] but can result in higher quality reflections.
+ Update the probe once on the next frame (recommended for most objects). The corresponding radiance map will be generated over the following six frames. This takes more time to update than [constant UPDATE_ALWAYS], but it has a lower performance cost and can result in higher-quality reflections. The ReflectionProbe is updated when its transform changes, but not when nearby geometry changes. You can force a [ReflectionProbe] update by moving the [ReflectionProbe] slightly in any direction.
</constant>
<constant name="UPDATE_ALWAYS" value="1" enum="UpdateMode">
- Update the probe every frame. This is needed when you want to capture dynamic objects. However, it results in an increased render time. Use [constant UPDATE_ONCE] whenever possible.
+ Update the probe every frame. This provides better results for fast-moving dynamic objects (such as cars). However, it has a significant performance cost. Due to the cost, it's recommended to only use one ReflectionProbe with [constant UPDATE_ALWAYS] at most per scene. For all other use cases, use [constant UPDATE_ONCE].
</constant>
<constant name="AMBIENT_DISABLED" value="0" enum="AmbientMode">
+ Do not apply any ambient lighting inside the [ReflectionProbe]'s [member extents].
</constant>
<constant name="AMBIENT_ENVIRONMENT" value="1" enum="AmbientMode">
+ Apply automatically-sourced environment lighting inside the [ReflectionProbe]'s [member extents].
</constant>
<constant name="AMBIENT_COLOR" value="2" enum="AmbientMode">
+ Apply custom ambient lighting inside the [ReflectionProbe]'s [member extents]. See [member ambient_color] and [member ambient_color_energy].
</constant>
</constants>
</class>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 4a3f99696d..4708654f9f 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -216,6 +216,9 @@
<member name="handle_input_locally" type="bool" setter="set_handle_input_locally" getter="is_handling_input_locally" default="true">
</member>
<member name="lod_threshold" type="float" setter="set_lod_threshold" getter="get_lod_threshold" default="1.0">
+ The automatic LOD bias to use for meshes rendered within the [Viewport] (this is analogous to [member ReflectionProbe.lod_threshold]). Higher values will use less detailed versions of meshes that have LOD variations generated. If set to [code]0.0[/code], automatic LOD is disabled. Increase [member lod_threshold] to improve performance at the cost of geometry detail.
+ To control this property on the root viewport, set the [member ProjectSettings.rendering/mesh_lod/lod_change/threshold_pixels] project setting.
+ [b]Note:[/b] [member lod_threshold] does not affect [GeometryInstance3D] visibility ranges (also known as "manual" LOD or hierarchical LOD).
</member>
<member name="msaa" type="int" setter="set_msaa" getter="get_msaa" enum="Viewport.MSAA" default="0">
The multisample anti-aliasing mode. A higher number results in smoother edges at the cost of significantly worse performance. A value of 2 or 4 is best unless targeting very high-end systems. See also bilinear scaling 3d [member scaling_3d_mode] for supersampling, which provides higher quality but is much more expensive.
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index ce33f54243..111c8c699e 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -388,7 +388,7 @@ void EditorSpinSlider::_draw_spin_slider() {
// Draw the horizontal slider's grabber.
c.a = 0.9;
- const Rect2 grabber_rect = Rect2(ofs + gofs, svofs + 1, grabber_w, 2 * EDSCALE);
+ const Rect2 grabber_rect = Rect2(ofs + gofs, svofs, grabber_w, 4 * EDSCALE);
draw_rect(grabber_rect, c);
grabbing_spinner_mouse_pos = get_global_position() + grabber_rect.get_center();
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index 0d9a546b8e..05b895519d 100644
--- a/editor/editor_toaster.cpp
+++ b/editor/editor_toaster.cpp
@@ -173,11 +173,7 @@ void EditorToaster::_error_handler(void *p_self, const char *p_func, const char
}
Severity severity = (p_type == ERR_HANDLER_WARNING) ? SEVERITY_WARNING : SEVERITY_ERROR;
- if (Thread::get_caller_id() != Thread::get_main_id()) {
- EditorToaster::get_singleton()->call_deferred(SNAME("popup_str"), err_str, severity, tooltip_str);
- } else {
- EditorToaster::get_singleton()->popup_str(err_str, severity, tooltip_str);
- }
+ EditorToaster::get_singleton()->popup_str(err_str, severity, tooltip_str);
}
}
@@ -387,6 +383,12 @@ Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_
}
void EditorToaster::popup_str(String p_message, Severity p_severity, String p_tooltip) {
+ // Since "_popup_str" adds nodes to the tree, and since the "add_child" method is not
+ // thread-safe, it's better to defer the call to the next cycle to be thread-safe.
+ call_deferred(SNAME("_popup_str"), p_message, p_severity, p_tooltip);
+}
+
+void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_tooltip) {
// Check if we already have a popup with the given message.
Control *control = nullptr;
for (KeyValue<Control *, Toast> element : toasts) {
@@ -440,6 +442,11 @@ EditorToaster *EditorToaster::get_singleton() {
return singleton;
}
+void EditorToaster::_bind_methods() {
+ // Binding method to make it defer-able.
+ ClassDB::bind_method(D_METHOD("_popup_str", "message", "severity", "tooltip"), &EditorToaster::_popup_str);
+}
+
EditorToaster::EditorToaster() {
set_notify_transform(true);
set_process_internal(true);
diff --git a/editor/editor_toaster.h b/editor/editor_toaster.h
index aac80d8fb1..502498986a 100644
--- a/editor/editor_toaster.h
+++ b/editor/editor_toaster.h
@@ -94,9 +94,11 @@ private:
void _set_notifications_enabled(bool p_enabled);
void _repop_old();
+ void _popup_str(String p_message, Severity p_severity, String p_tooltip);
protected:
static EditorToaster *singleton;
+ static void _bind_methods();
void _notification(int p_what);
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index f116f430e6..7b64c0564e 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -484,7 +484,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result = parser->head->get_datatype();
} else {
Ref<GDScriptParserRef> ref = get_parser_for(ScriptServer::get_global_class_path(first));
- if (ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
+ if (!ref.is_valid() || ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
push_error(vformat(R"(Could not parse global class "%s" from "%s".)", first, ScriptServer::get_global_class_path(first)), p_type);
return GDScriptParser::DataType();
}
@@ -3956,7 +3956,9 @@ Ref<GDScriptParserRef> GDScriptAnalyzer::get_parser_for(const String &p_path) {
} else {
Error err = OK;
ref = GDScriptCache::get_parser(p_path, GDScriptParserRef::EMPTY, err, parser->script_path);
- depended_parsers[p_path] = ref;
+ if (ref.is_valid()) {
+ depended_parsers[p_path] = ref;
+ }
}
return ref;
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index e2908a8a66..cfab021e24 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -942,7 +942,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
FontGlyph chr;
chr.found = true;
- chr.advance = advance.round();
+ chr.advance = advance;
if (shape.validate() && shape.contours.size() > 0) {
int w = (bounds.r - bounds.l);
@@ -1095,12 +1095,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
}
FontGlyph chr;
- chr.advance = (advance * p_data->scale / p_data->oversampling).round();
+ chr.advance = advance * p_data->scale / p_data->oversampling;
chr.texture_idx = tex_pos.index;
chr.found = true;
chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h);
- chr.rect.position = (Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling).round();
+ chr.rect.position = Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling;
chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling;
return chr;
}
@@ -1270,7 +1270,8 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
}
FT_Select_Size(fd->face, best_match);
} else {
- FT_Set_Pixel_Sizes(fd->face, 0, fd->size.x * fd->oversampling);
+ FT_Set_Pixel_Sizes(fd->face, 0, float(fd->size.x * fd->oversampling));
+ fd->scale = ((float)fd->size.x * fd->oversampling) / (float)fd->face->size->metrics.y_ppem;
}
fd->hb_handle = hb_ft_font_create(fd->face, nullptr);
@@ -2670,7 +2671,7 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
Vector2i size = _get_size(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
if (!_ensure_glyph(fd, size, p_index)) {
- return; // // Invalid or non graphicl glyph, do not display errors, nothing to draw.
+ return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
}
const FontGlyph &gl = fd->cache[size]->glyph_map[p_index];
@@ -2692,9 +2693,9 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
} else {
- Point2i cpos = p_pos;
+ Point2 cpos = p_pos.floor();
cpos += gl.rect.position;
- Size2i csize = gl.rect.size;
+ Size2 csize = gl.rect.size;
RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
}
}
@@ -2710,7 +2711,7 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
Vector2i size = _get_size_outline(fd, Vector2i(p_size, p_outline_size));
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
if (!_ensure_glyph(fd, size, p_index)) {
- return; // // Invalid or non graphicl glyph, do not display errors, nothing to draw.
+ return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
}
const FontGlyph &gl = fd->cache[size]->glyph_map[p_index];
@@ -2732,9 +2733,9 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
} else {
- Point2i cpos = p_pos;
+ Point2 cpos = p_pos.floor();
cpos += gl.rect.position;
- Size2i csize = gl.rect.size;
+ Size2 csize = gl.rect.size;
RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
}
}
@@ -3156,7 +3157,7 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con
}
ShapedTextDataAdvanced::Span span;
- span.start = sd->text.length();
+ span.start = sd->start + sd->text.length();
span.end = span.start + p_length;
span.embedded_key = p_key;
@@ -3322,60 +3323,72 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
ERR_FAIL_COND_V(sd->end < p_start + p_length, RID());
ShapedTextDataAdvanced *new_sd = memnew(ShapedTextDataAdvanced);
-
- new_sd->hb_buffer = hb_buffer_create();
new_sd->parent = p_shaped;
new_sd->start = p_start;
new_sd->end = p_start + p_length;
-
new_sd->orientation = sd->orientation;
new_sd->direction = sd->direction;
new_sd->custom_punct = sd->custom_punct;
new_sd->para_direction = sd->para_direction;
- new_sd->line_breaks_valid = sd->line_breaks_valid;
- new_sd->justification_ops_valid = sd->justification_ops_valid;
- new_sd->sort_valid = false;
- new_sd->upos = sd->upos;
- new_sd->uthk = sd->uthk;
+
+ if (!_shape_substr(new_sd, sd, p_start, p_length)) {
+ memdelete(new_sd);
+ return RID();
+ }
+ return shaped_owner.make_rid(new_sd);
+}
+
+bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int p_start, int p_length) const {
+ if (p_new_sd->valid) {
+ return true;
+ }
+
+ p_new_sd->hb_buffer = hb_buffer_create();
+
+ p_new_sd->line_breaks_valid = p_sd->line_breaks_valid;
+ p_new_sd->justification_ops_valid = p_sd->justification_ops_valid;
+ p_new_sd->sort_valid = false;
+ p_new_sd->upos = p_sd->upos;
+ p_new_sd->uthk = p_sd->uthk;
if (p_length > 0) {
- new_sd->text = sd->text.substr(p_start, p_length);
- new_sd->utf16 = new_sd->text.utf16();
- new_sd->script_iter = memnew(ScriptIterator(new_sd->text, 0, new_sd->text.length()));
+ p_new_sd->text = p_sd->text.substr(p_start - p_sd->start, p_length);
+ p_new_sd->utf16 = p_new_sd->text.utf16();
+ p_new_sd->script_iter = memnew(ScriptIterator(p_new_sd->text, 0, p_new_sd->text.length()));
- int sd_size = sd->glyphs.size();
- const Glyph *sd_glyphs = sd->glyphs.ptr();
- for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
+ int sd_size = p_sd->glyphs.size();
+ const Glyph *sd_glyphs = p_sd->glyphs.ptr();
+ for (int ov = 0; ov < p_sd->bidi_override.size(); ov++) {
UErrorCode err = U_ZERO_ERROR;
- if (sd->bidi_override[ov].x >= p_start + p_length || sd->bidi_override[ov].y <= p_start) {
+ if (p_sd->bidi_override[ov].x >= p_start + p_length || p_sd->bidi_override[ov].y <= p_start) {
continue;
}
- int start = _convert_pos_inv(sd, MAX(0, p_start - sd->bidi_override[ov].x));
- int end = _convert_pos_inv(sd, MIN(p_start + p_length, sd->bidi_override[ov].y) - sd->bidi_override[ov].x);
+ int start = _convert_pos_inv(p_sd, MAX(0, p_start - p_sd->bidi_override[ov].x));
+ int end = _convert_pos_inv(p_sd, MIN(p_start + p_length, p_sd->bidi_override[ov].y) - p_sd->bidi_override[ov].x);
- ERR_FAIL_COND_V_MSG((start < 0 || end - start > new_sd->utf16.length()), RID(), "Invalid BiDi override range.");
+ ERR_FAIL_COND_V_MSG((start < 0 || end - start > p_new_sd->utf16.length()), false, "Invalid BiDi override range.");
// Create temporary line bidi & shape.
UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);
- ERR_FAIL_COND_V_MSG(U_FAILURE(err), RID(), u_errorName(err));
- ubidi_setLine(sd->bidi_iter[ov], start, end, bidi_iter, &err);
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
+ ubidi_setLine(p_sd->bidi_iter[ov], start, end, bidi_iter, &err);
if (U_FAILURE(err)) {
ubidi_close(bidi_iter);
- ERR_FAIL_V_MSG(RID(), u_errorName(err));
+ ERR_FAIL_V_MSG(false, u_errorName(err));
}
- new_sd->bidi_iter.push_back(bidi_iter);
+ p_new_sd->bidi_iter.push_back(bidi_iter);
err = U_ZERO_ERROR;
int bidi_run_count = ubidi_countRuns(bidi_iter, &err);
- ERR_FAIL_COND_V_MSG(U_FAILURE(err), RID(), u_errorName(err));
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
for (int i = 0; i < bidi_run_count; i++) {
int32_t _bidi_run_start = 0;
int32_t _bidi_run_length = 0;
ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length);
- int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start);
- int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length);
+ int32_t bidi_run_start = _convert_pos(p_sd, p_sd->bidi_override[ov].x + start + _bidi_run_start);
+ int32_t bidi_run_end = _convert_pos(p_sd, p_sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length);
for (int j = 0; j < sd_size; j++) {
if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) {
@@ -3384,67 +3397,67 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
Variant key;
bool find_embedded = false;
if (gl.count == 1) {
- for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : p_sd->objects) {
if (E.value.pos == gl.start) {
find_embedded = true;
key = E.key;
- new_sd->objects[key] = E.value;
+ p_new_sd->objects[key] = E.value;
break;
}
}
}
if (find_embedded) {
- if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
- new_sd->objects[key].rect.position.x = new_sd->width;
- new_sd->width += new_sd->objects[key].rect.size.x;
+ if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {
+ p_new_sd->objects[key].rect.position.x = p_new_sd->width;
+ p_new_sd->width += p_new_sd->objects[key].rect.size.x;
} else {
- new_sd->objects[key].rect.position.y = new_sd->width;
- new_sd->width += new_sd->objects[key].rect.size.y;
+ p_new_sd->objects[key].rect.position.y = p_new_sd->width;
+ p_new_sd->width += p_new_sd->objects[key].rect.size.y;
}
} else {
if (gl.font_rid.is_valid()) {
- if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
- new_sd->ascent = MAX(new_sd->ascent, MAX(font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off));
- new_sd->descent = MAX(new_sd->descent, MAX(font_get_descent(gl.font_rid, gl.font_size), gl.y_off));
+ if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {
+ p_new_sd->ascent = MAX(p_new_sd->ascent, MAX(font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off));
+ p_new_sd->descent = MAX(p_new_sd->descent, MAX(font_get_descent(gl.font_rid, gl.font_size), gl.y_off));
} else {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
- new_sd->descent = MAX(new_sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
+ p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
+ p_new_sd->descent = MAX(p_new_sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
}
- } else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
+ } else if (p_new_sd->preserve_invalid || (p_new_sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
- if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
- new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
+ if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {
+ p_new_sd->ascent = MAX(p_new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
- new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ p_new_sd->descent = MAX(p_new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
}
}
- new_sd->width += gl.advance * gl.repeat;
+ p_new_sd->width += gl.advance * gl.repeat;
}
- new_sd->glyphs.push_back(gl);
+ p_new_sd->glyphs.push_back(gl);
}
}
}
}
// Align embedded objects to baseline.
- float full_ascent = new_sd->ascent;
- float full_descent = new_sd->descent;
- for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : new_sd->objects) {
- if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) {
- if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ float full_ascent = p_new_sd->ascent;
+ float full_descent = p_new_sd->descent;
+ for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : p_new_sd->objects) {
+ if ((E.value.pos >= p_new_sd->start) && (E.value.pos < p_new_sd->end)) {
+ if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
case INLINE_ALIGNMENT_TO_TOP: {
- E.value.rect.position.y = -new_sd->ascent;
+ E.value.rect.position.y = -p_new_sd->ascent;
} break;
case INLINE_ALIGNMENT_TO_CENTER: {
- E.value.rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
+ E.value.rect.position.y = (-p_new_sd->ascent + p_new_sd->descent) / 2;
} break;
case INLINE_ALIGNMENT_TO_BASELINE: {
E.value.rect.position.y = 0;
} break;
case INLINE_ALIGNMENT_TO_BOTTOM: {
- E.value.rect.position.y = new_sd->descent;
+ E.value.rect.position.y = p_new_sd->descent;
} break;
}
switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {
@@ -3463,16 +3476,16 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
} else {
switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
case INLINE_ALIGNMENT_TO_TOP: {
- E.value.rect.position.x = -new_sd->ascent;
+ E.value.rect.position.x = -p_new_sd->ascent;
} break;
case INLINE_ALIGNMENT_TO_CENTER: {
- E.value.rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
+ E.value.rect.position.x = (-p_new_sd->ascent + p_new_sd->descent) / 2;
} break;
case INLINE_ALIGNMENT_TO_BASELINE: {
E.value.rect.position.x = 0;
} break;
case INLINE_ALIGNMENT_TO_BOTTOM: {
- E.value.rect.position.x = new_sd->descent;
+ E.value.rect.position.x = p_new_sd->descent;
} break;
}
switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {
@@ -3491,12 +3504,12 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
}
}
- new_sd->ascent = full_ascent;
- new_sd->descent = full_descent;
+ p_new_sd->ascent = full_ascent;
+ p_new_sd->descent = full_descent;
}
- new_sd->valid = true;
+ p_new_sd->valid = true;
- return shaped_owner.make_rid(new_sd);
+ return true;
}
RID TextServerAdvanced::shaped_text_get_parent(RID p_shaped) const {
@@ -4225,8 +4238,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
for (int i = p_start; i < p_end; i++) {
if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
Glyph gl;
- gl.start = i;
- gl.end = i + 1;
+ gl.start = i + p_sd->start;
+ gl.end = i + 1 + p_sd->start;
gl.count = 1;
gl.index = p_sd->text[i];
gl.font_size = fs;
@@ -4252,6 +4265,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
RID f = p_fonts[p_fb_index];
hb_font_t *hb_font = _font_get_hb_handle(f, fs);
+ float scale = font_get_scale(f, fs);
+ float sp_sp = font_get_spacing(f, fs, SPACING_SPACE);
+ float sp_gl = font_get_spacing(f, fs, SPACING_GLYPH);
ERR_FAIL_COND(hb_font == nullptr);
hb_buffer_clear_contents(p_sd->hb_buffer);
@@ -4335,7 +4351,6 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
gl.index = glyph_info[i].codepoint;
if (gl.index != 0) {
- float scale = font_get_scale(f, fs);
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / scale));
} else {
@@ -4344,10 +4359,10 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / scale));
gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / scale));
}
- if (font_get_spacing(f, fs, SPACING_SPACE) && is_whitespace(p_sd->text[glyph_info[i].cluster])) {
- gl.advance += font_get_spacing(f, fs, SPACING_SPACE);
+ if (sp_sp && is_whitespace(p_sd->text[glyph_info[i].cluster])) {
+ gl.advance += sp_sp;
} else {
- gl.advance += font_get_spacing(f, fs, SPACING_GLYPH);
+ gl.advance += sp_gl;
}
if (p_sd->preserve_control) {
@@ -4385,10 +4400,13 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off);
p_sd->descent = MAX(p_sd->descent, w[i + j].y_off);
} else {
- p_sd->ascent = MAX(p_sd->ascent, Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5));
- p_sd->descent = MAX(p_sd->descent, Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5));
+ float gla = Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5);
+ p_sd->ascent = MAX(p_sd->ascent, gla);
+ p_sd->descent = MAX(p_sd->descent, gla);
}
p_sd->width += w[i + j].advance;
+ w[i + j].start += p_sd->start;
+ w[i + j].end += p_sd->start;
p_sd->glyphs.push_back(w[i + j]);
}
} else {
@@ -4421,10 +4439,14 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
return true;
}
+ invalidate(sd);
if (sd->parent != RID()) {
- full_copy(sd);
+ shaped_text_shape(sd->parent);
+ ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);
+ ERR_FAIL_COND_V(!parent_sd->valid, false);
+ ERR_FAIL_COND_V(!_shape_substr(sd, parent_sd, sd->start, sd->end - sd->start), false);
+ return true;
}
- invalidate(sd);
if (sd->text.length() == 0) {
sd->valid = true;
@@ -4440,15 +4462,17 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
}
if (sd->bidi_override.is_empty()) {
- sd->bidi_override.push_back(Vector2i(0, sd->end));
+ sd->bidi_override.push_back(Vector2i(sd->start, sd->end));
}
for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
// Create BiDi iterator.
- int start = _convert_pos_inv(sd, sd->bidi_override[ov].x);
- int end = _convert_pos_inv(sd, sd->bidi_override[ov].y);
+ int start = _convert_pos_inv(sd, sd->bidi_override[ov].x - sd->start);
+ int end = _convert_pos_inv(sd, sd->bidi_override[ov].y - sd->start);
- ERR_FAIL_COND_V_MSG((start < 0 || end - start > sd->utf16.length()), false, "Invalid BiDi override range.");
+ if (start < 0 || end - start > sd->utf16.length()) {
+ continue;
+ }
UErrorCode err = U_ZERO_ERROR;
UBiDi *bidi_iter = ubidi_openSized(end, 0, &err);
@@ -4502,8 +4526,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
}
}
- int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x + _bidi_run_start);
- int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x + _bidi_run_start + _bidi_run_length);
+ int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x - sd->start + _bidi_run_start);
+ int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x - sd->start + _bidi_run_start + _bidi_run_length);
// Shape runs.
@@ -4525,7 +4549,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
for (int k = spn_from; k != spn_to; k += spn_delta) {
const ShapedTextDataAdvanced::Span &span = sd->spans[k];
- if (span.start >= script_run_end || span.end <= script_run_start) {
+ if (span.start - sd->start >= script_run_end || span.end - sd->start <= script_run_start) {
continue;
}
if (span.embedded_key != Variant()) {
@@ -4566,7 +4590,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
}
fonts.append_array(fonts_scr_only);
fonts.append_array(fonts_no_match);
- _shape_run(sd, MAX(sd->spans[k].start, script_run_start), MIN(sd->spans[k].end, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0);
+ _shape_run(sd, MAX(sd->spans[k].start - sd->start, script_run_start), MIN(sd->spans[k].end - sd->start, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0);
}
}
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 414db8c7ea..9a22180f39 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -269,6 +269,7 @@ class TextServerAdvanced : public TextServer {
int _convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
int _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
+ bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int p_start, int p_length) const;
void _shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index);
Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size);
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 97a53143cf..8979d9ff4c 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -399,7 +399,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
FontGlyph chr;
chr.found = true;
- chr.advance = advance.round();
+ chr.advance = advance;
if (shape.validate() && shape.contours.size() > 0) {
int w = (bounds.r - bounds.l);
@@ -552,12 +552,12 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
}
FontGlyph chr;
- chr.advance = (advance * p_data->scale / p_data->oversampling).round();
+ chr.advance = advance * p_data->scale / p_data->oversampling;
chr.texture_idx = tex_pos.index;
chr.found = true;
chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h);
- chr.rect.position = (Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling).round();
+ chr.rect.position = Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling;
chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling;
return chr;
}
@@ -729,7 +729,8 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
}
FT_Select_Size(fd->face, best_match);
} else {
- FT_Set_Pixel_Sizes(fd->face, 0, fd->size.x * fd->oversampling);
+ FT_Set_Pixel_Sizes(fd->face, 0, Math::round(fd->size.x * fd->oversampling));
+ fd->scale = ((float)fd->size.x * fd->oversampling) / (float)fd->face->size->metrics.y_ppem;
}
fd->ascent = (fd->face->size->metrics.ascender / 64.0) / fd->oversampling * fd->scale;
@@ -1824,7 +1825,7 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
Vector2i size = _get_size(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
if (!_ensure_glyph(fd, size, p_index)) {
- return; // // Invalid or non graphicl glyph, do not display errors, nothing to draw.
+ return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
}
const FontGlyph &gl = fd->cache[size]->glyph_map[p_index];
@@ -1846,9 +1847,9 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
} else {
- Point2i cpos = p_pos;
+ Point2 cpos = p_pos.floor();
cpos += gl.rect.position;
- Size2i csize = gl.rect.size;
+ Size2 csize = gl.rect.size;
RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
}
}
@@ -1864,7 +1865,7 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
Vector2i size = _get_size_outline(fd, Vector2i(p_size, p_outline_size));
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
if (!_ensure_glyph(fd, size, p_index)) {
- return; // // Invalid or non graphicl glyph, do not display errors, nothing to draw.
+ return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
}
const FontGlyph &gl = fd->cache[size]->glyph_map[p_index];
@@ -1886,9 +1887,9 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
} else {
- Point2i cpos = p_pos;
+ Point2 cpos = p_pos.floor();
cpos += gl.rect.position;
- Size2i csize = gl.rect.size;
+ Size2 csize = gl.rect.size;
RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
}
}
@@ -2260,7 +2261,7 @@ bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, con
}
ShapedTextData::Span span;
- span.start = sd->text.length();
+ span.start = sd->start + sd->text.length();
span.end = span.start + p_length;
span.embedded_key = p_key;
@@ -2441,7 +2442,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->uthk = sd->uthk;
if (p_length > 0) {
- new_sd->text = sd->text.substr(p_start, p_length);
+ new_sd->text = sd->text.substr(p_start - sd->start, p_length);
int sd_size = sd->glyphs.size();
const Glyph *sd_glyphs = sd->glyphs.ptr();
@@ -2723,7 +2724,7 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
for (int i = 0; i < sd_size; i++) {
if (sd_glyphs[i].count > 0) {
- char32_t c = sd->text[sd_glyphs[i].start];
+ char32_t c = sd->text[sd_glyphs[i].start - sd->start];
if (c_punct_size == 0) {
if (is_punct(c)) {
sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
@@ -2980,7 +2981,7 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
gl.end = j + 1;
gl.count = 1;
gl.font_size = span.font_size;
- gl.index = (int32_t)sd->text[j]; // Use codepoint.
+ gl.index = (int32_t)sd->text[j - sd->start]; // Use codepoint.
if (gl.index == 0x0009 || gl.index == 0x000b) {
gl.index = 0x0020;
}
@@ -2996,7 +2997,7 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
}
if (gl.font_rid.is_valid()) {
- if (sd->text[j] != 0 && !is_linebreak(sd->text[j])) {
+ if (sd->text[j - sd->start] != 0 && !is_linebreak(sd->text[j - sd->start])) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
gl.advance = font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x;
gl.x_off = 0;
@@ -3011,7 +3012,7 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
sd->descent = MAX(sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
}
}
- if (font_get_spacing(gl.font_rid, gl.font_size, TextServer::SPACING_SPACE) && is_whitespace(sd->text[j])) {
+ if (font_get_spacing(gl.font_rid, gl.font_size, TextServer::SPACING_SPACE) && is_whitespace(sd->text[j - sd->start])) {
gl.advance += font_get_spacing(gl.font_rid, gl.font_size, TextServer::SPACING_SPACE);
} else {
gl.advance += font_get_spacing(gl.font_rid, gl.font_size, TextServer::SPACING_GLYPH);
diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp
index 133bd71ddb..20fe63bf7d 100644
--- a/modules/webrtc/webrtc_multiplayer_peer.cpp
+++ b/modules/webrtc/webrtc_multiplayer_peer.cpp
@@ -146,6 +146,10 @@ void WebRTCMultiplayerPeer::_find_next_peer() {
}
// After last.
while (E) {
+ if (!E->get()->connected) {
+ E = E->next();
+ continue;
+ }
for (const Ref<WebRTCDataChannel> &F : E->get()->channels) {
if (F->get_available_packet_count()) {
next_packet_peer = E->key();
@@ -157,6 +161,10 @@ void WebRTCMultiplayerPeer::_find_next_peer() {
E = peer_map.front();
// Before last
while (E) {
+ if (!E->get()->connected) {
+ E = E->next();
+ continue;
+ }
for (const Ref<WebRTCDataChannel> &F : E->get()->channels) {
if (F->get_available_packet_count()) {
next_packet_peer = E->key();
@@ -378,6 +386,9 @@ int WebRTCMultiplayerPeer::get_available_packet_count() const {
}
int size = 0;
for (const KeyValue<int, Ref<ConnectedPeer>> &E : peer_map) {
+ if (!E.value->connected) {
+ continue;
+ }
for (const Ref<WebRTCDataChannel> &F : E.value->channels) {
size += F->get_available_packet_count();
}
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index d2cf9a62ee..d7d78ff5dc 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -484,6 +484,9 @@ Error OS_Windows::create_process(const String &p_path, const List<String> &p_arg
#ifndef DEBUG_ENABLED
dwCreationFlags |= CREATE_NO_WINDOW;
#endif
+ if (p_path == get_executable_path() && GetConsoleWindow() != nullptr) {
+ dwCreationFlags |= CREATE_NEW_CONSOLE;
+ }
int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, dwCreationFlags, nullptr, nullptr, si_w, &pi.pi);
ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command);
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 9023b758b6..283a3a4883 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -882,6 +882,14 @@ void register_scene_types() {
ClassDB::add_compatibility_class("GIProbeData", "VoxelGIData");
ClassDB::add_compatibility_class("BakedLightmap", "LightmapGI");
ClassDB::add_compatibility_class("BakedLightmapData", "LightmapGIData");
+ // Portal and room occlusion was replaced by raster occlusion (OccluderInstance3D node).
+ ClassDB::add_compatibility_class("Portal", "Node3D");
+ ClassDB::add_compatibility_class("Room", "Node3D");
+ ClassDB::add_compatibility_class("RoomManager", "Node3D");
+ ClassDB::add_compatibility_class("RoomGroup", "Node3D");
+ ClassDB::add_compatibility_class("Occluder", "Node3D");
+ // The OccluderShapeSphere resource (used in the old Occluder node) is not present anymore.
+ ClassDB::add_compatibility_class("OccluderShapeSphere", "Resource");
// Renamed in 4.0.
// Keep alphabetical ordering to easily locate classes and avoid duplicates.
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 87aee0aae4..50e2de91f7 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -449,10 +449,10 @@ void BaseMaterial3D::_update_shader() {
texfilter_str = "filter_linear_mipmap";
break;
case TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC:
- texfilter_str = "filter_nearest_mipmap_aniso";
+ texfilter_str = "filter_nearest_mipmap_anisotropy";
break;
case TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC:
- texfilter_str = "filter_linear_mipmap_aniso";
+ texfilter_str = "filter_linear_mipmap_anisotropy";
break;
case TEXTURE_FILTER_MAX:
break; // Internal value, skip.
@@ -2569,7 +2569,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv2_world_triplanar"), "set_flag", "get_flag", FLAG_UV2_USE_WORLD_TRIPLANAR);
ADD_GROUP("Sampling", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropy,Linear Mipmap Anisotropy"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "texture_repeat"), "set_flag", "get_flag", FLAG_USE_TEXTURE_REPEAT);
ADD_GROUP("Shadows", "");
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index b077501a38..2a3abb0e82 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -214,8 +214,8 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
"FILTER_LINEAR",
"FILTER_NEAREST_MIPMAP",
"FILTER_LINEAR_MIPMAP",
- "FILTER_NEAREST_MIPMAP_ANISO",
- "FILTER_LINEAR_MIPMAP_ANISO",
+ "FILTER_NEAREST_MIPMAP_ANISOTROPY",
+ "FILTER_LINEAR_MIPMAP_ANISOTROPY",
"REPEAT_ENABLE",
"REPEAT_DISABLE",
"SHADER_TYPE",
@@ -328,8 +328,8 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_FILTER_LINEAR, "filter_linear" },
{ TK_FILTER_NEAREST_MIPMAP, "filter_nearest_mipmap" },
{ TK_FILTER_LINEAR_MIPMAP, "filter_linear_mipmap" },
- { TK_FILTER_NEAREST_MIPMAP_ANISO, "filter_nearest_mipmap_aniso" },
- { TK_FILTER_LINEAR_MIPMAP_ANISO, "filter_linear_mipmap_aniso" },
+ { TK_FILTER_NEAREST_MIPMAP_ANISOTROPY, "filter_nearest_mipmap_anisotropy" },
+ { TK_FILTER_LINEAR_MIPMAP_ANISOTROPY, "filter_linear_mipmap_anisotropy" },
{ TK_REPEAT_ENABLE, "repeat_enable" },
{ TK_REPEAT_DISABLE, "repeat_disable" },
{ TK_SHADER_TYPE, "shader_type" },
@@ -8082,10 +8082,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
uniform2.filter = FILTER_NEAREST_MIPMAP;
} else if (tk.type == TK_FILTER_LINEAR_MIPMAP) {
uniform2.filter = FILTER_LINEAR_MIPMAP;
- } else if (tk.type == TK_FILTER_NEAREST_MIPMAP_ANISO) {
- uniform2.filter = FILTER_NEAREST_MIPMAP_ANISO;
- } else if (tk.type == TK_FILTER_LINEAR_MIPMAP_ANISO) {
- uniform2.filter = FILTER_LINEAR_MIPMAP_ANISO;
+ } else if (tk.type == TK_FILTER_NEAREST_MIPMAP_ANISOTROPY) {
+ uniform2.filter = FILTER_NEAREST_MIPMAP_ANISOTROPY;
+ } else if (tk.type == TK_FILTER_LINEAR_MIPMAP_ANISOTROPY) {
+ uniform2.filter = FILTER_LINEAR_MIPMAP_ANISOTROPY;
} else if (tk.type == TK_REPEAT_DISABLE) {
uniform2.repeat = REPEAT_DISABLE;
} else if (tk.type == TK_REPEAT_ENABLE) {
@@ -9535,10 +9535,10 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
if (options.is_empty()) {
options.push_back("filter_linear");
options.push_back("filter_linear_mipmap");
- options.push_back("filter_linear_mipmap_aniso");
+ options.push_back("filter_linear_mipmap_anisotropy");
options.push_back("filter_nearest");
options.push_back("filter_nearest_mipmap");
- options.push_back("filter_nearest_mipmap_aniso");
+ options.push_back("filter_nearest_mipmap_anisotropy");
options.push_back("hint_albedo");
options.push_back("hint_anisotropy");
options.push_back("hint_black");
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 6681af2594..15333839d3 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -179,8 +179,8 @@ public:
TK_FILTER_LINEAR,
TK_FILTER_NEAREST_MIPMAP,
TK_FILTER_LINEAR_MIPMAP,
- TK_FILTER_NEAREST_MIPMAP_ANISO,
- TK_FILTER_LINEAR_MIPMAP_ANISO,
+ TK_FILTER_NEAREST_MIPMAP_ANISOTROPY,
+ TK_FILTER_LINEAR_MIPMAP_ANISOTROPY,
TK_REPEAT_ENABLE,
TK_REPEAT_DISABLE,
TK_SHADER_TYPE,
@@ -322,8 +322,8 @@ public:
FILTER_LINEAR,
FILTER_NEAREST_MIPMAP,
FILTER_LINEAR_MIPMAP,
- FILTER_NEAREST_MIPMAP_ANISO,
- FILTER_LINEAR_MIPMAP_ANISO,
+ FILTER_NEAREST_MIPMAP_ANISOTROPY,
+ FILTER_LINEAR_MIPMAP_ANISOTROPY,
FILTER_DEFAULT,
};