summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/extension/gdnative_interface.cpp12
-rw-r--r--core/extension/gdnative_interface.h2
-rw-r--r--core/input/input.cpp12
-rw-r--r--core/input/input.h4
-rw-r--r--core/os/os.cpp31
-rw-r--r--core/variant/dictionary.cpp8
-rw-r--r--core/variant/dictionary.h1
-rw-r--r--core/variant/variant_call.cpp6
-rw-r--r--doc/classes/Dictionary.xml8
-rw-r--r--doc/classes/Input.xml34
-rw-r--r--doc/classes/InputEventMouseMotion.xml2
-rw-r--r--doc/classes/MultiplayerSynchronizer.xml2
-rw-r--r--doc/classes/NodePath.xml6
-rw-r--r--doc/classes/StringName.xml8
-rw-r--r--doc/classes/Viewport.xml2
-rw-r--r--doc/classes/VisualShaderNodeFloatFunc.xml2
-rw-r--r--doc/classes/VisualShaderNodeVectorFunc.xml2
-rw-r--r--editor/editor_themes.cpp7
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp2
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp2
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp3
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp6
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp1
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp45
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp12
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp1
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp8
-rw-r--r--editor/scene_tree_editor.cpp5
-rw-r--r--modules/text_server_adv/text_server_adv.cpp6
-rw-r--r--modules/text_server_adv/text_server_adv.h2
-rw-r--r--modules/text_server_fb/text_server_fb.h2
-rw-r--r--scene/gui/rich_text_label.cpp90
-rw-r--r--scene/gui/rich_text_label.h6
-rw-r--r--scene/main/viewport.cpp16
-rw-r--r--scene/main/viewport.h2
-rw-r--r--scene/main/window.cpp2
-rw-r--r--scene/multiplayer/multiplayer_synchronizer.cpp2
-rw-r--r--scene/resources/texture.cpp10
-rw-r--r--scene/resources/visual_shader_nodes.cpp8
-rw-r--r--scene/resources/visual_shader_nodes.h4
40 files changed, 272 insertions, 112 deletions
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index a1d54f9c6d..58103e3af3 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -230,6 +230,16 @@ static void gdnative_variant_iter_get(const GDNativeVariantPtr p_self, GDNativeV
}
/// Variant functions.
+static GDNativeInt gdnative_variant_hash(const GDNativeVariantPtr p_self) {
+ const Variant *self = (const Variant *)p_self;
+ return self->hash();
+}
+
+static GDNativeInt gdnative_variant_recursive_hash(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count) {
+ const Variant *self = (const Variant *)p_self;
+ return self->recursive_hash(p_recursion_count);
+}
+
static GDNativeBool gdnative_variant_hash_compare(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other) {
const Variant *self = (const Variant *)p_self;
const Variant *other = (const Variant *)p_other;
@@ -944,6 +954,8 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.variant_iter_init = gdnative_variant_iter_init;
gdni.variant_iter_next = gdnative_variant_iter_next;
gdni.variant_iter_get = gdnative_variant_iter_get;
+ gdni.variant_hash = gdnative_variant_hash;
+ gdni.variant_recursive_hash = gdnative_variant_recursive_hash;
gdni.variant_hash_compare = gdnative_variant_hash_compare;
gdni.variant_booleanize = gdnative_variant_booleanize;
gdni.variant_sub = gdnative_variant_sub;
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 98976b29f6..095c7983ee 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -413,6 +413,8 @@ typedef struct {
GDNativeBool (*variant_iter_init)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
GDNativeBool (*variant_iter_next)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
void (*variant_iter_get)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
+ GDNativeInt (*variant_hash)(const GDNativeVariantPtr p_self);
+ GDNativeInt (*variant_recursive_hash)(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count);
GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other);
GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self);
void (*variant_sub)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst);
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 4befdfac58..b3a68bb98c 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -134,8 +134,12 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input);
+ ClassDB::bind_method(D_METHOD("is_using_accumulated_input"), &Input::is_using_accumulated_input);
ClassDB::bind_method(D_METHOD("flush_buffered_events"), &Input::flush_buffered_events);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_mode"), "set_mouse_mode", "get_mouse_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_accumulated_input"), "set_use_accumulated_input", "is_using_accumulated_input");
+
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
@@ -897,6 +901,10 @@ void Input::set_use_accumulated_input(bool p_enable) {
use_accumulated_input = p_enable;
}
+bool Input::is_using_accumulated_input() {
+ return use_accumulated_input;
+}
+
void Input::release_pressed_events() {
flush_buffered_events(); // this is needed to release actions strengths
@@ -1401,8 +1409,8 @@ String Input::get_joy_guid(int p_device) const {
return joy_names[p_device].uid;
}
-Array Input::get_connected_joypads() {
- Array ret;
+TypedArray<int> Input::get_connected_joypads() {
+ TypedArray<int> ret;
HashMap<int, Joypad>::Iterator elem = joy_names.begin();
while (elem) {
if (elem->value.connected) {
diff --git a/core/input/input.h b/core/input/input.h
index 9a5b8e6e06..f02f2abae5 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -36,6 +36,7 @@
#include "core/os/keyboard.h"
#include "core/os/thread_safe.h"
#include "core/templates/rb_set.h"
+#include "core/variant/typed_array.h"
class Input : public Object {
GDCLASS(Input, Object);
@@ -259,7 +260,7 @@ public:
float get_joy_axis(int p_device, JoyAxis p_axis) const;
String get_joy_name(int p_idx);
- Array get_connected_joypads();
+ TypedArray<int> get_connected_joypads();
Vector2 get_joy_vibration_strength(int p_device);
float get_joy_vibration_duration(int p_device);
uint64_t get_joy_vibration_timestamp(int p_device);
@@ -326,6 +327,7 @@ public:
bool is_using_input_buffering();
void set_use_input_buffering(bool p_enable);
void set_use_accumulated_input(bool p_enable);
+ bool is_using_accumulated_input();
void release_pressed_events();
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 4f7095b0fc..327f1c95f2 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -413,19 +413,29 @@ bool OS::has_feature(const String &p_feature) {
if (sizeof(void *) == 4 && p_feature == "32") {
return true;
}
-#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__)
+#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)
+#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
if (p_feature == "x86_64") {
return true;
}
-#elif (defined(__i386) || defined(__i386__))
+#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
+ if (p_feature == "x86_32") {
+ return true;
+ }
+#endif
if (p_feature == "x86") {
return true;
}
-#elif defined(__aarch64__)
+#elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
+#if defined(__aarch64__) || defined(_M_ARM64)
if (p_feature == "arm64") {
return true;
}
-#elif defined(__arm__)
+#elif defined(__arm__) || defined(_M_ARM)
+ if (p_feature == "arm32") {
+ return true;
+ }
+#endif
#if defined(__ARM_ARCH_7A__)
if (p_feature == "armv7a" || p_feature == "armv7") {
return true;
@@ -457,6 +467,19 @@ bool OS::has_feature(const String &p_feature) {
if (p_feature == "ppc") {
return true;
}
+#elif defined(__wasm__)
+#if defined(__wasm64__)
+ if (p_feature == "wasm64") {
+ return true;
+ }
+#elif defined(__wasm32__)
+ if (p_feature == "wasm32") {
+ return true;
+ }
+#endif
+ if (p_feature == "wasm") {
+ return true;
+ }
#endif
if (_check_internal_feature_support(p_feature)) {
diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp
index bda8c93a79..822021f440 100644
--- a/core/variant/dictionary.cpp
+++ b/core/variant/dictionary.cpp
@@ -269,6 +269,14 @@ void Dictionary::clear() {
_p->variant_map.clear();
}
+void Dictionary::merge(const Dictionary &p_dictionary, bool p_overwrite) {
+ for (const KeyValue<Variant, Variant> &E : p_dictionary._p->variant_map) {
+ if (p_overwrite || !has(E.key)) {
+ this->operator[](E.key) = E.value;
+ }
+ }
+}
+
void Dictionary::_unref() const {
ERR_FAIL_COND(!_p);
if (_p->refcount.unref()) {
diff --git a/core/variant/dictionary.h b/core/variant/dictionary.h
index 1224a4ff6f..2632893e8d 100644
--- a/core/variant/dictionary.h
+++ b/core/variant/dictionary.h
@@ -62,6 +62,7 @@ public:
int size() const;
bool is_empty() const;
void clear();
+ void merge(const Dictionary &p_dictionary, bool p_overwrite = false);
bool has(const Variant &p_key) const;
bool has_all(const Array &p_keys) const;
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index a3568a8d6a..3fe5ead347 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1472,6 +1472,10 @@ static void _register_variant_builtin_methods() {
bind_static_method(String, chr, sarray("char"), varray());
bind_static_method(String, humanize_size, sarray("size"), varray());
+ /* StringName */
+
+ bind_method(StringName, hash, sarray(), varray());
+
/* Vector2 */
bind_method(Vector2, angle, sarray(), varray());
@@ -1684,6 +1688,7 @@ static void _register_variant_builtin_methods() {
bind_method(NodePath, get_name_count, sarray(), varray());
bind_method(NodePath, get_name, sarray("idx"), varray());
bind_method(NodePath, get_subname_count, sarray(), varray());
+ bind_method(NodePath, hash, sarray(), varray());
bind_method(NodePath, get_subname, sarray("idx"), varray());
bind_method(NodePath, get_concatenated_subnames, sarray(), varray());
bind_method(NodePath, get_as_property_path, sarray(), varray());
@@ -1808,6 +1813,7 @@ static void _register_variant_builtin_methods() {
bind_method(Dictionary, size, sarray(), varray());
bind_method(Dictionary, is_empty, sarray(), varray());
bind_method(Dictionary, clear, sarray(), varray());
+ bind_method(Dictionary, merge, sarray("dictionary", "overwrite"), varray(false));
bind_method(Dictionary, has, sarray("key"), varray());
bind_method(Dictionary, has_all, sarray("keys"), varray());
bind_method(Dictionary, erase, sarray("key"), varray());
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index b46719c758..6f2ad5205c 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -291,6 +291,14 @@
Returns the list of keys in the [Dictionary].
</description>
</method>
+ <method name="merge">
+ <return type="void" />
+ <argument index="0" name="dictionary" type="Dictionary" />
+ <argument index="1" name="overwrite" type="bool" default="false" />
+ <description>
+ Adds elements from [code]dictionary[/code] to this [Dictionary]. By default, duplicate keys will not be copied over, unless [code]overwrite[/code] is [code]true[/code].
+ </description>
+ </method>
<method name="size" qualifiers="const">
<return type="int" />
<description>
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 2a4381b41b..66683fa0ee 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -40,7 +40,7 @@
<method name="flush_buffered_events">
<return type="void" />
<description>
- Sends all input events which are in the current buffer to the game loop. These events may have been buffered as a result of accumulated input ([method set_use_accumulated_input]) or agile input flushing ([member ProjectSettings.input_devices/buffering/agile_event_flushing]).
+ Sends all input events which are in the current buffer to the game loop. These events may have been buffered as a result of accumulated input ([member use_accumulated_input]) or agile input flushing ([member ProjectSettings.input_devices/buffering/agile_event_flushing]).
The engine will already do this itself at key execution points (at least once per frame). However, this can be useful in advanced cases where you want precise control over the timing of event handling.
</description>
</method>
@@ -80,7 +80,7 @@
</description>
</method>
<method name="get_connected_joypads">
- <return type="Array" />
+ <return type="int[]" />
<description>
Returns an [Array] containing the device IDs of all currently connected joypads.
</description>
@@ -160,12 +160,6 @@
Returns mouse buttons as a bitmask. If multiple mouse buttons are pressed at the same time, the bits are added together.
</description>
</method>
- <method name="get_mouse_mode" qualifiers="const">
- <return type="int" enum="Input.MouseMode" />
- <description>
- Returns the mouse mode. See the constants for more information.
- </description>
- </method>
<method name="get_vector" qualifiers="const">
<return type="Vector2" />
<argument index="0" name="negative_x" type="StringName" />
@@ -338,21 +332,6 @@
[b]Note:[/b] This value can be immediately overwritten by the hardware sensor value on Android and iOS.
</description>
</method>
- <method name="set_mouse_mode">
- <return type="void" />
- <argument index="0" name="mode" type="int" enum="Input.MouseMode" />
- <description>
- Sets the mouse mode. See the constants for more information.
- </description>
- </method>
- <method name="set_use_accumulated_input">
- <return type="void" />
- <argument index="0" name="enable" type="bool" />
- <description>
- Enables or disables the accumulation of similar input events sent by the operating system. When input accumulation is enabled, all input events generated during a frame will be merged and emitted when the frame is done rendering. Therefore, this limits the number of input method calls per second to the rendering FPS.
- Input accumulation is enabled by default. It can be disabled to get slightly more precise/reactive input at the cost of increased CPU usage. In applications where drawing freehand lines is required, input accumulation should generally be disabled while the user is drawing the line to get results that closely follow the actual input.
- </description>
- </method>
<method name="start_joy_vibration">
<return type="void" />
<argument index="0" name="device" type="int" />
@@ -389,6 +368,15 @@
</description>
</method>
</methods>
+ <members>
+ <member name="mouse_mode" type="int" setter="set_mouse_mode" getter="get_mouse_mode" enum="Input.MouseMode">
+ Controls the mouse mode. See [enum MouseMode] for more information.
+ </member>
+ <member name="use_accumulated_input" type="bool" setter="set_use_accumulated_input" getter="is_using_accumulated_input">
+ If [code]true[/code], similar input events sent by the operating system are accumulated. When input accumulation is enabled, all input events generated during a frame will be merged and emitted when the frame is done rendering. Therefore, this limits the number of input method calls per second to the rendering FPS.
+ Input accumulation can be disabled to get slightly more precise/reactive input at the cost of increased CPU usage. In applications where drawing freehand lines is required, input accumulation should generally be disabled while the user is drawing the line to get results that closely follow the actual input.
+ </member>
+ </members>
<signals>
<signal name="joy_connection_changed">
<argument index="0" name="device" type="int" />
diff --git a/doc/classes/InputEventMouseMotion.xml b/doc/classes/InputEventMouseMotion.xml
index 7cc3de8fcb..ad74204d82 100644
--- a/doc/classes/InputEventMouseMotion.xml
+++ b/doc/classes/InputEventMouseMotion.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Contains mouse and pen motion information. Supports relative, absolute positions and velocity. See [method Node._input].
- [b]Note:[/b] By default, this event is only emitted once per frame rendered at most. If you need more precise input reporting, call [method Input.set_use_accumulated_input] with [code]false[/code] to make events emitted as often as possible. If you use InputEventMouseMotion to draw lines, consider implementing [url=https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm]Bresenham's line algorithm[/url] as well to avoid visible gaps in lines if the user is moving the mouse quickly.
+ [b]Note:[/b] By default, this event is only emitted once per frame rendered at most. If you need more precise input reporting, set [member Input.use_accumulated_input] to [code]false[/code] to make events emitted as often as possible. If you use InputEventMouseMotion to draw lines, consider implementing [url=https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm]Bresenham's line algorithm[/url] as well to avoid visible gaps in lines if the user is moving the mouse quickly.
</description>
<tutorials>
<link title="Mouse and input coordinates">$DOCS_URL/tutorials/inputs/mouse_and_input_coordinates.html</link>
diff --git a/doc/classes/MultiplayerSynchronizer.xml b/doc/classes/MultiplayerSynchronizer.xml
index 43355481b6..ac067791e6 100644
--- a/doc/classes/MultiplayerSynchronizer.xml
+++ b/doc/classes/MultiplayerSynchronizer.xml
@@ -7,7 +7,7 @@
<tutorials>
</tutorials>
<members>
- <member name="congiruation" type="SceneReplicationConfig" setter="set_replication_config" getter="get_replication_config">
+ <member name="replication_config" type="SceneReplicationConfig" setter="set_replication_config" getter="get_replication_config">
</member>
<member name="replication_interval" type="float" setter="set_replication_interval" getter="get_replication_interval" default="0.0">
</member>
diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml
index 3319e5d822..0d286a20b7 100644
--- a/doc/classes/NodePath.xml
+++ b/doc/classes/NodePath.xml
@@ -157,6 +157,12 @@
For example, [code]"Path2D/PathFollow2D/Sprite2D:texture:load_path"[/code] has 2 subnames.
</description>
</method>
+ <method name="hash" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the 32-bit hash value representing the [NodePath]'s contents.
+ </description>
+ </method>
<method name="is_absolute" qualifiers="const">
<return type="bool" />
<description>
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index ffa1227500..a2bcac9788 100644
--- a/doc/classes/StringName.xml
+++ b/doc/classes/StringName.xml
@@ -32,6 +32,14 @@
</description>
</constructor>
</constructors>
+ <methods>
+ <method name="hash" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the 32-bit hash value representing the [StringName]'s contents.
+ </description>
+ </method>
+ </methods>
<operators>
<operator name="operator !=">
<return type="bool" />
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 148c6d7064..def99b8a7a 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -227,7 +227,7 @@
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.
</member>
<member name="own_world_3d" type="bool" setter="set_use_own_world_3d" getter="is_using_own_world_3d" default="false">
- If [code]true[/code], the viewport will use the [World3D] defined in [member world_3d].
+ If [code]true[/code], the viewport will use a unique copy of the [World3D] defined in [member world_3d].
</member>
<member name="physics_object_picking" type="bool" setter="set_physics_object_picking" getter="get_physics_object_picking" default="false">
If [code]true[/code], the objects rendered by viewport become subjects of mouse picking process.
diff --git a/doc/classes/VisualShaderNodeFloatFunc.xml b/doc/classes/VisualShaderNodeFloatFunc.xml
index 0f057b2e6d..1226013c67 100644
--- a/doc/classes/VisualShaderNodeFloatFunc.xml
+++ b/doc/classes/VisualShaderNodeFloatFunc.xml
@@ -65,7 +65,7 @@
<constant name="FUNC_CEIL" value="16" enum="Function">
Finds the nearest integer that is greater than or equal to the parameter. Translates to [code]ceil(x)[/code] in the Godot Shader Language.
</constant>
- <constant name="FUNC_FRAC" value="17" enum="Function">
+ <constant name="FUNC_FRACT" value="17" enum="Function">
Computes the fractional part of the argument. Translates to [code]fract(x)[/code] in the Godot Shader Language.
</constant>
<constant name="FUNC_SATURATE" value="18" enum="Function">
diff --git a/doc/classes/VisualShaderNodeVectorFunc.xml b/doc/classes/VisualShaderNodeVectorFunc.xml
index bc4e12c0b3..7524025f21 100644
--- a/doc/classes/VisualShaderNodeVectorFunc.xml
+++ b/doc/classes/VisualShaderNodeVectorFunc.xml
@@ -68,7 +68,7 @@
<constant name="FUNC_FLOOR" value="17" enum="Function">
Finds the nearest integer less than or equal to the parameter.
</constant>
- <constant name="FUNC_FRAC" value="18" enum="Function">
+ <constant name="FUNC_FRACT" value="18" enum="Function">
Computes the fractional part of the argument.
</constant>
<constant name="FUNC_INVERSE_SQRT" value="19" enum="Function">
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index c53c04af4e..fa106979be 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -1484,6 +1484,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const int gn_margin_side = 2;
const int gn_margin_bottom = 2;
+ // StateMachine
+ const int sm_margin_side = 10;
+
Color graphnode_bg = dark_color_3;
if (!dark_theme) {
graphnode_bg = prop_section_color;
@@ -1510,10 +1513,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
graphsbposition->set_border_color(error_color);
graphsbposition->set_shadow_color(error_color * Color(1.0, 1.0, 1.0, 0.2));
Ref<StyleBoxEmpty> graphsbslot = make_empty_stylebox(12, 0, 12, 0);
- Ref<StyleBoxFlat> smgraphsb = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), gn_margin_side, 24, gn_margin_side, gn_margin_bottom, corner_width);
+ Ref<StyleBoxFlat> smgraphsb = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), sm_margin_side, 24, sm_margin_side, gn_margin_bottom, corner_width);
smgraphsb->set_border_width_all(border_width);
smgraphsb->set_border_color(graphnode_bg);
- Ref<StyleBoxFlat> smgraphsbselected = make_flat_stylebox(graphnode_bg * Color(1, 1, 1, 0.9), gn_margin_side, 24, gn_margin_side, gn_margin_bottom, corner_width);
+ Ref<StyleBoxFlat> smgraphsbselected = make_flat_stylebox(graphnode_bg * Color(1, 1, 1, 0.9), sm_margin_side, 24, sm_margin_side, gn_margin_bottom, corner_width);
smgraphsbselected->set_border_width_all(2 * EDSCALE + border_width);
smgraphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
smgraphsbselected->set_shadow_size(8 * EDSCALE);
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index ae4482155c..2e4dcab203 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -83,7 +83,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
for (const StringName &E : classes) {
String name = String(E).replace_first("AnimationNode", "");
- if (name == "Animation") {
+ if (name == "Animation" || name == "StartState" || name == "EndState") {
continue;
}
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index 4b7df75aec..86addde87b 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -107,7 +107,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
for (const StringName &E : classes) {
String name = String(E).replace_first("AnimationNode", "");
- if (name == "Animation") {
+ if (name == "Animation" || name == "StartState" || name == "EndState") {
continue; // nope
}
int idx = menu->get_item_count();
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index bd9b89cbb7..ece0c6a0ce 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -1220,7 +1220,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
for (const StringName &E : nodes) {
Ref<AnimationNode> anode = state_machine->get_node(E);
String name = E;
- bool needs_editor = EditorNode::get_singleton()->item_has_editor(anode.ptr());
+ bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode);
Ref<StyleBox> sb = selected_nodes.has(E) ? style_selected : style;
Size2 s = sb->get_minimum_size();
@@ -1432,7 +1432,6 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
} else {
state_machine_draw->draw_texture(edit, nr.edit.position);
}
- offset.x += sep + edit->get_width();
}
}
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index d28629b41a..4377eff322 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -1284,8 +1284,10 @@ void CanvasItemEditor::_pan_callback(Vector2 p_scroll_vec) {
}
void CanvasItemEditor::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
- zoom_widget->set_zoom_by_increments(-1, p_alt);
- if (!Math::is_equal_approx(p_scroll_vec.y, (real_t)1.0)) {
+ int scroll_sign = (int)SIGN(p_scroll_vec.y);
+ // Inverted so that scrolling up (-1) zooms in, scrolling down (+1) zooms out.
+ zoom_widget->set_zoom_by_increments(-scroll_sign, p_alt);
+ if (!Math::is_equal_approx(ABS(p_scroll_vec.y), (real_t)1.0)) {
// Handle high-precision (analog) scrolling.
zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * p_scroll_vec.y + 1.f));
}
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 06ad0f8918..c2c5b63917 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -414,6 +414,7 @@ void Node3DEditorViewport::cancel_transform() {
void Node3DEditorViewport::_update_shrink() {
bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION));
subviewport_container->set_stretch_shrink(shrink ? 2 : 1);
+ subviewport_container->set_texture_filter(shrink ? TEXTURE_FILTER_NEAREST : TEXTURE_FILTER_PARENT_NODE);
}
float Node3DEditorViewport::get_znear() const {
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 467af8c34b..36f559b2ae 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -37,6 +37,19 @@
#include "node_3d_editor_plugin.h"
#include "scene/resources/curve.h"
+static bool _is_in_handle(int p_id, int p_num_points) {
+ int t = (p_id + 1) % 2;
+ int idx = (p_id + 1) / 2;
+ // order of points is [out_0, out_1, in_1, out_2, in_2, ... out_n-1, in_n-1, in_n]
+ if (idx == 0) {
+ return false;
+ } else if (idx == (p_num_points - 1)) {
+ return true;
+ } else {
+ return (t == 1);
+ }
+}
+
String Path3DGizmo::get_handle_name(int p_id, bool p_secondary) const {
Ref<Curve3D> c = path->get_curve();
if (c.is_null()) {
@@ -47,12 +60,10 @@ String Path3DGizmo::get_handle_name(int p_id, bool p_secondary) const {
return TTR("Curve Point #") + itos(p_id);
}
- p_id += 1; // Account for the first point only having an "out" handle
-
- int idx = p_id / 2;
- int t = p_id % 2;
+ // (p_id + 1) Accounts for the first point only having an "out" handle
+ int idx = (p_id + 1) / 2;
String n = TTR("Curve Point #") + itos(idx);
- if (t == 1) {
+ if (_is_in_handle(p_id, c->get_point_count())) {
n += " In";
} else {
n += " Out";
@@ -72,13 +83,11 @@ Variant Path3DGizmo::get_handle_value(int p_id, bool p_secondary) const {
return original;
}
- p_id += 1; // Account for the first point only having an "out" handle
-
- int idx = p_id / 2;
- int t = p_id % 2;
+ // (p_id + 1) Accounts for the first point only having an "out" handle
+ int idx = (p_id + 1) / 2;
Vector3 ofs;
- if (t == 1) {
+ if (_is_in_handle(p_id, c->get_point_count())) {
ofs = c->get_point_in(idx);
} else {
ofs = c->get_point_out(idx);
@@ -119,10 +128,8 @@ void Path3DGizmo::set_handle(int p_id, bool p_secondary, Camera3D *p_camera, con
return;
}
- p_id += 1; // Account for the first point only having an "out" handle
-
- int idx = p_id / 2;
- int t = p_id % 2;
+ // (p_id + 1) Accounts for the first point only having an "out" handle
+ int idx = (p_id + 1) / 2;
Vector3 base = c->get_point_position(idx);
@@ -144,7 +151,7 @@ void Path3DGizmo::set_handle(int p_id, bool p_secondary, Camera3D *p_camera, con
local.snap(Vector3(snap, snap, snap));
}
- if (t == 1) {
+ if (_is_in_handle(p_id, c->get_point_count())) {
c->set_point_in(idx, local);
if (Path3DEditorPlugin::singleton->mirror_angle_enabled()) {
c->set_point_out(idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_out_length));
@@ -179,12 +186,10 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res
return;
}
- p_id += 1; // Account for the first point only having an "out" handle
-
- int idx = p_id / 2;
- int t = p_id % 2;
+ // (p_id + 1) Accounts for the first point only having an "out" handle
+ int idx = (p_id + 1) / 2;
- if (t == 1) {
+ if (_is_in_handle(p_id, c->get_point_count())) {
if (p_cancel) {
c->set_point_in(p_id, p_restore);
return;
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index 244c718ebe..d035c038d3 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -776,13 +776,13 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
button_advanced_menu = memnew(MenuButton);
button_advanced_menu->set_flat(true);
button_advanced_menu->set_toggle_mode(true);
- button_advanced_menu->get_popup()->add_item(TTR("Reset to default tile shape"), RESET_TO_DEFAULT_TILE);
- button_advanced_menu->get_popup()->add_item(TTR("Clear"), CLEAR_TILE);
+ button_advanced_menu->get_popup()->add_item(TTR("Reset to default tile shape"), RESET_TO_DEFAULT_TILE, Key::F);
+ button_advanced_menu->get_popup()->add_item(TTR("Clear"), CLEAR_TILE, Key::C);
button_advanced_menu->get_popup()->add_separator();
- button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("RotateRight"), SNAME("EditorIcons")), TTR("Rotate Right"), ROTATE_RIGHT);
- button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("RotateLeft"), SNAME("EditorIcons")), TTR("Rotate Left"), ROTATE_LEFT);
- button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("MirrorX"), SNAME("EditorIcons")), TTR("Flip Horizontally"), FLIP_HORIZONTALLY);
- button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("MirrorY"), SNAME("EditorIcons")), TTR("Flip Vertically"), FLIP_VERTICALLY);
+ button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("RotateRight"), SNAME("EditorIcons")), TTR("Rotate Right"), ROTATE_RIGHT, Key::R);
+ button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("RotateLeft"), SNAME("EditorIcons")), TTR("Rotate Left"), ROTATE_LEFT, Key::E);
+ button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("MirrorX"), SNAME("EditorIcons")), TTR("Flip Horizontally"), FLIP_HORIZONTALLY, Key::H);
+ button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("MirrorY"), SNAME("EditorIcons")), TTR("Flip Vertically"), FLIP_VERTICALLY, Key::V);
button_advanced_menu->get_popup()->connect("id_pressed", callable_mp(this, &GenericTilePolygonEditor::_advanced_menu_item_pressed));
button_advanced_menu->set_focus_mode(FOCUS_ALL);
toolbar->add_child(button_advanced_menu);
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 6c39244f80..cd8aca2a8e 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -3428,6 +3428,7 @@ void TileMapEditor::_notification(int p_what) {
void TileMapEditor::_on_grid_toggled(bool p_pressed) {
EditorSettings::get_singleton()->set("editors/tiles_editor/display_grid", p_pressed);
+ CanvasItemEditor::get_singleton()->update_viewport();
}
void TileMapEditor::_layers_selection_button_draw() {
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 642973648e..19cd354eaf 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -5329,7 +5329,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Exp", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-e Exponential."), { VisualShaderNodeFloatFunc::FUNC_EXP }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Exp2", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 Exponential."), { VisualShaderNodeFloatFunc::FUNC_EXP2 }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Floor", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeFloatFunc::FUNC_FLOOR }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Fract", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeFloatFunc::FUNC_FRAC }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Fract", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeFloatFunc::FUNC_FRACT }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("InverseSqrt", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse of the square root of the parameter."), { VisualShaderNodeFloatFunc::FUNC_INVERSE_SQRT }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Log", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Natural logarithm."), { VisualShaderNodeFloatFunc::FUNC_LOG }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Log2", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 logarithm."), { VisualShaderNodeFloatFunc::FUNC_LOG2 }, VisualShaderNode::PORT_TYPE_SCALAR));
@@ -5513,9 +5513,9 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Floor", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("Floor", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Floor", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRAC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRAC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRAC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRACT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRACT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRACT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
add_options.push_back(AddOption("Fresnel", "Vector", "Functions", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("InverseSqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse of the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_INVERSE_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("InverseSqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse of the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_INVERSE_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index b5b70b827b..5536e09da7 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -584,6 +584,11 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select
p_parent = tree->get_root();
}
+ if (!p_parent) {
+ // Tree is empty, nothing to do here.
+ return false;
+ }
+
bool keep = false;
for (TreeItem *child = p_parent->get_first_child(); child; child = child->get_next()) {
keep = _update_filter(child, p_scroll_to_selected) || keep;
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 598ccd1238..d18ed97def 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -1329,7 +1329,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
- hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform.columns[0][1]);
+ hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform[0][1]);
if (!p_font_data->face_init) {
// Get style flags and name.
@@ -3272,7 +3272,7 @@ void TextServerAdvanced::font_set_global_oversampling(double p_oversampling) {
int64_t TextServerAdvanced::_convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const {
int64_t limit = p_pos;
if (p_utf32.length() != p_utf16.length()) {
- const UChar *data = p_utf16.ptr();
+ const UChar *data = p_utf16.get_data();
for (int i = 0; i < p_pos; i++) {
if (U16_IS_LEAD(data[i])) {
limit--;
@@ -5591,7 +5591,7 @@ PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_stri
HashSet<int> breaks;
UErrorCode err = U_ZERO_ERROR;
- UBreakIterator *bi = ubrk_open(UBRK_LINE, p_language.ascii().get_data(), (const UChar *)utf16.ptr(), utf16.length(), &err);
+ UBreakIterator *bi = ubrk_open(UBRK_LINE, p_language.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);
if (U_FAILURE(err)) {
// No data loaded - use fallback.
for (int i = 0; i < p_string.length(); i++) {
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index fe1d4bdcbf..62f94472b5 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -67,8 +67,8 @@
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/templates/hash_map.hpp>
+#include <godot_cpp/templates/hash_set.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
-#include <godot_cpp/templates/set.hpp>
#include <godot_cpp/templates/thread_work_pool.hpp>
#include <godot_cpp/templates/vector.hpp>
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 0d2fc2628d..f3d516edea 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -67,8 +67,8 @@
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/templates/hash_map.hpp>
+#include <godot_cpp/templates/hash_set.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
-#include <godot_cpp/templates/set.hpp>
#include <godot_cpp/templates/thread_work_pool.hpp>
#include <godot_cpp/templates/vector.hpp>
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 94c2a9e64b..cf7bf930a5 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -414,7 +414,7 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
}
l.offset.y = p_h;
- return l.offset.y + l.text_buf->get_size().y + l.text_buf->get_line_count() * get_theme_constant(SNAME("line_separation"));
+ return _calculate_line_vertical_offset(l);
}
float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, float p_h, int *r_char_offset) {
@@ -683,7 +683,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
*r_char_offset = l.char_offset + l.char_count;
l.offset.y = p_h;
- return l.offset.y + l.text_buf->get_size().y + l.text_buf->get_line_count() * get_theme_constant(SNAME("line_separation"));
+ return _calculate_line_vertical_offset(l);
}
int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, 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) {
@@ -1566,7 +1566,7 @@ int RichTextLabel::_find_first_line(int p_from, int p_to, int p_vofs) const {
while (l < r) {
int m = Math::floor(double(l + r) / 2.0);
MutexLock lock(main->lines[m].text_buf->get_mutex());
- int ofs = main->lines[m].offset.y + main->lines[m].text_buf->get_size().y + main->lines[m].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation"));
+ int ofs = _calculate_line_vertical_offset(main->lines[m]);
if (ofs < p_vofs) {
l = m + 1;
} else {
@@ -1576,6 +1576,10 @@ int RichTextLabel::_find_first_line(int p_from, int p_to, int p_vofs) const {
return l;
}
+_FORCE_INLINE_ float RichTextLabel::_calculate_line_vertical_offset(const RichTextLabel::Line &line) const {
+ return line.get_height(get_theme_constant(SNAME("line_separation")));
+}
+
void RichTextLabel::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_MOUSE_EXIT: {
@@ -1609,6 +1613,7 @@ void RichTextLabel::_notification(int p_what) {
update();
} break;
+ case NOTIFICATION_PREDELETE:
case NOTIFICATION_EXIT_TREE: {
_stop_thread();
} break;
@@ -2489,7 +2494,7 @@ bool RichTextLabel::_validate_line_caches() {
// Resize lines without reshaping.
int fi = main->first_resized_line.load();
- float total_height = 0;
+ float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
for (int i = fi; i < (int)main->lines.size(); i++) {
total_height = _resize_line(main, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height);
@@ -2551,6 +2556,10 @@ bool RichTextLabel::_validate_line_caches() {
void RichTextLabel::_process_line_caches() {
// Shape invalid lines.
+ if (!is_inside_tree()) {
+ return;
+ }
+
MutexLock data_lock(data_mutex);
Rect2 text_rect = _get_text_rect();
@@ -2560,10 +2569,9 @@ void RichTextLabel::_process_line_caches() {
int fi = main->first_invalid_line.load();
int total_chars = (fi == 0) ? 0 : (main->lines[fi].char_offset + main->lines[fi].char_count);
- float total_height = 0;
+ float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
for (int i = fi; i < (int)main->lines.size(); i++) {
total_height = _shape_line(main, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height, &total_chars);
-
updating_scroll = true;
bool exceeds = total_height > ctrl_height && scroll_active;
if (exceeds != scroll_visible) {
@@ -2577,11 +2585,11 @@ void RichTextLabel::_process_line_caches() {
scroll_w = 0;
vscroll->hide();
}
-
main->first_invalid_line.store(0);
main->first_resized_line.store(0);
main->first_invalid_font_line.store(0);
+ // since scroll was added or removed we need to resize all lines
total_height = 0;
for (int j = 0; j <= i; j++) {
total_height = _resize_line(main, j, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height);
@@ -3369,21 +3377,34 @@ void RichTextLabel::append_text(const String &p_bbcode) {
bool in_bold = false;
bool in_italics = false;
+ bool after_list_open_tag = false;
+ bool after_list_close_tag = false;
set_process_internal(false);
- while (pos < p_bbcode.length()) {
+ while (pos <= p_bbcode.length()) {
int brk_pos = p_bbcode.find("[", pos);
if (brk_pos < 0) {
brk_pos = p_bbcode.length();
}
- if (brk_pos > pos) {
- add_text(p_bbcode.substr(pos, brk_pos - pos));
+ String text = brk_pos > pos ? p_bbcode.substr(pos, brk_pos - pos) : "";
+
+ // Trim the first newline character, it may be added later as needed.
+ if (after_list_close_tag || after_list_open_tag) {
+ text = text.trim_prefix("\n");
}
if (brk_pos == p_bbcode.length()) {
+ // For tags that are not properly closed.
+ if (text.is_empty() && after_list_open_tag) {
+ text = "\n";
+ }
+
+ if (!text.is_empty()) {
+ add_text(text);
+ }
break; //nothing else to add
}
@@ -3391,7 +3412,8 @@ void RichTextLabel::append_text(const String &p_bbcode) {
if (brk_end == -1) {
//no close, add the rest
- add_text(p_bbcode.substr(brk_pos, p_bbcode.length() - brk_pos));
+ text += p_bbcode.substr(brk_pos, p_bbcode.length() - brk_pos);
+ add_text(text);
break;
}
@@ -3437,18 +3459,60 @@ void RichTextLabel::append_text(const String &p_bbcode) {
}
if (!tag_ok) {
- add_text("[" + tag);
+ text += "[" + tag;
+ add_text(text);
+ after_list_open_tag = false;
+ after_list_close_tag = false;
pos = brk_end;
continue;
}
+ if (text.is_empty() && after_list_open_tag) {
+ text = "\n"; // Make empty list have at least one item.
+ }
+ after_list_open_tag = false;
+
+ if (tag == "/ol" || tag == "/ul") {
+ if (!text.is_empty()) {
+ // Make sure text ends with a newline character, that is, the last item
+ // will wrap at the end of block.
+ if (!text.ends_with("\n")) {
+ text += "\n";
+ }
+ } else if (!after_list_close_tag) {
+ text = "\n"; // Make the innermost list item wrap at the end of lists.
+ }
+ after_list_close_tag = true;
+ } else {
+ after_list_close_tag = false;
+ }
+
+ if (!text.is_empty()) {
+ add_text(text);
+ }
+
tag_stack.pop_front();
pos = brk_end + 1;
if (tag != "/img" && tag != "/dropcap") {
pop();
}
+ continue;
+ }
+
+ if (tag == "ol" || tag.begins_with("ol ") || tag == "ul" || tag.begins_with("ul ")) {
+ if (text.is_empty() && after_list_open_tag) {
+ text = "\n"; // Make each list have at least one item at the beginning.
+ }
+ after_list_open_tag = true;
+ } else {
+ after_list_open_tag = false;
+ }
+ if (!text.is_empty()) {
+ add_text(text);
+ }
+ after_list_close_tag = false;
- } else if (tag == "b") {
+ if (tag == "b") {
//use bold font
in_bold = true;
if (in_italics) {
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 7fbd5f1745..93e57058b0 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -117,6 +117,10 @@ private:
int char_count = 0;
Line() { text_buf.instantiate(); }
+
+ _FORCE_INLINE_ float get_height(float line_separation) const {
+ return offset.y + text_buf->get_size().y + text_buf->get_line_count() * line_separation;
+ }
};
struct Item {
@@ -504,6 +508,8 @@ private:
void _scroll_changed(double);
int _find_first_line(int p_from, int p_to, int p_vofs) const;
+ _FORCE_INLINE_ float _calculate_line_vertical_offset(const Line &line) const;
+
virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual String get_tooltip(const Point2 &p_pos) const override;
Item *_get_next_item(Item *p_item, bool p_free = false) const;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 590c73de0b..7c7809fd75 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -3458,8 +3458,8 @@ void Viewport::_own_world_3d_changed() {
_update_audio_listener_3d();
}
-void Viewport::set_use_own_world_3d(bool p_world_3d) {
- if (p_world_3d == own_world_3d.is_valid()) {
+void Viewport::set_use_own_world_3d(bool p_use_own_world_3d) {
+ if (p_use_own_world_3d == own_world_3d.is_valid()) {
return;
}
@@ -3467,18 +3467,18 @@ void Viewport::set_use_own_world_3d(bool p_world_3d) {
_propagate_exit_world_3d(this);
}
- if (!p_world_3d) {
- own_world_3d = Ref<World3D>();
- if (world_3d.is_valid()) {
- world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
- }
- } else {
+ if (p_use_own_world_3d) {
if (world_3d.is_valid()) {
own_world_3d = world_3d->duplicate();
world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
} else {
own_world_3d = Ref<World3D>(memnew(World3D));
}
+ } else {
+ own_world_3d = Ref<World3D>();
+ if (world_3d.is_valid()) {
+ world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ }
}
if (is_inside_tree()) {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 5bca5a2dda..833b302e97 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -676,7 +676,7 @@ public:
Ref<World3D> get_world_3d() const;
Ref<World3D> find_world_3d() const;
void _own_world_3d_changed();
- void set_use_own_world_3d(bool p_world_3d);
+ void set_use_own_world_3d(bool p_use_own_world_3d);
bool is_using_own_world_3d() const;
void _propagate_enter_world_3d(Node *p_node);
void _propagate_exit_world_3d(Node *p_node);
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 193f18c075..9b347ed7c8 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -681,7 +681,7 @@ void Window::_update_viewport_size() {
} break;
case CONTENT_SCALE_MODE_VIEWPORT: {
- final_size = viewport_size;
+ final_size = (viewport_size / content_scale_factor).floor();
attach_to_screen_rect = Rect2(margin, screen_size);
} break;
diff --git a/scene/multiplayer/multiplayer_synchronizer.cpp b/scene/multiplayer/multiplayer_synchronizer.cpp
index 34d5abf9f6..78cec9ee10 100644
--- a/scene/multiplayer/multiplayer_synchronizer.cpp
+++ b/scene/multiplayer/multiplayer_synchronizer.cpp
@@ -96,7 +96,7 @@ void MultiplayerSynchronizer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_replication_config", "config"), &MultiplayerSynchronizer::set_replication_config);
ClassDB::bind_method(D_METHOD("get_replication_config"), &MultiplayerSynchronizer::get_replication_config);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "congiruation", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "replication_config", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config");
}
void MultiplayerSynchronizer::_notification(int p_what) {
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 9442a58ac1..04b85e3e36 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -2161,7 +2161,7 @@ void GradientTexture1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &GradientTexture1D::_update);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,16384"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
}
@@ -2249,7 +2249,7 @@ void GradientTexture1D::_update() {
}
void GradientTexture1D::set_width(int p_width) {
- ERR_FAIL_COND(p_width <= 0);
+ ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
width = p_width;
_queue_update();
}
@@ -2413,6 +2413,7 @@ float GradientTexture2D::_get_gradient_offset_at(int x, int y) const {
}
void GradientTexture2D::set_width(int p_width) {
+ ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
width = p_width;
_queue_update();
}
@@ -2422,6 +2423,7 @@ int GradientTexture2D::get_width() const {
}
void GradientTexture2D::set_height(int p_height) {
+ ERR_FAIL_COND_MSG(p_height <= 0 || p_height > 16384, "Texture dimensions have to be within 1 to 16384 range.");
height = p_height;
_queue_update();
}
@@ -2515,8 +2517,8 @@ void GradientTexture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &GradientTexture2D::_update);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,or_greater"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,or_greater"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
ADD_GROUP("Fill", "fill_");
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 5c0f36ca92..b8667f07fe 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -2462,7 +2462,7 @@ void VisualShaderNodeFloatFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeFloatFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeFloatFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Fract,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_SIN);
BIND_ENUM_CONSTANT(FUNC_COS);
@@ -2481,7 +2481,7 @@ void VisualShaderNodeFloatFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_FLOOR);
BIND_ENUM_CONSTANT(FUNC_ROUND);
BIND_ENUM_CONSTANT(FUNC_CEIL);
- BIND_ENUM_CONSTANT(FUNC_FRAC);
+ BIND_ENUM_CONSTANT(FUNC_FRACT);
BIND_ENUM_CONSTANT(FUNC_SATURATE);
BIND_ENUM_CONSTANT(FUNC_NEGATE);
BIND_ENUM_CONSTANT(FUNC_ACOSH);
@@ -2713,7 +2713,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Fract,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_NORMALIZE);
BIND_ENUM_CONSTANT(FUNC_SATURATE);
@@ -2733,7 +2733,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_EXP);
BIND_ENUM_CONSTANT(FUNC_EXP2);
BIND_ENUM_CONSTANT(FUNC_FLOOR);
- BIND_ENUM_CONSTANT(FUNC_FRAC);
+ BIND_ENUM_CONSTANT(FUNC_FRACT);
BIND_ENUM_CONSTANT(FUNC_INVERSE_SQRT);
BIND_ENUM_CONSTANT(FUNC_LOG);
BIND_ENUM_CONSTANT(FUNC_LOG2);
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index b159d25eba..1eb7b7240f 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -934,7 +934,7 @@ public:
FUNC_FLOOR,
FUNC_ROUND,
FUNC_CEIL,
- FUNC_FRAC,
+ FUNC_FRACT,
FUNC_SATURATE,
FUNC_NEGATE,
FUNC_ACOSH,
@@ -1053,7 +1053,7 @@ public:
FUNC_EXP,
FUNC_EXP2,
FUNC_FLOOR,
- FUNC_FRAC,
+ FUNC_FRACT,
FUNC_INVERSE_SQRT,
FUNC_LOG,
FUNC_LOG2,