summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.pre-commit-config.yaml3
-rw-r--r--core/io/file_access.cpp10
-rw-r--r--core/io/file_access.h2
-rw-r--r--core/io/marshalls.h10
-rw-r--r--core/io/stream_peer.cpp26
-rw-r--r--core/io/stream_peer.h2
-rw-r--r--core/object/worker_thread_pool.h8
-rw-r--r--core/string/translation.cpp6
-rw-r--r--doc/classes/AABB.xml6
-rw-r--r--doc/classes/AnimationMixer.xml44
-rw-r--r--doc/classes/AnimationNodeTimeSeek.xml5
-rw-r--r--doc/classes/FileAccess.xml13
-rw-r--r--doc/classes/LookAtModifier3D.xml4
-rw-r--r--doc/classes/PackedInt64Array.xml2
-rw-r--r--doc/classes/PackedVector4Array.xml1
-rw-r--r--doc/classes/StreamPeer.xml13
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp54
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h36
-rw-r--r--drivers/gles3/shaders/canvas.glsl46
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl36
-rw-r--r--editor/export/editor_export_platform.cpp26
-rw-r--r--editor/export/editor_export_platform.h2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp4
-rw-r--r--editor/plugins/lightmap_gi_editor_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp2
-rw-r--r--main/performance.cpp4
-rw-r--r--modules/gdscript/gdscript_editor.cpp21
-rw-r--r--modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg10
-rw-r--r--modules/gdscript/tests/scripts/completion/common/self.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local/local.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member/member.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/infered.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/no_type.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/infered.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/no_type.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg4
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp115
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs17
-rw-r--r--platform/windows/display_server_windows.cpp4
-rw-r--r--platform/windows/tts_windows.cpp10
-rw-r--r--platform/windows/tts_windows.h4
-rw-r--r--scene/3d/lightmap_gi.cpp2
-rw-r--r--scene/3d/lightmapper.h1
-rw-r--r--scene/animation/animation_blend_tree.cpp16
-rw-r--r--scene/animation/animation_blend_tree.h7
-rw-r--r--scene/animation/animation_mixer.cpp131
-rw-r--r--scene/animation/animation_mixer.h4
-rw-r--r--scene/animation/root_motion_view.cpp5
-rw-r--r--scene/gui/color_picker.cpp58
-rw-r--r--scene/gui/color_picker.h5
-rw-r--r--scene/gui/rich_text_label.cpp42
-rw-r--r--scene/gui/rich_text_label.h3
-rw-r--r--scene/resources/3d/primitive_meshes.cpp169
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp61
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h47
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl46
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl49
-rw-r--r--tests/core/io/test_file_access.h94
-rw-r--r--tests/core/io/test_marshalls.h21
-rw-r--r--tests/core/io/test_stream_peer.h22
-rw-r--r--tests/data/floating_point_big_endian.bin1
-rw-r--r--tests/data/floating_point_little_endian.bin1
-rw-r--r--tests/data/half_precision_floating_point_big_endian.bin1
-rw-r--r--tests/data/half_precision_floating_point_little_endian.bin1
106 files changed, 1133 insertions, 410 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 2fa0493544..56f64ad079 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -187,7 +187,8 @@ repos:
modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment\.notest\.gd$|
modules/gdscript/tests/scripts/parser/warnings/empty_file_newline\.notest\.gd$|
platform/android/java/editor/src/main/java/com/android/.*|
- platform/android/java/lib/src/com/google/.*
+ platform/android/java/lib/src/com/google/.*|
+ tests/data/.*\.bin$
)
- id: dotnet-format
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index ef5ca502d4..29027cade1 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -268,6 +268,10 @@ uint64_t FileAccess::get_64() const {
return data;
}
+float FileAccess::get_half() const {
+ return Math::half_to_float(get_16());
+}
+
float FileAccess::get_float() const {
MarshallFloat m;
m.i = get_32();
@@ -527,6 +531,10 @@ void FileAccess::store_real(real_t p_real) {
}
}
+void FileAccess::store_half(float p_dest) {
+ store_16(Math::make_half_float(p_dest));
+}
+
void FileAccess::store_float(float p_dest) {
MarshallFloat m;
m.f = p_dest;
@@ -833,6 +841,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_16"), &FileAccess::get_16);
ClassDB::bind_method(D_METHOD("get_32"), &FileAccess::get_32);
ClassDB::bind_method(D_METHOD("get_64"), &FileAccess::get_64);
+ ClassDB::bind_method(D_METHOD("get_half"), &FileAccess::get_half);
ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
@@ -851,6 +860,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("store_16", "value"), &FileAccess::store_16);
ClassDB::bind_method(D_METHOD("store_32", "value"), &FileAccess::store_32);
ClassDB::bind_method(D_METHOD("store_64", "value"), &FileAccess::store_64);
+ ClassDB::bind_method(D_METHOD("store_half", "value"), &FileAccess::store_half);
ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 88c8110a51..48984c6c1b 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -148,6 +148,7 @@ public:
virtual uint32_t get_32() const; ///< get 32 bits uint
virtual uint64_t get_64() const; ///< get 64 bits uint
+ virtual float get_half() const;
virtual float get_float() const;
virtual double get_double() const;
virtual real_t get_real() const;
@@ -179,6 +180,7 @@ public:
virtual void store_32(uint32_t p_dest); ///< store 32 bits uint
virtual void store_64(uint64_t p_dest); ///< store 64 bits uint
+ virtual void store_half(float p_dest);
virtual void store_float(float p_dest);
virtual void store_double(double p_dest);
virtual void store_real(real_t p_real);
diff --git a/core/io/marshalls.h b/core/io/marshalls.h
index 6f015ac386..82c760c28d 100644
--- a/core/io/marshalls.h
+++ b/core/io/marshalls.h
@@ -84,6 +84,12 @@ static inline unsigned int encode_uint32(uint32_t p_uint, uint8_t *p_arr) {
return sizeof(uint32_t);
}
+static inline unsigned int encode_half(float p_float, uint8_t *p_arr) {
+ encode_uint16(Math::make_half_float(p_float), p_arr);
+
+ return sizeof(uint16_t);
+}
+
static inline unsigned int encode_float(float p_float, uint8_t *p_arr) {
MarshallFloat mf;
mf.f = p_float;
@@ -172,6 +178,10 @@ static inline uint32_t decode_uint32(const uint8_t *p_arr) {
return u;
}
+static inline float decode_half(const uint8_t *p_arr) {
+ return Math::half_to_float(decode_uint16(p_arr));
+}
+
static inline float decode_float(const uint8_t *p_arr) {
MarshallFloat mf;
mf.i = decode_uint32(p_arr);
diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp
index 3f1c468fb3..045904fb5d 100644
--- a/core/io/stream_peer.cpp
+++ b/core/io/stream_peer.cpp
@@ -178,6 +178,18 @@ void StreamPeer::put_64(int64_t p_val) {
put_data(buf, 8);
}
+void StreamPeer::put_half(float p_val) {
+ uint8_t buf[2];
+
+ encode_half(p_val, buf);
+ uint16_t *p16 = (uint16_t *)buf;
+ if (big_endian) {
+ *p16 = BSWAP16(*p16);
+ }
+
+ put_data(buf, 2);
+}
+
void StreamPeer::put_float(float p_val) {
uint8_t buf[4];
@@ -294,6 +306,18 @@ int64_t StreamPeer::get_64() {
return r;
}
+float StreamPeer::get_half() {
+ uint8_t buf[2];
+ get_data(buf, 2);
+
+ uint16_t *p16 = (uint16_t *)buf;
+ if (big_endian) {
+ *p16 = BSWAP16(*p16);
+ }
+
+ return decode_half(buf);
+}
+
float StreamPeer::get_float() {
uint8_t buf[4];
get_data(buf, 4);
@@ -385,6 +409,7 @@ void StreamPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("put_u32", "value"), &StreamPeer::put_u32);
ClassDB::bind_method(D_METHOD("put_64", "value"), &StreamPeer::put_64);
ClassDB::bind_method(D_METHOD("put_u64", "value"), &StreamPeer::put_u64);
+ ClassDB::bind_method(D_METHOD("put_half", "value"), &StreamPeer::put_half);
ClassDB::bind_method(D_METHOD("put_float", "value"), &StreamPeer::put_float);
ClassDB::bind_method(D_METHOD("put_double", "value"), &StreamPeer::put_double);
ClassDB::bind_method(D_METHOD("put_string", "value"), &StreamPeer::put_string);
@@ -399,6 +424,7 @@ void StreamPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_u32"), &StreamPeer::get_u32);
ClassDB::bind_method(D_METHOD("get_64"), &StreamPeer::get_64);
ClassDB::bind_method(D_METHOD("get_u64"), &StreamPeer::get_u64);
+ ClassDB::bind_method(D_METHOD("get_half"), &StreamPeer::get_half);
ClassDB::bind_method(D_METHOD("get_float"), &StreamPeer::get_float);
ClassDB::bind_method(D_METHOD("get_double"), &StreamPeer::get_double);
ClassDB::bind_method(D_METHOD("get_string", "bytes"), &StreamPeer::get_string, DEFVAL(-1));
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index 29cdb82615..44bbfbf1d5 100644
--- a/core/io/stream_peer.h
+++ b/core/io/stream_peer.h
@@ -73,6 +73,7 @@ public:
void put_u32(uint32_t p_val);
void put_64(int64_t p_val);
void put_u64(uint64_t p_val);
+ void put_half(float p_val);
void put_float(float p_val);
void put_double(double p_val);
void put_string(const String &p_string);
@@ -87,6 +88,7 @@ public:
int32_t get_32();
uint64_t get_u64();
int64_t get_64();
+ float get_half();
float get_float();
double get_double();
String get_string(int p_bytes = -1);
diff --git a/core/object/worker_thread_pool.h b/core/object/worker_thread_pool.h
index 62296ac040..58e86e3e48 100644
--- a/core/object/worker_thread_pool.h
+++ b/core/object/worker_thread_pool.h
@@ -258,7 +258,13 @@ public:
bool is_group_task_completed(GroupID p_group) const;
void wait_for_group_task_completion(GroupID p_group);
- _FORCE_INLINE_ int get_thread_count() const { return threads.size(); }
+ _FORCE_INLINE_ int get_thread_count() const {
+#ifdef THREADS_ENABLED
+ return threads.size();
+#else
+ return 1;
+#endif
+ }
static WorkerThreadPool *get_singleton() { return singleton; }
static int get_thread_index();
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 020949371f..d944135a70 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -80,8 +80,10 @@ void Translation::set_locale(const String &p_locale) {
if (Thread::is_main_thread()) {
_notify_translation_changed_if_applies();
} else {
- // Avoid calling non-thread-safe functions here.
- callable_mp(this, &Translation::_notify_translation_changed_if_applies).call_deferred();
+ // This has to happen on the main thread (bypassing the ResourceLoader per-thread call queue)
+ // because it interacts with the generally non-thread-safe window management, leading to
+ // different issues across platforms otherwise.
+ MessageQueue::get_main_singleton()->push_callable(callable_mp(this, &Translation::_notify_translation_changed_if_applies));
}
}
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index ae2de055cb..57ac241eb2 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -345,14 +345,14 @@
</methods>
<members>
<member name="end" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)">
- The ending point. This is usually the corner on the top-right and forward of the bounding box, and is equivalent to [code]position + size[/code]. Setting this point affects the [member size].
+ The ending point. This is usually the corner on the top-right and back of the bounding box, and is equivalent to [code]position + size[/code]. Setting this point affects the [member size].
</member>
<member name="position" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)">
- The origin point. This is usually the corner on the bottom-left and back of the bounding box.
+ The origin point. This is usually the corner on the bottom-left and forward of the bounding box.
</member>
<member name="size" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)">
The bounding box's width, height, and depth starting from [member position]. Setting this value also affects the [member end] point.
- [b]Note:[/b] It's recommended setting the width, height, and depth to non-negative values. This is because most methods in Godot assume that the [member position] is the bottom-left-back corner, and the [member end] is the top-right-forward corner. To get an equivalent bounding box with non-negative size, use [method abs].
+ [b]Note:[/b] It's recommended setting the width, height, and depth to non-negative values. This is because most methods in Godot assume that the [member position] is the bottom-left-forward corner, and the [member end] is the top-right-back corner. To get an equivalent bounding box with non-negative size, use [method abs].
</member>
</members>
<operators>
diff --git a/doc/classes/AnimationMixer.xml b/doc/classes/AnimationMixer.xml
index d762ffa5a6..36cb675776 100644
--- a/doc/classes/AnimationMixer.xml
+++ b/doc/classes/AnimationMixer.xml
@@ -112,13 +112,13 @@
The most basic example is applying position to [CharacterBody3D]:
[codeblocks]
[gdscript]
- var current_rotation: Quaternion
+ var current_rotation
func _process(delta):
if Input.is_action_just_pressed("animate"):
current_rotation = get_quaternion()
state_machine.travel("Animate")
- var velocity: Vector3 = current_rotation * animation_tree.get_root_motion_position() / delta
+ var velocity = current_rotation * animation_tree.get_root_motion_position() / delta
set_velocity(velocity)
move_and_slide()
[/gdscript]
@@ -130,7 +130,20 @@
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
- var velocity: Vector3 = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta
+ var velocity = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta
+ set_velocity(velocity)
+ move_and_slide()
+ [/gdscript]
+ [/codeblocks]
+ If [member root_motion_local] is [code]true[/code], return the pre-multiplied translation value with the inverted rotation.
+ In this case, the code can be written as follows:
+ [codeblocks]
+ [gdscript]
+ func _process(delta):
+ if Input.is_action_just_pressed("animate"):
+ state_machine.travel("Animate")
+ set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
+ var velocity = get_quaternion() * animation_tree.get_root_motion_position() / delta
set_velocity(velocity)
move_and_slide()
[/gdscript]
@@ -145,13 +158,13 @@
For example, if an animation with only one key [code]Vector3(0, 0, 0)[/code] is played in the previous frame and then an animation with only one key [code]Vector3(1, 0, 1)[/code] is played in the next frame, the difference can be calculated as follows:
[codeblocks]
[gdscript]
- var prev_root_motion_position_accumulator: Vector3
+ var prev_root_motion_position_accumulator
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
- var current_root_motion_position_accumulator: Vector3 = animation_tree.get_root_motion_position_accumulator()
- var difference: Vector3 = current_root_motion_position_accumulator - prev_root_motion_position_accumulator
+ var current_root_motion_position_accumulator = animation_tree.get_root_motion_position_accumulator()
+ var difference = current_root_motion_position_accumulator - prev_root_motion_position_accumulator
prev_root_motion_position_accumulator = current_root_motion_position_accumulator
transform.origin += difference
[/gdscript]
@@ -185,13 +198,13 @@
For example, if an animation with only one key [code]Quaternion(0, 0, 0, 1)[/code] is played in the previous frame and then an animation with only one key [code]Quaternion(0, 0.707, 0, 0.707)[/code] is played in the next frame, the difference can be calculated as follows:
[codeblocks]
[gdscript]
- var prev_root_motion_rotation_accumulator: Quaternion
+ var prev_root_motion_rotation_accumulator
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
- var current_root_motion_rotation_accumulator: Quaternion = animation_tree.get_root_motion_rotation_accumulator()
- var difference: Quaternion = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator
+ var current_root_motion_rotation_accumulator = animation_tree.get_root_motion_rotation_accumulator()
+ var difference = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator
prev_root_motion_rotation_accumulator = current_root_motion_rotation_accumulator
transform.basis *= Basis(difference)
[/gdscript]
@@ -208,8 +221,8 @@
The most basic example is applying scale to [CharacterBody3D]:
[codeblocks]
[gdscript]
- var current_scale: Vector3 = Vector3(1, 1, 1)
- var scale_accum: Vector3 = Vector3(1, 1, 1)
+ var current_scale = Vector3(1, 1, 1)
+ var scale_accum = Vector3(1, 1, 1)
func _process(delta):
if Input.is_action_just_pressed("animate"):
@@ -229,13 +242,13 @@
For example, if an animation with only one key [code]Vector3(1, 1, 1)[/code] is played in the previous frame and then an animation with only one key [code]Vector3(2, 2, 2)[/code] is played in the next frame, the difference can be calculated as follows:
[codeblocks]
[gdscript]
- var prev_root_motion_scale_accumulator: Vector3
+ var prev_root_motion_scale_accumulator
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
- var current_root_motion_scale_accumulator: Vector3 = animation_tree.get_root_motion_scale_accumulator()
- var difference: Vector3 = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator
+ var current_root_motion_scale_accumulator = animation_tree.get_root_motion_scale_accumulator()
+ var difference = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator
prev_root_motion_scale_accumulator = current_root_motion_scale_accumulator
transform.basis = transform.basis.scaled(difference)
[/gdscript]
@@ -304,6 +317,9 @@
This is used by the editor. If set to [code]true[/code], the scene will be saved with the effects of the reset animation (the animation with the key [code]"RESET"[/code]) applied as if it had been seeked to time 0, with the editor keeping the values that the scene had before saving.
This makes it more convenient to preview and edit animations in the editor, as changes to the scene will not be saved as long as they are set in the reset animation.
</member>
+ <member name="root_motion_local" type="bool" setter="set_root_motion_local" getter="is_root_motion_local">
+ If [code]true[/code], [method get_root_motion_position] value is extracted as a local translation value before blending. In other words, it is treated like the translation is done after the rotation.
+ </member>
<member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath(&quot;&quot;)">
The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. The [member root_motion_track] uses the same format as [method Animation.track_set_path], but note that a bone must be specified.
If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D], or [constant Animation.TYPE_SCALE_3D] the transformation will be canceled visually, and the animation will appear to stay in place. See also [method get_root_motion_position], [method get_root_motion_rotation], [method get_root_motion_scale], and [RootMotionView].
diff --git a/doc/classes/AnimationNodeTimeSeek.xml b/doc/classes/AnimationNodeTimeSeek.xml
index d00b3fca3a..865e94ec43 100644
--- a/doc/classes/AnimationNodeTimeSeek.xml
+++ b/doc/classes/AnimationNodeTimeSeek.xml
@@ -30,4 +30,9 @@
<tutorials>
<link title="Using AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
</tutorials>
+ <members>
+ <member name="explicit_elapse" type="bool" setter="set_explicit_elapse" getter="is_explicit_elapse" default="true">
+ If [code]true[/code], some processes are executed to handle keys between seeks, such as calculating root motion and finding the nearest discrete key.
+ </member>
+ </members>
</class>
diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml
index d7ca8afc2c..846897a463 100644
--- a/doc/classes/FileAccess.xml
+++ b/doc/classes/FileAccess.xml
@@ -173,6 +173,12 @@
Returns the next 32 bits from the file as a floating-point number.
</description>
</method>
+ <method name="get_half" qualifiers="const">
+ <return type="float" />
+ <description>
+ Returns the next 16 bits from the file as a half-precision floating-point number.
+ </description>
+ </method>
<method name="get_hidden_attribute" qualifiers="static">
<return type="bool" />
<param index="0" name="file" type="String" />
@@ -471,6 +477,13 @@
Stores a floating-point number as 32 bits in the file.
</description>
</method>
+ <method name="store_half">
+ <return type="void" />
+ <param index="0" name="value" type="float" />
+ <description>
+ Stores a half-precision floating-point number as 16 bits in the file.
+ </description>
+ </method>
<method name="store_line">
<return type="void" />
<param index="0" name="line" type="String" />
diff --git a/doc/classes/LookAtModifier3D.xml b/doc/classes/LookAtModifier3D.xml
index e85da06c3a..b6d106c4c5 100644
--- a/doc/classes/LookAtModifier3D.xml
+++ b/doc/classes/LookAtModifier3D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="LookAtModifier3D" inherits="SkeletonModifier3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- The [SkeletonModifier3D] rotates a bone to look a target.
+ The [LookAtModifier3D] rotates a bone to look at a target.
</brief_description>
<description>
- This [SkeletonModifier3D] rotates a bone to look a target. This is helpful for moving character's head to look at the player, rotating a turret to look at a target, or any other case where you want to make a bone rotate towards something quickly and easily.
+ This [SkeletonModifier3D] rotates a bone to look at a target. This is helpful for moving a character's head to look at the player, rotating a turret to look at a target, or any other case where you want to make a bone rotate towards something quickly and easily.
When applying multiple [LookAtModifier3D]s, the [LookAtModifier3D] assigned to the parent bone must be put above the [LookAtModifier3D] assigned to the child bone in the list in order for the child bone results to be correct.
</description>
<tutorials>
diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml
index cfaf012a55..b82d0de350 100644
--- a/doc/classes/PackedInt64Array.xml
+++ b/doc/classes/PackedInt64Array.xml
@@ -6,7 +6,7 @@
<description>
An array specifically designed to hold 64-bit integer values. Packs data tightly, so it saves memory for large array sizes.
[b]Note:[/b] This type stores signed 64-bit integers, which means it can take values in the interval [code][-2^63, 2^63 - 1][/code], i.e. [code][-9223372036854775808, 9223372036854775807][/code]. Exceeding those bounds will wrap around. If you only need to pack 32-bit integers tightly, see [PackedInt32Array] for a more memory-friendly alternative.
- [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedInt32Array] versus [code]Array[int][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
+ [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedInt64Array] versus [code]Array[int][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
[b]Note:[/b] Packed arrays are always passed by reference. To get a copy of an array that can be modified independently of the original array, use [method duplicate]. This is [i]not[/i] the case for built-in properties and methods. The returned packed array of these are a copies, and changing it will [i]not[/i] affect the original value. To update a built-in property you need to modify the returned array, and then assign it to the property again.
</description>
<tutorials>
diff --git a/doc/classes/PackedVector4Array.xml b/doc/classes/PackedVector4Array.xml
index 6dbfc7413d..7bebee79c7 100644
--- a/doc/classes/PackedVector4Array.xml
+++ b/doc/classes/PackedVector4Array.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
An array specifically designed to hold [Vector4]. Packs data tightly, so it saves memory for large array sizes.
+ [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedVector4Array] versus [code]Array[Vector4][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
[b]Note:[/b] Packed arrays are always passed by reference. To get a copy of an array that can be modified independently of the original array, use [method duplicate]. This is [i]not[/i] the case for built-in properties and methods. The returned packed array of these are a copies, and changing it will [i]not[/i] affect the original value. To update a built-in property you need to modify the returned array, and then assign it to the property again.
</description>
<tutorials>
diff --git a/doc/classes/StreamPeer.xml b/doc/classes/StreamPeer.xml
index ad5c5472b8..acff5cf604 100644
--- a/doc/classes/StreamPeer.xml
+++ b/doc/classes/StreamPeer.xml
@@ -59,6 +59,12 @@
Gets a single-precision float from the stream.
</description>
</method>
+ <method name="get_half">
+ <return type="float" />
+ <description>
+ Gets a half-precision float from the stream.
+ </description>
+ </method>
<method name="get_partial_data">
<return type="Array" />
<param index="0" name="bytes" type="int" />
@@ -162,6 +168,13 @@
Puts a single-precision float into the stream.
</description>
</method>
+ <method name="put_half">
+ <return type="void" />
+ <param index="0" name="value" type="float" />
+ <description>
+ Puts a half-precision float into the stream.
+ </description>
+ </method>
<method name="put_partial_data">
<return type="Array" />
<param index="0" name="data" type="PackedByteArray" />
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 2fd3f7d7e2..5fd90744a4 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -720,11 +720,14 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
}
}
- bool success = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(shader_version, variant, specialization);
+ bool success = material_storage->shaders.canvas_shader.version_bind_shader(shader_version, variant, specialization);
if (!success) {
continue;
}
+ // Bind per-batch uniforms.
+ material_storage->shaders.canvas_shader.version_set_uniform(CanvasShaderGLES3::BATCH_FLAGS, state.canvas_instance_batches[i].flags, shader_version, variant, specialization);
+
GLES3::CanvasShaderData::BlendMode blend_mode = state.canvas_instance_batches[i].blend_mode;
Color blend_color = state.canvas_instance_batches[i].blend_color;
@@ -847,6 +850,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
uint32_t lights[4] = { 0, 0, 0, 0 };
uint16_t light_count = 0;
+ uint16_t shadow_mask = 0;
{
Light *light = p_lights;
@@ -856,6 +860,10 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
uint32_t light_index = light->render_index_cache;
lights[light_count >> 2] |= light_index << ((light_count & 3) * 8);
+ if (p_item->light_mask & light->item_shadow_mask) {
+ shadow_mask |= 1 << light_count;
+ }
+
light_count++;
if (light_count == data.max_lights_per_item - 1) {
@@ -865,7 +873,8 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
light = light->next_ptr;
}
- base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
+ base_flags |= light_count << INSTANCE_FLAGS_LIGHT_COUNT_SHIFT;
+ base_flags |= shadow_mask << INSTANCE_FLAGS_SHADOW_MASKED_SHIFT;
}
bool lights_disabled = light_count == 0 && !state.using_directional_lights;
@@ -906,7 +915,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.instance_data_array[r_index].lights[2] = lights[2];
state.instance_data_array[r_index].lights[3] = lights[3];
- state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); // Reset on each command for safety, keep canvastexture binding config.
+ state.instance_data_array[r_index].flags = base_flags;
Color blend_color = base_color;
GLES3::CanvasShaderData::BlendMode blend_mode = p_blend_mode;
@@ -939,6 +948,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_RECT;
state.canvas_instance_batches[state.current_batch_index].command = c;
state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
+ state.canvas_instance_batches[state.current_batch_index].flags = 0;
}
_prepare_canvas_texture(rect->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@@ -961,20 +971,18 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
if (rect->flags & CANVAS_RECT_FLIP_H) {
src_rect.size.x *= -1;
- state.instance_data_array[r_index].flags |= FLAGS_FLIP_H;
}
if (rect->flags & CANVAS_RECT_FLIP_V) {
src_rect.size.y *= -1;
- state.instance_data_array[r_index].flags |= FLAGS_FLIP_V;
}
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
- state.instance_data_array[r_index].flags |= FLAGS_TRANSPOSE_RECT;
+ state.instance_data_array[r_index].flags |= INSTANCE_FLAGS_TRANSPOSE_RECT;
}
if (rect->flags & CANVAS_RECT_CLIP_UV) {
- state.instance_data_array[r_index].flags |= FLAGS_CLIP_RECT_UV;
+ state.instance_data_array[r_index].flags |= INSTANCE_FLAGS_CLIP_RECT_UV;
}
} else {
@@ -993,13 +1001,13 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
}
if (rect->flags & CANVAS_RECT_MSDF) {
- state.instance_data_array[r_index].flags |= FLAGS_USE_MSDF;
+ state.instance_data_array[r_index].flags |= INSTANCE_FLAGS_USE_MSDF;
state.instance_data_array[r_index].msdf[0] = rect->px_range; // Pixel range.
state.instance_data_array[r_index].msdf[1] = rect->outline; // Outline size.
state.instance_data_array[r_index].msdf[2] = 0.f; // Reserved.
state.instance_data_array[r_index].msdf[3] = 0.f; // Reserved.
} else if (rect->flags & CANVAS_RECT_LCD) {
- state.instance_data_array[r_index].flags |= FLAGS_USE_LCD;
+ state.instance_data_array[r_index].flags |= INSTANCE_FLAGS_USE_LCD;
}
state.instance_data_array[r_index].modulation[0] = rect->modulate.r * base_color.r;
@@ -1030,6 +1038,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].command = c;
state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_NINEPATCH;
+ state.canvas_instance_batches[state.current_batch_index].flags = 0;
}
_prepare_canvas_texture(np->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@@ -1067,11 +1076,11 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.instance_data_array[r_index].dst_rect[2] = dst_rect.size.width;
state.instance_data_array[r_index].dst_rect[3] = dst_rect.size.height;
- state.instance_data_array[r_index].flags |= int(np->axis_x) << FLAGS_NINEPATCH_H_MODE_SHIFT;
- state.instance_data_array[r_index].flags |= int(np->axis_y) << FLAGS_NINEPATCH_V_MODE_SHIFT;
+ state.instance_data_array[r_index].flags |= int(np->axis_x) << INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT;
+ state.instance_data_array[r_index].flags |= int(np->axis_y) << INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT;
if (np->draw_center) {
- state.instance_data_array[r_index].flags |= FLAGS_NINEPACH_DRAW_CENTER;
+ state.instance_data_array[r_index].flags |= INSTANCE_FLAGS_NINEPACH_DRAW_CENTER;
}
state.instance_data_array[r_index].ninepatch_margins[0] = np->margin[SIDE_LEFT];
@@ -1097,6 +1106,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].command = c;
state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_ATTRIBUTES;
+ state.canvas_instance_batches[state.current_batch_index].flags = 0;
_prepare_canvas_texture(polygon->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@@ -1125,6 +1135,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].command = c;
state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_PRIMITIVE;
+ state.canvas_instance_batches[state.current_batch_index].flags = 0;
}
_prepare_canvas_texture(state.canvas_instance_batches[state.current_batch_index].tex, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@@ -1165,12 +1176,13 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
case Item::Command::TYPE_MESH:
case Item::Command::TYPE_MULTIMESH:
case Item::Command::TYPE_PARTICLES: {
- // Mesh's can't be batched, so always create a new batch
+ // Meshes can't be batched, so always create a new batch.
_new_batch(r_batch_broken);
Color modulate(1, 1, 1, 1);
state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_ATTRIBUTES;
+ state.canvas_instance_batches[state.current_batch_index].flags = 0;
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
state.canvas_instance_batches[state.current_batch_index].tex = m->texture;
@@ -1183,10 +1195,10 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_INSTANCING;
if (GLES3::MeshStorage::get_singleton()->multimesh_uses_colors(mm->multimesh)) {
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_COLORS;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_INSTANCING_HAS_COLORS;
}
if (GLES3::MeshStorage::get_singleton()->multimesh_uses_custom_data(mm->multimesh)) {
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA;
}
} else if (c->type == Item::Command::TYPE_PARTICLES) {
GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
@@ -1196,8 +1208,8 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
RID particles = pt->particles;
state.canvas_instance_batches[state.current_batch_index].tex = pt->texture;
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_INSTANCING;
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_COLORS;
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_INSTANCING_HAS_COLORS;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA;
if (particles_storage->particles_has_collision(particles) && texture_storage->render_target_is_sdf_enabled(p_render_target)) {
// Pass collision information.
@@ -2364,15 +2376,15 @@ void RasterizerCanvasGLES3::_prepare_canvas_texture(RID p_texture, RS::CanvasIte
GLES3::Texture *normal_map = texture_storage->get_texture(ct->normal_map);
if (ct->specular_color.a < 0.999) {
- state.instance_data_array[r_index].flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED;
} else {
- state.instance_data_array[r_index].flags &= ~FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ state.canvas_instance_batches[state.current_batch_index].flags &= ~BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
if (normal_map) {
- state.instance_data_array[r_index].flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED;
} else {
- state.instance_data_array[r_index].flags &= ~FLAGS_DEFAULT_NORMAL_MAP_USED;
+ state.canvas_instance_batches[state.current_batch_index].flags &= ~BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED;
}
state.instance_data_array[r_index].specular_shininess = uint32_t(CLAMP(ct->specular_color.a * 255.0, 0, 255)) << 24;
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index b9d9a44e2a..e099fd0cc0 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -54,29 +54,27 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
_FORCE_INLINE_ void _update_transform_to_mat4(const Transform3D &p_transform, float *p_mat4);
enum {
+ INSTANCE_FLAGS_LIGHT_COUNT_SHIFT = 0, // 4 bits for light count.
- FLAGS_INSTANCING_MASK = 0x7F,
- FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
- FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8),
+ INSTANCE_FLAGS_CLIP_RECT_UV = (1 << 4),
+ INSTANCE_FLAGS_TRANSPOSE_RECT = (1 << 5),
+ INSTANCE_FLAGS_USE_MSDF = (1 << 6),
+ INSTANCE_FLAGS_USE_LCD = (1 << 7),
- FLAGS_CLIP_RECT_UV = (1 << 9),
- FLAGS_TRANSPOSE_RECT = (1 << 10),
+ INSTANCE_FLAGS_NINEPACH_DRAW_CENTER = (1 << 8),
+ INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT = 9,
+ INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT = 11,
- FLAGS_NINEPACH_DRAW_CENTER = (1 << 12),
-
- FLAGS_USE_SKELETON = (1 << 15),
- FLAGS_NINEPATCH_H_MODE_SHIFT = 16,
- FLAGS_NINEPATCH_V_MODE_SHIFT = 18,
- FLAGS_LIGHT_COUNT_SHIFT = 20,
-
- FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 26),
- FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27),
+ INSTANCE_FLAGS_SHADOW_MASKED_SHIFT = 13, // 16 bits.
+ };
- FLAGS_USE_MSDF = (1 << 28),
- FLAGS_USE_LCD = (1 << 29),
+ enum {
+ BATCH_FLAGS_INSTANCING_MASK = 0x7F,
+ BATCH_FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
+ BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8),
- FLAGS_FLIP_H = (1 << 30),
- FLAGS_FLIP_V = (1 << 31),
+ BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 9),
+ BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 10),
};
enum {
@@ -279,6 +277,8 @@ public:
const Item::Command *command = nullptr;
Item::Command::Type command_type = Item::Command::TYPE_ANIMATION_SLICE; // Can default to any type that doesn't form a batch.
uint32_t primitive_points = 0;
+
+ uint32_t flags = 0;
};
// DataBuffer contains our per-frame data. I.e. the resources that are updated each frame.
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 1ac289d5a2..3857aa8841 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -110,6 +110,9 @@ layout(std140) uniform MaterialUniforms{ //ubo:4
};
#endif
+
+uniform mediump uint batch_flags;
+
/* clang-format on */
#include "canvas_uniforms_inc.glsl"
@@ -179,13 +182,13 @@ void main() {
vec2 uv = uv_attrib;
#ifdef USE_INSTANCING
- if (bool(read_draw_data_flags & FLAGS_INSTANCING_HAS_COLORS)) {
+ if (bool(batch_flags & BATCH_FLAGS_INSTANCING_HAS_COLORS)) {
vec4 instance_color;
instance_color.xy = unpackHalf2x16(uint(instance_color_custom_data.x));
instance_color.zw = unpackHalf2x16(uint(instance_color_custom_data.y));
color *= instance_color;
}
- if (bool(read_draw_data_flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
+ if (bool(batch_flags & BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
instance_custom.xy = unpackHalf2x16(instance_color_custom_data.z);
instance_custom.zw = unpackHalf2x16(instance_color_custom_data.w);
}
@@ -218,7 +221,7 @@ void main() {
else if (vertex_id == 5)
vertex_base = vec2(1.0, 1.0);
- vec2 uv = read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) * ((read_draw_data_flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
+ vec2 uv = read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) * ((read_draw_data_flags & INSTANCE_FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
vec4 color = read_draw_data_modulation;
vec2 vertex = read_draw_data_dst_rect.xy + abs(read_draw_data_dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(read_draw_data_src_rect.zw, vec2(0.0, 0.0)));
@@ -336,6 +339,8 @@ uniform sampler2D specular_texture; //texunit:-7
uniform sampler2D color_texture; //texunit:0
+uniform mediump uint batch_flags;
+
layout(location = 0) out vec4 frag_color;
/* clang-format off */
@@ -519,7 +524,7 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
} else if (pixel >= draw_size - margin_end) {
return (tex_size - (draw_size - pixel)) * tex_pixel_size;
} else {
- if (!bool(read_draw_data_flags & FLAGS_NINEPACH_DRAW_CENTER)) {
+ if (!bool(read_draw_data_flags & INSTANCE_FLAGS_NINEPATCH_DRAW_CENTER)) {
draw_center--;
}
@@ -567,8 +572,8 @@ void main() {
int draw_center = 2;
uv = vec2(
- map_ninepatch_axis(pixel_size_interp.x, abs(read_draw_data_dst_rect_z), read_draw_data_color_texture_pixel_size.x, read_draw_data_ninepatch_margins.x, read_draw_data_ninepatch_margins.z, int(read_draw_data_flags >> FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
- map_ninepatch_axis(pixel_size_interp.y, abs(read_draw_data_dst_rect_w), read_draw_data_color_texture_pixel_size.y, read_draw_data_ninepatch_margins.y, read_draw_data_ninepatch_margins.w, int(read_draw_data_flags >> FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
+ map_ninepatch_axis(pixel_size_interp.x, abs(read_draw_data_dst_rect_z), read_draw_data_color_texture_pixel_size.x, read_draw_data_ninepatch_margins.x, read_draw_data_ninepatch_margins.z, int(read_draw_data_flags >> INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
+ map_ninepatch_axis(pixel_size_interp.y, abs(read_draw_data_dst_rect_w), read_draw_data_color_texture_pixel_size.y, read_draw_data_ninepatch_margins.y, read_draw_data_ninepatch_margins.w, int(read_draw_data_flags >> INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
if (draw_center == 0) {
color.a = 0.0;
@@ -577,7 +582,7 @@ void main() {
uv = uv * read_draw_data_src_rect.zw + read_draw_data_src_rect.xy; //apply region if needed
#endif
- if (bool(read_draw_data_flags & FLAGS_CLIP_RECT_UV)) {
+ if (bool(read_draw_data_flags & INSTANCE_FLAGS_CLIP_RECT_UV)) {
vec2 half_texpixel = read_draw_data_color_texture_pixel_size * 0.5;
uv = clamp(uv, read_draw_data_src_rect.xy + half_texpixel, read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) - half_texpixel);
}
@@ -585,7 +590,7 @@ void main() {
#endif
#ifndef USE_PRIMITIVE
- if (bool(read_draw_data_flags & FLAGS_USE_MSDF)) {
+ if (bool(read_draw_data_flags & INSTANCE_FLAGS_USE_MSDF)) {
float px_range = read_draw_data_ninepatch_margins.x;
float outline_thickness = read_draw_data_ninepatch_margins.y;
@@ -603,7 +608,7 @@ void main() {
float a = clamp(d * px_size + 0.5, 0.0, 1.0);
color.a = a * color.a;
}
- } else if (bool(read_draw_data_flags & FLAGS_USE_LCD)) {
+ } else if (bool(read_draw_data_flags & INSTANCE_FLAGS_USE_LCD)) {
vec4 lcd_sample = texture(color_texture, uv);
if (lcd_sample.a == 1.0) {
color.rgb = lcd_sample.rgb * color.a;
@@ -617,7 +622,7 @@ void main() {
color *= texture(color_texture, uv);
}
- uint light_count = (read_draw_data_flags >> uint(FLAGS_LIGHT_COUNT_SHIFT)) & uint(0xF); //max 16 lights
+ uint light_count = read_draw_data_flags & uint(0xF); // Max 16 lights.
bool using_light = light_count > 0u || directional_light_count > 0u;
vec3 normal;
@@ -628,17 +633,16 @@ void main() {
bool normal_used = false;
#endif
- if (normal_used || (using_light && bool(read_draw_data_flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
+ if (normal_used || (using_light && bool(batch_flags & BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(normal_texture, uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
- if (bool(read_draw_data_flags & FLAGS_TRANSPOSE_RECT)) {
+
+#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
+ if (bool(read_draw_data_flags & INSTANCE_FLAGS_TRANSPOSE_RECT)) {
normal.xy = normal.yx;
}
- if (bool(read_draw_data_flags & FLAGS_FLIP_H)) {
- normal.x = -normal.x;
- }
- if (bool(read_draw_data_flags & FLAGS_FLIP_V)) {
- normal.y = -normal.y;
- }
+ normal.xy *= sign(read_draw_data_src_rect.zw);
+#endif
+
normal.z = sqrt(max(0.0, 1.0 - dot(normal.xy, normal.xy)));
normal_used = true;
} else {
@@ -654,7 +658,7 @@ void main() {
bool specular_shininess_used = false;
#endif
- if (specular_shininess_used || (using_light && normal_used && bool(read_draw_data_flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
+ if (specular_shininess_used || (using_light && normal_used && bool(batch_flags & BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
specular_shininess = texture(specular_texture, uv);
specular_shininess *= godot_unpackUnorm4x8(read_draw_data_specular_shininess);
specular_shininess_used = true;
@@ -727,7 +731,7 @@ void main() {
}
#endif
- if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW) && bool(read_draw_data_flags & uint(INSTANCE_FLAGS_SHADOW_MASKED << i))) {
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array[light_base].shadow_matrix[0], light_array[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec4 shadow_uv = vec4(shadow_pos.x, light_array[light_base].shadow_y_ofs, shadow_pos.y * light_array[light_base].shadow_zfar_inv, 1.0);
@@ -802,7 +806,7 @@ void main() {
}
#endif
- if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW) && bool(read_draw_data_flags & uint(INSTANCE_FLAGS_SHADOW_MASKED << i))) {
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array[light_base].shadow_matrix[0], light_array[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec2 pos_norm = normalize(shadow_pos);
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index f6ad2b730a..7abd5f0eee 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -5,29 +5,29 @@
#define SDF_MAX_LENGTH 16384.0
-//1 means enabled, 2+ means trails in use
-#define FLAGS_INSTANCING_MASK uint(0x7F)
-#define FLAGS_INSTANCING_HAS_COLORS uint(1 << 7)
-#define FLAGS_INSTANCING_HAS_CUSTOM_DATA uint(1 << 8)
+#define INSTANCE_FLAGS_LIGHT_COUNT_SHIFT 0 // 4 bits.
-#define FLAGS_CLIP_RECT_UV uint(1 << 9)
-#define FLAGS_TRANSPOSE_RECT uint(1 << 10)
-// (1 << 11) is for FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR in RD backends, unused here.
-#define FLAGS_NINEPACH_DRAW_CENTER uint(1 << 12)
+#define INSTANCE_FLAGS_CLIP_RECT_UV uint(1 << 4)
+#define INSTANCE_FLAGS_TRANSPOSE_RECT uint(1 << 5)
+#define INSTANCE_FLAGS_USE_MSDF uint(1 << 6)
+#define INSTANCE_FLAGS_USE_LCD uint(1 << 7)
-#define FLAGS_NINEPATCH_H_MODE_SHIFT 16
-#define FLAGS_NINEPATCH_V_MODE_SHIFT 18
+#define INSTANCE_FLAGS_NINEPATCH_DRAW_CENTER uint(1 << 8)
+#define INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT 9
+#define INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT 11
-#define FLAGS_LIGHT_COUNT_SHIFT 20
+#define INSTANCE_FLAGS_SHADOW_MASKED_SHIFT 13u // 16 bits.
+#define INSTANCE_FLAGS_SHADOW_MASKED uint(1 << INSTANCE_FLAGS_SHADOW_MASKED_SHIFT)
-#define FLAGS_DEFAULT_NORMAL_MAP_USED uint(1 << 26)
-#define FLAGS_DEFAULT_SPECULAR_MAP_USED uint(1 << 27)
+// 1 means enabled, 2+ means trails in use
+#define BATCH_FLAGS_INSTANCING_MASK uint(0x7F)
+#define BATCH_FLAGS_INSTANCING_HAS_COLORS_SHIFT 7
+#define BATCH_FLAGS_INSTANCING_HAS_COLORS uint(1 << BATCH_FLAGS_INSTANCING_HAS_COLORS_SHIFT)
+#define BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT 8
+#define BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA uint(1 << BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT)
-#define FLAGS_USE_MSDF uint(1 << 28)
-#define FLAGS_USE_LCD uint(1 << 29)
-
-#define FLAGS_FLIP_H uint(1 << 30)
-#define FLAGS_FLIP_V uint(1 << 31)
+#define BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED uint(1 << 9)
+#define BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED uint(1 << 10)
layout(std140) uniform GlobalShaderUniformData { //ubo:1
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index 91c9ff9807..27216c2399 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -1495,7 +1495,15 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
Vector<String> forced_export = get_forced_export_files();
for (int i = 0; i < forced_export.size(); i++) {
- Vector<uint8_t> array = FileAccess::get_file_as_bytes(forced_export[i]);
+ Vector<uint8_t> array;
+ if (GDExtension::get_extension_list_config_file() == forced_export[i]) {
+ array = _filter_extension_list_config_file(forced_export[i], paths);
+ if (array.size() == 0) {
+ continue;
+ }
+ } else {
+ array = FileAccess::get_file_as_bytes(forced_export[i]);
+ }
err = p_save_func(p_udata, forced_export[i], array, idx, total, enc_in_filters, enc_ex_filters, key, seed);
if (err != OK) {
return err;
@@ -1534,6 +1542,22 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
return OK;
}
+Vector<uint8_t> EditorExportPlatform::_filter_extension_list_config_file(const String &p_config_path, const HashSet<String> &p_paths) {
+ Ref<FileAccess> f = FileAccess::open(p_config_path, FileAccess::READ);
+ if (f.is_null()) {
+ ERR_FAIL_V_MSG(Vector<uint8_t>(), "Can't open file from path '" + String(p_config_path) + "'.");
+ }
+ Vector<uint8_t> data;
+ while (!f->eof_reached()) {
+ String l = f->get_line().strip_edges();
+ if (p_paths.has(l)) {
+ data.append_array(l.to_utf8_buffer());
+ data.append('\n');
+ }
+ }
+ return data;
+}
+
Error EditorExportPlatform::_pack_add_shared_object(void *p_userdata, const SharedObject &p_so) {
PackData *pack_data = (PackData *)p_userdata;
if (pack_data->so_files) {
diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h
index c7378ffec7..a33bdce72a 100644
--- a/editor/export/editor_export_platform.h
+++ b/editor/export/editor_export_platform.h
@@ -135,6 +135,8 @@ private:
void _edit_files_with_filter(Ref<DirAccess> &da, const Vector<String> &p_filters, HashSet<String> &r_list, bool exclude);
void _edit_filter_list(HashSet<String> &r_list, const String &p_filter, bool exclude);
+ static Vector<uint8_t> _filter_extension_list_config_file(const String &p_config_path, const HashSet<String> &p_paths);
+
struct FileExportCache {
uint64_t source_modified_time = 0;
String source_md5;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index f91a052a24..d3bae447cc 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -3612,7 +3612,7 @@ void CanvasItemEditor::_draw_selection() {
// Remove non-movable nodes.
for (CanvasItem *ci : selection) {
- if (!_is_node_movable(ci, true)) {
+ if (!_is_node_movable(ci)) {
selection.erase(ci);
}
}
@@ -3913,7 +3913,7 @@ void CanvasItemEditor::_draw_message() {
Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));
int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));
- Point2 msgpos = Point2(RULER_WIDTH + 5 * EDSCALE, viewport->get_size().y - 20 * EDSCALE);
+ Point2 msgpos = Point2(RULER_WIDTH + 10 * EDSCALE, viewport->get_size().y - 14 * EDSCALE);
viewport->draw_string(font, msgpos + Point2(1, 1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
viewport->draw_string(font, msgpos + Point2(-1, -1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
viewport->draw_string(font, msgpos, message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1, 1, 1, 1));
diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp
index 4cff3504f5..3f21d5d11c 100644
--- a/editor/plugins/lightmap_gi_editor_plugin.cpp
+++ b/editor/plugins/lightmap_gi_editor_plugin.cpp
@@ -152,7 +152,7 @@ EditorProgress *LightmapGIEditorPlugin::tmp_progress = nullptr;
bool LightmapGIEditorPlugin::bake_func_step(float p_progress, const String &p_description, void *, bool p_refresh) {
if (!tmp_progress) {
- tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), 1000, false));
+ tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), 1000, true));
ERR_FAIL_NULL_V(tmp_progress, false);
}
return tmp_progress->step(p_description, p_progress * 1000, p_refresh);
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 810d1674ca..daede895b5 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -3265,7 +3265,7 @@ void Node3DEditorViewport::_draw() {
if (message_time > 0) {
Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));
int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));
- Point2 msgpos = Point2(5, get_size().y - 20);
+ Point2 msgpos = Point2(10 * EDSCALE, get_size().y - 14 * EDSCALE);
font->draw_string(ci, msgpos + Point2(1, 1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
font->draw_string(ci, msgpos + Point2(-1, -1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
font->draw_string(ci, msgpos, message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1, 1, 1, 1));
diff --git a/main/performance.cpp b/main/performance.cpp
index c73fb62b76..398511995b 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -132,11 +132,9 @@ String Performance::get_monitor_name(Monitor p_monitor) const {
PNAME("physics_2d/active_objects"),
PNAME("physics_2d/collision_pairs"),
PNAME("physics_2d/islands"),
-#ifndef _3D_DISABLED
PNAME("physics_3d/active_objects"),
PNAME("physics_3d/collision_pairs"),
PNAME("physics_3d/islands"),
-#endif // _3D_DISABLED
PNAME("audio/driver/output_latency"),
PNAME("navigation/active_maps"),
PNAME("navigation/regions"),
@@ -280,11 +278,9 @@ Performance::MonitorType Performance::get_monitor_type(Monitor p_monitor) const
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
-#ifndef _3D_DISABLED
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
-#endif // _3D_DISABLED
MONITOR_TYPE_TIME,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index d58cd2c3f7..cfff20f6d3 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1139,10 +1139,12 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
continue;
}
option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
- if (member.function->parameters.size() > 0) {
+ if (member.function->parameters.size() > 0 || (member.function->info.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
break;
case GDScriptParser::ClassNode::Member::SIGNAL:
@@ -1184,6 +1186,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (!p_types_only && base_type.is_meta_type && base_type.kind != GDScriptParser::DataType::BUILTIN && base_type.kind != GDScriptParser::DataType::ENUM) {
ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, ScriptLanguage::LOCATION_LOCAL);
option.insert_text += "(";
+ option.display += U"(\u2026)";
r_result.insert(option.display, option);
}
@@ -1241,10 +1244,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
int location = p_recursion_depth + _get_method_location(scr->get_class_name(), E.name);
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
- if (E.arguments.size()) {
+ if (E.arguments.size() || (E.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1327,10 +1332,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
int location = p_recursion_depth + _get_method_location(type, E.name);
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
- if (E.arguments.size()) {
+ if (E.arguments.size() || (E.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1398,10 +1405,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
continue;
}
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
- if (E.arguments.size()) {
+ if (E.arguments.size() || (E.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1433,8 +1442,10 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
ScriptLanguage::CodeCompletionOption option(String(E), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
if (function.arguments.size() || (function.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1481,6 +1492,7 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
while (*kwa) {
ScriptLanguage::CodeCompletionOption option(*kwa, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
option.insert_text += "(";
+ option.display += U"(\u2026)";
r_result.insert(option.display, option);
kwa++;
}
@@ -1491,6 +1503,7 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
for (List<StringName>::Element *E = utility_func_names.front(); E; E = E->next()) {
ScriptLanguage::CodeCompletionOption option(E->get(), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
option.insert_text += "(";
+ option.display += U"(\u2026)"; // As all utility functions contain an argument or more, this is hardcoded here.
r_result.insert(option.display, option);
}
diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg
index e4759ac76b..a2c332adad 100644
--- a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg
+++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg
@@ -1,6 +1,6 @@
[output]
include=[
- {"display": "new"},
+ {"display": "new(…)"},
{"display": "SIZE_EXPAND"},
{"display": "SIZE_EXPAND_FILL"},
{"display": "SIZE_FILL"},
diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg
index e4759ac76b..a2c332adad 100644
--- a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg
+++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg
@@ -1,6 +1,6 @@
[output]
include=[
- {"display": "new"},
+ {"display": "new(…)"},
{"display": "SIZE_EXPAND"},
{"display": "SIZE_EXPAND_FILL"},
{"display": "SIZE_FILL"},
diff --git a/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg b/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg
index 5f08f9c265..f2dff734b6 100644
--- a/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: identifiers.gd
@@ -16,8 +16,8 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg b/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg
index 5f08f9c265..f2dff734b6 100644
--- a/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: identifiers.gd
@@ -16,8 +16,8 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg b/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg
index 5f08f9c265..f2dff734b6 100644
--- a/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: identifiers.gd
@@ -16,8 +16,8 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg b/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg
index 462846c9b2..e012919051 100644
--- a/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg
@@ -2,14 +2,14 @@ scene="res://completion/get_node/get_node.tscn"
[output]
exclude=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
- {"display": "add_child"},
+ {"display": "add_child(…)"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: no_completion_in_string.gd
@@ -17,8 +17,8 @@ exclude=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/self.cfg b/modules/gdscript/tests/scripts/completion/common/self.cfg
index 871a404e3a..dcce1df0d0 100644
--- a/modules/gdscript/tests/scripts/completion/common/self.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/self.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: self.gd
@@ -16,6 +16,6 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg b/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
index 72c0549d3b..d647135bc6 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg
index 1894e72c65..a6118908de 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg
index c8ab63f6d6..d8390ca33c 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg b/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
index 72c0549d3b..d647135bc6 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg
index 502038bef7..2f747e0bac 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg
@@ -3,7 +3,7 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
@@ -11,6 +11,6 @@ include=[
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg
index 1810e9fe5f..f060413898 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg
@@ -3,7 +3,7 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
@@ -11,6 +11,6 @@ include=[
exclude=[
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg
index 1894e72c65..a6118908de 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg
index c8ab63f6d6..d8390ca33c 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/infered.cfg b/modules/gdscript/tests/scripts/completion/types/local/infered.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/infered.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg b/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/infered.cfg b/modules/gdscript/tests/scripts/completion/types/member/infered.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/infered.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg b/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg
index 81401316ec..d32bbac65e 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg
@@ -1,13 +1,13 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 8ba6f9e2ba..bd71e29d0a 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -247,7 +247,9 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
}
if (p_step_function) {
- p_step_function(0.1, RTR("Determining optimal atlas size"), p_bake_userdata, true);
+ if (p_step_function(0.1, RTR("Determining optimal atlas size"), p_bake_userdata, true)) {
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
atlas_size = Size2i(max, max);
@@ -324,7 +326,9 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
emission_images.resize(atlas_slices);
if (p_step_function) {
- p_step_function(0.2, RTR("Blitting albedo and emission"), p_bake_userdata, true);
+ if (p_step_function(0.2, RTR("Blitting albedo and emission"), p_bake_userdata, true)) {
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
for (int i = 0; i < atlas_slices; i++) {
@@ -1013,7 +1017,9 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh
if (p_step_function) {
int percent = (s + 1) * 100 / p_atlas_slices;
float p = float(s) / p_atlas_slices * 0.1;
- p_step_function(0.8 + p, vformat(RTR("Denoising %d%%"), percent), p_bake_userdata, false);
+ if (p_step_function(0.8 + p, vformat(RTR("Denoising %d%%"), percent), p_bake_userdata, false)) {
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
}
@@ -1265,7 +1271,15 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->buffer_update(bake_parameters_buffer, 0, sizeof(BakeParameters), &bake_parameters);
if (p_step_function) {
- p_step_function(0.47, RTR("Preparing shaders"), p_bake_userdata, true);
+ if (p_step_function(0.47, RTR("Preparing shaders"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
//shaders
@@ -1497,7 +1511,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->sync();
if (p_step_function) {
- p_step_function(0.49, RTR("Un-occluding geometry"), p_bake_userdata, true);
+ if (p_step_function(0.49, RTR("Un-occluding geometry"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
PushConstant push_constant;
@@ -1539,7 +1563,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
if (p_step_function) {
- p_step_function(0.5, RTR("Plot direct lighting"), p_bake_userdata, true);
+ if (p_step_function(0.5, RTR("Plot direct lighting"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
// Set ray count to the quality used for direct light and bounces.
@@ -1699,7 +1733,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->sync();
if (p_step_function) {
- p_step_function(0.6, RTR("Integrate indirect lighting"), p_bake_userdata, true);
+ if (p_step_function(0.6, RTR("Integrate indirect lighting"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
int count = 0;
@@ -1738,7 +1782,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
int total = (atlas_slices * x_regions * y_regions * ray_iterations);
int percent = count * 100 / total;
float p = float(count) / total * 0.1;
- p_step_function(0.6 + p, vformat(RTR("Integrate indirect lighting %d%%"), percent), p_bake_userdata, false);
+ if (p_step_function(0.6 + p, vformat(RTR("Integrate indirect lighting %d%%"), percent), p_bake_userdata, false)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
}
}
@@ -1754,7 +1808,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
light_probe_buffer = rd->storage_buffer_create(sizeof(float) * 4 * 9 * probe_positions.size());
if (p_step_function) {
- p_step_function(0.7, RTR("Baking light probes"), p_bake_userdata, true);
+ if (p_step_function(0.7, RTR("Baking light probes"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ if (probe_positions.size() > 0) {
+ rd->free(light_probe_buffer);
+ }
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
Vector<RD::Uniform> uniforms;
@@ -1822,7 +1889,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
if (p_step_function) {
int percent = i * 100 / ray_iterations;
float p = float(i) / ray_iterations * 0.1;
- p_step_function(0.7 + p, vformat(RTR("Integrating light probes %d%%"), percent), p_bake_userdata, false);
+ if (p_step_function(0.7 + p, vformat(RTR("Integrating light probes %d%%"), percent), p_bake_userdata, false)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ if (probe_positions.size() > 0) {
+ rd->free(light_probe_buffer);
+ }
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
}
}
@@ -1844,7 +1924,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
if (p_use_denoiser) {
if (p_step_function) {
- p_step_function(0.8, RTR("Denoising"), p_bake_userdata, true);
+ if (p_step_function(0.8, RTR("Denoising"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ if (probe_positions.size() > 0) {
+ rd->free(light_probe_buffer);
+ }
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
{
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index ed78353f92..a8033914e7 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -781,8 +781,18 @@ namespace Godot.SourceGenerators
return false; // Non-generic Dictionary, so there's no hint to add
Debug.Assert(elementTypes.Length == 2);
- var keyElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[0], typeCache)!.Value;
- var keyElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(keyElementMarshalType)!.Value;
+ var keyElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[0], typeCache);
+ var valueElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[1], typeCache);
+
+ if (keyElementMarshalType == null || valueElementMarshalType == null)
+ {
+ // To maintain compatibility with previous versions of Godot before 4.4,
+ // we must preserve the old behavior for generic dictionaries with non-marshallable
+ // generic type arguments.
+ return false;
+ }
+
+ var keyElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(keyElementMarshalType.Value)!.Value;
var keyIsPresetHint = false;
var keyHintString = (string?)null;
@@ -809,8 +819,7 @@ namespace Godot.SourceGenerators
}
}
- var valueElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[1], typeCache)!.Value;
- var valueElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(valueElementMarshalType)!.Value;
+ var valueElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(valueElementMarshalType.Value)!.Value;
var valueIsPresetHint = false;
var valueHintString = (string?)null;
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 467873ee7c..e300bd1c47 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -3244,6 +3244,10 @@ void DisplayServerWindows::process_events() {
}
_THREAD_SAFE_UNLOCK_
+ if (tts) {
+ tts->process_events();
+ }
+
if (!drop_events) {
_process_key_events();
Input::get_singleton()->flush_buffered_events();
diff --git a/platform/windows/tts_windows.cpp b/platform/windows/tts_windows.cpp
index 39a8f3e120..e9ef50d736 100644
--- a/platform/windows/tts_windows.cpp
+++ b/platform/windows/tts_windows.cpp
@@ -43,7 +43,7 @@ void __stdcall TTS_Windows::speech_event_callback(WPARAM wParam, LPARAM lParam)
} else if (event.eEventId == SPEI_END_INPUT_STREAM) {
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_ENDED, tts->ids[stream_num].id);
tts->ids.erase(stream_num);
- tts->_update_tts();
+ tts->update_requested = true;
} else if (event.eEventId == SPEI_WORD_BOUNDARY) {
const Char16String &string = tts->ids[stream_num].string;
int pos = 0;
@@ -60,8 +60,8 @@ void __stdcall TTS_Windows::speech_event_callback(WPARAM wParam, LPARAM lParam)
}
}
-void TTS_Windows::_update_tts() {
- if (!is_speaking() && !paused && queue.size() > 0) {
+void TTS_Windows::process_events() {
+ if (update_requested && !paused && queue.size() > 0 && !is_speaking()) {
DisplayServer::TTSUtterance &message = queue.front()->get();
String text;
@@ -110,6 +110,8 @@ void TTS_Windows::_update_tts() {
ids[(uint32_t)stream_number] = ut;
queue.pop_front();
+
+ update_requested = false;
}
}
@@ -207,7 +209,7 @@ void TTS_Windows::speak(const String &p_text, const String &p_voice, int p_volum
if (is_paused()) {
resume();
} else {
- _update_tts();
+ update_requested = true;
}
}
diff --git a/platform/windows/tts_windows.h b/platform/windows/tts_windows.h
index 33b597c612..657cb608d6 100644
--- a/platform/windows/tts_windows.h
+++ b/platform/windows/tts_windows.h
@@ -55,9 +55,9 @@ class TTS_Windows {
int id;
};
HashMap<uint32_t, UTData> ids;
+ bool update_requested = false;
static void __stdcall speech_event_callback(WPARAM wParam, LPARAM lParam);
- void _update_tts();
static TTS_Windows *singleton;
@@ -73,6 +73,8 @@ public:
void resume();
void stop();
+ void process_events();
+
TTS_Windows();
~TTS_Windows();
};
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index cdbd95d930..aa4445a7ba 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1189,6 +1189,8 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
return BAKE_ERROR_MESHES_INVALID;
} else if (bake_err == Lightmapper::BAKE_ERROR_ATLAS_TOO_SMALL) {
return BAKE_ERROR_ATLAS_TOO_SMALL;
+ } else if (bake_err == Lightmapper::BAKE_ERROR_USER_ABORTED) {
+ return BAKE_ERROR_USER_ABORTED;
}
// POSTBAKE: Save Textures.
diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h
index 9aa8ef8ccb..1228c63edc 100644
--- a/scene/3d/lightmapper.h
+++ b/scene/3d/lightmapper.h
@@ -147,6 +147,7 @@ public:
BAKE_ERROR_TEXTURE_EXCEEDS_MAX_SIZE,
BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES,
BAKE_ERROR_ATLAS_TOO_SMALL,
+ BAKE_ERROR_USER_ABORTED,
};
enum BakeQuality {
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index e172286d05..d0773fc83f 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -1003,6 +1003,14 @@ String AnimationNodeTimeSeek::get_caption() const {
return "TimeSeek";
}
+void AnimationNodeTimeSeek::set_explicit_elapse(bool p_enable) {
+ explicit_elapse = p_enable;
+}
+
+bool AnimationNodeTimeSeek::is_explicit_elapse() const {
+ return explicit_elapse;
+}
+
AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
double cur_seek_pos = get_parameter(seek_pos_request);
@@ -1011,7 +1019,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer
if (Animation::is_greater_or_equal_approx(cur_seek_pos, 0)) {
pi.time = cur_seek_pos;
pi.seeked = true;
- pi.is_external_seeking = true;
+ pi.is_external_seeking = explicit_elapse;
set_parameter(seek_pos_request, -1.0); // Reset.
}
@@ -1022,6 +1030,12 @@ AnimationNodeTimeSeek::AnimationNodeTimeSeek() {
add_input("in");
}
+void AnimationNodeTimeSeek::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_explicit_elapse", "enable"), &AnimationNodeTimeSeek::set_explicit_elapse);
+ ClassDB::bind_method(D_METHOD("is_explicit_elapse"), &AnimationNodeTimeSeek::is_explicit_elapse);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "explicit_elapse"), "set_explicit_elapse", "is_explicit_elapse");
+}
+
/////////////////////////////////////////////////
bool AnimationNodeTransition::_set(const StringName &p_path, const Variant &p_value) {
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index 5c912f0095..c48d799eea 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -302,6 +302,10 @@ class AnimationNodeTimeSeek : public AnimationNode {
GDCLASS(AnimationNodeTimeSeek, AnimationNode);
StringName seek_pos_request = PNAME("seek_request");
+ bool explicit_elapse = true;
+
+protected:
+ static void _bind_methods();
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
@@ -311,6 +315,9 @@ public:
virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override;
+ void set_explicit_elapse(bool p_enable);
+ bool is_explicit_elapse() const;
+
AnimationNodeTimeSeek();
};
diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp
index 3a2adead98..d4c8af4a4c 100644
--- a/scene/animation/animation_mixer.cpp
+++ b/scene/animation/animation_mixer.cpp
@@ -129,6 +129,9 @@ void AnimationMixer::_validate_property(PropertyInfo &p_property) const {
p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
#endif // TOOLS_ENABLED
+ if (root_motion_track.is_empty() && p_property.name == "root_motion_local") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
}
/* -------------------------------------------- */
@@ -1212,6 +1215,10 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion && calc_root) {
+ int rot_track = -1;
+ if (root_motion_local) {
+ rot_track = a->find_track(a->track_get_path(i), Animation::TYPE_ROTATION_3D);
+ }
double prev_time = time - delta;
if (!backward) {
if (Animation::is_less_approx(prev_time, start)) {
@@ -1246,41 +1253,92 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
}
}
- Vector3 loc[2];
- if (!backward) {
- if (Animation::is_greater_approx(prev_time, time)) {
- Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
- if (err != OK) {
- continue;
+ if (rot_track >= 0) {
+ Vector3 loc[2];
+ Quaternion rot;
+ if (!backward) {
+ if (Animation::is_greater_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, end, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+
+ a->try_rotation_track_interpolate(rot_track, end, &rot);
+ rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);
+
+ root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;
+ prev_time = start;
}
- loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
- a->try_position_track_interpolate(i, end, &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
- root_motion_cache.loc += (loc[1] - loc[0]) * blend;
- prev_time = start;
+ } else {
+ if (Animation::is_less_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, start, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+
+ a->try_rotation_track_interpolate(rot_track, start, &rot);
+ rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);
+
+ root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;
+ prev_time = end;
+ }
+ }
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
}
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, time, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+
+ a->try_rotation_track_interpolate(rot_track, time, &rot);
+ rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);
+
+ root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;
+ prev_time = !backward ? start : end;
} else {
- if (Animation::is_less_approx(prev_time, time)) {
- Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
- if (err != OK) {
- continue;
+ Vector3 loc[2];
+ if (!backward) {
+ if (Animation::is_greater_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, end, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+ root_motion_cache.loc += (loc[1] - loc[0]) * blend;
+ prev_time = start;
+ }
+ } else {
+ if (Animation::is_less_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, start, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+ root_motion_cache.loc += (loc[1] - loc[0]) * blend;
+ prev_time = end;
}
- loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
- a->try_position_track_interpolate(i, start, &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
- root_motion_cache.loc += (loc[1] - loc[0]) * blend;
- prev_time = end;
}
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, time, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+ root_motion_cache.loc += (loc[1] - loc[0]) * blend;
+ prev_time = !backward ? start : end;
}
- Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
- if (err != OK) {
- continue;
- }
- loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
- a->try_position_track_interpolate(i, time, &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
- root_motion_cache.loc += (loc[1] - loc[0]) * blend;
- prev_time = !backward ? start : end;
}
{
Vector3 loc;
@@ -1355,6 +1413,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
a->try_rotation_track_interpolate(i, start, &rot[1]);
+ rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
prev_time = end;
}
@@ -1430,8 +1489,8 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);
a->try_scale_track_interpolate(i, end, &scale[1]);
- root_motion_cache.scale += (scale[1] - scale[0]) * blend;
scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
+ root_motion_cache.scale += (scale[1] - scale[0]) * blend;
prev_time = start;
}
} else {
@@ -2002,12 +2061,21 @@ void AnimationMixer::clear_caches() {
void AnimationMixer::set_root_motion_track(const NodePath &p_track) {
root_motion_track = p_track;
+ notify_property_list_changed();
}
NodePath AnimationMixer::get_root_motion_track() const {
return root_motion_track;
}
+void AnimationMixer::set_root_motion_local(bool p_enabled) {
+ root_motion_local = p_enabled;
+}
+
+bool AnimationMixer::is_root_motion_local() const {
+ return root_motion_local;
+}
+
Vector3 AnimationMixer::get_root_motion_position() const {
return root_motion_position;
}
@@ -2353,6 +2421,8 @@ void AnimationMixer::_bind_methods() {
/* ---- Root motion accumulator for Skeleton3D ---- */
ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationMixer::set_root_motion_track);
ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationMixer::get_root_motion_track);
+ ClassDB::bind_method(D_METHOD("set_root_motion_local", "enabled"), &AnimationMixer::set_root_motion_local);
+ ClassDB::bind_method(D_METHOD("is_root_motion_local"), &AnimationMixer::is_root_motion_local);
ClassDB::bind_method(D_METHOD("get_root_motion_position"), &AnimationMixer::get_root_motion_position);
ClassDB::bind_method(D_METHOD("get_root_motion_rotation"), &AnimationMixer::get_root_motion_rotation);
@@ -2380,6 +2450,7 @@ void AnimationMixer::_bind_methods() {
ADD_GROUP("Root Motion", "root_motion_");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "root_motion_local"), "set_root_motion_local", "is_root_motion_local");
ADD_GROUP("Audio", "audio_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_max_polyphony", PROPERTY_HINT_RANGE, "1,127,1"), "set_audio_max_polyphony", "get_audio_max_polyphony");
diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h
index 822a7aef25..82deccaa95 100644
--- a/scene/animation/animation_mixer.h
+++ b/scene/animation/animation_mixer.h
@@ -334,6 +334,7 @@ protected:
/* ---- Root motion accumulator for Skeleton3D ---- */
NodePath root_motion_track;
+ bool root_motion_local = false;
Vector3 root_motion_position = Vector3(0, 0, 0);
Quaternion root_motion_rotation = Quaternion(0, 0, 0, 1);
Vector3 root_motion_scale = Vector3(0, 0, 0);
@@ -447,6 +448,9 @@ public:
void set_root_motion_track(const NodePath &p_track);
NodePath get_root_motion_track() const;
+ void set_root_motion_local(bool p_enabled);
+ bool is_root_motion_local() const;
+
Vector3 get_root_motion_position() const;
Quaternion get_root_motion_rotation() const;
Vector3 get_root_motion_scale() const;
diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp
index fd520dadd6..2c0222b3b8 100644
--- a/scene/animation/root_motion_view.cpp
+++ b/scene/animation/root_motion_view.cpp
@@ -94,7 +94,6 @@ void RootMotionView::_notification(int p_what) {
if (has_node(path)) {
Node *node = get_node(path);
-
AnimationMixer *mixer = Object::cast_to<AnimationMixer>(node);
if (mixer && mixer->is_active() && mixer->get_root_motion_track() != NodePath()) {
if (is_processing_internal() && mixer->get_callback_mode_process() == AnimationMixer::ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS) {
@@ -106,12 +105,12 @@ void RootMotionView::_notification(int p_what) {
set_process_internal(true);
set_physics_process_internal(false);
}
+
transform.origin = mixer->get_root_motion_position();
transform.basis = mixer->get_root_motion_rotation(); // Scale is meaningless.
- diff = mixer->get_root_motion_rotation_accumulator();
+ diff = mixer->is_root_motion_local() ? Quaternion() : mixer->get_root_motion_rotation_accumulator();
}
}
-
if (!first && transform == Transform3D()) {
return;
}
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 997120ff25..06dff67172 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -217,14 +217,14 @@ void fragment() {
circle_ok_color_shader->set_code(OK_COLOR_SHADER + R"(
// ColorPicker ok color hsv circle shader.
-uniform float v = 1.0;
+uniform float ok_hsl_l = 1.0;
void fragment() {
float x = UV.x - 0.5;
float y = UV.y - 0.5;
float h = atan(y, x) / (2.0 * M_PI);
float s = sqrt(x * x + y * y) * 2.0;
- vec3 col = okhsl_to_srgb(vec3(h, s, v));
+ vec3 col = okhsl_to_srgb(vec3(h, s, ok_hsl_l));
x += 0.001;
y += 0.001;
float b = float(sqrt(x * x + y * y) < 0.5);
@@ -387,10 +387,21 @@ void ColorPicker::_slider_value_changed() {
color = modes[current_mode]->get_color();
modes[current_mode]->_value_changed();
- if (current_mode == MODE_HSV || current_mode == MODE_OKHSL) {
+ if (current_mode == MODE_HSV) {
h = sliders[0]->get_value() / 360.0;
s = sliders[1]->get_value() / 100.0;
v = sliders[2]->get_value() / 100.0;
+ ok_hsl_h = color.get_ok_hsl_h();
+ ok_hsl_s = color.get_ok_hsl_s();
+ ok_hsl_l = color.get_ok_hsl_l();
+ last_color = color;
+ } else if (current_mode == MODE_OKHSL) {
+ ok_hsl_h = sliders[0]->get_value() / 360.0;
+ ok_hsl_s = sliders[1]->get_value() / 100.0;
+ ok_hsl_l = sliders[2]->get_value() / 100.0;
+ h = color.get_h();
+ s = color.get_s();
+ v = color.get_v();
last_color = color;
}
@@ -504,20 +515,17 @@ Vector<float> ColorPicker::get_active_slider_values() {
}
void ColorPicker::_copy_color_to_hsv() {
- if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) {
- h = color.get_ok_hsl_h();
- s = color.get_ok_hsl_s();
- v = color.get_ok_hsl_l();
- } else {
- h = color.get_h();
- s = color.get_s();
- v = color.get_v();
- }
+ ok_hsl_h = color.get_ok_hsl_h();
+ ok_hsl_s = color.get_ok_hsl_s();
+ ok_hsl_l = color.get_ok_hsl_l();
+ h = color.get_h();
+ s = color.get_s();
+ v = color.get_v();
}
void ColorPicker::_copy_hsv_to_color() {
if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) {
- color.set_ok_hsl(h, s, v, color.a);
+ color.set_ok_hsl(ok_hsl_h, ok_hsl_s, ok_hsl_l, color.a);
} else {
color.set_hsv(h, s, v, color.a);
}
@@ -1201,8 +1209,8 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
int x;
int y;
if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) {
- x = center.x + (center.x * Math::cos(h * Math_TAU) * s) - (theme_cache.picker_cursor->get_width() / 2);
- y = center.y + (center.y * Math::sin(h * Math_TAU) * s) - (theme_cache.picker_cursor->get_height() / 2);
+ x = center.x + (center.x * Math::cos((actual_shape == SHAPE_OKHSL_CIRCLE ? ok_hsl_h : h) * Math_TAU) * s) - (theme_cache.picker_cursor->get_width() / 2);
+ y = center.y + (center.y * Math::sin((actual_shape == SHAPE_OKHSL_CIRCLE ? ok_hsl_h : h) * Math_TAU) * s) - (theme_cache.picker_cursor->get_height() / 2);
} else {
real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0;
real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0;
@@ -1238,11 +1246,11 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
Vector<Point2> points;
Vector<Color> colors;
Color col;
- col.set_ok_hsl(h, s, 1);
+ col.set_ok_hsl(ok_hsl_h, ok_hsl_s, 1);
Color col2;
- col2.set_ok_hsl(h, s, 0.5);
+ col2.set_ok_hsl(ok_hsl_h, ok_hsl_s, 0.5);
Color col3;
- col3.set_ok_hsl(h, s, 0);
+ col3.set_ok_hsl(ok_hsl_h, ok_hsl_s, 0);
points.resize(6);
colors.resize(6);
points.set(0, Vector2(c->get_size().x, 0));
@@ -1258,8 +1266,8 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
colors.set(4, col2);
colors.set(5, col);
c->draw_polygon(points, colors);
- int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1);
- col.set_ok_hsl(h, 1, v);
+ int y = c->get_size().y - c->get_size().y * CLAMP(ok_hsl_l, 0, 1);
+ col.set_ok_hsl(ok_hsl_h, 1, ok_hsl_l);
c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
} else if (actual_shape == SHAPE_VHS_CIRCLE) {
Vector<Point2> points;
@@ -1283,8 +1291,10 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
}
} else if (p_which == 2) {
c->draw_rect(Rect2(Point2(), c->get_size()), Color(1, 1, 1));
- if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) {
+ if (actual_shape == SHAPE_VHS_CIRCLE) {
circle_mat->set_shader_parameter("v", v);
+ } else if (actual_shape == SHAPE_OKHSL_CIRCLE) {
+ circle_mat->set_shader_parameter("ok_hsl_l", ok_hsl_l);
}
}
}
@@ -1308,6 +1318,8 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
real_t rad = center.angle_to_point(bev->get_position());
h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
s = CLAMP(dist / center.x, 0, 1);
+ ok_hsl_h = h;
+ ok_hsl_s = s;
} else {
return;
}
@@ -1375,6 +1387,8 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
real_t rad = center.angle_to_point(mev->get_position());
h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
s = CLAMP(dist / center.x, 0, 1);
+ ok_hsl_h = h;
+ ok_hsl_s = s;
} else {
if (spinning) {
real_t rad = center.angle_to_point(mev->get_position());
@@ -1412,6 +1426,7 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height);
if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) {
v = 1.0 - (y / w_edit->get_size().height);
+ ok_hsl_l = v;
} else {
h = y / w_edit->get_size().height;
}
@@ -1440,6 +1455,7 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
float y = CLAMP((float)mev->get_position().y, 0, w_edit->get_size().height);
if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) {
v = 1.0 - (y / w_edit->get_size().height);
+ ok_hsl_l = v;
} else {
h = y / w_edit->get_size().height;
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 59540d9ace..aedf4aef16 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -211,6 +211,11 @@ private:
float h = 0.0;
float s = 0.0;
float v = 0.0;
+
+ float ok_hsl_h = 0.0;
+ float ok_hsl_s = 0.0;
+ float ok_hsl_l = 0.0;
+
Color last_color;
struct ThemeCache {
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index a349d50236..b0886a95d7 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1833,8 +1833,7 @@ void RichTextLabel::_notification(int p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED: {
- // If `text` is empty, it could mean that the tag stack is being used instead. Leave it be.
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
}
@@ -3109,6 +3108,10 @@ void RichTextLabel::add_text(const String &p_text) {
}
void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline) {
+ if (!internal_stack_editing) {
+ stack_externally_modified = true;
+ }
+
p_item->parent = current;
p_item->E = current->subitems.push_back(p_item);
p_item->index = current_idx++;
@@ -3382,6 +3385,8 @@ bool RichTextLabel::remove_paragraph(int p_paragraph, bool p_no_invalidate) {
return false;
}
+ stack_externally_modified = true;
+
if (main->lines.size() == 1) {
// Clear all.
main->_clear_children();
@@ -4016,6 +4021,8 @@ void RichTextLabel::clear() {
set_process_internal(false);
MutexLock data_lock(data_mutex);
+ stack_externally_modified = false;
+
main->_clear_children();
current = main;
current_frame = main;
@@ -5818,11 +5825,19 @@ void RichTextLabel::set_text(const String &p_bbcode) {
return;
}
+ stack_externally_modified = false;
+
text = p_bbcode;
_apply_translation();
}
void RichTextLabel::_apply_translation() {
+ if (text.is_empty()) {
+ return;
+ }
+
+ internal_stack_editing = true;
+
String xl_text = atr(text);
if (use_bbcode) {
parse_bbcode(xl_text);
@@ -5830,6 +5845,8 @@ void RichTextLabel::_apply_translation() {
clear();
add_text(xl_text);
}
+
+ internal_stack_editing = false;
}
String RichTextLabel::get_text() const {
@@ -5843,8 +5860,7 @@ void RichTextLabel::set_use_bbcode(bool p_enable) {
use_bbcode = p_enable;
notify_property_list_changed();
- // If `text` is empty, it could mean that the tag stack is being used instead. Leave it be.
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
}
}
@@ -5854,7 +5870,7 @@ bool RichTextLabel::is_using_bbcode() const {
}
String RichTextLabel::get_parsed_text() const {
- String txt = "";
+ String txt;
Item *it = main;
while (it) {
if (it->type == ITEM_DROPCAP) {
@@ -5881,7 +5897,7 @@ void RichTextLabel::set_text_direction(Control::TextDirection p_text_direction)
if (text_direction != p_text_direction) {
text_direction = p_text_direction;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -5901,7 +5917,7 @@ void RichTextLabel::set_horizontal_alignment(HorizontalAlignment p_alignment) {
if (default_alignment != p_alignment) {
default_alignment = p_alignment;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -5920,7 +5936,7 @@ void RichTextLabel::set_justification_flags(BitField<TextServer::JustificationFl
if (default_jst_flags != p_flags) {
default_jst_flags = p_flags;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -5939,7 +5955,7 @@ void RichTextLabel::set_tab_stops(const PackedFloat32Array &p_tab_stops) {
if (default_tab_stops != p_tab_stops) {
default_tab_stops = p_tab_stops;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -5958,7 +5974,7 @@ void RichTextLabel::set_structured_text_bidi_override(TextServer::StructuredText
_stop_thread();
st_parser = p_parser;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -5992,7 +6008,7 @@ void RichTextLabel::set_language(const String &p_language) {
_stop_thread();
language = p_language;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -6050,7 +6066,7 @@ float RichTextLabel::get_visible_ratio() const {
void RichTextLabel::set_effects(Array p_effects) {
custom_effects = p_effects;
- if ((!text.is_empty()) && use_bbcode) {
+ if (!stack_externally_modified && use_bbcode) {
parse_bbcode(atr(text));
}
}
@@ -6065,7 +6081,7 @@ void RichTextLabel::install_effect(const Variant effect) {
ERR_FAIL_COND_MSG(rteffect.is_null(), "Invalid RichTextEffect resource.");
custom_effects.push_back(effect);
- if ((!text.is_empty()) && use_bbcode) {
+ if (!stack_externally_modified && use_bbcode) {
parse_bbcode(atr(text));
}
}
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index a01da02b27..ef4d17b8aa 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -626,6 +626,9 @@ private:
String text;
void _apply_translation();
+ bool internal_stack_editing = false;
+ bool stack_externally_modified = false;
+
bool fit_content = false;
struct ThemeCache {
diff --git a/scene/resources/3d/primitive_meshes.cpp b/scene/resources/3d/primitive_meshes.cpp
index ceeb73d0ef..4d04ae77b1 100644
--- a/scene/resources/3d/primitive_meshes.cpp
+++ b/scene/resources/3d/primitive_meshes.cpp
@@ -31,6 +31,7 @@
#include "primitive_meshes.h"
#include "core/config/project_settings.h"
+#include "core/math/math_funcs.h"
#include "scene/resources/theme.h"
#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
@@ -261,6 +262,9 @@ void PrimitiveMesh::_bind_methods() {
}
void PrimitiveMesh::set_material(const Ref<Material> &p_material) {
+ if (p_material == material) {
+ return;
+ }
material = p_material;
if (!pending_request) {
// just apply it, else it'll happen when _update is called.
@@ -279,6 +283,9 @@ Array PrimitiveMesh::get_mesh_arrays() const {
}
void PrimitiveMesh::set_custom_aabb(const AABB &p_custom) {
+ if (p_custom.is_equal_approx(custom_aabb)) {
+ return;
+ }
custom_aabb = p_custom;
RS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
emit_changed();
@@ -289,6 +296,9 @@ AABB PrimitiveMesh::get_custom_aabb() const {
}
void PrimitiveMesh::set_flip_faces(bool p_enable) {
+ if (p_enable == flip_faces) {
+ return;
+ }
flip_faces = p_enable;
request_update();
}
@@ -298,12 +308,18 @@ bool PrimitiveMesh::get_flip_faces() const {
}
void PrimitiveMesh::set_add_uv2(bool p_enable) {
+ if (p_enable == add_uv2) {
+ return;
+ }
add_uv2 = p_enable;
_update_lightmap_size();
request_update();
}
void PrimitiveMesh::set_uv2_padding(float p_padding) {
+ if (Math::is_equal_approx(p_padding, uv2_padding)) {
+ return;
+ }
uv2_padding = p_padding;
_update_lightmap_size();
request_update();
@@ -578,6 +594,10 @@ void CapsuleMesh::_bind_methods() {
}
void CapsuleMesh::set_radius(const float p_radius) {
+ if (Math::is_equal_approx(radius, p_radius)) {
+ return;
+ }
+
radius = p_radius;
if (radius > height * 0.5) {
height = radius * 2.0;
@@ -591,6 +611,10 @@ float CapsuleMesh::get_radius() const {
}
void CapsuleMesh::set_height(const float p_height) {
+ if (Math::is_equal_approx(height, p_height)) {
+ return;
+ }
+
height = p_height;
if (radius > height * 0.5) {
radius = height * 0.5;
@@ -604,6 +628,10 @@ float CapsuleMesh::get_height() const {
}
void CapsuleMesh::set_radial_segments(const int p_segments) {
+ if (radial_segments == p_segments) {
+ return;
+ }
+
radial_segments = p_segments > 4 ? p_segments : 4;
request_update();
}
@@ -613,6 +641,10 @@ int CapsuleMesh::get_radial_segments() const {
}
void CapsuleMesh::set_rings(const int p_rings) {
+ if (rings == p_rings) {
+ return;
+ }
+
ERR_FAIL_COND(p_rings < 0);
rings = p_rings;
request_update();
@@ -908,6 +940,10 @@ void BoxMesh::_bind_methods() {
}
void BoxMesh::set_size(const Vector3 &p_size) {
+ if (p_size.is_equal_approx(size)) {
+ return;
+ }
+
size = p_size;
_update_lightmap_size();
request_update();
@@ -918,6 +954,10 @@ Vector3 BoxMesh::get_size() const {
}
void BoxMesh::set_subdivide_width(const int p_divisions) {
+ if (p_divisions == subdivide_w) {
+ return;
+ }
+
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -927,6 +967,10 @@ int BoxMesh::get_subdivide_width() const {
}
void BoxMesh::set_subdivide_height(const int p_divisions) {
+ if (p_divisions == subdivide_h) {
+ return;
+ }
+
subdivide_h = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -936,6 +980,10 @@ int BoxMesh::get_subdivide_height() const {
}
void BoxMesh::set_subdivide_depth(const int p_divisions) {
+ if (p_divisions == subdivide_d) {
+ return;
+ }
+
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1183,6 +1231,10 @@ void CylinderMesh::_bind_methods() {
}
void CylinderMesh::set_top_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, top_radius)) {
+ return;
+ }
+
top_radius = p_radius;
_update_lightmap_size();
request_update();
@@ -1193,6 +1245,10 @@ float CylinderMesh::get_top_radius() const {
}
void CylinderMesh::set_bottom_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, bottom_radius)) {
+ return;
+ }
+
bottom_radius = p_radius;
_update_lightmap_size();
request_update();
@@ -1203,6 +1259,10 @@ float CylinderMesh::get_bottom_radius() const {
}
void CylinderMesh::set_height(const float p_height) {
+ if (Math::is_equal_approx(p_height, height)) {
+ return;
+ }
+
height = p_height;
_update_lightmap_size();
request_update();
@@ -1213,6 +1273,10 @@ float CylinderMesh::get_height() const {
}
void CylinderMesh::set_radial_segments(const int p_segments) {
+ if (p_segments == radial_segments) {
+ return;
+ }
+
radial_segments = p_segments > 4 ? p_segments : 4;
request_update();
}
@@ -1222,6 +1286,10 @@ int CylinderMesh::get_radial_segments() const {
}
void CylinderMesh::set_rings(const int p_rings) {
+ if (p_rings == rings) {
+ return;
+ }
+
ERR_FAIL_COND(p_rings < 0);
rings = p_rings;
request_update();
@@ -1232,6 +1300,10 @@ int CylinderMesh::get_rings() const {
}
void CylinderMesh::set_cap_top(bool p_cap_top) {
+ if (p_cap_top == cap_top) {
+ return;
+ }
+
cap_top = p_cap_top;
request_update();
}
@@ -1241,6 +1313,10 @@ bool CylinderMesh::is_cap_top() const {
}
void CylinderMesh::set_cap_bottom(bool p_cap_bottom) {
+ if (p_cap_bottom == cap_bottom) {
+ return;
+ }
+
cap_bottom = p_cap_bottom;
request_update();
}
@@ -1375,6 +1451,9 @@ void PlaneMesh::_bind_methods() {
}
void PlaneMesh::set_size(const Size2 &p_size) {
+ if (p_size == size) {
+ return;
+ }
size = p_size;
_update_lightmap_size();
request_update();
@@ -1385,6 +1464,9 @@ Size2 PlaneMesh::get_size() const {
}
void PlaneMesh::set_subdivide_width(const int p_divisions) {
+ if (p_divisions == subdivide_w || (subdivide_w == 0 && p_divisions < 0)) {
+ return;
+ }
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1394,6 +1476,9 @@ int PlaneMesh::get_subdivide_width() const {
}
void PlaneMesh::set_subdivide_depth(const int p_divisions) {
+ if (p_divisions == subdivide_d || (subdivide_d == 0 && p_divisions < 0)) {
+ return;
+ }
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1403,6 +1488,9 @@ int PlaneMesh::get_subdivide_depth() const {
}
void PlaneMesh::set_center_offset(const Vector3 p_offset) {
+ if (p_offset.is_equal_approx(center_offset)) {
+ return;
+ }
center_offset = p_offset;
request_update();
}
@@ -1412,6 +1500,9 @@ Vector3 PlaneMesh::get_center_offset() const {
}
void PlaneMesh::set_orientation(const Orientation p_orientation) {
+ if (p_orientation == orientation) {
+ return;
+ }
orientation = p_orientation;
request_update();
}
@@ -1719,6 +1810,9 @@ void PrismMesh::_bind_methods() {
}
void PrismMesh::set_left_to_right(const float p_left_to_right) {
+ if (Math::is_equal_approx(p_left_to_right, left_to_right)) {
+ return;
+ }
left_to_right = p_left_to_right;
request_update();
}
@@ -1728,6 +1822,9 @@ float PrismMesh::get_left_to_right() const {
}
void PrismMesh::set_size(const Vector3 &p_size) {
+ if (p_size.is_equal_approx(size)) {
+ return;
+ }
size = p_size;
_update_lightmap_size();
request_update();
@@ -1738,6 +1835,9 @@ Vector3 PrismMesh::get_size() const {
}
void PrismMesh::set_subdivide_width(const int p_divisions) {
+ if (p_divisions == subdivide_w || (p_divisions < 0 && subdivide_w == 0)) {
+ return;
+ }
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1747,6 +1847,9 @@ int PrismMesh::get_subdivide_width() const {
}
void PrismMesh::set_subdivide_height(const int p_divisions) {
+ if (p_divisions == subdivide_h || (p_divisions < 0 && subdivide_h == 0)) {
+ return;
+ }
subdivide_h = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1756,6 +1859,9 @@ int PrismMesh::get_subdivide_height() const {
}
void PrismMesh::set_subdivide_depth(const int p_divisions) {
+ if (p_divisions == subdivide_d || (p_divisions < 0 && subdivide_d == 0)) {
+ return;
+ }
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1902,6 +2008,9 @@ void SphereMesh::_bind_methods() {
}
void SphereMesh::set_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, radius)) {
+ return;
+ }
radius = p_radius;
_update_lightmap_size();
request_update();
@@ -1912,6 +2021,9 @@ float SphereMesh::get_radius() const {
}
void SphereMesh::set_height(const float p_height) {
+ if (Math::is_equal_approx(height, p_height)) {
+ return;
+ }
height = p_height;
_update_lightmap_size();
request_update();
@@ -1922,6 +2034,9 @@ float SphereMesh::get_height() const {
}
void SphereMesh::set_radial_segments(const int p_radial_segments) {
+ if (p_radial_segments == radial_segments || (radial_segments == 4 && p_radial_segments < 4)) {
+ return;
+ }
radial_segments = p_radial_segments > 4 ? p_radial_segments : 4;
request_update();
}
@@ -1931,6 +2046,9 @@ int SphereMesh::get_radial_segments() const {
}
void SphereMesh::set_rings(const int p_rings) {
+ if (p_rings == rings) {
+ return;
+ }
ERR_FAIL_COND(p_rings < 1);
rings = p_rings;
request_update();
@@ -1941,6 +2059,9 @@ int SphereMesh::get_rings() const {
}
void SphereMesh::set_is_hemisphere(const bool p_is_hemisphere) {
+ if (p_is_hemisphere == is_hemisphere) {
+ return;
+ }
is_hemisphere = p_is_hemisphere;
_update_lightmap_size();
request_update();
@@ -2086,6 +2207,9 @@ void TorusMesh::_bind_methods() {
}
void TorusMesh::set_inner_radius(const float p_inner_radius) {
+ if (Math::is_equal_approx(p_inner_radius, inner_radius)) {
+ return;
+ }
inner_radius = p_inner_radius;
request_update();
}
@@ -2095,6 +2219,9 @@ float TorusMesh::get_inner_radius() const {
}
void TorusMesh::set_outer_radius(const float p_outer_radius) {
+ if (Math::is_equal_approx(p_outer_radius, outer_radius)) {
+ return;
+ }
outer_radius = p_outer_radius;
request_update();
}
@@ -2104,6 +2231,9 @@ float TorusMesh::get_outer_radius() const {
}
void TorusMesh::set_rings(const int p_rings) {
+ if (p_rings == rings) {
+ return;
+ }
ERR_FAIL_COND(p_rings < 3);
rings = p_rings;
request_update();
@@ -2114,6 +2244,9 @@ int TorusMesh::get_rings() const {
}
void TorusMesh::set_ring_segments(const int p_ring_segments) {
+ if (p_ring_segments == ring_segments) {
+ return;
+ }
ERR_FAIL_COND(p_ring_segments < 3);
ring_segments = p_ring_segments;
request_update();
@@ -2143,6 +2276,9 @@ PointMesh::PointMesh() {
// TUBE TRAIL
void TubeTrailMesh::set_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, radius)) {
+ return;
+ }
radius = p_radius;
request_update();
}
@@ -2151,6 +2287,9 @@ float TubeTrailMesh::get_radius() const {
}
void TubeTrailMesh::set_radial_steps(const int p_radial_steps) {
+ if (p_radial_steps == radial_steps) {
+ return;
+ }
ERR_FAIL_COND(p_radial_steps < 3 || p_radial_steps > 128);
radial_steps = p_radial_steps;
request_update();
@@ -2160,6 +2299,9 @@ int TubeTrailMesh::get_radial_steps() const {
}
void TubeTrailMesh::set_sections(const int p_sections) {
+ if (p_sections == sections) {
+ return;
+ }
ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
sections = p_sections;
request_update();
@@ -2169,6 +2311,9 @@ int TubeTrailMesh::get_sections() const {
}
void TubeTrailMesh::set_section_length(float p_section_length) {
+ if (p_section_length == section_length) {
+ return;
+ }
section_length = p_section_length;
request_update();
}
@@ -2177,6 +2322,9 @@ float TubeTrailMesh::get_section_length() const {
}
void TubeTrailMesh::set_section_rings(const int p_section_rings) {
+ if (p_section_rings == section_rings) {
+ return;
+ }
ERR_FAIL_COND(p_section_rings < 1 || p_section_rings > 1024);
section_rings = p_section_rings;
request_update();
@@ -2186,6 +2334,9 @@ int TubeTrailMesh::get_section_rings() const {
}
void TubeTrailMesh::set_cap_top(bool p_cap_top) {
+ if (p_cap_top == cap_top) {
+ return;
+ }
cap_top = p_cap_top;
request_update();
}
@@ -2195,6 +2346,9 @@ bool TubeTrailMesh::is_cap_top() const {
}
void TubeTrailMesh::set_cap_bottom(bool p_cap_bottom) {
+ if (p_cap_bottom == cap_bottom) {
+ return;
+ }
cap_bottom = p_cap_bottom;
request_update();
}
@@ -2501,6 +2655,9 @@ TubeTrailMesh::TubeTrailMesh() {
// RIBBON TRAIL
void RibbonTrailMesh::set_shape(Shape p_shape) {
+ if (p_shape == shape) {
+ return;
+ }
shape = p_shape;
request_update();
}
@@ -2509,6 +2666,9 @@ RibbonTrailMesh::Shape RibbonTrailMesh::get_shape() const {
}
void RibbonTrailMesh::set_size(const float p_size) {
+ if (Math::is_equal_approx(p_size, size)) {
+ return;
+ }
size = p_size;
request_update();
}
@@ -2517,6 +2677,9 @@ float RibbonTrailMesh::get_size() const {
}
void RibbonTrailMesh::set_sections(const int p_sections) {
+ if (p_sections == sections) {
+ return;
+ }
ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
sections = p_sections;
request_update();
@@ -2526,6 +2689,9 @@ int RibbonTrailMesh::get_sections() const {
}
void RibbonTrailMesh::set_section_length(float p_section_length) {
+ if (p_section_length == section_length) {
+ return;
+ }
section_length = p_section_length;
request_update();
}
@@ -2534,6 +2700,9 @@ float RibbonTrailMesh::get_section_length() const {
}
void RibbonTrailMesh::set_section_segments(const int p_section_segments) {
+ if (p_section_segments == section_segments) {
+ return;
+ }
ERR_FAIL_COND(p_section_segments < 1 || p_section_segments > 1024);
section_segments = p_section_segments;
request_update();
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 0dcdb90948..165168cb29 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -666,6 +666,8 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * light_count, &state.light_uniforms[0]);
}
+ bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target);
+
{
//update canvas state uniform buffer
State::Buffer state_buffer;
@@ -684,7 +686,6 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
normal_transform.columns[2] = Vector2();
_update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform);
- bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target);
Color modulate = p_modulate;
if (use_linear_colors) {
modulate = p_modulate.srgb_to_linear();
@@ -722,6 +723,8 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
//print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale));
state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5);
+ state_buffer.flags = use_linear_colors ? CANVAS_FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR : 0;
+
RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer);
}
@@ -752,8 +755,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
RenderTarget to_render_target;
to_render_target.render_target = p_to_render_target;
- bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target);
- to_render_target.base_flags = use_linear_colors ? FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR : 0;
+ to_render_target.use_linear_colors = use_linear_colors;
while (ci) {
if (ci->copy_back_buffer && canvas_group_owner == nullptr) {
@@ -2244,7 +2246,7 @@ RendererCanvasRenderRD::InstanceData *RendererCanvasRenderRD::new_instance_data(
instance_data->world[i] = p_world[i];
}
- instance_data->flags = p_base_flags | p_info->flags; // Reset on each command for safety, keep canvas texture binding config.
+ instance_data->flags = p_base_flags; // Reset on each command for safety.
instance_data->color_texture_pixel_size[0] = p_info->texpixel_size.width;
instance_data->color_texture_pixel_size[1] = p_info->texpixel_size.height;
@@ -2265,8 +2267,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
_update_transform_2d_to_mat2x3(base_transform, world);
Color base_color = p_item->final_modulate;
- bool use_linear_colors = bool(p_render_target.base_flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR);
- uint32_t base_flags = p_render_target.base_flags;
+ bool use_linear_colors = p_render_target.use_linear_colors;
+ uint32_t base_flags = 0;
bool reclip = false;
@@ -2276,6 +2278,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
uint32_t lights[4] = { 0, 0, 0, 0 };
uint16_t light_count = 0;
+ uint16_t shadow_mask = 0;
{
Light *light = p_lights;
@@ -2285,6 +2288,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
uint32_t light_index = light->render_index_cache;
lights[light_count >> 2] |= light_index << ((light_count & 3) * 8);
+ if (p_item->light_mask & light->item_shadow_mask) {
+ shadow_mask |= 1 << light_count;
+ }
+
light_count++;
if (light_count == MAX_LIGHTS_PER_ITEM - 1) {
@@ -2294,7 +2301,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
light = light->next_ptr;
}
- base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
+ base_flags |= light_count << INSTANCE_FLAGS_LIGHT_COUNT_SHIFT;
+ base_flags |= shadow_mask << INSTANCE_FLAGS_SHADOW_MASKED_SHIFT;
}
bool use_lighting = (light_count > 0 || using_directional_lights);
@@ -2323,6 +2331,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
// default variant
r_current_batch->shader_variant = SHADER_VARIANT_QUAD;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
+ r_current_batch->flags = 0;
}
RenderingServer::CanvasItemTextureRepeat rect_repeat = texture_repeat;
@@ -2378,20 +2387,18 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
if (rect->flags & CANVAS_RECT_FLIP_H) {
src_rect.size.x *= -1;
- instance_data->flags |= FLAGS_FLIP_H;
}
if (rect->flags & CANVAS_RECT_FLIP_V) {
src_rect.size.y *= -1;
- instance_data->flags |= FLAGS_FLIP_V;
}
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
- instance_data->flags |= FLAGS_TRANSPOSE_RECT;
+ instance_data->flags |= INSTANCE_FLAGS_TRANSPOSE_RECT;
}
if (rect->flags & CANVAS_RECT_CLIP_UV) {
- instance_data->flags |= FLAGS_CLIP_RECT_UV;
+ instance_data->flags |= INSTANCE_FLAGS_CLIP_RECT_UV;
}
} else {
@@ -2410,13 +2417,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
}
if (has_msdf) {
- instance_data->flags |= FLAGS_USE_MSDF;
+ instance_data->flags |= INSTANCE_FLAGS_USE_MSDF;
instance_data->msdf[0] = rect->px_range; // Pixel range.
instance_data->msdf[1] = rect->outline; // Outline size.
instance_data->msdf[2] = 0.f; // Reserved.
instance_data->msdf[3] = 0.f; // Reserved.
} else if (rect->flags & CANVAS_RECT_LCD) {
- instance_data->flags |= FLAGS_USE_LCD;
+ instance_data->flags |= INSTANCE_FLAGS_USE_LCD;
}
instance_data->modulation[0] = modulated.r;
@@ -2447,6 +2454,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->has_blend = false;
r_current_batch->shader_variant = SHADER_VARIANT_NINEPATCH;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
+ r_current_batch->flags = 0;
}
TextureState tex_state(np->texture, texture_filter, texture_repeat, false, use_linear_colors);
@@ -2498,11 +2506,11 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->dst_rect[2] = dst_rect.size.width;
instance_data->dst_rect[3] = dst_rect.size.height;
- instance_data->flags |= int(np->axis_x) << FLAGS_NINEPATCH_H_MODE_SHIFT;
- instance_data->flags |= int(np->axis_y) << FLAGS_NINEPATCH_V_MODE_SHIFT;
+ instance_data->flags |= int(np->axis_x) << INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT;
+ instance_data->flags |= int(np->axis_y) << INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT;
if (np->draw_center) {
- instance_data->flags |= FLAGS_NINEPACH_DRAW_CENTER;
+ instance_data->flags |= INSTANCE_FLAGS_NINEPACH_DRAW_CENTER;
}
instance_data->ninepatch_margins[0] = np->margin[SIDE_LEFT];
@@ -2522,6 +2530,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->command_type = Item::Command::TYPE_POLYGON;
r_current_batch->has_blend = false;
r_current_batch->command = c;
+ r_current_batch->flags = 0;
TextureState tex_state(polygon->texture, texture_filter, texture_repeat, false, use_linear_colors);
TextureInfo *tex_info = texture_info_map.getptr(tex_state);
@@ -2566,6 +2575,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->has_blend = false;
r_current_batch->command = c;
r_current_batch->primitive_points = primitive->point_count;
+ r_current_batch->flags = 0;
ERR_CONTINUE(primitive->point_count == 0 || primitive->point_count > 4);
@@ -2648,6 +2658,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->command = c;
r_current_batch->command_type = c->type;
r_current_batch->has_blend = false;
+ r_current_batch->flags = 0;
InstanceData *instance_data = nullptr;
@@ -2690,13 +2701,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->tex_info = tex_info;
instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
- instance_data->flags |= 1; // multimesh, trails disabled
+ r_current_batch->flags |= 1; // multimesh, trails disabled
if (mesh_storage->multimesh_uses_colors(mm->multimesh)) {
- instance_data->flags |= FLAGS_INSTANCING_HAS_COLORS;
+ r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_COLORS;
}
if (mesh_storage->multimesh_uses_custom_data(mm->multimesh)) {
- instance_data->flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
+ r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA;
}
} else if (c->type == Item::Command::TYPE_PARTICLES) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
@@ -2714,13 +2725,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
uint32_t divisor = 1;
r_current_batch->mesh_instance_count = particles_storage->particles_get_amount(pt->particles, divisor);
- instance_data->flags |= (divisor & FLAGS_INSTANCING_MASK);
+ r_current_batch->flags |= (divisor & BATCH_FLAGS_INSTANCING_MASK);
r_current_batch->mesh_instance_count /= divisor;
RID particles = pt->particles;
- instance_data->flags |= FLAGS_INSTANCING_HAS_COLORS;
- instance_data->flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
+ r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_COLORS;
+ r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA;
if (particles_storage->particles_has_collision(particles) && texture_storage->render_target_is_sdf_enabled(p_render_target.render_target)) {
// Pass collision information.
@@ -2806,6 +2817,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
// default variant
r_current_batch->shader_variant = SHADER_VARIANT_QUAD;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
+ r_current_batch->flags = 0;
}
// 2: If the current batch has lighting, start a new batch.
@@ -2920,6 +2932,7 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
push_constant.specular_shininess = p_batch->tex_info->specular_shininess;
+ push_constant.batch_flags = p_batch->tex_info->flags | p_batch->flags;
RID pipeline;
PipelineKey pipeline_key;
@@ -3168,11 +3181,11 @@ void RendererCanvasRenderRD::_prepare_batch_texture_info(RID p_texture, TextureS
// cache values to be copied to instance data
if (info.specular_color.a < 0.999) {
- p_info->flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ p_info->flags |= BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
if (info.use_normal) {
- p_info->flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
+ p_info->flags |= BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED;
}
uint8_t a = uint8_t(CLAMP(info.specular_color.a * 255.0, 0.0, 255.0));
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 1bdc5076c5..e4f1779b09 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -65,31 +65,31 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
};
enum {
+ INSTANCE_FLAGS_LIGHT_COUNT_SHIFT = 0, // 4 bits for light count.
- FLAGS_INSTANCING_MASK = 0x7F,
- FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
- FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8),
+ INSTANCE_FLAGS_CLIP_RECT_UV = (1 << 4),
+ INSTANCE_FLAGS_TRANSPOSE_RECT = (1 << 5),
+ INSTANCE_FLAGS_USE_MSDF = (1 << 6),
+ INSTANCE_FLAGS_USE_LCD = (1 << 7),
- FLAGS_CLIP_RECT_UV = (1 << 9),
- FLAGS_TRANSPOSE_RECT = (1 << 10),
+ INSTANCE_FLAGS_NINEPACH_DRAW_CENTER = (1 << 8),
+ INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT = 9,
+ INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT = 11,
- FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR = (1 << 11),
-
- FLAGS_NINEPACH_DRAW_CENTER = (1 << 12),
-
- FLAGS_USE_SKELETON = (1 << 15),
- FLAGS_NINEPATCH_H_MODE_SHIFT = 16,
- FLAGS_NINEPATCH_V_MODE_SHIFT = 18,
- FLAGS_LIGHT_COUNT_SHIFT = 20,
+ INSTANCE_FLAGS_SHADOW_MASKED_SHIFT = 13, // 16 bits.
+ };
- FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 24),
- FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 25),
+ enum {
+ BATCH_FLAGS_INSTANCING_MASK = 0x7F,
+ BATCH_FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
+ BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8),
- FLAGS_USE_MSDF = (1 << 26),
- FLAGS_USE_LCD = (1 << 27),
+ BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 9),
+ BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 10),
+ };
- FLAGS_FLIP_H = (1 << 28),
- FLAGS_FLIP_V = (1 << 29),
+ enum {
+ CANVAS_FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR = (1 << 0),
};
enum {
@@ -370,7 +370,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t base_instance_index;
ShaderSpecialization shader_specialization;
uint32_t specular_shininess;
- uint32_t pad;
+ uint32_t batch_flags;
};
// TextureState is used to determine when a new batch is required due to a change of texture state.
@@ -508,6 +508,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t mesh_instance_count;
};
bool has_blend = false;
+ uint32_t flags = 0;
};
HashMap<TextureState, TextureInfo, HashableHasher<TextureState>> texture_info_map;
@@ -535,7 +536,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t directional_light_count;
float tex_to_sdf;
- uint32_t pad1;
+ uint32_t flags;
uint32_t pad2;
};
@@ -596,9 +597,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
struct RenderTarget {
// Current render target for the canvas.
RID render_target;
- // The base flags for each InstanceData, derived from the render target.
- // Either FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR or 0
- uint32_t base_flags = 0;
+ bool use_linear_colors = false;
};
inline RID _get_pipeline_specialization_or_ubershader(CanvasShaderData *p_shader_data, PipelineKey &r_pipeline_key, PushConstant &r_push_constant, RID p_mesh_instance = RID(), void *p_surface = nullptr, uint32_t p_surface_index = 0, RID *r_vertex_array = nullptr);
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index f665bc24a4..b66aa71f6b 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -101,7 +101,7 @@ void main() {
vec2 vertex = vertex_attrib;
vec4 color = color_attrib;
- if (bool(draw_data.flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR)) {
+ if (bool(canvas_data.flags & CANVAS_FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR)) {
color.rgb = srgb_to_linear(color.rgb);
}
color *= draw_data.modulation;
@@ -122,7 +122,7 @@ void main() {
vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
vec2 vertex_base = vertex_base_arr[gl_VertexIndex];
- vec2 uv = draw_data.src_rect.xy + abs(draw_data.src_rect.zw) * ((draw_data.flags & FLAGS_TRANSPOSE_RECT) != 0 ? vertex_base.yx : vertex_base.xy);
+ vec2 uv = draw_data.src_rect.xy + abs(draw_data.src_rect.zw) * ((draw_data.flags & INSTANCE_FLAGS_TRANSPOSE_RECT) != 0 ? vertex_base.yx : vertex_base.xy);
vec4 color = draw_data.modulation;
vec2 vertex = draw_data.dst_rect.xy + abs(draw_data.dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data.src_rect.zw, vec2(0.0, 0.0)));
uvec4 bones = uvec4(0, 0, 0, 0);
@@ -133,7 +133,7 @@ void main() {
#ifdef USE_ATTRIBUTES
- uint instancing = draw_data.flags & FLAGS_INSTANCING_MASK;
+ uint instancing = params.batch_flags & BATCH_FLAGS_INSTANCING_MASK;
if (instancing > 1) {
// trails
@@ -172,19 +172,19 @@ void main() {
vertex = new_vertex;
color *= pcolor;
} else if (instancing == 1) {
- uint stride = 2 + bitfieldExtract(draw_data.flags, FLAGS_INSTANCING_HAS_COLORS_SHIFT, 1) + bitfieldExtract(draw_data.flags, FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT, 1);
+ uint stride = 2 + bitfieldExtract(params.batch_flags, BATCH_FLAGS_INSTANCING_HAS_COLORS_SHIFT, 1) + bitfieldExtract(params.batch_flags, BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT, 1);
uint offset = stride * gl_InstanceIndex;
mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
offset += 2;
- if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
+ if (bool(params.batch_flags & BATCH_FLAGS_INSTANCING_HAS_COLORS)) {
color *= transforms.data[offset];
offset += 1;
}
- if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
+ if (bool(params.batch_flags & BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
instance_custom = transforms.data[offset];
}
@@ -331,7 +331,7 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
} else if (pixel >= draw_size - margin_end) {
return (tex_size - (draw_size - pixel)) * tex_pixel_size;
} else {
- draw_center -= 1 - int(bitfieldExtract(draw_data.flags, FLAGS_NINEPACH_DRAW_CENTER_SHIFT, 1));
+ draw_center -= 1 - int(bitfieldExtract(draw_data.flags, INSTANCE_FLAGS_NINEPATCH_DRAW_CENTER_SHIFT, 1));
// np_repeat is passed as uniform using NinePatchRect::AxisStretchMode enum.
if (np_repeat == 0) { // Stretch.
@@ -472,8 +472,8 @@ void main() {
int draw_center = 2;
uv = vec2(
- map_ninepatch_axis(pixel_size_interp.x, abs(draw_data.dst_rect.z), draw_data.color_texture_pixel_size.x, draw_data.ninepatch_margins.x, draw_data.ninepatch_margins.z, int(bitfieldExtract(draw_data.flags, FLAGS_NINEPATCH_H_MODE_SHIFT, 2)), draw_center),
- map_ninepatch_axis(pixel_size_interp.y, abs(draw_data.dst_rect.w), draw_data.color_texture_pixel_size.y, draw_data.ninepatch_margins.y, draw_data.ninepatch_margins.w, int(bitfieldExtract(draw_data.flags, FLAGS_NINEPATCH_V_MODE_SHIFT, 2)), draw_center));
+ map_ninepatch_axis(pixel_size_interp.x, abs(draw_data.dst_rect.z), draw_data.color_texture_pixel_size.x, draw_data.ninepatch_margins.x, draw_data.ninepatch_margins.z, int(bitfieldExtract(draw_data.flags, INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT, 2)), draw_center),
+ map_ninepatch_axis(pixel_size_interp.y, abs(draw_data.dst_rect.w), draw_data.color_texture_pixel_size.y, draw_data.ninepatch_margins.y, draw_data.ninepatch_margins.w, int(bitfieldExtract(draw_data.flags, INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT, 2)), draw_center));
if (draw_center == 0) {
color.a = 0.0;
@@ -482,7 +482,7 @@ void main() {
uv = uv * draw_data.src_rect.zw + draw_data.src_rect.xy; //apply region if needed
#endif
- if (bool(draw_data.flags & FLAGS_CLIP_RECT_UV)) {
+ if (bool(draw_data.flags & INSTANCE_FLAGS_CLIP_RECT_UV)) {
vec2 half_texpixel = draw_data.color_texture_pixel_size * 0.5;
uv = clamp(uv, draw_data.src_rect.xy + half_texpixel, draw_data.src_rect.xy + abs(draw_data.src_rect.zw) - half_texpixel);
}
@@ -490,7 +490,7 @@ void main() {
#endif
#ifndef USE_PRIMITIVE
- if (bool(draw_data.flags & FLAGS_USE_MSDF)) {
+ if (bool(draw_data.flags & INSTANCE_FLAGS_USE_MSDF)) {
float px_range = draw_data.ninepatch_margins.x;
float outline_thickness = draw_data.ninepatch_margins.y;
//float reserved1 = draw_data.ninepatch_margins.z;
@@ -510,7 +510,7 @@ void main() {
float a = clamp(d * px_size + 0.5, 0.0, 1.0);
color.a = a * color.a;
}
- } else if (bool(draw_data.flags & FLAGS_USE_LCD)) {
+ } else if (bool(draw_data.flags & INSTANCE_FLAGS_USE_LCD)) {
vec4 lcd_sample = texture(sampler2D(color_texture, texture_sampler), uv);
if (lcd_sample.a == 1.0) {
color.rgb = lcd_sample.rgb * color.a;
@@ -524,7 +524,7 @@ void main() {
color *= texture(sampler2D(color_texture, texture_sampler), uv);
}
- uint light_count = bitfieldExtract(draw_data.flags, FLAGS_LIGHT_COUNT_SHIFT, 4); //max 15 lights
+ uint light_count = draw_data.flags & 15u; //max 15 lights
bool using_light = (light_count + canvas_data.directional_light_count) > 0;
vec3 normal;
@@ -535,17 +535,15 @@ void main() {
bool normal_used = false;
#endif
- if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
+ if (normal_used || (using_light && bool(params.batch_flags & BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
- if (bool(draw_data.flags & FLAGS_TRANSPOSE_RECT)) {
+
+#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
+ if (bool(draw_data.flags & INSTANCE_FLAGS_TRANSPOSE_RECT)) {
normal.xy = normal.yx;
}
- if (bool(draw_data.flags & FLAGS_FLIP_H)) {
- normal.x = -normal.x;
- }
- if (bool(draw_data.flags & FLAGS_FLIP_V)) {
- normal.y = -normal.y;
- }
+ normal.xy *= sign(draw_data.src_rect.zw);
+#endif
normal.z = sqrt(max(0.0, 1.0 - dot(normal.xy, normal.xy)));
normal_used = true;
} else {
@@ -561,7 +559,7 @@ void main() {
bool specular_shininess_used = false;
#endif
- if (specular_shininess_used || (using_light && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
+ if (specular_shininess_used || (using_light && normal_used && bool(params.batch_flags & BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
specular_shininess = texture(sampler2D(specular_texture, texture_sampler), uv);
specular_shininess *= unpackUnorm4x8(params.specular_shininess);
specular_shininess_used = true;
@@ -632,7 +630,7 @@ void main() {
}
#endif
- if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW) && bool(draw_data.flags & (INSTANCE_FLAGS_SHADOW_MASKED << i))) {
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0);
@@ -692,7 +690,7 @@ void main() {
}
#endif
- if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW) && bool(draw_data.flags & (INSTANCE_FLAGS_SHADOW_MASKED << i))) {
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec2 pos_norm = normalize(shadow_pos);
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index 84017a1fe1..2186b08e89 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -5,32 +5,19 @@
#define SDF_MAX_LENGTH 16384.0
-//1 means enabled, 2+ means trails in use
-#define FLAGS_INSTANCING_MASK 0x7F
-#define FLAGS_INSTANCING_HAS_COLORS_SHIFT 7
-#define FLAGS_INSTANCING_HAS_COLORS (1 << FLAGS_INSTANCING_HAS_COLORS_SHIFT)
-#define FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT 8
-#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT)
-
-#define FLAGS_CLIP_RECT_UV (1 << 9)
-#define FLAGS_TRANSPOSE_RECT (1 << 10)
-#define FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR (1 << 11)
-#define FLAGS_NINEPACH_DRAW_CENTER_SHIFT 12
-#define FLAGS_NINEPACH_DRAW_CENTER (1 << FLAGS_NINEPACH_DRAW_CENTER_SHIFT)
-
-#define FLAGS_NINEPATCH_H_MODE_SHIFT 16
-#define FLAGS_NINEPATCH_V_MODE_SHIFT 18
+#define INSTANCE_FLAGS_LIGHT_COUNT_SHIFT 0 // 4 bits.
-#define FLAGS_LIGHT_COUNT_SHIFT 20
+#define INSTANCE_FLAGS_CLIP_RECT_UV (1 << 4)
+#define INSTANCE_FLAGS_TRANSPOSE_RECT (1 << 5)
+#define INSTANCE_FLAGS_USE_MSDF (1 << 6)
+#define INSTANCE_FLAGS_USE_LCD (1 << 7)
-#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 24)
-#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 25)
+#define INSTANCE_FLAGS_NINEPATCH_DRAW_CENTER_SHIFT 8
+#define INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT 9
+#define INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT 11
-#define FLAGS_USE_MSDF (1 << 26)
-#define FLAGS_USE_LCD (1 << 27)
-
-#define FLAGS_FLIP_H (1 << 28)
-#define FLAGS_FLIP_V (1 << 29)
+#define INSTANCE_FLAGS_SHADOW_MASKED_SHIFT 13 // 16 bits.
+#define INSTANCE_FLAGS_SHADOW_MASKED (1 << INSTANCE_FLAGS_SHADOW_MASKED_SHIFT)
struct InstanceData {
vec2 world_x;
@@ -54,11 +41,21 @@ struct InstanceData {
uint lights[4];
};
+//1 means enabled, 2+ means trails in use
+#define BATCH_FLAGS_INSTANCING_MASK 0x7F
+#define BATCH_FLAGS_INSTANCING_HAS_COLORS_SHIFT 7
+#define BATCH_FLAGS_INSTANCING_HAS_COLORS (1 << BATCH_FLAGS_INSTANCING_HAS_COLORS_SHIFT)
+#define BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT 8
+#define BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT)
+
+#define BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 9)
+#define BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 10)
+
layout(push_constant, std430) uniform Params {
uint base_instance_index; // base index to instance data
uint sc_packed_0;
uint specular_shininess;
- uint pad;
+ uint batch_flags;
}
params;
@@ -94,6 +91,8 @@ bool sc_use_lighting() {
/* SET0: Globals */
+#define CANVAS_FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR (1 << 0)
+
// The values passed per draw primitives are cached within it
layout(set = 0, binding = 1, std140) uniform CanvasData {
@@ -111,7 +110,7 @@ layout(set = 0, binding = 1, std140) uniform CanvasData {
uint directional_light_count;
float tex_to_sdf;
- uint pad1;
+ uint flags;
uint pad2;
}
canvas_data;
diff --git a/tests/core/io/test_file_access.h b/tests/core/io/test_file_access.h
index a4d3fd1d70..00d33eaf30 100644
--- a/tests/core/io/test_file_access.h
+++ b/tests/core/io/test_file_access.h
@@ -39,7 +39,7 @@ namespace TestFileAccess {
TEST_CASE("[FileAccess] CSV read") {
Ref<FileAccess> f = FileAccess::open(TestUtils::get_data_path("testdata.csv"), FileAccess::READ);
- REQUIRE(!f.is_null());
+ REQUIRE(f.is_valid());
Vector<String> header = f->get_csv_line(); // Default delimiter: ",".
REQUIRE(header.size() == 4);
@@ -107,6 +107,98 @@ TEST_CASE("[FileAccess] Get as UTF-8 String") {
CHECK(s_cr == "Hello darkness\rMy old friend\rI've come to talk\rWith you again\r");
CHECK(s_cr_nocr == "Hello darknessMy old friendI've come to talkWith you again");
}
+
+TEST_CASE("[FileAccess] Get/Store floating point values") {
+ // BigEndian Hex: 0x40490E56
+ // LittleEndian Hex: 0x560E4940
+ float value = 3.1415f;
+
+ SUBCASE("Little Endian") {
+ const String file_path = TestUtils::get_data_path("floating_point_little_endian.bin");
+ const String file_path_new = TestUtils::get_data_path("floating_point_little_endian_new.bin");
+
+ Ref<FileAccess> f = FileAccess::open(file_path, FileAccess::READ);
+ REQUIRE(f.is_valid());
+ CHECK_EQ(f->get_float(), value);
+
+ Ref<FileAccess> fw = FileAccess::open(file_path_new, FileAccess::WRITE);
+ REQUIRE(fw.is_valid());
+ fw->store_float(value);
+ fw->close();
+
+ CHECK_EQ(FileAccess::get_sha256(file_path_new), FileAccess::get_sha256(file_path));
+
+ DirAccess::remove_file_or_error(file_path_new);
+ }
+
+ SUBCASE("Big Endian") {
+ const String file_path = TestUtils::get_data_path("floating_point_big_endian.bin");
+ const String file_path_new = TestUtils::get_data_path("floating_point_big_endian_new.bin");
+
+ Ref<FileAccess> f = FileAccess::open(file_path, FileAccess::READ);
+ REQUIRE(f.is_valid());
+ f->set_big_endian(true);
+ CHECK_EQ(f->get_float(), value);
+
+ Ref<FileAccess> fw = FileAccess::open(file_path_new, FileAccess::WRITE);
+ REQUIRE(fw.is_valid());
+ fw->set_big_endian(true);
+ fw->store_float(value);
+ fw->close();
+
+ CHECK_EQ(FileAccess::get_sha256(file_path_new), FileAccess::get_sha256(file_path));
+
+ DirAccess::remove_file_or_error(file_path_new);
+ }
+}
+
+TEST_CASE("[FileAccess] Get/Store floating point half precision values") {
+ // IEEE 754 half-precision binary floating-point format:
+ // sign exponent (5 bits) fraction (10 bits)
+ // 0 01101 0101010101
+ // BigEndian Hex: 0x3555
+ // LittleEndian Hex: 0x5535
+ float value = 0.33325195f;
+
+ SUBCASE("Little Endian") {
+ const String file_path = TestUtils::get_data_path("half_precision_floating_point_little_endian.bin");
+ const String file_path_new = TestUtils::get_data_path("half_precision_floating_point_little_endian_new.bin");
+
+ Ref<FileAccess> f = FileAccess::open(file_path, FileAccess::READ);
+ REQUIRE(f.is_valid());
+ CHECK_EQ(f->get_half(), value);
+
+ Ref<FileAccess> fw = FileAccess::open(file_path_new, FileAccess::WRITE);
+ REQUIRE(fw.is_valid());
+ fw->store_half(value);
+ fw->close();
+
+ CHECK_EQ(FileAccess::get_sha256(file_path_new), FileAccess::get_sha256(file_path));
+
+ DirAccess::remove_file_or_error(file_path_new);
+ }
+
+ SUBCASE("Big Endian") {
+ const String file_path = TestUtils::get_data_path("half_precision_floating_point_big_endian.bin");
+ const String file_path_new = TestUtils::get_data_path("half_precision_floating_point_big_endian_new.bin");
+
+ Ref<FileAccess> f = FileAccess::open(file_path, FileAccess::READ);
+ REQUIRE(f.is_valid());
+ f->set_big_endian(true);
+ CHECK_EQ(f->get_half(), value);
+
+ Ref<FileAccess> fw = FileAccess::open(file_path_new, FileAccess::WRITE);
+ REQUIRE(fw.is_valid());
+ fw->set_big_endian(true);
+ fw->store_half(value);
+ fw->close();
+
+ CHECK_EQ(FileAccess::get_sha256(file_path_new), FileAccess::get_sha256(file_path));
+
+ DirAccess::remove_file_or_error(file_path_new);
+ }
+}
+
} // namespace TestFileAccess
#endif // TEST_FILE_ACCESS_H
diff --git a/tests/core/io/test_marshalls.h b/tests/core/io/test_marshalls.h
index 6716984681..eb92c3f752 100644
--- a/tests/core/io/test_marshalls.h
+++ b/tests/core/io/test_marshalls.h
@@ -90,6 +90,20 @@ TEST_CASE("[Marshalls] Unsigned 64 bit integer decoding") {
CHECK(decode_uint64(arr) == 0x0f123456789abcdef);
}
+TEST_CASE("[Marshalls] Floating point half precision encoding") {
+ uint8_t arr[2];
+
+ // Decimal: 0.33325195
+ // IEEE 754 half-precision binary floating-point format:
+ // sign exponent (5 bits) fraction (10 bits)
+ // 0 01101 0101010101
+ // Hexadecimal: 0x3555
+ unsigned int actual_size = encode_half(0.33325195f, arr);
+ CHECK(actual_size == sizeof(uint16_t));
+ CHECK(arr[0] == 0x55);
+ CHECK(arr[1] == 0x35);
+}
+
TEST_CASE("[Marshalls] Floating point single precision encoding") {
uint8_t arr[4];
@@ -126,6 +140,13 @@ TEST_CASE("[Marshalls] Floating point double precision encoding") {
CHECK(arr[7] == 0x3f);
}
+TEST_CASE("[Marshalls] Floating point half precision decoding") {
+ uint8_t arr[] = { 0x55, 0x35 };
+
+ // See floating point half precision encoding test case for details behind expected values.
+ CHECK(decode_half(arr) == 0.33325195f);
+}
+
TEST_CASE("[Marshalls] Floating point single precision decoding") {
uint8_t arr[] = { 0x00, 0x00, 0x20, 0x3e };
diff --git a/tests/core/io/test_stream_peer.h b/tests/core/io/test_stream_peer.h
index 31bd69edd0..961b4ac070 100644
--- a/tests/core/io/test_stream_peer.h
+++ b/tests/core/io/test_stream_peer.h
@@ -127,6 +127,17 @@ TEST_CASE("[StreamPeer] Get and sets through StreamPeerBuffer") {
CHECK_EQ(spb->get_u64(), value);
}
+ SUBCASE("A half-precision float value") {
+ float value = 3.1415927f;
+ float expected = 3.14062f;
+
+ spb->clear();
+ spb->put_half(value);
+ spb->seek(0);
+
+ CHECK(spb->get_half() == doctest::Approx(expected));
+ }
+
SUBCASE("A float value") {
float value = 42.0f;
@@ -255,6 +266,17 @@ TEST_CASE("[StreamPeer] Get and sets big endian through StreamPeerBuffer") {
CHECK_EQ(spb->get_float(), value);
}
+ SUBCASE("A half-precision float value") {
+ float value = 3.1415927f;
+ float expected = 3.14062f;
+
+ spb->clear();
+ spb->put_half(value);
+ spb->seek(0);
+
+ CHECK(spb->get_half() == doctest::Approx(expected));
+ }
+
SUBCASE("A double value") {
double value = 42.0;
diff --git a/tests/data/floating_point_big_endian.bin b/tests/data/floating_point_big_endian.bin
new file mode 100644
index 0000000000..9534605ce1
--- /dev/null
+++ b/tests/data/floating_point_big_endian.bin
@@ -0,0 +1 @@
+@IV \ No newline at end of file
diff --git a/tests/data/floating_point_little_endian.bin b/tests/data/floating_point_little_endian.bin
new file mode 100644
index 0000000000..8cd66219d8
--- /dev/null
+++ b/tests/data/floating_point_little_endian.bin
@@ -0,0 +1 @@
+VI@ \ No newline at end of file
diff --git a/tests/data/half_precision_floating_point_big_endian.bin b/tests/data/half_precision_floating_point_big_endian.bin
new file mode 100644
index 0000000000..6519f7500a
--- /dev/null
+++ b/tests/data/half_precision_floating_point_big_endian.bin
@@ -0,0 +1 @@
+5U \ No newline at end of file
diff --git a/tests/data/half_precision_floating_point_little_endian.bin b/tests/data/half_precision_floating_point_little_endian.bin
new file mode 100644
index 0000000000..4f748ab1e9
--- /dev/null
+++ b/tests/data/half_precision_floating_point_little_endian.bin
@@ -0,0 +1 @@
+U5 \ No newline at end of file