From f49c9d7cd1d33586fbd106057a894b3effc04331 Mon Sep 17 00:00:00 2001 From: Andrew Price Date: Sat, 31 Aug 2024 18:35:15 +0100 Subject: [PATCH 01/59] unix: Don't create world-writable files when safe save is enabled When the "filesystem/on_save/safe_save_on_backup_then_rename" option is enabled files are created with 0666 permissions (-rw-rw-rw-) which is too loose. Use 0644 (-rw-r--r--) instead which is how the files would normally be created with the setting disabled and the system umask taken into account. --- drivers/unix/file_access_unix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 32f2d7dd79a..5c6c04e0beb 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -97,7 +97,7 @@ Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) { last_error = ERR_FILE_CANT_OPEN; return last_error; } - fchmod(fd, 0666); + fchmod(fd, 0644); path = String::utf8(cs.ptr()); f = fdopen(fd, mode_string); From 64077ff3de40d12eec83501cb06280a0e02027fc Mon Sep 17 00:00:00 2001 From: Andrew Price Date: Fri, 6 Sep 2024 19:32:35 +0100 Subject: [PATCH 02/59] unix: Limit named pipe permissions to the current user Named pipes created using the "pipe://" file access scheme should not be world-writable or readable. Limit their access to the current user by creating them with 0600 permissions instead of 0666. --- drivers/unix/file_access_unix_pipe.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/unix/file_access_unix_pipe.cpp b/drivers/unix/file_access_unix_pipe.cpp index 34758e8c7d9..bdf02f53792 100644 --- a/drivers/unix/file_access_unix_pipe.cpp +++ b/drivers/unix/file_access_unix_pipe.cpp @@ -65,7 +65,7 @@ Error FileAccessUnixPipe::open_internal(const String &p_path, int p_mode_flags) struct stat st = {}; int err = stat(path.utf8().get_data(), &st); if (err) { - if (mkfifo(path.utf8().get_data(), 0666) != 0) { + if (mkfifo(path.utf8().get_data(), 0600) != 0) { last_error = ERR_FILE_CANT_OPEN; return last_error; } From edde380e9cb1545d77e99bba99aaf55f55e7dc86 Mon Sep 17 00:00:00 2001 From: "Yevhen Babiichuk (DustDFG)" Date: Tue, 1 Oct 2024 20:03:21 +0300 Subject: [PATCH 03/59] Editor: forbid deleting inherited metadata properties Signed-off-by: Yevhen Babiichuk (DustDFG) Co-authored-by: Tomek --- editor/editor_inspector.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 21f67772ea2..e6553cc92b0 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -3401,6 +3401,14 @@ void EditorInspector::update_tree() { editors.append_array(late_editors); + const Node *node = Object::cast_to(object); + + Vector sstack; + if (node != nullptr) { + const Node *es = EditorNode::get_singleton()->get_edited_scene(); + sstack = PropertyUtils::get_node_states_stack(node, es); + } + for (int i = 0; i < editors.size(); i++) { EditorProperty *ep = Object::cast_to(editors[i].property_editor); const Vector &properties = editors[i].properties; @@ -3453,7 +3461,15 @@ void EditorInspector::update_tree() { ep->set_checked(checked); ep->set_keying(keying); ep->set_read_only(property_read_only || all_read_only); - ep->set_deletable(deletable_properties || p.name.begins_with("metadata/")); + if (p.name.begins_with("metadata/")) { + Variant _default = Variant(); + if (node != nullptr) { + _default = PropertyUtils::get_property_default_value(node, p.name, nullptr, &sstack, false, nullptr, nullptr); + } + ep->set_deletable(_default == Variant()); + } else { + ep->set_deletable(deletable_properties); + } } current_vbox->add_child(editors[i].property_editor); From 2191df0cea66f895e3c51f624052c83dcc5d3f47 Mon Sep 17 00:00:00 2001 From: tetrapod00 <145553014+tetrapod00@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:50:30 -0700 Subject: [PATCH 04/59] VisualShader: Add LinearToSRGB and SRGBToLinear to ColorFunc node --- doc/classes/VisualShaderNodeColorFunc.xml | 27 ++++++++++++++++++- .../plugins/visual_shader_editor_plugin.cpp | 2 ++ scene/resources/visual_shader_nodes.cpp | 27 ++++++++++++++++++- scene/resources/visual_shader_nodes.h | 2 ++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/doc/classes/VisualShaderNodeColorFunc.xml b/doc/classes/VisualShaderNodeColorFunc.xml index edb52383258..aa2dcca1d58 100644 --- a/doc/classes/VisualShaderNodeColorFunc.xml +++ b/doc/classes/VisualShaderNodeColorFunc.xml @@ -40,7 +40,32 @@ return vec3(r, g, b); [/codeblock] - + + Converts color from linear color space to sRGB color space using the following formula: + [codeblock] + vec3 c = clamp(c, vec3(0.0), vec3(1.0)); + const vec3 a = vec3(0.055f); + return mix((vec3(1.0f) + a) * pow(c.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * c.rgb, lessThan(c.rgb, vec3(0.0031308f))); + [/codeblock] + The Compatibility renderer uses a simpler formula: + [codeblock] + vec3 c = input; + return max(vec3(1.055) * pow(c, vec3(0.416666667)) - vec3(0.055), vec3(0.0)); + [/codeblock] + + + Converts color from sRGB color space to linear color space using the following formula: + [codeblock] + vec3 c = input; + return mix(pow((c.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), c.rgb * (1.0 / 12.92), lessThan(c.rgb, vec3(0.04045))); + [/codeblock] + The Compatibility renderer uses a simpler formula: + [codeblock] + vec3 c = input; + return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878); + [/codeblock] + + Represents the size of the [enum Function] enum. diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index f98a30ebb3d..d3eb1fe880a 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -6775,8 +6775,10 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Grayscale", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Grayscale function."), { VisualShaderNodeColorFunc::FUNC_GRAYSCALE }, VisualShaderNode::PORT_TYPE_VECTOR_3D)); add_options.push_back(AddOption("HSV2RGB", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts HSV vector to RGB equivalent."), { VisualShaderNodeColorFunc::FUNC_HSV2RGB, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D)); + add_options.push_back(AddOption("LinearToSRGB", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts color from linear to sRGB color space."), { VisualShaderNodeColorFunc::FUNC_LINEAR_TO_SRGB }, VisualShaderNode::PORT_TYPE_VECTOR_3D)); add_options.push_back(AddOption("RGB2HSV", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts RGB vector to HSV equivalent."), { VisualShaderNodeColorFunc::FUNC_RGB2HSV, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D)); add_options.push_back(AddOption("Sepia", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Sepia function."), { VisualShaderNodeColorFunc::FUNC_SEPIA }, VisualShaderNode::PORT_TYPE_VECTOR_3D)); + add_options.push_back(AddOption("SRGBToLinear", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts color from sRGB to linear color space."), { VisualShaderNodeColorFunc::FUNC_SRGB_TO_LINEAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D)); add_options.push_back(AddOption("Burn", "Color/Operators", "VisualShaderNodeColorOp", TTR("Burn operator."), { VisualShaderNodeColorOp::OP_BURN }, VisualShaderNode::PORT_TYPE_VECTOR_3D)); add_options.push_back(AddOption("Darken", "Color/Operators", "VisualShaderNodeColorOp", TTR("Darken operator."), { VisualShaderNodeColorOp::OP_DARKEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D)); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 3db1ab93380..5350672a863 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -3243,6 +3243,29 @@ String VisualShaderNodeColorFunc::generate_code(Shader::Mode p_mode, VisualShade code += " " + p_output_vars[0] + " = vec3(r, g, b);\n"; code += " }\n"; break; + case FUNC_LINEAR_TO_SRGB: + code += " {\n"; + if (RenderingServer::get_singleton()->is_low_end()) { + code += " vec3 c = " + p_input_vars[0] + ";\n"; + code += " " + p_output_vars[0] + " = max(vec3(1.055) * pow(c, vec3(0.416666667)) - vec3(0.055), vec3(0.0));\n"; + } else { + code += " vec3 c = clamp(" + p_input_vars[0] + ", vec3(0.0), vec3(1.0));\n"; + code += " const vec3 a = vec3(0.055f);\n"; + code += " " + p_output_vars[0] + " = mix((vec3(1.0f) + a) * pow(c.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * c.rgb, lessThan(c.rgb, vec3(0.0031308f)));\n"; + } + code += " }\n"; + break; + case FUNC_SRGB_TO_LINEAR: + code += " {\n"; + if (RenderingServer::get_singleton()->is_low_end()) { + code += " vec3 c = " + p_input_vars[0] + ";\n"; + code += " " + p_output_vars[0] + " = c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);\n"; + } else { + code += " vec3 c = " + p_input_vars[0] + ";\n"; + code += " " + p_output_vars[0] + " = mix(pow((c.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), c.rgb * (1.0 / 12.92), lessThan(c.rgb, vec3(0.04045)));\n"; + } + code += " }\n"; + break; default: break; } @@ -3273,12 +3296,14 @@ void VisualShaderNodeColorFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeColorFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeColorFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,HSV2RGB,RGB2HSV,Sepia"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,HSV2RGB,RGB2HSV,Sepia,LinearToSRGB,SRGBToLinear"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_GRAYSCALE); BIND_ENUM_CONSTANT(FUNC_HSV2RGB); BIND_ENUM_CONSTANT(FUNC_RGB2HSV); BIND_ENUM_CONSTANT(FUNC_SEPIA); + BIND_ENUM_CONSTANT(FUNC_LINEAR_TO_SRGB); + BIND_ENUM_CONSTANT(FUNC_SRGB_TO_LINEAR); BIND_ENUM_CONSTANT(FUNC_MAX); } diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 67dc8f73537..36b9560ced4 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -1353,6 +1353,8 @@ class VisualShaderNodeColorFunc : public VisualShaderNode { FUNC_HSV2RGB, FUNC_RGB2HSV, FUNC_SEPIA, + FUNC_LINEAR_TO_SRGB, + FUNC_SRGB_TO_LINEAR, FUNC_MAX, }; From 05b266bd8950330935c51938e0ebe159d87316c8 Mon Sep 17 00:00:00 2001 From: Keegan McGonigle <31631874+thedinosoar@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:21:50 -0700 Subject: [PATCH 05/59] Fix PWA callback assignment and error handling --- misc/dist/html/editor.html | 34 +++++++++++++----------- misc/dist/html/full-size.html | 8 +++++- platform/web/js/engine/engine.js | 6 ++++- platform/web/js/libs/library_godot_os.js | 25 +++++++++++------ 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/misc/dist/html/editor.html b/misc/dist/html/editor.html index 3a22055546c..4f2a3bc0531 100644 --- a/misc/dist/html/editor.html +++ b/misc/dist/html/editor.html @@ -363,24 +363,28 @@

Important - Please read btn.style.display = ''; } if ('serviceWorker' in navigator) { - navigator.serviceWorker.register('service.worker.js').then(function (reg) { - if (reg.waiting) { - notifyUpdate(reg.waiting); - } - reg.addEventListener('updatefound', function () { - const update = reg.installing; - update.addEventListener('statechange', function () { - if (update.state === 'installed') { - // It's a new install, claim and perform aggressive caching. - if (!reg.active) { - update.postMessage('claim'); - } else { - notifyUpdate(update); + try { + navigator.serviceWorker.register('service.worker.js').then(function (reg) { + if (reg.waiting) { + notifyUpdate(reg.waiting); + } + reg.addEventListener('updatefound', function () { + const update = reg.installing; + update.addEventListener('statechange', function () { + if (update.state === 'installed') { + // It's a new install, claim and perform aggressive caching. + if (!reg.active) { + update.postMessage('claim'); + } else { + notifyUpdate(update); + } } - } + }); }); }); - }); + } catch (e) { + console.error('Error while registering service worker:', e); + } } const missing = Engine.getMissingFeatures({ diff --git a/misc/dist/html/full-size.html b/misc/dist/html/full-size.html index 352046df30b..4998863cb85 100644 --- a/misc/dist/html/full-size.html +++ b/misc/dist/html/full-size.html @@ -152,9 +152,15 @@ if (missing.length !== 0) { if (GODOT_CONFIG['serviceWorker'] && GODOT_CONFIG['ensureCrossOriginIsolationHeaders'] && 'serviceWorker' in navigator) { + let serviceWorkerRegistrationPromise; + try { + serviceWorkerRegistrationPromise = navigator.serviceWorker.getRegistration(); + } catch (err) { + serviceWorkerRegistrationPromise = Promise.reject(new Error('Service worker registration failed.')); + } // There's a chance that installing the service worker would fix the issue Promise.race([ - navigator.serviceWorker.getRegistration().then((registration) => { + serviceWorkerRegistrationPromise.then((registration) => { if (registration != null) { return Promise.reject(new Error('Service worker already exists.')); } diff --git a/platform/web/js/engine/engine.js b/platform/web/js/engine/engine.js index 04c4c44c5ee..1aeeb62f18d 100644 --- a/platform/web/js/engine/engine.js +++ b/platform/web/js/engine/engine.js @@ -241,7 +241,11 @@ const Engine = (function () { */ installServiceWorker: function () { if (this.config.serviceWorker && 'serviceWorker' in navigator) { - return navigator.serviceWorker.register(this.config.serviceWorker); + try { + return navigator.serviceWorker.register(this.config.serviceWorker); + } catch (e) { + return Promise.reject(e); + } } return Promise.resolve(); }, diff --git a/platform/web/js/libs/library_godot_os.js b/platform/web/js/libs/library_godot_os.js index 568212275ba..2899d7e45fc 100644 --- a/platform/web/js/libs/library_godot_os.js +++ b/platform/web/js/libs/library_godot_os.js @@ -441,8 +441,12 @@ const GodotPWA = { godot_js_pwa_cb__sig: 'vi', godot_js_pwa_cb: function (p_update_cb) { if ('serviceWorker' in navigator) { - const cb = GodotRuntime.get_func(p_update_cb); - navigator.serviceWorker.getRegistration().then(GodotPWA.updateState.bind(null, cb)); + try { + const cb = GodotRuntime.get_func(p_update_cb); + navigator.serviceWorker.getRegistration().then(GodotPWA.updateState.bind(null, cb)); + } catch (e) { + GodotRuntime.error('Failed to assign PWA callback', e); + } } }, @@ -450,12 +454,17 @@ const GodotPWA = { godot_js_pwa_update__sig: 'i', godot_js_pwa_update: function () { if ('serviceWorker' in navigator && GodotPWA.hasUpdate) { - navigator.serviceWorker.getRegistration().then(function (reg) { - if (!reg || !reg.waiting) { - return; - } - reg.waiting.postMessage('update'); - }); + try { + navigator.serviceWorker.getRegistration().then(function (reg) { + if (!reg || !reg.waiting) { + return; + } + reg.waiting.postMessage('update'); + }); + } catch (e) { + GodotRuntime.error(e); + return 1; + } return 0; } return 1; From 5f8df2ca63369fbb0c7b29aad03d44ad1b337c3c Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Fri, 8 Nov 2024 11:49:47 +0800 Subject: [PATCH 06/59] Remove unnecessary `_3D_DISABLED` checks in `Performance` --- main/performance.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/main/performance.cpp b/main/performance.cpp index c73fb62b760..398511995b0 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, From 761a20f7a720864af1c43747f5ac31b9915d04e3 Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Sun, 18 Aug 2024 04:00:43 +0900 Subject: [PATCH 07/59] Add hint for oneshot & warning when it will be updated continuously --- core/core_constants.cpp | 1 + core/object/object.h | 1 + doc/classes/@GlobalScope.xml | 5 ++++- scene/2d/audio_stream_player_2d.cpp | 2 +- scene/2d/cpu_particles_2d.cpp | 6 +++++- scene/2d/gpu_particles_2d.cpp | 5 ++++- scene/3d/audio_stream_player_3d.cpp | 2 +- scene/3d/cpu_particles_3d.cpp | 6 +++++- scene/3d/gpu_particles_3d.cpp | 6 +++++- scene/animation/animation_mixer.cpp | 9 +++++++++ scene/audio/audio_stream_player.cpp | 2 +- 11 files changed, 37 insertions(+), 8 deletions(-) diff --git a/core/core_constants.cpp b/core/core_constants.cpp index 25da49fa5c3..cdb4f2c800d 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -678,6 +678,7 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TOOL_BUTTON); + BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ONESHOT); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX); BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE); diff --git a/core/object/object.h b/core/object/object.h index 110d2790c58..678e0d0d49f 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -88,6 +88,7 @@ enum PropertyHint { PROPERTY_HINT_LAYERS_AVOIDANCE, PROPERTY_HINT_DICTIONARY_TYPE, PROPERTY_HINT_TOOL_BUTTON, + PROPERTY_HINT_ONESHOT, ///< the property will be changed by self after setting, such as AudioStreamPlayer.playing, Particles.emitting. PROPERTY_HINT_MAX, }; diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 55d00b6cf90..90036959ada 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2941,7 +2941,10 @@ [/codeblock] [b]Note:[/b] A [Callable] cannot be properly serialized and stored in a file, so it is recommended to use [constant PROPERTY_USAGE_EDITOR] instead of [constant PROPERTY_USAGE_DEFAULT]. - + + Hints that a property will be changed on its own after setting, such as [member AudioStreamPlayer.playing] or [member GPUParticles3D.emitting]. + + Represents the size of the [enum PropertyHint] enum. diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 7c60e47e641..8aaa230075e 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -410,7 +410,7 @@ void AudioStreamPlayer2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24,suffix:dB"), "set_volume_db", "get_volume_db"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_ONESHOT, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "1,4096,1,or_greater,exp,suffix:px"), "set_max_distance", "get_max_distance"); diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 754afb05274..5c1524b2117 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -506,6 +506,10 @@ bool CPUParticles2D::get_split_scale() { } void CPUParticles2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "emitting") { + p_property.hint = one_shot ? PROPERTY_HINT_ONESHOT : PROPERTY_HINT_NONE; + } + if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { p_property.usage = PROPERTY_USAGE_NONE; } @@ -1285,7 +1289,7 @@ void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("restart"), &CPUParticles2D::restart); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp,suffix:s"), "set_lifetime", "get_lifetime"); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index cfdcbee86a7..c71df49b616 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -384,6 +384,9 @@ Ref GPUParticles2D::get_texture() const { } void GPUParticles2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "emitting") { + p_property.hint = one_shot ? PROPERTY_HINT_ONESHOT : PROPERTY_HINT_NONE; + } } void GPUParticles2D::emit_particle(const Transform2D &p_transform2d, const Vector2 &p_velocity2d, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { @@ -816,7 +819,7 @@ void GPUParticles2D::_bind_methods() { ADD_SIGNAL(MethodInfo("finished")); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting"); ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false. ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amount_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001"), "set_amount_ratio", "get_amount_ratio"); diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 98bee2115c2..eb75650399d 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -834,7 +834,7 @@ void AudioStreamPlayer3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.01,or_greater"), "set_unit_size", "get_unit_size"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_db", PROPERTY_HINT_RANGE, "-24,6,suffix:dB"), "set_max_db", "get_max_db"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_ONESHOT, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,or_greater,suffix:m"), "set_max_distance", "get_max_distance"); diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index acbc443a93b..b8ad046db81 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -543,6 +543,10 @@ AABB CPUParticles3D::capture_aabb() const { } void CPUParticles3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "emitting") { + p_property.hint = one_shot ? PROPERTY_HINT_ONESHOT : PROPERTY_HINT_NONE; + } + if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { p_property.usage = PROPERTY_USAGE_NONE; } @@ -1480,7 +1484,7 @@ void CPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("restart"), &CPUParticles3D::restart); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp,suffix:s"), "set_lifetime", "get_lifetime"); diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index 2cef607d296..be927c28719 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -414,6 +414,10 @@ AABB GPUParticles3D::capture_aabb() const { } void GPUParticles3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "emitting") { + p_property.hint = one_shot ? PROPERTY_HINT_ONESHOT : PROPERTY_HINT_NONE; + } + if (p_property.name.begins_with("draw_pass_")) { int index = p_property.name.get_slicec('_', 2).to_int() - 1; if (index >= draw_passes.size()) { @@ -742,7 +746,7 @@ void GPUParticles3D::_bind_methods() { ADD_SIGNAL(MethodInfo("finished")); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting"); ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false. ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amount_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001"), "set_amount_ratio", "get_amount_ratio"); diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index eb8bc8c3824..f41affe581c 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -716,6 +716,15 @@ bool AnimationMixer::_update_caches() { } } + if (is_value && callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) { + if (child) { + PropertyInfo prop_info; + ClassDB::get_property_info(child->get_class_name(), path.get_concatenated_subnames(), &prop_info); + if (prop_info.hint == PROPERTY_HINT_ONESHOT) { + WARN_PRINT_ED(vformat("%s: '%s', Value Track: '%s' is oneshot property, but will be continuously updated. Consider setting a value other than ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS to AnimationMixer.callback_mode_dominant.", mixer_name, String(E), String(path))); + } + } + } } break; case Animation::TYPE_POSITION_3D: case Animation::TYPE_ROTATION_3D: diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index d4b44a8b69e..3996ec9b1e4 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -262,7 +262,7 @@ void AudioStreamPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24,suffix:dB"), "set_volume_db", "get_volume_db"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_ONESHOT, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_target", PROPERTY_HINT_ENUM, "Stereo,Surround,Center"), "set_mix_target", "get_mix_target"); From 09b6466e1414d75c9497a6af4c4eb37d4358a777 Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Mon, 11 Nov 2024 15:54:11 +0800 Subject: [PATCH 08/59] Translate the name of the debugger session tabs --- editor/debugger/editor_debugger_node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 0f948b4ed59..7bb42378a2d 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -120,7 +120,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() { tabs->add_child(node); - node->set_name("Session " + itos(tabs->get_tab_count())); + node->set_name(vformat(TTR("Session %d"), tabs->get_tab_count())); if (tabs->get_tab_count() > 1) { node->clear_style(); tabs->set_tabs_visible(true); From 9625fdc1d747c03c8e642f73c9fff02aa7e9bb09 Mon Sep 17 00:00:00 2001 From: yahkr <62478788+yahkr@users.noreply.github.com> Date: Mon, 11 Nov 2024 08:33:47 -0500 Subject: [PATCH 09/59] Fix float value used for MONITOR_TYPE_QUANTITY --- editor/debugger/editor_performance_profiler.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp index 1ea9a665347..31c09c9b377 100644 --- a/editor/debugger/editor_performance_profiler.cpp +++ b/editor/debugger/editor_performance_profiler.cpp @@ -81,6 +81,9 @@ void EditorPerformanceProfiler::Monitor::reset() { String EditorPerformanceProfiler::_create_label(float p_value, Performance::MonitorType p_type) { switch (p_type) { + case Performance::MONITOR_TYPE_QUANTITY: { + return TS->format_number(itos(p_value)); + } case Performance::MONITOR_TYPE_MEMORY: { return String::humanize_size(p_value); } From 1768a1b991093857d424d720945020129c01a9c3 Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Sun, 10 Nov 2024 21:11:52 -0800 Subject: [PATCH 10/59] Remove deprecated worker.js file --- platform/web/SCsub | 7 +++---- platform/web/emscripten_helpers.py | 7 +------ platform/web/export/export_plugin.cpp | 7 ------- platform/web/js/engine/config.js | 2 -- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/platform/web/SCsub b/platform/web/SCsub index b30bf20f26c..07088ac9856 100644 --- a/platform/web/SCsub +++ b/platform/web/SCsub @@ -59,7 +59,7 @@ for ext in sys_env["JS_EXTERNS"]: sys_env["ENV"]["EMCC_CLOSURE_ARGS"] += " --externs " + ext.abspath build = [] -build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm", "#bin/godot${PROGSUFFIX}.worker.js"] +build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"] if env["dlink_enabled"]: # Reset libraries. The main runtime will only link emscripten libraries, not godot ones. sys_env["LIBS"] = [] @@ -108,6 +108,5 @@ js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFI # 0 - unwrapped js file (use wrapped one instead) # 1 - wasm file -# 2 - worker file -# 3 - wasm side (when dlink is enabled). -env.CreateTemplateZip(js_wrapped, build[1], build[2], build[3] if len(build) > 3 else None) +# 2 - wasm side (when dlink is enabled). +env.CreateTemplateZip(js_wrapped, build[1], build[2] if len(build) > 2 else None) diff --git a/platform/web/emscripten_helpers.py b/platform/web/emscripten_helpers.py index 3122271a714..aca5d4ecba1 100644 --- a/platform/web/emscripten_helpers.py +++ b/platform/web/emscripten_helpers.py @@ -30,7 +30,7 @@ def create_engine_file(env, target, source, externs, threads_enabled): return env.Substfile(target=target, source=[env.File(s) for s in source], SUBST_DICT=subst_dict) -def create_template_zip(env, js, wasm, worker, side): +def create_template_zip(env, js, wasm, side): binary_name = "godot.editor" if env.editor_build else "godot" zip_dir = env.Dir(env.GetTemplateZipPath()) in_files = [ @@ -45,9 +45,6 @@ def create_template_zip(env, js, wasm, worker, side): zip_dir.File(binary_name + ".audio.worklet.js"), zip_dir.File(binary_name + ".audio.position.worklet.js"), ] - if env["threads"]: - in_files.append(worker) - out_files.append(zip_dir.File(binary_name + ".worker.js")) # Dynamic linking (extensions) specific. if env["dlink_enabled"]: in_files.append(side) # Side wasm (contains the actual Godot code). @@ -66,8 +63,6 @@ def create_template_zip(env, js, wasm, worker, side): "logo.svg", "favicon.png", ] - if env["threads"]: - cache.append("godot.editor.worker.js") opt_cache = ["godot.editor.wasm"] subst_dict = { "___GODOT_VERSION___": get_build_version(False), diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp index efe3c95496c..a32fa6dd3c9 100644 --- a/platform/web/export/export_plugin.cpp +++ b/platform/web/export/export_plugin.cpp @@ -214,9 +214,6 @@ Error EditorExportPlatformWeb::_add_manifest_icon(const String &p_path, const St } Error EditorExportPlatformWeb::_build_pwa(const Ref &p_preset, const String p_path, const Vector &p_shared_objects) { - List preset_features; - get_preset_features(p_preset, &preset_features); - String proj_name = GLOBAL_GET("application/config/name"); if (proj_name.is_empty()) { proj_name = "Godot Game"; @@ -243,9 +240,6 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref &p_prese cache_files.push_back(name + ".apple-touch-icon.png"); } - if (preset_features.find("threads")) { - cache_files.push_back(name + ".worker.js"); - } cache_files.push_back(name + ".audio.worklet.js"); cache_files.push_back(name + ".audio.position.worklet.js"); replaces["___GODOT_CACHE___"] = Variant(cache_files).to_json_string(); @@ -839,7 +833,6 @@ Error EditorExportPlatformWeb::_export_project(const Ref &p_ DirAccess::remove_file_or_error(basepath + ".html"); DirAccess::remove_file_or_error(basepath + ".offline.html"); DirAccess::remove_file_or_error(basepath + ".js"); - DirAccess::remove_file_or_error(basepath + ".worker.js"); DirAccess::remove_file_or_error(basepath + ".audio.worklet.js"); DirAccess::remove_file_or_error(basepath + ".audio.position.worklet.js"); DirAccess::remove_file_or_error(basepath + ".service.worker.js"); diff --git a/platform/web/js/engine/config.js b/platform/web/js/engine/config.js index 61b488cf81c..3947195fa10 100644 --- a/platform/web/js/engine/config.js +++ b/platform/web/js/engine/config.js @@ -295,8 +295,6 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- 'locateFile': function (path) { if (!path.startsWith('godot.')) { return path; - } else if (path.endsWith('.worker.js')) { - return `${loadPath}.worker.js`; } else if (path.endsWith('.audio.worklet.js')) { return `${loadPath}.audio.worklet.js`; } else if (path.endsWith('.audio.position.worklet.js')) { From eb86670f94ef505e9b4adc37bc0948a3a5588ed8 Mon Sep 17 00:00:00 2001 From: Pablo Andres Fuente Date: Tue, 1 Oct 2024 23:41:13 -0300 Subject: [PATCH 11/59] Add half precision floating point support to `StreamPeer` Closes godotengine/godot-proposals#5983 Adds put/get methods to `StreamPeer` that handles half precision floating point values. Adds endode/decode half precision floating point to `marshalls`. Adds `get_half` and `store_half` to `FileAccess` Co-Authored-By: "Alfonso J. Ramos" --- .pre-commit-config.yaml | 3 +- core/io/file_access.cpp | 10 ++ core/io/file_access.h | 2 + core/io/marshalls.h | 10 ++ core/io/stream_peer.cpp | 26 +++++ core/io/stream_peer.h | 2 + doc/classes/FileAccess.xml | 13 +++ doc/classes/StreamPeer.xml | 13 +++ tests/core/io/test_file_access.h | 94 ++++++++++++++++++- tests/core/io/test_marshalls.h | 21 +++++ tests/core/io/test_stream_peer.h | 22 +++++ tests/data/floating_point_big_endian.bin | 1 + tests/data/floating_point_little_endian.bin | 1 + ...lf_precision_floating_point_big_endian.bin | 1 + ...precision_floating_point_little_endian.bin | 1 + 15 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 tests/data/floating_point_big_endian.bin create mode 100644 tests/data/floating_point_little_endian.bin create mode 100644 tests/data/half_precision_floating_point_big_endian.bin create mode 100644 tests/data/half_precision_floating_point_little_endian.bin diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d81c1043a7c..a0eba862445 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 d8bf645a7de..01b189f5f27 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -263,6 +263,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(); @@ -522,6 +526,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; @@ -828,6 +836,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); @@ -846,6 +855,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 7f5687fe036..de23edf5b5c 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -142,6 +142,7 @@ class FileAccess : public RefCounted { 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; @@ -173,6 +174,7 @@ class FileAccess : public RefCounted { 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 6f015ac386e..82c760c28d2 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 3f1c468fb31..045904fb5d5 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 29cdb826151..44bbfbf1d52 100644 --- a/core/io/stream_peer.h +++ b/core/io/stream_peer.h @@ -73,6 +73,7 @@ class StreamPeer : public RefCounted { 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 @@ class StreamPeer : public RefCounted { 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/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml index b782937a8ab..a8fb648f7b0 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. + + + + Returns the next 16 bits from the file as a half-precision floating-point number. + + @@ -470,6 +476,13 @@ Stores a floating-point number as 32 bits in the file. + + + + + Stores a half-precision floating-point number as 16 bits in the file. + + diff --git a/doc/classes/StreamPeer.xml b/doc/classes/StreamPeer.xml index ad5c5472b89..acff5cf6049 100644 --- a/doc/classes/StreamPeer.xml +++ b/doc/classes/StreamPeer.xml @@ -59,6 +59,12 @@ Gets a single-precision float from the stream. + + + + Gets a half-precision float from the stream. + + @@ -162,6 +168,13 @@ Puts a single-precision float into the stream. + + + + + Puts a half-precision float into the stream. + + diff --git a/tests/core/io/test_file_access.h b/tests/core/io/test_file_access.h index a4d3fd1d704..00d33eaf306 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 f = FileAccess::open(TestUtils::get_data_path("testdata.csv"), FileAccess::READ); - REQUIRE(!f.is_null()); + REQUIRE(f.is_valid()); Vector 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 f = FileAccess::open(file_path, FileAccess::READ); + REQUIRE(f.is_valid()); + CHECK_EQ(f->get_float(), value); + + Ref 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 f = FileAccess::open(file_path, FileAccess::READ); + REQUIRE(f.is_valid()); + f->set_big_endian(true); + CHECK_EQ(f->get_float(), value); + + Ref 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 f = FileAccess::open(file_path, FileAccess::READ); + REQUIRE(f.is_valid()); + CHECK_EQ(f->get_half(), value); + + Ref 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 f = FileAccess::open(file_path, FileAccess::READ); + REQUIRE(f.is_valid()); + f->set_big_endian(true); + CHECK_EQ(f->get_half(), value); + + Ref 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 de8d6e14067..29e713c3a97 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 31bd69edd0a..961b4ac0709 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 00000000000..9534605ce18 --- /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 00000000000..8cd66219d8f --- /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 00000000000..6519f7500ae --- /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 00000000000..4f748ab1e92 --- /dev/null +++ b/tests/data/half_precision_floating_point_little_endian.bin @@ -0,0 +1 @@ +U5 \ No newline at end of file From b31cc6960d20b758b2ad6d3a3d497a9d7964823e Mon Sep 17 00:00:00 2001 From: Thaddeus Crews Date: Sat, 16 Nov 2024 13:16:48 -0600 Subject: [PATCH 12/59] =?UTF-8?q?CI:=20Bump=20SCons=20to=20latest=20(4.8.0?= =?UTF-8?q?=20=E2=86=92=204.8.1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/godot-deps/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/godot-deps/action.yml b/.github/actions/godot-deps/action.yml index bd9a1f55ed3..3344323fd48 100644 --- a/.github/actions/godot-deps/action.yml +++ b/.github/actions/godot-deps/action.yml @@ -10,7 +10,7 @@ inputs: default: x64 scons-version: description: The SCons version to use. - default: 4.8.0 + default: 4.8.1 runs: using: composite From b4f8135d4692e8fd85e38f37e42bf4de2dca9391 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Mon, 11 Nov 2024 11:30:41 +0100 Subject: [PATCH 13/59] [Web] Fix Web Editor plugin being added to SCons multiple times Move the Web Editor plugin files to an editor sub-folder inside the platform folder. --- platform/web/SCsub | 4 +++- platform/web/api/api.cpp | 2 -- platform/web/{api => editor}/web_tools_editor_plugin.cpp | 4 ---- platform/web/{api => editor}/web_tools_editor_plugin.h | 4 ---- platform/web/web_main.cpp | 8 ++++++++ 5 files changed, 11 insertions(+), 11 deletions(-) rename platform/web/{api => editor}/web_tools_editor_plugin.cpp (98%) rename platform/web/{api => editor}/web_tools_editor_plugin.h (96%) diff --git a/platform/web/SCsub b/platform/web/SCsub index b30bf20f26c..a85fbcd0f57 100644 --- a/platform/web/SCsub +++ b/platform/web/SCsub @@ -27,9 +27,11 @@ web_files = [ "javascript_bridge_singleton.cpp", "web_main.cpp", "os_web.cpp", - "api/web_tools_editor_plugin.cpp", ] +if env["target"] == "editor": + env.add_source_files(web_files, "editor/*.cpp") + sys_env = env.Clone() sys_env.AddJSLibraries( [ diff --git a/platform/web/api/api.cpp b/platform/web/api/api.cpp index 40417bde7e7..f9c1f0fd91c 100644 --- a/platform/web/api/api.cpp +++ b/platform/web/api/api.cpp @@ -31,14 +31,12 @@ #include "api.h" #include "javascript_bridge_singleton.h" -#include "web_tools_editor_plugin.h" #include "core/config/engine.h" static JavaScriptBridge *javascript_bridge_singleton; void register_web_api() { - WebToolsEditorPlugin::initialize(); GDREGISTER_ABSTRACT_CLASS(JavaScriptObject); GDREGISTER_ABSTRACT_CLASS(JavaScriptBridge); javascript_bridge_singleton = memnew(JavaScriptBridge); diff --git a/platform/web/api/web_tools_editor_plugin.cpp b/platform/web/editor/web_tools_editor_plugin.cpp similarity index 98% rename from platform/web/api/web_tools_editor_plugin.cpp rename to platform/web/editor/web_tools_editor_plugin.cpp index 61801372ba1..a98d45a49a6 100644 --- a/platform/web/api/web_tools_editor_plugin.cpp +++ b/platform/web/editor/web_tools_editor_plugin.cpp @@ -30,8 +30,6 @@ #include "web_tools_editor_plugin.h" -#if defined(TOOLS_ENABLED) && defined(WEB_ENABLED) - #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/io/dir_access.h" @@ -155,5 +153,3 @@ void WebToolsEditorPlugin::_zip_recursive(String p_path, String p_base_path, zip cur = dir->get_next(); } } - -#endif // TOOLS_ENABLED && WEB_ENABLED diff --git a/platform/web/api/web_tools_editor_plugin.h b/platform/web/editor/web_tools_editor_plugin.h similarity index 96% rename from platform/web/api/web_tools_editor_plugin.h rename to platform/web/editor/web_tools_editor_plugin.h index 2902f60f242..70b47ab49cb 100644 --- a/platform/web/api/web_tools_editor_plugin.h +++ b/platform/web/editor/web_tools_editor_plugin.h @@ -31,8 +31,6 @@ #ifndef WEB_TOOLS_EDITOR_PLUGIN_H #define WEB_TOOLS_EDITOR_PLUGIN_H -#if defined(TOOLS_ENABLED) && defined(WEB_ENABLED) - #include "core/io/zip_io.h" #include "editor/plugins/editor_plugin.h" @@ -57,6 +55,4 @@ class WebToolsEditorPlugin { static void initialize() {} }; -#endif // TOOLS_ENABLED && WEB_ENABLED - #endif // WEB_TOOLS_EDITOR_PLUGIN_H diff --git a/platform/web/web_main.cpp b/platform/web/web_main.cpp index d0c3bd7c0e1..3487ed2ded6 100644 --- a/platform/web/web_main.cpp +++ b/platform/web/web_main.cpp @@ -38,6 +38,10 @@ #include "scene/main/scene_tree.h" #include "scene/main/window.h" // SceneTree only forward declares it. +#ifdef TOOLS_ENABLED +#include "editor/web_tools_editor_plugin.h" +#endif + #include #include @@ -104,6 +108,10 @@ void main_loop_callback() { extern EMSCRIPTEN_KEEPALIVE int godot_web_main(int argc, char *argv[]) { os = new OS_Web(); +#ifdef TOOLS_ENABLED + WebToolsEditorPlugin::initialize(); +#endif + // We must override main when testing is enabled TEST_MAIN_OVERRIDE From edd6acdfd4f00bd9476054b534df74c003d010de Mon Sep 17 00:00:00 2001 From: passivestar <60579014+passivestar@users.noreply.github.com> Date: Tue, 19 Nov 2024 01:14:09 +0400 Subject: [PATCH 14/59] Expose state machine focus color to theming --- editor/plugins/animation_state_machine_editor.cpp | 3 ++- editor/plugins/animation_state_machine_editor.h | 1 + editor/themes/editor_theme_manager.cpp | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index d10daa2bfcc..8526150e0c0 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -917,7 +917,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { } if (state_machine_draw->has_focus()) { - state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), theme_cache.highlight_color, false); + state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), theme_cache.focus_color, false); } int sep = 3 * EDSCALE; @@ -1642,6 +1642,7 @@ void AnimationNodeStateMachineEditor::_bind_methods() { BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, transition_icon_disabled_color, "transition_icon_disabled_color", "GraphStateMachine"); BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, highlight_color, "highlight_color", "GraphStateMachine"); BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, highlight_disabled_color, "highlight_disabled_color", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, focus_color, "focus_color", "GraphStateMachine"); BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, guideline_color, "guideline_color", "GraphStateMachine"); BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[0], "TransitionImmediateBig", "EditorIcons"); diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index eb623a147d6..0b6320f0ce5 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -117,6 +117,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { Color transition_icon_disabled_color; Color highlight_color; Color highlight_disabled_color; + Color focus_color; Color guideline_color; Ref transition_icons[6]{}; diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp index 32079f3753f..a4251bfd290 100644 --- a/editor/themes/editor_theme_manager.cpp +++ b/editor/themes/editor_theme_manager.cpp @@ -2506,6 +2506,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref &p_theme p_theme->set_color("transition_icon_disabled_color", "GraphStateMachine", Color(1, 1, 1, 0.2)); p_theme->set_color("highlight_color", "GraphStateMachine", p_config.accent_color); p_theme->set_color("highlight_disabled_color", "GraphStateMachine", p_config.accent_color * Color(1, 1, 1, 0.6)); + p_theme->set_color("focus_color", "GraphStateMachine", p_config.accent_color); p_theme->set_color("guideline_color", "GraphStateMachine", p_config.font_color * Color(1, 1, 1, 0.3)); p_theme->set_color("playback_color", "GraphStateMachine", p_config.font_color); From 755bcf47373bae9bd717b56a1d60765e7f3144bc Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Mon, 18 Nov 2024 22:16:59 +0900 Subject: [PATCH 15/59] Add root_motion_local option to AnimationMixer --- doc/classes/AnimationMixer.xml | 44 ++++++--- scene/animation/animation_mixer.cpp | 131 +++++++++++++++++++++------ scene/animation/animation_mixer.h | 4 + scene/animation/root_motion_view.cpp | 5 +- 4 files changed, 137 insertions(+), 47 deletions(-) diff --git a/doc/classes/AnimationMixer.xml b/doc/classes/AnimationMixer.xml index d762ffa5a65..36cb675776a 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. + + 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. + 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/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index b40c677f6e8..37242778967 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -127,6 +127,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; + } } /* -------------------------------------------- */ @@ -1200,6 +1203,10 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { } TrackCacheTransform *t = static_cast(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)) { @@ -1234,41 +1241,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; @@ -1343,6 +1401,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; } @@ -1418,8 +1477,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 { @@ -1990,12 +2049,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; } @@ -2341,6 +2409,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); @@ -2368,6 +2438,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 3769fa268c0..a1f1a754dc3 100644 --- a/scene/animation/animation_mixer.h +++ b/scene/animation/animation_mixer.h @@ -334,6 +334,7 @@ class AnimationMixer : public Node { /* ---- 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); @@ -446,6 +447,9 @@ class AnimationMixer : public Node { 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 fd520dadd66..2c0222b3b8a 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(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; } From 4988fa1ece653938e07ee3bbc89a9bafea5ef7ea Mon Sep 17 00:00:00 2001 From: Adam Scott Date: Mon, 18 Nov 2024 22:27:17 -0500 Subject: [PATCH 16/59] Force `get_thread_count()` to `1` if single threaded --- core/object/worker_thread_pool.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/object/worker_thread_pool.h b/core/object/worker_thread_pool.h index 62296ac0405..58e86e3e48e 100644 --- a/core/object/worker_thread_pool.h +++ b/core/object/worker_thread_pool.h @@ -258,7 +258,13 @@ class WorkerThreadPool : public Object { 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(); From a64b3fd3f81b785ea9b3c2d96e66f124122bad5e Mon Sep 17 00:00:00 2001 From: Chaosus Date: Wed, 31 Jul 2024 18:33:16 +0300 Subject: [PATCH 17/59] Allow `SCREEN_UV` to be used in light function of spatial shader --- drivers/gles3/shaders/scene.glsl | 22 +++++++++---------- .../plugins/visual_shader_editor_plugin.cpp | 3 ++- scene/resources/visual_shader.cpp | 1 + .../scene_forward_clustered.glsl | 6 ++--- .../forward_mobile/scene_forward_mobile.glsl | 6 ++--- .../shaders/scene_forward_lights_inc.glsl | 10 ++++----- servers/rendering/shader_types.cpp | 1 + 7 files changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index fcfbeddb9e4..2022c8ee436 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1259,7 +1259,7 @@ float SchlickFresnel(float u) { return m2 * m2 * m; // pow(m,5) } -void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_directional, float attenuation, vec3 f0, float roughness, float metallic, float specular_amount, vec3 albedo, inout float alpha, +void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_directional, float attenuation, vec3 f0, float roughness, float metallic, float specular_amount, vec3 albedo, inout float alpha, vec2 screen_uv, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -1423,7 +1423,7 @@ float get_omni_spot_attenuation(float distance, float inv_range, float decay) { } #if !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI) -void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha, +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -1450,7 +1450,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f omni_attenuation *= shadow; - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1469,7 +1469,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f #endif // !DISABLE_LIGHT_OMNI #if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT) -void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha, +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -1506,7 +1506,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f spot_attenuation *= shadow; - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -2114,7 +2114,7 @@ void main() { continue; } #endif - light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, true, 1.0, f0, roughness, metallic, 1.0, albedo, alpha, + light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, true, 1.0, f0, roughness, metallic, 1.0, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -2143,7 +2143,7 @@ void main() { continue; } #endif - light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha, + light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -2171,7 +2171,7 @@ void main() { continue; } #endif - light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha, + light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -2389,7 +2389,7 @@ void main() { #endif // SHADOWS_DISABLED #ifndef USE_VERTEX_LIGHTING - light_compute(normal, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].size, directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, directional_shadow, f0, roughness, metallic, 1.0, albedo, alpha, + light_compute(normal, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].size, directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, directional_shadow, f0, roughness, metallic, 1.0, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -2421,7 +2421,7 @@ void main() { #endif // SHADOWS_DISABLED #ifndef USE_VERTEX_LIGHTING - light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha, + light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -2451,7 +2451,7 @@ void main() { #endif // SHADOWS_DISABLED #ifndef USE_VERTEX_LIGHTING - light_process_spot(spot_light_index, vertex, view, normal, f0, roughness, metallic, spot_shadow, albedo, alpha, + light_process_spot(spot_light_index, vertex, view, normal, f0, roughness, metallic, spot_shadow, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 82495960451..987002f472d 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -7026,7 +7026,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("NodePositionView", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("NodePositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("PointCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Tangent", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent", "TANGENT"), { "tangent" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Vertex", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("View", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view", "VIEW"), { "view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); @@ -7044,6 +7044,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("LightIsDirectional", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_is_directional", "LIGHT_IS_DIRECTIONAL"), { "light_is_directional" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Metallic", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "metallic", "METALLIC"), { "metallic" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Roughness", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness", "ROUGHNESS"), { "roughness" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("ScreenUV", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Specular", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular", "SPECULAR_LIGHT"), { "specular" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("View", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view", "VIEW"), { "view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 847867fa4d8..7c1adeac963 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -3167,6 +3167,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection_matrix", "PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular", "SPECULAR_LIGHT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 81d3d87a22b..1e1b6d89371 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -2299,7 +2299,7 @@ void fragment_shader(in SceneData scene_data) { #else directional_lights.data[i].color * directional_lights.data[i].energy * tint, #endif - true, shadow, f0, orms, 1.0, albedo, alpha, + true, shadow, f0, orms, 1.0, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -2373,7 +2373,7 @@ void fragment_shader(in SceneData scene_data) { shadow = blur_shadow(shadow); - light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -2445,7 +2445,7 @@ void fragment_shader(in SceneData scene_data) { shadow = blur_shadow(shadow); - light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index da8ad3db15a..0cb34557ea8 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -1591,7 +1591,7 @@ void main() { light_compute(normal, directional_lights.data[i].direction, view, size_A, directional_lights.data[i].color * directional_lights.data[i].energy * tint, - true, shadow, f0, orms, 1.0, albedo, alpha, + true, shadow, f0, orms, 1.0, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1628,7 +1628,7 @@ void main() { shadow = blur_shadow(shadow); // Fragment lighting - light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1661,7 +1661,7 @@ void main() { shadow = blur_shadow(shadow); - light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index a1a185d0fdf..1e8fc7eab48 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -39,7 +39,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) { return mix(vec3(dielectric), albedo, vec3(metallic)); } -void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_directional, float attenuation, vec3 f0, uint orms, float specular_amount, vec3 albedo, inout float alpha, +void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_directional, float attenuation, vec3 f0, uint orms, float specular_amount, vec3 albedo, inout float alpha, vec2 screen_uv, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -547,7 +547,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr return 1.0; } -void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -675,7 +675,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v light_attenuation *= shadow; - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, albedo, alpha, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -793,7 +793,7 @@ vec2 normal_to_panorama(vec3 n) { return panorama_coords; } -void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -884,7 +884,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v } light_attenuation *= shadow; - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, albedo, alpha, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index 821009f07cb..4b71007ebfd 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -201,6 +201,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SPATIAL].functions["light"].can_discard = true; shader_modes[RS::SHADER_SPATIAL].functions["light"].main_function = true; From 61cf0253ce4204d2911cd91d15ec9a2c78c78c7d Mon Sep 17 00:00:00 2001 From: Giganzo <158825920+Giganzo@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:25:28 +0100 Subject: [PATCH 18/59] Fix toast spam about child of container position --- editor/plugins/canvas_item_editor_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index f91a052a247..e17a12dbb2d 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); } } From 5de38f7fd35606e1f494d81919f094e5e7baf0c0 Mon Sep 17 00:00:00 2001 From: Illauriel Date: Sun, 24 Dec 2023 03:57:36 +0100 Subject: [PATCH 19/59] Add persistent folding to Animation Library Editor --- editor/plugins/animation_library_editor.cpp | 203 +++++++++++++++++++- editor/plugins/animation_library_editor.h | 7 + scene/animation/animation_mixer.cpp | 12 ++ scene/animation/animation_mixer.h | 1 + 4 files changed, 222 insertions(+), 1 deletion(-) diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index 4e8a1bd89b6..46410b581e8 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -30,7 +30,12 @@ #include "animation_library_editor.h" +#include "core/string/print_string.h" +#include "core/string/ustring.h" +#include "core/templates/vector.h" +#include "core/variant/variant.h" #include "editor/editor_node.h" +#include "editor/editor_paths.h" #include "editor/editor_settings.h" #include "editor/editor_string_names.h" #include "editor/editor_undo_redo_manager.h" @@ -518,6 +523,8 @@ void AnimationLibraryEditor::_item_renamed() { if (restore_text) { ti->set_text(0, old_text); } + + _save_mixer_lib_folding(ti); } void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button) { @@ -670,6 +677,8 @@ void AnimationLibraryEditor::update_tree() { TreeItem *root = tree->create_item(); List libs; + Vector collapsed_lib_ids = _load_mixer_libs_folding(); + mixer->get_animation_library_list(&libs); for (const StringName &K : libs) { @@ -759,12 +768,203 @@ void AnimationLibraryEditor::update_tree() { anitem->set_text(1, anim_path.get_file()); } } + anitem->add_button(1, get_editor_theme_icon("Save"), ANIM_BUTTON_FILE, animation_library_is_foreign, TTR("Save animation to resource on disk.")); anitem->add_button(1, get_editor_theme_icon("Remove"), ANIM_BUTTON_DELETE, animation_library_is_foreign, TTR("Remove animation from Library.")); + + for (const uint64_t &lib_id : collapsed_lib_ids) { + Object *lib_obj = ObjectDB::get_instance(ObjectID(lib_id)); + AnimationLibrary *cur_lib = Object::cast_to(lib_obj); + StringName M = mixer->get_animation_library_name(cur_lib); + + if (M == K) { + libitem->set_collapsed_recursive(true); + } + } } } } +void AnimationLibraryEditor::_save_mixer_lib_folding(TreeItem *p_item) { + //Check if ti is a library or animation + if (p_item->get_parent()->get_parent() != nullptr) { + return; + } + + Ref config; + config.instantiate(); + + String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("lib_folding.cfg"); + Error err = config->load(path); + if (err != OK && err != ERR_FILE_NOT_FOUND) { + ERR_PRINT("Error loading lib_folding.cfg: " + itos(err)); + } + + // Get unique identifier for this scene+mixer combination + String md = (mixer->get_tree()->get_edited_scene_root()->get_scene_file_path() + mixer->get_path()).md5_text(); + + PackedStringArray collapsed_lib_names; + PackedStringArray collapsed_lib_ids; + + if (config->has_section(md)) { + collapsed_lib_names = String(config->get_value(md, "folding")).split("\n"); + collapsed_lib_ids = String(config->get_value(md, "id")).split("\n"); + } + + String lib_name = p_item->get_text(0); + + // Get library reference and check validity + Ref al; + uint64_t lib_id = 0; + + if (mixer->has_animation_library(lib_name)) { + al = mixer->get_animation_library(lib_name); + ERR_FAIL_COND(al.is_null()); + lib_id = uint64_t(al->get_instance_id()); + } else { + ERR_PRINT("Library not found: " + lib_name); + } + + int at = collapsed_lib_names.find(lib_name); + if (p_item->is_collapsed()) { + if (at != -1) { + //Entry exists and needs updating + collapsed_lib_ids.set(at, String::num_int64(lib_id + INT64_MIN)); + } else { + //Check if it's a rename + int id_at = collapsed_lib_ids.find(String::num_int64(lib_id + INT64_MIN)); + if (id_at != -1) { + //It's actually a rename + collapsed_lib_names.set(id_at, lib_name); + } else { + //It's a new entry + collapsed_lib_names.append(lib_name); + collapsed_lib_ids.append(String::num_int64(lib_id + INT64_MIN)); + } + } + } else { + if (at != -1) { + collapsed_lib_names.remove_at(at); + collapsed_lib_ids.remove_at(at); + } + } + + //Runtime IDs + config->set_value(md, "root", uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id())); + config->set_value(md, "mixer", uint64_t(mixer->get_instance_id())); + + //Plan B recovery mechanism + config->set_value(md, "mixer_signature", _get_mixer_signature()); + + //Save folding state as text and runtime ID + config->set_value(md, "folding", String("\n").join(collapsed_lib_names)); + config->set_value(md, "id", String("\n").join(collapsed_lib_ids)); + + err = config->save(path); + if (err != OK) { + ERR_PRINT("Error saving lib_folding.cfg: " + itos(err)); + } +} + +Vector AnimationLibraryEditor::_load_mixer_libs_folding() { + Ref config; + config.instantiate(); + + String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("lib_folding.cfg"); + Error err = config->load(path); + if (err != OK && err != ERR_FILE_NOT_FOUND) { + ERR_PRINT("Error loading lib_folding.cfg: " + itos(err)); + return Vector(); + } + + // Get unique identifier for this scene+mixer combination + String md = (mixer->get_tree()->get_edited_scene_root()->get_scene_file_path() + mixer->get_path()).md5_text(); + + Vector collapsed_lib_ids; + + if (config->has_section(md)) { + _load_config_libs_folding(collapsed_lib_ids, config.ptr(), md); + + } else { + //The scene/mixer combination is no longer valid and we'll try to recover + uint64_t current_mixer_id = uint64_t(mixer->get_instance_id()); + String current_mixer_signature = _get_mixer_signature(); + List sections; + config->get_sections(§ions); + + for (const String §ion : sections) { + Variant mixer_id = config->get_value(section, "mixer"); + if ((mixer_id.get_type() == Variant::INT && uint64_t(mixer_id) == current_mixer_id) || config->get_value(section, "mixer_signature") == current_mixer_signature) { // Ensure value exists and is correct type + // Found the mixer in a different section! + _load_config_libs_folding(collapsed_lib_ids, config.ptr(), section); + + //Cleanup old entry and copy fold data into new one! + String collapsed_lib_names_str = String(config->get_value(section, "folding")); + String collapsed_lib_ids_str = String(config->get_value(section, "id")); + config->erase_section(section); + + config->set_value(md, "root", uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id())); + config->set_value(md, "mixer", uint64_t(mixer->get_instance_id())); + config->set_value(md, "mixer_signature", _get_mixer_signature()); + config->set_value(md, "folding", collapsed_lib_names_str); + config->set_value(md, "id", collapsed_lib_ids_str); + + err = config->save(path); + if (err != OK) { + ERR_PRINT("Error saving lib_folding.cfg: " + itos(err)); + } + break; + } + } + } + + return collapsed_lib_ids; +} + +void AnimationLibraryEditor::_load_config_libs_folding(Vector &p_lib_ids, ConfigFile *p_config, String p_section) { + if (uint64_t(p_config->get_value(p_section, "root", 0)) != uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id())) { + // Root changed - tries to match by library names + PackedStringArray collapsed_lib_names = String(p_config->get_value(p_section, "folding", "")).split("\n"); + for (const String &lib_name : collapsed_lib_names) { + if (mixer->has_animation_library(lib_name)) { + p_lib_ids.append(mixer->get_animation_library(lib_name)->get_instance_id()); + } else { + print_line("Can't find ", lib_name, " in mixer"); + } + } + } else { + // Root same - uses saved instance IDs + for (const String &saved_id : String(p_config->get_value(p_section, "id")).split("\n")) { + p_lib_ids.append(uint64_t(saved_id.to_int() - INT64_MIN)); + } + } +} + +String AnimationLibraryEditor::_get_mixer_signature() const { + String signature = String(); + + // Get all libraries sorted for consistency + List libs; + mixer->get_animation_library_list(&libs); + libs.sort_custom(); + + // Add libraries and their animations to signature + for (const StringName &lib_name : libs) { + signature += "::" + String(lib_name); + Ref lib = mixer->get_animation_library(lib_name); + if (lib.is_valid()) { + List anims; + lib->get_animation_list(&anims); + anims.sort_custom(); + for (const StringName &anim_name : anims) { + signature += "," + String(anim_name); + } + } + } + + return signature.md5_text(); +} + void AnimationLibraryEditor::show_dialog() { update_tree(); popup_centered_ratio(0.5); @@ -855,11 +1055,12 @@ AnimationLibraryEditor::AnimationLibraryEditor() { tree->set_column_custom_minimum_width(1, EDSCALE * 250); tree->set_column_expand(1, false); tree->set_hide_root(true); - tree->set_hide_folding(true); + tree->set_hide_folding(false); tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); tree->connect("item_edited", callable_mp(this, &AnimationLibraryEditor::_item_renamed)); tree->connect("button_clicked", callable_mp(this, &AnimationLibraryEditor::_button_pressed)); + tree->connect("item_collapsed", callable_mp(this, &AnimationLibraryEditor::_save_mixer_lib_folding)); file_popup = memnew(PopupMenu); add_child(file_popup); diff --git a/editor/plugins/animation_library_editor.h b/editor/plugins/animation_library_editor.h index beb34c6343a..c4ad1684a63 100644 --- a/editor/plugins/animation_library_editor.h +++ b/editor/plugins/animation_library_editor.h @@ -31,6 +31,8 @@ #ifndef ANIMATION_LIBRARY_EDITOR_H #define ANIMATION_LIBRARY_EDITOR_H +#include "core/io/config_file.h" +#include "core/templates/vector.h" #include "editor/animation_track_editor.h" #include "editor/plugins/editor_plugin.h" #include "scene/animation/animation_mixer.h" @@ -103,6 +105,11 @@ class AnimationLibraryEditor : public AcceptDialog { void _load_file(const String &p_path); void _load_files(const PackedStringArray &p_paths); + void _save_mixer_lib_folding(TreeItem *p_item); + Vector _load_mixer_libs_folding(); + void _load_config_libs_folding(Vector &p_lib_ids, ConfigFile *p_config, String p_section); + String _get_mixer_signature() const; + void _item_renamed(); void _button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button); diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index b40c677f6e8..3a2adead98f 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -33,6 +33,8 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" +#include "core/string/print_string.h" +#include "core/string/string_name.h" #include "scene/2d/audio_stream_player_2d.h" #include "scene/animation/animation_player.h" #include "scene/audio/audio_stream_player.h" @@ -267,6 +269,16 @@ bool AnimationMixer::has_animation_library(const StringName &p_name) const { return false; } +StringName AnimationMixer::get_animation_library_name(const Ref &p_animation_library) const { + ERR_FAIL_COND_V(p_animation_library.is_null(), StringName()); + for (const AnimationLibraryData &lib : animation_libraries) { + if (lib.library == p_animation_library) { + return lib.name; + } + } + return StringName(); +} + StringName AnimationMixer::find_animation_library(const Ref &p_animation) const { for (const KeyValue &E : animation_set) { if (E.value.animation == p_animation) { diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h index 3769fa268c0..822a7aef251 100644 --- a/scene/animation/animation_mixer.h +++ b/scene/animation/animation_mixer.h @@ -409,6 +409,7 @@ class AnimationMixer : public Node { void get_animation_library_list(List *p_animations) const; Ref get_animation_library(const StringName &p_name) const; bool has_animation_library(const StringName &p_name) const; + StringName get_animation_library_name(const Ref &p_animation_library) const; StringName find_animation_library(const Ref &p_animation) const; Error add_animation_library(const StringName &p_name, const Ref &p_animation_library); void remove_animation_library(const StringName &p_name); From 3ab88c2e6a9adf8226aa1f7b572135d97f02e8eb Mon Sep 17 00:00:00 2001 From: Johannes Kung Date: Wed, 13 Nov 2024 21:50:31 +0100 Subject: [PATCH 20/59] Document `AudioStreamPlayer.get_playback_position()` intentionally always returning `0.0` when using `AudioStreamInteractive` --- doc/classes/AudioStreamPlayer.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml index 93680de21e0..900318e4f45 100644 --- a/doc/classes/AudioStreamPlayer.xml +++ b/doc/classes/AudioStreamPlayer.xml @@ -22,6 +22,7 @@ Returns the position in the [AudioStream] of the latest sound, in seconds. Returns [code]0.0[/code] if no sounds are playing. [b]Note:[/b] The position is not always accurate, as the [AudioServer] does not mix audio every processed frame. To get more accurate results, add [method AudioServer.get_time_since_last_mix] to the returned position. + [b]Note:[/b] This method always returns [code]0.0[/code] if the [member stream] is an [AudioStreamInteractive], since it can have multiple clips playing at once. From 117158d2718d11c5026f4e2791c7784b4815d0aa Mon Sep 17 00:00:00 2001 From: Markus Sauermann <6299227+Sauermann@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:28:57 +0100 Subject: [PATCH 21/59] Introduce a `SubViewportContainer` config for drag-and-drop targets With the drag-and-drop rewrite, `SubViewportContainer` nodes were no longer available as drop-locations. This PR introduces a configuration option, that allows `SubViewportContainer` to be considered as drop-location, but disables the `Control` nodes inside its `SubViewport` children as drop-location. --- doc/classes/SubViewportContainer.xml | 4 ++++ scene/gui/subviewport_container.cpp | 12 ++++++++++++ scene/gui/subviewport_container.h | 5 +++++ scene/main/viewport.cpp | 8 ++++++++ 4 files changed, 29 insertions(+) diff --git a/doc/classes/SubViewportContainer.xml b/doc/classes/SubViewportContainer.xml index b7d097cc919..310f235abf6 100644 --- a/doc/classes/SubViewportContainer.xml +++ b/doc/classes/SubViewportContainer.xml @@ -20,6 +20,10 @@ + + If [code]false[/code], the [SubViewportContainer] is not available as a drop target in drag-and-drop operations, and instead the [Control] nodes inside its [Viewport] children are potential drop targets. + If [code]true[/code], the [SubViewportContainer] itself will be considered as a drop target in drag-and-drop operations, preventing the [Control] nodes inside its [Viewport] children from becoming drop targets. + If [code]true[/code], the sub-viewport will be automatically resized to the control's size. diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index a443ae9abfa..775db65c3fc 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -246,6 +246,14 @@ bool SubViewportContainer::_is_propagated_in_gui_input(const Ref &p_ return false; } +void SubViewportContainer::set_consume_drag_and_drop(bool p_enable) { + consume_drag_and_drop = p_enable; +} + +bool SubViewportContainer::is_consume_drag_and_drop_enabled() { + return consume_drag_and_drop; +} + void SubViewportContainer::add_child_notify(Node *p_child) { if (Object::cast_to(p_child)) { queue_redraw(); @@ -286,8 +294,12 @@ void SubViewportContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stretch_shrink", "amount"), &SubViewportContainer::set_stretch_shrink); ClassDB::bind_method(D_METHOD("get_stretch_shrink"), &SubViewportContainer::get_stretch_shrink); + ClassDB::bind_method(D_METHOD("set_consume_drag_and_drop", "amount"), &SubViewportContainer::set_consume_drag_and_drop); + ClassDB::bind_method(D_METHOD("is_consume_drag_and_drop_enabled"), &SubViewportContainer::is_consume_drag_and_drop_enabled); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch"), "set_stretch", "is_stretch_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink", PROPERTY_HINT_RANGE, "1,32,1,or_greater"), "set_stretch_shrink", "get_stretch_shrink"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "consume_drag_and_drop"), "set_consume_drag_and_drop", "is_consume_drag_and_drop_enabled"); GDVIRTUAL_BIND(_propagate_input_event, "event"); } diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h index 06420de7303..72306157719 100644 --- a/scene/gui/subviewport_container.h +++ b/scene/gui/subviewport_container.h @@ -38,6 +38,8 @@ class SubViewportContainer : public Container { bool stretch = false; int shrink = 1; + bool consume_drag_and_drop = false; + void _notify_viewports(int p_notification); bool _is_propagated_in_gui_input(const Ref &p_event); void _send_event_to_viewports(const Ref &p_event); @@ -63,6 +65,9 @@ class SubViewportContainer : public Container { int get_stretch_shrink() const; void recalc_force_viewport_sizes(); + void set_consume_drag_and_drop(bool p_enable); + bool is_consume_drag_and_drop_enabled(); + virtual Size2 get_minimum_size() const override; virtual Vector get_allowed_size_flags_horizontal() const override; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index e70407f36ea..9b27a288314 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3062,6 +3062,14 @@ void Viewport::_update_mouse_over(Vector2 p_pos) { } v->_update_mouse_over(v->get_final_transform().affine_inverse().xform(pos)); } + + Viewport *section_root = get_section_root_viewport(); + if (section_root && c->is_consume_drag_and_drop_enabled()) { + // Evaluating `consume_drag_and_drop` and adjusting target_control needs to happen + // after `_update_mouse_over` in the SubViewports, because otherwise physics picking + // would not work inside SubViewports. + section_root->gui.target_control = over; + } } } From 6467beb75dbba17bf89b05abed61d7712baa9a10 Mon Sep 17 00:00:00 2001 From: "Yevhen Babiichuk (DustDFG)" Date: Sat, 16 Nov 2024 21:58:23 +0200 Subject: [PATCH 22/59] SCons: Move `swappy` option to android and slightly refactor `detect.py` Signed-off-by: Yevhen Babiichuk (DustDFG) --- SConstruct | 1 - platform/android/detect.py | 19 ++++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/SConstruct b/SConstruct index 7c7d3d25a0d..8ad8ac3e8d5 100644 --- a/SConstruct +++ b/SConstruct @@ -227,7 +227,6 @@ opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loade opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True)) opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "") opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True)) -opts.Add(BoolVariable("swappy", "Use Swappy Frame Pacing Library in Android builds.", False)) # Advanced options opts.Add( diff --git a/platform/android/detect.py b/platform/android/detect.py index 4bc7e9474bc..03a208391cf 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -31,6 +31,7 @@ def get_opts(): ), BoolVariable("store_release", "Editor build for Google Play Store (for official builds only)", False), BoolVariable("generate_apk", "Generate an APK/AAB after building Android library by calling Gradle", False), + BoolVariable("swappy", "Use Swappy Frame Pacing library", False), ] @@ -100,7 +101,7 @@ def detect_swappy(): archs = ["arm64-v8a", "armeabi-v7a", "x86", "x86_64"] has_swappy = True for arch in archs: - if not os.path.isfile("thirdparty/swappy-frame-pacing/" + arch + "/libswappy_static.a"): + if not os.path.isfile(f"thirdparty/swappy-frame-pacing/{arch}/libswappy_static.a"): has_swappy = False return has_swappy @@ -176,7 +177,7 @@ def configure(env: "SConsEnvironment"): env["AS"] = compiler_path + "/clang" env.Append( - CCFLAGS=("-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden".split()) + CCFLAGS=(["-fpic", "-ffunction-sections", "-funwind-tables", "-fstack-protector-strong", "-fvisibility=hidden"]) ) has_swappy = detect_swappy() @@ -200,28 +201,28 @@ def configure(env: "SConsEnvironment"): # The NDK adds this if targeting API < 24, so we can drop it when Godot targets it at least env.Append(CCFLAGS=["-mstackrealign"]) if has_swappy: - env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/x86"]) + env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/x86"]) elif env["arch"] == "x86_64": if has_swappy: - env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/x86_64"]) + env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/x86_64"]) elif env["arch"] == "arm32": - env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split()) + env.Append(CCFLAGS=["-march=armv7-a", "-mfloat-abi=softfp"]) env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"]) env.Append(CPPDEFINES=["__ARM_NEON__"]) if has_swappy: - env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/armeabi-v7a"]) + env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/armeabi-v7a"]) elif env["arch"] == "arm64": env.Append(CCFLAGS=["-mfix-cortex-a53-835769"]) env.Append(CPPDEFINES=["__ARM_ARCH_8A__"]) if has_swappy: - env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/arm64-v8a"]) + env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/arm64-v8a"]) env.Append(CCFLAGS=["-ffp-contract=off"]) # Link flags - env.Append(LINKFLAGS="-Wl,--gc-sections -Wl,--no-undefined -Wl,-z,now".split()) - env.Append(LINKFLAGS="-Wl,-soname,libgodot_android.so") + env.Append(LINKFLAGS=["-Wl,--gc-sections", "-Wl,--no-undefined", "-Wl,-z,now"]) + env.Append(LINKFLAGS=["-Wl,-soname,libgodot_android.so"]) env.Prepend(CPPPATH=["#platform/android"]) env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"]) From a0c47980c07128314341fe802f2319844114baca Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Sat, 16 Nov 2024 16:35:26 +0100 Subject: [PATCH 23/59] [Codeowners] Add missing test ownership --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6c8a8ef9198..713c982123b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -121,6 +121,7 @@ /modules/mbedtls/tests/ @godotengine/network @godotengine/tests /modules/multiplayer/ @godotengine/network /modules/multiplayer/doc_classes/ @godotengine/network @godotengine/documentation +/modules/multiplayer/tests/ @godotengine/network @godotengine/tests /modules/upnp/ @godotengine/network /modules/upnp/doc_classes/ @godotengine/network @godotengine/documentation /modules/webrtc/ @godotengine/network From 8bfb631afc0d8f4e7a4c5ee073c53069d667b00d Mon Sep 17 00:00:00 2001 From: Dario Date: Wed, 20 Nov 2024 10:04:17 -0300 Subject: [PATCH 24/59] Do not check for command intersections when not using the write list. --- servers/rendering/rendering_device_graph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp index c8ad0e2722f..ebfe3283930 100644 --- a/servers/rendering/rendering_device_graph.cpp +++ b/servers/rendering/rendering_device_graph.cpp @@ -527,7 +527,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr // The index is just the latest command index that wrote to the resource. if (search_tracker->write_command_or_list_index == p_command_index) { ERR_FAIL_MSG("Command can't have itself as a dependency."); - } else if (_check_command_intersection(resource_tracker, search_tracker->write_command_or_list_index, p_command_index)) { + } else { _add_adjacent_command(search_tracker->write_command_or_list_index, p_command_index, r_command); } } From 9ab94df7725d4a31d28056630fe6038d64c92b5a Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Sun, 17 Nov 2024 18:25:52 +0900 Subject: [PATCH 25/59] Add explicit_elapse option to NodeSeek to handle some processes --- doc/classes/AnimationNodeTimeSeek.xml | 5 +++++ scene/animation/animation_blend_tree.cpp | 16 +++++++++++++++- scene/animation/animation_blend_tree.h | 7 +++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/doc/classes/AnimationNodeTimeSeek.xml b/doc/classes/AnimationNodeTimeSeek.xml index d00b3fca3ad..865e94ec430 100644 --- a/doc/classes/AnimationNodeTimeSeek.xml +++ b/doc/classes/AnimationNodeTimeSeek.xml @@ -30,4 +30,9 @@ $DOCS_URL/tutorials/animation/animation_tree.html + + + If [code]true[/code], some processes are executed to handle keys between seeks, such as calculating root motion and finding the nearest discrete key. + + diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index e172286d054..d0773fc83fc 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 5c912f00956..c48d799eea6 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 *r_list) const override; @@ -311,6 +315,9 @@ class AnimationNodeTimeSeek : public AnimationNode { 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(); }; From f4c1f89add61c819b7fbbfa299d1b8a24db8475b Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Wed, 20 Nov 2024 06:33:18 -0800 Subject: [PATCH 26/59] Suggest using OS.has_feature instead of the engine architecture name for bitness --- doc/classes/Engine.xml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index bba51570538..3ae37539307 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -13,21 +13,7 @@ Returns the name of the CPU architecture the Godot binary was built for. Possible return values include [code]"x86_64"[/code], [code]"x86_32"[/code], [code]"arm64"[/code], [code]"arm32"[/code], [code]"rv64"[/code], [code]"riscv"[/code], [code]"ppc64"[/code], [code]"ppc"[/code], [code]"wasm64"[/code], and [code]"wasm32"[/code]. - To detect whether the current build is 64-bit, you can use the fact that all 64-bit architecture names contain [code]64[/code] in their name: - [codeblocks] - [gdscript] - if "64" in Engine.get_architecture_name(): - print("Running a 64-bit build of Godot.") - else: - print("Running a 32-bit build of Godot.") - [/gdscript] - [csharp] - if (Engine.GetArchitectureName().Contains("64")) - GD.Print("Running a 64-bit build of Godot."); - else - GD.Print("Running a 32-bit build of Godot."); - [/csharp] - [/codeblocks] + To detect whether the current build is 64-bit, or the type of architecture, don't use the architecture name. Instead, use [method OS.has_feature] to check for the [code]"64"[/code] feature tag, or tags such as [code]"x86"[/code] or [code]"arm"[/code]. See the [url=$DOCS_URL/tutorials/export/feature_tags.html]Feature Tags[/url] documentation for more details. [b]Note:[/b] This method does [i]not[/i] return the name of the system's CPU architecture (like [method OS.get_processor_name]). For example, when running an [code]x86_32[/code] Godot binary on an [code]x86_64[/code] system, the returned value will still be [code]"x86_32"[/code]. From 0896bdd7bc9d0f23d225a0b6b8209700e4d8e9d1 Mon Sep 17 00:00:00 2001 From: "Yevhen Babiichuk (DustDFG)" Date: Wed, 20 Nov 2024 18:18:12 +0200 Subject: [PATCH 27/59] SCons: Misc improvements * Delete old gcc 7 check * Use f-strings where it is easy * Use AddVariables instead of Add for collections of options Signed-off-by: Yevhen Babiichuk (DustDFG) --- SConstruct | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/SConstruct b/SConstruct index 7c7d3d25a0d..f9499fc0b09 100644 --- a/SConstruct +++ b/SConstruct @@ -383,8 +383,7 @@ if env["platform"] not in platform_list: # Add platform-specific options. if env["platform"] in platform_opts: - for opt in platform_opts[env["platform"]]: - opts.Add(opt) + opts.AddVariables(*platform_opts[env["platform"]]) # Platform-specific flags. # These can sometimes override default options, so they need to be processed @@ -440,12 +439,11 @@ for name, path in modules_detected.items(): else: enabled = False - opts.Add(BoolVariable("module_" + name + "_enabled", "Enable module '%s'" % (name,), enabled)) + opts.Add(BoolVariable(f"module_{name}_enabled", f"Enable module '{name}'", enabled)) # Add module-specific options. try: - for opt in config.get_opts(env["platform"]): - opts.Add(opt) + opts.AddVariables(*config.get_opts(env["platform"])) except AttributeError: pass @@ -580,7 +578,7 @@ env.Append(RCFLAGS=env.get("rcflags", "").split()) # Feature build profile env.disabled_classes = [] if env["build_profile"] != "": - print('Using feature build profile: "{}"'.format(env["build_profile"])) + print(f'Using feature build profile: "{env["build_profile"]}"') import json try: @@ -592,7 +590,7 @@ if env["build_profile"] != "": for c in dbo: env[c] = dbo[c] except json.JSONDecodeError: - print_error('Failed to open feature build profile: "{}"'.format(env["build_profile"])) + print_error(f'Failed to open feature build profile: "{env["build_profile"]}"') Exit(255) # 'dev_mode' and 'production' are aliases to set default options if they haven't been @@ -854,8 +852,6 @@ else: # GCC, Clang if methods.using_gcc(env): common_warnings += ["-Wshadow", "-Wno-misleading-indentation"] - if cc_version_major == 7: # Bogus warning fixed in 8+. - common_warnings += ["-Wno-strict-overflow"] if cc_version_major < 11: # Regression in GCC 9/10, spams so much in our variadic templates # that we need to outright disable it. @@ -931,7 +927,7 @@ env.module_icons_paths = [] env.doc_class_path = platform_doc_class_path for name, path in modules_detected.items(): - if not env["module_" + name + "_enabled"]: + if not env[f"module_{name}_enabled"]: continue sys.path.insert(0, path) env.current_module = name @@ -1044,7 +1040,7 @@ if env["compiledb"]: if env["ninja"]: if env.scons_version < (4, 2, 0): - print_error("The `ninja=yes` option requires SCons 4.2 or later, but your version is %s." % scons_raw_version) + print_error(f"The `ninja=yes` option requires SCons 4.2 or later, but your version is {scons_raw_version}.") Exit(255) SetOption("experimental", "ninja") From 5cd0d42d2bbca7e05472d383c8c91ba99988ea22 Mon Sep 17 00:00:00 2001 From: passivestar <60579014+passivestar@users.noreply.github.com> Date: Thu, 21 Nov 2024 08:24:08 +0400 Subject: [PATCH 28/59] Fix viewport message offsets --- editor/plugins/canvas_item_editor_plugin.cpp | 2 +- editor/plugins/node_3d_editor_plugin.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index f91a052a247..446ddddbc14 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -3913,7 +3913,7 @@ void CanvasItemEditor::_draw_message() { Ref 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/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 810d1674ca1..daede895b5c 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 = 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)); From f6751d8d174c01aee3fb50e213acb11c75bb13be Mon Sep 17 00:00:00 2001 From: LuoZhihao Date: Wed, 20 Nov 2024 19:34:31 +0800 Subject: [PATCH 29/59] ColorPicker: fix OKHSL circle in HSV mode --- scene/gui/color_picker.cpp | 58 ++++++++++++++++++++++++-------------- scene/gui/color_picker.h | 5 ++++ 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 997120ff251..06dff671727 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 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 points; Vector 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 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 &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 &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 &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 &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 59540d9ace0..aedf4aef16f 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -211,6 +211,11 @@ class ColorPicker : public VBoxContainer { 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 { From 84db024f6f68e44bff84a04fa737aefad31dd81a Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 13 Sep 2024 21:38:26 +0200 Subject: [PATCH 30/59] Use scons to calculate all the sources needed for vsproj generation. Scons knows every file - sources, headers, etc - that the binary depends on, and trying to figure that out manually is just too prone to error. --- methods.py | 101 ++++++++++++++++++++------------------------------ modules/SCsub | 5 --- 2 files changed, 41 insertions(+), 65 deletions(-) diff --git a/methods.py b/methods.py index d89185f5858..c543e24edc7 100644 --- a/methods.py +++ b/methods.py @@ -1007,6 +1007,30 @@ def format_key_value(v): return v[0] if len(v) == 1 else f"{v[0]}={v[1]}" return v + def get_dependencies(file, env, exts, headers, sources, others): + for child in file.children(): + if isinstance(child, str): + child = env.File(x) + fname = "" + try: + fname = child.path + except AttributeError: + # It's not a file. + pass + + if fname: + parts = os.path.splitext(fname) + if len(parts) > 1: + ext = parts[1].lower() + if ext in exts["sources"]: + sources += [fname] + elif ext in exts["headers"]: + headers += [fname] + elif ext in exts["others"]: + others += [fname] + + get_dependencies(child, env, exts, headers, sources, others) + filtered_args = original_args.copy() # Ignore the "vsproj" option to not regenerate the VS project on every build @@ -1068,26 +1092,28 @@ def format_key_value(v): sys.path.remove(tmppath) sys.modules.pop("msvs") + extensions = {} + extensions["headers"] = [".h", ".hh", ".hpp", ".hxx", ".inc"] + extensions["sources"] = [".c", ".cc", ".cpp", ".cxx", ".m", ".mm", ".java"] + extensions["others"] = [".natvis", ".glsl", ".rc"] + headers = [] headers_dirs = [] - for file in glob_recursive_2("*.h", headers_dirs): - headers.append(str(file).replace("/", "\\")) - for file in glob_recursive_2("*.hpp", headers_dirs): - headers.append(str(file).replace("/", "\\")) + for ext in extensions["headers"]: + for file in glob_recursive_2("*" + ext, headers_dirs): + headers.append(str(file).replace("/", "\\")) sources = [] sources_dirs = [] - for file in glob_recursive_2("*.cpp", sources_dirs): - sources.append(str(file).replace("/", "\\")) - for file in glob_recursive_2("*.c", sources_dirs): - sources.append(str(file).replace("/", "\\")) + for ext in extensions["sources"]: + for file in glob_recursive_2("*" + ext, sources_dirs): + sources.append(str(file).replace("/", "\\")) others = [] others_dirs = [] - for file in glob_recursive_2("*.natvis", others_dirs): - others.append(str(file).replace("/", "\\")) - for file in glob_recursive_2("*.glsl", others_dirs): - others.append(str(file).replace("/", "\\")) + for ext in extensions["others"]: + for file in glob_recursive_2("*" + ext, others_dirs): + others.append(str(file).replace("/", "\\")) skip_filters = False import hashlib @@ -1151,58 +1177,13 @@ def format_key_value(v): with open(f"{project_name}.vcxproj.filters", "w", encoding="utf-8", newline="\r\n") as f: f.write(filters_template) - envsources = [] - - envsources += env.core_sources - envsources += env.drivers_sources - envsources += env.main_sources - envsources += env.modules_sources - envsources += env.scene_sources - envsources += env.servers_sources - if env.editor_build: - envsources += env.editor_sources - envsources += env.platform_sources - headers_active = [] sources_active = [] others_active = [] - for x in envsources: - fname = "" - if isinstance(x, str): - fname = env.File(x).path - else: - # Some object files might get added directly as a File object and not a list. - try: - fname = env.File(x)[0].path - except Exception: - fname = x.path - pass - if fname: - fname = fname.replace("\\\\", "/") - parts = os.path.splitext(fname) - basename = parts[0] - ext = parts[1] - idx = fname.find(env["OBJSUFFIX"]) - if ext in [".h", ".hpp"]: - headers_active += [fname] - elif ext in [".c", ".cpp"]: - sources_active += [fname] - elif idx > 0: - basename = fname[:idx] - if os.path.isfile(basename + ".h"): - headers_active += [basename + ".h"] - elif os.path.isfile(basename + ".hpp"): - headers_active += [basename + ".hpp"] - elif basename.endswith(".gen") and os.path.isfile(basename[:-4] + ".h"): - headers_active += [basename[:-4] + ".h"] - if os.path.isfile(basename + ".c"): - sources_active += [basename + ".c"] - elif os.path.isfile(basename + ".cpp"): - sources_active += [basename + ".cpp"] - else: - fname = os.path.relpath(os.path.abspath(fname), env.Dir("").abspath) - others_active += [fname] + get_dependencies( + env.File(f"#bin/godot{env['PROGSUFFIX']}"), env, extensions, headers_active, sources_active, others_active + ) all_items = [] properties = [] diff --git a/modules/SCsub b/modules/SCsub index fea2f2eeb86..09944241ea5 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -63,7 +63,6 @@ register_module_types = env.CommandNoCache( ) -vs_sources = [] test_headers = [] # libmodule_.a for each active module. for name, path in env.module_list.items(): @@ -75,8 +74,6 @@ for name, path in env.module_list.items(): lib = env_modules.add_library("module_%s" % name, env.modules_sources) env.Prepend(LIBS=[lib]) - if env["vsproj"]: - vs_sources += env.modules_sources if env["tests"]: # Lookup potential headers in `tests` subfolder. @@ -104,5 +101,3 @@ env.modules_sources = [] env_modules.add_source_files(env.modules_sources, register_module_types) lib = env_modules.add_library("modules", env.modules_sources) env.Prepend(LIBS=[lib]) -if env["vsproj"]: - env.modules_sources += vs_sources From 0524e29b5cf9b4b099e7f2a7be09f21fd80e1e14 Mon Sep 17 00:00:00 2001 From: Chaosus Date: Mon, 5 Aug 2024 22:36:55 +0300 Subject: [PATCH 31/59] Fix crash when division by zero/modulo by zero happen on vectors --- modules/gdscript/gdscript_byte_codegen.cpp | 21 +++++++++++++++++-- .../runtime/errors/division_by_zero.gd | 3 +++ .../runtime/errors/division_by_zero.out | 6 ++++++ .../scripts/runtime/errors/modulo_by_zero.gd | 3 +++ .../scripts/runtime/errors/modulo_by_zero.out | 6 ++++++ 5 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd create mode 100644 modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out create mode 100644 modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd create mode 100644 modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index b77c641eb55..fb4d27caab4 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -585,8 +585,25 @@ void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Va } void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) { - // Avoid validated evaluator for modulo and division when operands are int, since there's no check for division by zero. - if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand) && ((p_operator != Variant::OP_DIVIDE && p_operator != Variant::OP_MODULE) || p_left_operand.type.builtin_type != Variant::INT || p_right_operand.type.builtin_type != Variant::INT)) { + bool valid = HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand); + + // Avoid validated evaluator for modulo and division when operands are int or integer vector, since there's no check for division by zero. + if (valid && (p_operator == Variant::OP_DIVIDE || p_operator == Variant::OP_MODULE)) { + switch (p_left_operand.type.builtin_type) { + case Variant::INT: + valid = p_right_operand.type.builtin_type != Variant::INT; + break; + case Variant::VECTOR2I: + case Variant::VECTOR3I: + case Variant::VECTOR4I: + valid = p_right_operand.type.builtin_type != Variant::INT && p_right_operand.type.builtin_type != p_left_operand.type.builtin_type; + break; + default: + break; + } + } + + if (valid) { if (p_target.mode == Address::TEMPORARY) { Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type); Variant::Type temp_type = temporaries[p_target.address].type; diff --git a/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd new file mode 100644 index 00000000000..ace5397f40a --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd @@ -0,0 +1,3 @@ +func test(): + var integer: int = 1 + integer /= 0 diff --git a/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out new file mode 100644 index 00000000000..6a9d11cd772 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/division_by_zero.gd +>> 3 +>> Division by zero error in operator '/'. diff --git a/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd new file mode 100644 index 00000000000..99792e4e326 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd @@ -0,0 +1,3 @@ +func test(): + var integer: int = 1 + integer %= 0 diff --git a/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out new file mode 100644 index 00000000000..79c512888f4 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/modulo_by_zero.gd +>> 3 +>> Modulo by zero error in operator '%'. From c57eaf77571765461a83cde7e01a57460f02ff87 Mon Sep 17 00:00:00 2001 From: mendrak Date: Thu, 19 Sep 2024 20:56:02 -0700 Subject: [PATCH 32/59] Fix issue #97207 by filtering extension_list.cfg The implemented solution to the problem of the error message appearing when an excluded GDExtension in an export of a project, is to filter the lines in the extension_list.cfg file to only include those that are in the paths actually included for export. If there are no entries remaining, don't write the file at all. --- editor/export/editor_export_platform.cpp | 26 +++++++++++++++++++++++- editor/export/editor_export_platform.h | 2 ++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 91c9ff9807c..27216c2399a 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 & Vector forced_export = get_forced_export_files(); for (int i = 0; i < forced_export.size(); i++) { - Vector array = FileAccess::get_file_as_bytes(forced_export[i]); + Vector 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 & return OK; } +Vector EditorExportPlatform::_filter_extension_list_config_file(const String &p_config_path, const HashSet &p_paths) { + Ref f = FileAccess::open(p_config_path, FileAccess::READ); + if (f.is_null()) { + ERR_FAIL_V_MSG(Vector(), "Can't open file from path '" + String(p_config_path) + "'."); + } + Vector 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 c7378ffec7e..a33bdce72a7 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -135,6 +135,8 @@ class EditorExportPlatform : public RefCounted { void _edit_files_with_filter(Ref &da, const Vector &p_filters, HashSet &r_list, bool exclude); void _edit_filter_list(HashSet &r_list, const String &p_filter, bool exclude); + static Vector _filter_extension_list_config_file(const String &p_config_path, const HashSet &p_paths); + struct FileExportCache { uint64_t source_modified_time = 0; String source_md5; From 31c8aadc47170abce59226cf5b4ca547a7636f7b Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:43:00 +0100 Subject: [PATCH 33/59] [Buildsystem] Prevent cache check mangling access time Checking for text files using `open` changes `atime`, which breaks cache access sorting, this ensures the cache access time is preserved. --- methods.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/methods.py b/methods.py index 1c33b00051b..da6b3419cd8 100644 --- a/methods.py +++ b/methods.py @@ -863,16 +863,21 @@ def clean_cache(cache_path: str, cache_limit: int, verbose: bool): texts = [] stats = [] for file in files: - # Failing a utf-8 decode is the easiest way to determine if a file is binary. try: - with open(file, encoding="utf-8") as out: - out.read(1024) - except UnicodeDecodeError: - stats.append((file, *os.stat(file)[6:8])) + # Save file stats to rewrite after modifying. + tmp_stat = os.stat(file) + # Failing a utf-8 decode is the easiest way to determine if a file is binary. + try: + with open(file, encoding="utf-8") as out: + out.read(1024) + except UnicodeDecodeError: + stats.append((file, *tmp_stat[6:8])) + # Restore file stats after reading. + os.utime(file, (tmp_stat[7], tmp_stat[8])) + else: + texts.append(file) except OSError: print_error(f'Failed to access cache file "{file}"; skipping.') - else: - texts.append(file) if texts: count = len(texts) From 5bca028e2bd5cde8a9a06fc1a4469cafa28d362b Mon Sep 17 00:00:00 2001 From: Bad Sector Date: Thu, 21 Nov 2024 03:00:21 +0200 Subject: [PATCH 34/59] Add lightmap bake cancelling --- editor/plugins/lightmap_gi_editor_plugin.cpp | 2 +- modules/lightmapper_rd/lightmapper_rd.cpp | 115 +++++++++++++++++-- scene/3d/lightmap_gi.cpp | 2 + scene/3d/lightmapper.h | 1 + 4 files changed, 108 insertions(+), 12 deletions(-) diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp index 4cff3504f51..3f21d5d11c1 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/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index 8ba6f9e2ba0..bd71e29d0a1 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, Refbuffer_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 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/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index cdbd95d9302..aa4445a7ba8 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 9aa8ef8ccbc..1228c63edce 100644 --- a/scene/3d/lightmapper.h +++ b/scene/3d/lightmapper.h @@ -147,6 +147,7 @@ class Lightmapper : public RefCounted { BAKE_ERROR_TEXTURE_EXCEEDS_MAX_SIZE, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, BAKE_ERROR_ATLAS_TOO_SMALL, + BAKE_ERROR_USER_ABORTED, }; enum BakeQuality { From 4e5080d8057422cd9b21bfa19be667d1cb680e15 Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Wed, 20 Nov 2024 20:48:38 +0100 Subject: [PATCH 35/59] [.NET] Preserve no-hint behavior for unmarshallable generics in dictionaries --- .../ScriptPropertiesGenerator.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) 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 ed78353f929..a8033914e77 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 @@ static bool GetStringArrayEnumHint(VariantType elementVariantType, 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 @@ static bool GetStringArrayEnumHint(VariantType elementVariantType, } } - 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; From c4bb252294f9e081809df0cd9ff47009136af01d Mon Sep 17 00:00:00 2001 From: Giganzo <158825920+Giganzo@users.noreply.github.com> Date: Thu, 21 Nov 2024 20:23:24 +0100 Subject: [PATCH 36/59] Change how multi selection scale is applied to canvas item --- editor/plugins/canvas_item_editor_plugin.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index f91a052a247..187a01c859e 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1995,15 +1995,14 @@ bool CanvasItemEditor::_gui_input_scale(const Ref &p_event) { } } + Transform2D edit_transform; + bool using_temp_pivot = !Math::is_inf(temp_pivot.x) || !Math::is_inf(temp_pivot.y); + if (using_temp_pivot) { + edit_transform = Transform2D(drag_selection.front()->get()->_edit_get_rotation(), temp_pivot); + } else { + edit_transform = drag_selection.front()->get()->_edit_get_transform(); + } for (CanvasItem *ci : drag_selection) { - Transform2D edit_transform; - bool using_temp_pivot = !Math::is_inf(temp_pivot.x) || !Math::is_inf(temp_pivot.y); - if (using_temp_pivot) { - edit_transform = Transform2D(ci->_edit_get_rotation(), temp_pivot); - } else { - edit_transform = ci->_edit_get_transform(); - } - Transform2D parent_xform = ci->get_global_transform_with_canvas() * ci->get_transform().affine_inverse(); Transform2D unscaled_transform = (transform * parent_xform * edit_transform).orthonormalized(); Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform; From 429ea1c8e34b136db5737fa1bc71d432193b33ad Mon Sep 17 00:00:00 2001 From: Micky Date: Thu, 21 Nov 2024 21:33:55 +0100 Subject: [PATCH 37/59] Fix typo in AudioStream's documentation --- doc/classes/AudioStream.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/classes/AudioStream.xml b/doc/classes/AudioStream.xml index 44edff122e7..d11e070d89b 100644 --- a/doc/classes/AudioStream.xml +++ b/doc/classes/AudioStream.xml @@ -48,7 +48,7 @@ - Override this method to customize the returned value of [method instantiate_playback]. Should returned a new [AudioStreamPlayback] created when the stream is played (such as by an [AudioStreamPlayer]).. + Override this method to customize the returned value of [method instantiate_playback]. Should return a new [AudioStreamPlayback] created when the stream is played (such as by an [AudioStreamPlayer]). From 6f4fadf65def83a6a6c885e4aaa11f8982f37916 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Thu, 7 Nov 2024 10:59:02 -0700 Subject: [PATCH 38/59] Expose standardize_locale add_default param publicly Comparing locales can have surprising outcomes since it standardizes locales with defaults. For example, zh and zh_CN result in an exact match since the defaults change them both to zh_Hans_CN. Expose the add_default parameter publicly with a default of false so the fully standardized locale can be inspected. --- core/string/translation_server.compat.inc | 41 +++++++++++++++++++ core/string/translation_server.cpp | 7 ++-- core/string/translation_server.h | 8 +++- doc/classes/TranslationServer.xml | 3 +- .../4.3-stable.expected | 7 ++++ tests/core/string/test_translation_server.h | 30 ++++++++++++++ 6 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 core/string/translation_server.compat.inc diff --git a/core/string/translation_server.compat.inc b/core/string/translation_server.compat.inc new file mode 100644 index 00000000000..11f508c6543 --- /dev/null +++ b/core/string/translation_server.compat.inc @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* translation_server.compat.inc */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DISABLE_DEPRECATED + +String TranslationServer::_standardize_locale_bind_compat_98972(const String &p_locale) const { + return standardize_locale(p_locale, false); +} + +void TranslationServer::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("standardize_locale", "locale"), &TranslationServer::_standardize_locale_bind_compat_98972); +} + +#endif // DISABLE_DEPRECATED diff --git a/core/string/translation_server.cpp b/core/string/translation_server.cpp index 31c221dad72..3d49d482dd6 100644 --- a/core/string/translation_server.cpp +++ b/core/string/translation_server.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "translation_server.h" +#include "translation_server.compat.inc" #include "core/config/project_settings.h" #include "core/io/resource_loader.h" @@ -218,8 +219,8 @@ TranslationServer::Locale::Locale(const TranslationServer &p_server, const Strin } } -String TranslationServer::standardize_locale(const String &p_locale) const { - return Locale(*this, p_locale, false).operator String(); +String TranslationServer::standardize_locale(const String &p_locale, bool p_add_defaults) const { + return Locale(*this, p_locale, p_add_defaults).operator String(); } int TranslationServer::compare_locales(const String &p_locale_a, const String &p_locale_b) const { @@ -591,7 +592,7 @@ void TranslationServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tool_locale"), &TranslationServer::get_tool_locale); ClassDB::bind_method(D_METHOD("compare_locales", "locale_a", "locale_b"), &TranslationServer::compare_locales); - ClassDB::bind_method(D_METHOD("standardize_locale", "locale"), &TranslationServer::standardize_locale); + ClassDB::bind_method(D_METHOD("standardize_locale", "locale", "add_defaults"), &TranslationServer::standardize_locale, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_all_languages"), &TranslationServer::get_all_languages); ClassDB::bind_method(D_METHOD("get_language_name", "language"), &TranslationServer::get_language_name); diff --git a/core/string/translation_server.h b/core/string/translation_server.h index bc59c34a38a..b6e4bba6e51 100644 --- a/core/string/translation_server.h +++ b/core/string/translation_server.h @@ -52,10 +52,14 @@ class TranslationServer : public Object { static inline TranslationServer *singleton = nullptr; bool _load_translations(const String &p_from); - String _standardize_locale(const String &p_locale, bool p_add_defaults) const; static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + String _standardize_locale_bind_compat_98972(const String &p_locale) const; + static void _bind_compatibility_methods(); +#endif + struct LocaleScriptInfo { String name; String script; @@ -129,7 +133,7 @@ class TranslationServer : public Object { void set_pseudolocalization_enabled(bool p_enabled); void reload_pseudolocalization(); - String standardize_locale(const String &p_locale) const; + String standardize_locale(const String &p_locale, bool p_add_defaults = false) const; int compare_locales(const String &p_locale_a, const String &p_locale_b) const; diff --git a/doc/classes/TranslationServer.xml b/doc/classes/TranslationServer.xml index 69ca984f67d..f30a1da014c 100644 --- a/doc/classes/TranslationServer.xml +++ b/doc/classes/TranslationServer.xml @@ -160,8 +160,9 @@ + - Returns a [param locale] string standardized to match known locales (e.g. [code]en-US[/code] would be matched to [code]en_US[/code]). + Returns a [param locale] string standardized to match known locales (e.g. [code]en-US[/code] would be matched to [code]en_US[/code]). If [param add_defaults] is [code]true[/code], the locale may have a default script or country added. diff --git a/misc/extension_api_validation/4.3-stable.expected b/misc/extension_api_validation/4.3-stable.expected index 75e81b5ff40..3d862b10c15 100644 --- a/misc/extension_api_validation/4.3-stable.expected +++ b/misc/extension_api_validation/4.3-stable.expected @@ -122,3 +122,10 @@ GH-98918 Validate extension JSON: Error: Field 'classes/FileAccess/methods/open_encrypted/arguments': size changed value in new API, from 3 to 4. Optional argument added to allow setting initialization vector. Compatibility method registered. + + +GH-98972 +-------- +Validate extension JSON: Error: Field 'classes/TranslationServer/methods/standardize_locale/arguments': size changed value in new API, from 1 to 2. + +Optional argument added. Compatibility method registered. diff --git a/tests/core/string/test_translation_server.h b/tests/core/string/test_translation_server.h index 6668a7b57bf..1274d8810ec 100644 --- a/tests/core/string/test_translation_server.h +++ b/tests/core/string/test_translation_server.h @@ -104,6 +104,36 @@ TEST_CASE("[TranslationServer] Locale operations") { res = ts->standardize_locale(loc); CHECK(res == "de_DE"); + + // No added defaults. + loc = "es_ES"; + res = ts->standardize_locale(loc, true); + + CHECK(res == "es_ES"); + + // Add default script. + loc = "az_AZ"; + res = ts->standardize_locale(loc, true); + + CHECK(res == "az_Latn_AZ"); + + // Add default country. + loc = "pa_Arab"; + res = ts->standardize_locale(loc, true); + + CHECK(res == "pa_Arab_PK"); + + // Add default script and country. + loc = "zh"; + res = ts->standardize_locale(loc, true); + + CHECK(res == "zh_Hans_CN"); + + // Explicitly don't add defaults. + loc = "zh"; + res = ts->standardize_locale(loc, false); + + CHECK(res == "zh"); } TEST_CASE("[TranslationServer] Comparing locales") { From c874e284ebd0551f14d0ebed5ed2ecfce8ebf1fc Mon Sep 17 00:00:00 2001 From: Carson Bates Date: Tue, 19 Nov 2024 20:04:41 -0800 Subject: [PATCH 39/59] Optimize mesh generation by preventing unneeded shape recalculations Co-authored-by: Sequoia Haynes --- scene/resources/3d/primitive_meshes.cpp | 169 ++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/scene/resources/3d/primitive_meshes.cpp b/scene/resources/3d/primitive_meshes.cpp index ceeb73d0ef2..4d04ae77b1b 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 &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(); From 133cf62d26abd5dd75655e2b9336c9c253b5b007 Mon Sep 17 00:00:00 2001 From: mechalynx <8427257+mechalynx@users.noreply.github.com> Date: Fri, 22 Nov 2024 06:23:06 +0200 Subject: [PATCH 40/59] Correct PackedInt64Array comparison in description All Packed classes that have the same paragraph will compare the currently viewed Packed array type with the equivalent typed Array but here the comparison was with the Int32 version instead of the Int64 version --- doc/classes/PackedInt64Array.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml index cfaf012a55b..b82d0de350e 100644 --- a/doc/classes/PackedInt64Array.xml +++ b/doc/classes/PackedInt64Array.xml @@ -6,7 +6,7 @@ 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. From acf351fa6aee36199f5f5c6665f48993622aa16f Mon Sep 17 00:00:00 2001 From: mechalynx <8427257+mechalynx@users.noreply.github.com> Date: Fri, 22 Nov 2024 07:12:56 +0200 Subject: [PATCH 41/59] Update PackedVector4Array description to include explanation shared by PackedArray classes --- doc/classes/PackedVector4Array.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/classes/PackedVector4Array.xml b/doc/classes/PackedVector4Array.xml index 6dbfc7413d4..7bebee79c71 100644 --- a/doc/classes/PackedVector4Array.xml +++ b/doc/classes/PackedVector4Array.xml @@ -5,6 +5,7 @@ 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. From 2b68c63a886f1442f7afdb91f6bae16e755325cc Mon Sep 17 00:00:00 2001 From: clayjohn Date: Mon, 4 Nov 2024 21:21:38 -0800 Subject: [PATCH 42/59] Mask out shadows on CanvasItems that don't have a matching item_shadow_mask This restores the behavior from 3.x --- drivers/gles3/rasterizer_canvas_gles3.cpp | 54 +++++++++------- drivers/gles3/rasterizer_canvas_gles3.h | 36 +++++------ drivers/gles3/shaders/canvas.glsl | 46 +++++++------- .../gles3/shaders/canvas_uniforms_inc.glsl | 36 +++++------ .../renderer_rd/renderer_canvas_render_rd.cpp | 61 +++++++++++-------- .../renderer_rd/renderer_canvas_render_rd.h | 47 +++++++------- .../rendering/renderer_rd/shaders/canvas.glsl | 46 +++++++------- .../shaders/canvas_uniforms_inc.glsl | 49 ++++++++------- 8 files changed, 200 insertions(+), 175 deletions(-) diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 2fd3f7d7e27..5fd90744a42 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(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 b9d9a44e2aa..e099fd0cc02 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 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender { 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 1ac289d5a24..3857aa8841a 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 f6ad2b730ab..7abd5f0eeef 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/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 0dcdb90948a..165168cb298 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 1bdc5076c5b..e4f1779b09a 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> 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 f665bc24a47..b66aa71f6ba 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 84017a1fe19..2186b08e899 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; From 7a25173ff469b3b593cb8a5a311617c5cde9b80a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Fri, 22 Nov 2024 09:44:07 +0100 Subject: [PATCH 43/59] Make loading translations from threads safe --- core/string/translation.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/string/translation.cpp b/core/string/translation.cpp index 020949371f2..d944135a709 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)); } } From 24d51f763500479aa4a676f255123b4294920224 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:15:46 +0200 Subject: [PATCH 44/59] [Windows] Fix TTS events arriving out of order. --- platform/windows/display_server_windows.cpp | 4 ++++ platform/windows/tts_windows.cpp | 10 ++++++---- platform/windows/tts_windows.h | 4 +++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 467873ee7c2..e300bd1c472 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 39a8f3e1204..e9ef50d7367 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 33b597c6125..657cb608d60 100644 --- a/platform/windows/tts_windows.h +++ b/platform/windows/tts_windows.h @@ -55,9 +55,9 @@ class TTS_Windows { int id; }; HashMap 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 @@ class TTS_Windows { void resume(); void stop(); + void process_events(); + TTS_Windows(); ~TTS_Windows(); }; From ae853e1a428234692d7860ca09c46aad2bf7944e Mon Sep 17 00:00:00 2001 From: Lazy-Rabbit-2001 <2733679597@qq.com> Date: Fri, 22 Nov 2024 18:24:45 +0800 Subject: [PATCH 45/59] Improve GDScript autocompletion for methods --- modules/gdscript/gdscript_editor.cpp | 21 +++++++++++++++---- .../assignment_options/enum_attribute.cfg | 2 +- .../enum_attribute_identifier.cfg | 2 +- .../completion/common/identifiers_in_call.cfg | 8 +++---- .../common/identifiers_in_function_body.cfg | 8 +++---- .../common/identifiers_in_unclosed_call.cfg | 8 +++---- .../common/no_completion_in_string.cfg | 10 ++++----- .../tests/scripts/completion/common/self.cfg | 8 +++---- .../completion/get_node/literal/dollar.cfg | 2 +- .../completion/get_node/literal/percent.cfg | 2 +- .../literal_scene/dollar_class_scene.cfg | 4 ++-- .../literal_scene/dollar_native_scene.cfg | 4 ++-- .../literal_scene/percent_class_scene.cfg | 4 ++-- .../literal_scene/percent_native_scene.cfg | 4 ++-- .../completion/get_node/local/local.cfg | 2 +- .../get_node/local_infered/local_infered.cfg | 2 +- .../class_local_infered_scene.cfg | 4 ++-- .../native_local_infered_scene.cfg | 4 ++-- .../local_scene/class_local_scene.cfg | 4 ++-- .../local_scene/native_local_scene.cfg | 4 ++-- .../local_typehint/class_local_typehint.cfg | 4 ++-- .../local_typehint/native_local_typehint.cfg | 4 ++-- .../class_local_typehint_scene.cfg | 4 ++-- .../native_local_typehint_scene.cfg | 4 ++-- .../class_local_typehint_scene_broad.cfg | 4 ++-- .../native_local_typehint_scene_broad.cfg | 4 ++-- ...lass_local_typehint_scene_incompatible.cfg | 6 +++--- ...tive_local_typehint_scene_incompatible.cfg | 6 +++--- .../completion/get_node/member/member.cfg | 2 +- .../member_infered/member_infered.cfg | 2 +- .../class_member_infered_scene.cfg | 4 ++-- .../native_member_infered_scene.cfg | 4 ++-- .../member_scene/class_member_scene.cfg | 4 ++-- .../member_scene/native_member_scene.cfg | 4 ++-- .../member_typehint/class_member_typehint.cfg | 4 ++-- .../native_member_typehint.cfg | 4 ++-- .../class_member_typehint_scene.cfg | 4 ++-- .../native_member_typehint_scene.cfg | 4 ++-- .../class_member_typehint_scene_broad.cfg | 4 ++-- .../native_member_typehint_scene_broad.cfg | 4 ++-- ...ass_member_typehint_scene_incompatible.cfg | 6 +++--- ...ive_member_typehint_scene_incompatible.cfg | 6 +++--- .../completion/types/local/infered.cfg | 4 ++-- .../completion/types/local/no_type.cfg | 4 ++-- .../completion/types/local/typehint.cfg | 4 ++-- .../completion/types/local/typehint_broad.cfg | 4 ++-- .../types/local/typehint_incompatible.cfg | 4 ++-- .../completion/types/member/infered.cfg | 4 ++-- .../completion/types/member/no_type.cfg | 4 ++-- .../completion/types/member/typehint.cfg | 4 ++-- .../types/member/typehint_broad.cfg | 4 ++-- .../types/member/typehint_incompatible.cfg | 4 ++-- 52 files changed, 126 insertions(+), 113 deletions(-) diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index d58cd2c3f79..cfff20f6d33 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::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 e4759ac76b8..a2c332adadb 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 e4759ac76b8..a2c332adadb 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 5f08f9c265e..f2dff734b63 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 5f08f9c265e..f2dff734b63 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 5f08f9c265e..f2dff734b63 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 462846c9b29..e0129190515 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 871a404e3ad..dcce1df0d08 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 ae7d34d87dc..319c5121b51 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 ae7d34d87dc..319c5121b51 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 9c580b711d8..7518bf5ae58 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 446198dd353..174fdcb1840 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 9c580b711d8..7518bf5ae58 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 446198dd353..174fdcb1840 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 ae7d34d87dc..319c5121b51 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 ae7d34d87dc..319c5121b51 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 9c580b711d8..7518bf5ae58 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 446198dd353..174fdcb1840 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 9c580b711d8..7518bf5ae58 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 446198dd353..174fdcb1840 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 8b68d51a893..050b0d61a37 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 72c0549d3b8..d647135bc61 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 9c580b711d8..7518bf5ae58 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 446198dd353..174fdcb1840 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 9c580b711d8..7518bf5ae58 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 446198dd353..174fdcb1840 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 1894e72c651..a6118908de9 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 c8ab63f6d60..d8390ca33c3 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 ae7d34d87dc..319c5121b51 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 ae7d34d87dc..319c5121b51 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 9c580b711d8..7518bf5ae58 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 446198dd353..174fdcb1840 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 9c580b711d8..7518bf5ae58 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 446198dd353..174fdcb1840 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 8b68d51a893..050b0d61a37 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 72c0549d3b8..d647135bc61 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 9c580b711d8..7518bf5ae58 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 446198dd353..174fdcb1840 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 502038bef7a..2f747e0bace 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 1810e9fe5f5..f060413898c 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 1894e72c651..a6118908de9 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 c8ab63f6d60..d8390ca33c3 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 8b68d51a893..050b0d61a37 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 8b68d51a893..050b0d61a37 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 8b68d51a893..050b0d61a37 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 8b68d51a893..050b0d61a37 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 8b68d51a893..050b0d61a37 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 8b68d51a893..050b0d61a37 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 8b68d51a893..050b0d61a37 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 8b68d51a893..050b0d61a37 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 81401316ec8..d32bbac65ea 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 8b68d51a893..050b0d61a37 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"}, ] From 03b05cf9acd69b7eeced919012c215b22cd901ab Mon Sep 17 00:00:00 2001 From: Danil Alexeev Date: Fri, 22 Nov 2024 14:03:21 +0300 Subject: [PATCH 46/59] Core: Fix built-in enum constant bindings --- core/variant/variant.cpp | 3 - core/variant/variant.h | 3 +- core/variant/variant_call.cpp | 61 ++++++------ doc/classes/Projection.xml | 12 +-- doc/classes/Vector2.xml | 4 +- doc/classes/Vector2i.xml | 4 +- doc/classes/Vector3.xml | 6 +- doc/classes/Vector3i.xml | 6 +- doc/classes/Vector4.xml | 8 +- doc/classes/Vector4i.xml | 8 +- doc/tools/make_rst.py | 4 +- editor/doc_tools.cpp | 17 ++++ .../4.3-stable.expected | 30 ++++++ modules/gdscript/gdscript_analyzer.cpp | 97 +++++++++++++++---- .../analyzer/errors/enum_builtin_access.gd | 2 + .../analyzer/errors/enum_builtin_access.out | 2 + .../analyzer/errors/enum_global_access.gd | 2 + .../analyzer/errors/enum_global_access.out | 2 + .../analyzer/errors/enum_native_access.gd | 2 + .../analyzer/errors/enum_native_access.out | 2 + .../global_builtin_and_native_enums.gd | 28 ++++++ .../global_builtin_and_native_enums.out | 25 +++++ modules/mono/editor/bindings_generator.cpp | 35 ++++--- tests/core/object/test_class_db.h | 23 +++-- 24 files changed, 278 insertions(+), 108 deletions(-) create mode 100644 modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd create mode 100644 modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out create mode 100644 modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd create mode 100644 modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out create mode 100644 modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd create mode 100644 modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out create mode 100644 modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd create mode 100644 modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 3e74dc4e67a..8aca56c1d56 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -3560,9 +3560,6 @@ bool Variant::is_ref_counted() const { return type == OBJECT && _get_obj().id.is_ref_counted(); } -void Variant::static_assign(const Variant &p_variant) { -} - bool Variant::is_type_shared(Variant::Type p_type) { switch (p_type) { case OBJECT: diff --git a/core/variant/variant.h b/core/variant/variant.h index 9702c67a371..babd2cf0847 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -792,7 +792,6 @@ class Variant { String stringify(int recursion_count = 0) const; String to_json_string() const; - void static_assign(const Variant &p_variant); static void get_constants_for_type(Variant::Type p_type, List *p_constants); static int get_constants_count_for_type(Variant::Type p_type); static bool has_constant(Variant::Type p_type, const StringName &p_value); @@ -801,6 +800,8 @@ class Variant { static void get_enums_for_type(Variant::Type p_type, List *p_enums); static void get_enumerations_for_enum(Variant::Type p_type, const StringName &p_enum_name, List *p_enumerations); static int get_enum_value(Variant::Type p_type, const StringName &p_enum_name, const StringName &p_enumeration, bool *r_valid = nullptr); + static bool has_enum(Variant::Type p_type, const StringName &p_enum_name); + static StringName get_enum_for_enumeration(Variant::Type p_type, const StringName &p_enumeration); typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud); typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 381b848b2b4..d612cb9cead 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1091,6 +1091,11 @@ struct _VariantCall { static ConstantData *constant_data; static void add_constant(int p_type, const StringName &p_constant_name, int64_t p_constant_value) { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(constant_data[p_type].value.has(p_constant_name)); + ERR_FAIL_COND(enum_data[p_type].value.has(p_constant_name)); + ERR_FAIL_COND(enum_data[p_type].value_to_enum.has(p_constant_name)); +#endif constant_data[p_type].value[p_constant_name] = p_constant_value; #ifdef DEBUG_ENABLED constant_data[p_type].value_ordered.push_back(p_constant_name); @@ -1106,12 +1111,19 @@ struct _VariantCall { struct EnumData { HashMap> value; + HashMap value_to_enum; }; static EnumData *enum_data; static void add_enum_constant(int p_type, const StringName &p_enum_type_name, const StringName &p_enumeration_name, int p_enum_value) { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(constant_data[p_type].value.has(p_enumeration_name)); + ERR_FAIL_COND(enum_data[p_type].value.has(p_enumeration_name)); + ERR_FAIL_COND(enum_data[p_type].value_to_enum.has(p_enumeration_name)); +#endif enum_data[p_type].value[p_enum_type_name][p_enumeration_name] = p_enum_value; + enum_data[p_type].value_to_enum[p_enumeration_name] = p_enum_type_name; } }; @@ -1561,6 +1573,23 @@ int Variant::get_enum_value(Variant::Type p_type, const StringName &p_enum_name, return V->value; } +bool Variant::has_enum(Variant::Type p_type, const StringName &p_enum_name) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false); + + _VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type]; + + return enum_data.value.has(p_enum_name); +} + +StringName Variant::get_enum_for_enumeration(Variant::Type p_type, const StringName &p_enumeration) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, StringName()); + + _VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type]; + + const StringName *enum_name = enum_data.value_to_enum.getptr(p_enumeration); + return (enum_name == nullptr) ? StringName() : *enum_name; +} + #ifdef DEBUG_METHODS_ENABLED #define bind_method(m_type, m_method, m_arg_names, m_default_args) \ METHOD_CLASS(m_type, m_method, &m_type::m_method); \ @@ -2660,10 +2689,6 @@ static void _register_variant_builtin_constants() { _VariantCall::add_variant_constant(Variant::COLOR, Color::get_named_color_name(i), Color::get_named_color(i)); } - _VariantCall::add_constant(Variant::VECTOR3, "AXIS_X", Vector3::AXIS_X); - _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Y", Vector3::AXIS_Y); - _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Z", Vector3::AXIS_Z); - _VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_X", Vector3::AXIS_X); _VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_Y", Vector3::AXIS_Y); _VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_Z", Vector3::AXIS_Z); @@ -2685,32 +2710,19 @@ static void _register_variant_builtin_constants() { _VariantCall::add_variant_constant(Variant::VECTOR3, "MODEL_FRONT", Vector3(0, 0, 1)); _VariantCall::add_variant_constant(Variant::VECTOR3, "MODEL_REAR", Vector3(0, 0, -1)); - _VariantCall::add_constant(Variant::VECTOR4, "AXIS_X", Vector4::AXIS_X); - _VariantCall::add_constant(Variant::VECTOR4, "AXIS_Y", Vector4::AXIS_Y); - _VariantCall::add_constant(Variant::VECTOR4, "AXIS_Z", Vector4::AXIS_Z); - _VariantCall::add_constant(Variant::VECTOR4, "AXIS_W", Vector4::AXIS_W); - _VariantCall::add_enum_constant(Variant::VECTOR4, "Axis", "AXIS_X", Vector4::AXIS_X); _VariantCall::add_enum_constant(Variant::VECTOR4, "Axis", "AXIS_Y", Vector4::AXIS_Y); _VariantCall::add_enum_constant(Variant::VECTOR4, "Axis", "AXIS_Z", Vector4::AXIS_Z); _VariantCall::add_enum_constant(Variant::VECTOR4, "Axis", "AXIS_W", Vector4::AXIS_W); + _VariantCall::add_variant_constant(Variant::VECTOR4, "ZERO", Vector4(0, 0, 0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR4, "ONE", Vector4(1, 1, 1, 1)); _VariantCall::add_variant_constant(Variant::VECTOR4, "INF", Vector4(INFINITY, INFINITY, INFINITY, INFINITY)); - _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_X", Vector3i::AXIS_X); - _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3i::AXIS_Y); - _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Z", Vector3i::AXIS_Z); - _VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_X", Vector3i::AXIS_X); _VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_Y", Vector3i::AXIS_Y); _VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_Z", Vector3i::AXIS_Z); - _VariantCall::add_constant(Variant::VECTOR4I, "AXIS_X", Vector4i::AXIS_X); - _VariantCall::add_constant(Variant::VECTOR4I, "AXIS_Y", Vector4i::AXIS_Y); - _VariantCall::add_constant(Variant::VECTOR4I, "AXIS_Z", Vector4i::AXIS_Z); - _VariantCall::add_constant(Variant::VECTOR4I, "AXIS_W", Vector4i::AXIS_W); - _VariantCall::add_enum_constant(Variant::VECTOR4I, "Axis", "AXIS_X", Vector4i::AXIS_X); _VariantCall::add_enum_constant(Variant::VECTOR4I, "Axis", "AXIS_Y", Vector4i::AXIS_Y); _VariantCall::add_enum_constant(Variant::VECTOR4I, "Axis", "AXIS_Z", Vector4i::AXIS_Z); @@ -2732,15 +2744,9 @@ static void _register_variant_builtin_constants() { _VariantCall::add_variant_constant(Variant::VECTOR3I, "FORWARD", Vector3i(0, 0, -1)); _VariantCall::add_variant_constant(Variant::VECTOR3I, "BACK", Vector3i(0, 0, 1)); - _VariantCall::add_constant(Variant::VECTOR2, "AXIS_X", Vector2::AXIS_X); - _VariantCall::add_constant(Variant::VECTOR2, "AXIS_Y", Vector2::AXIS_Y); - _VariantCall::add_enum_constant(Variant::VECTOR2, "Axis", "AXIS_X", Vector2::AXIS_X); _VariantCall::add_enum_constant(Variant::VECTOR2, "Axis", "AXIS_Y", Vector2::AXIS_Y); - _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_X", Vector2i::AXIS_X); - _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_Y", Vector2i::AXIS_Y); - _VariantCall::add_enum_constant(Variant::VECTOR2I, "Axis", "AXIS_X", Vector2i::AXIS_X); _VariantCall::add_enum_constant(Variant::VECTOR2I, "Axis", "AXIS_Y", Vector2i::AXIS_Y); @@ -2789,13 +2795,6 @@ static void _register_variant_builtin_constants() { _VariantCall::add_variant_constant(Variant::QUATERNION, "IDENTITY", Quaternion(0, 0, 0, 1)); - _VariantCall::add_constant(Variant::PROJECTION, "PLANE_NEAR", Projection::PLANE_NEAR); - _VariantCall::add_constant(Variant::PROJECTION, "PLANE_FAR", Projection::PLANE_FAR); - _VariantCall::add_constant(Variant::PROJECTION, "PLANE_LEFT", Projection::PLANE_LEFT); - _VariantCall::add_constant(Variant::PROJECTION, "PLANE_TOP", Projection::PLANE_TOP); - _VariantCall::add_constant(Variant::PROJECTION, "PLANE_RIGHT", Projection::PLANE_RIGHT); - _VariantCall::add_constant(Variant::PROJECTION, "PLANE_BOTTOM", Projection::PLANE_BOTTOM); - _VariantCall::add_enum_constant(Variant::PROJECTION, "Planes", "PLANE_NEAR", Projection::PLANE_NEAR); _VariantCall::add_enum_constant(Variant::PROJECTION, "Planes", "PLANE_FAR", Projection::PLANE_FAR); _VariantCall::add_enum_constant(Variant::PROJECTION, "Planes", "PLANE_LEFT", Projection::PLANE_LEFT); diff --git a/doc/classes/Projection.xml b/doc/classes/Projection.xml index f781083abfc..091e0bf54f4 100644 --- a/doc/classes/Projection.xml +++ b/doc/classes/Projection.xml @@ -278,22 +278,22 @@ - + The index value of the projection's near clipping plane. - + The index value of the projection's far clipping plane. - + The index value of the projection's left clipping plane. - + The index value of the projection's top clipping plane. - + The index value of the projection's right clipping plane. - + The index value of the projection bottom clipping plane. diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index 78183ae36ce..c03262bb33b 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -424,10 +424,10 @@ - + Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index]. diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml index 4afc62e0387..53c7c92ca38 100644 --- a/doc/classes/Vector2i.xml +++ b/doc/classes/Vector2i.xml @@ -170,10 +170,10 @@ - + Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index]. diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index c04fcd0b24d..4ab3140eb63 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -421,13 +421,13 @@ - + Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the Z axis. Returned by [method max_axis_index] and [method min_axis_index]. diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml index df4624dbb10..7fe469aec07 100644 --- a/doc/classes/Vector3i.xml +++ b/doc/classes/Vector3i.xml @@ -168,13 +168,13 @@ - + Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the Z axis. Returned by [method max_axis_index] and [method min_axis_index]. diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml index f70c59fbeff..8fa17b57e6c 100644 --- a/doc/classes/Vector4.xml +++ b/doc/classes/Vector4.xml @@ -287,16 +287,16 @@ - + Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the Z axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the W axis. Returned by [method max_axis_index] and [method min_axis_index]. diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml index b351f2ccb61..e1d65eb1b55 100644 --- a/doc/classes/Vector4i.xml +++ b/doc/classes/Vector4i.xml @@ -169,16 +169,16 @@ - + Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the Z axis. Returned by [method max_axis_index] and [method min_axis_index]. - + Enumerated value for the W axis. Returned by [method max_axis_index] and [method min_axis_index]. diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index e1a6aa4a98a..38e3edef2f1 100755 --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -1555,9 +1555,7 @@ def make_enum(t: str, is_bitfield: bool, state: State) -> str: else: return f":ref:`{e}`" - # Don't fail for `Vector3.Axis`, as this enum is a special case which is expected not to be resolved. - if f"{c}.{e}" != "Vector3.Axis": - print_error(f'{state.current_class}.xml: Unresolved enum "{t}".', state) + print_error(f'{state.current_class}.xml: Unresolved enum "{t}".', state) return t diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 79e0c7ebd1b..842c4acce06 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -908,6 +908,23 @@ void DocTools::generate(BitField p_flags) { c.properties.sort(); + List enums; + Variant::get_enums_for_type(Variant::Type(i), &enums); + + for (const StringName &E : enums) { + List enumerations; + Variant::get_enumerations_for_enum(Variant::Type(i), E, &enumerations); + + for (const StringName &F : enumerations) { + DocData::ConstantDoc constant; + constant.name = F; + constant.value = itos(Variant::get_enum_value(Variant::Type(i), E, F)); + constant.is_value_valid = true; + constant.enumeration = E; + c.constants.push_back(constant); + } + } + List constants; Variant::get_constants_for_type(Variant::Type(i), &constants); diff --git a/misc/extension_api_validation/4.3-stable.expected b/misc/extension_api_validation/4.3-stable.expected index 3d862b10c15..506844e6d63 100644 --- a/misc/extension_api_validation/4.3-stable.expected +++ b/misc/extension_api_validation/4.3-stable.expected @@ -129,3 +129,33 @@ GH-98972 Validate extension JSON: Error: Field 'classes/TranslationServer/methods/standardize_locale/arguments': size changed value in new API, from 1 to 2. Optional argument added. Compatibility method registered. + + +GH-99424 +-------- +Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_BOTTOM +Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_FAR +Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_LEFT +Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_NEAR +Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_RIGHT +Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_TOP +Validate extension JSON: API was removed: builtin_classes/Vector2/constants/AXIS_X +Validate extension JSON: API was removed: builtin_classes/Vector2/constants/AXIS_Y +Validate extension JSON: API was removed: builtin_classes/Vector2i/constants/AXIS_X +Validate extension JSON: API was removed: builtin_classes/Vector2i/constants/AXIS_Y +Validate extension JSON: API was removed: builtin_classes/Vector3/constants/AXIS_X +Validate extension JSON: API was removed: builtin_classes/Vector3/constants/AXIS_Y +Validate extension JSON: API was removed: builtin_classes/Vector3/constants/AXIS_Z +Validate extension JSON: API was removed: builtin_classes/Vector3i/constants/AXIS_X +Validate extension JSON: API was removed: builtin_classes/Vector3i/constants/AXIS_Y +Validate extension JSON: API was removed: builtin_classes/Vector3i/constants/AXIS_Z +Validate extension JSON: API was removed: builtin_classes/Vector4/constants/AXIS_W +Validate extension JSON: API was removed: builtin_classes/Vector4/constants/AXIS_X +Validate extension JSON: API was removed: builtin_classes/Vector4/constants/AXIS_Y +Validate extension JSON: API was removed: builtin_classes/Vector4/constants/AXIS_Z +Validate extension JSON: API was removed: builtin_classes/Vector4i/constants/AXIS_W +Validate extension JSON: API was removed: builtin_classes/Vector4i/constants/AXIS_X +Validate extension JSON: API was removed: builtin_classes/Vector4i/constants/AXIS_Y +Validate extension JSON: API was removed: builtin_classes/Vector4i/constants/AXIS_Z + +These constants have been replaced with corresponding enum constants. diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 6241ada06a1..af92450835d 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -169,7 +169,9 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_enum_n GDScriptParser::DataType type = make_enum_type(p_enum_name, native_base, p_meta); if (p_meta) { - type.builtin_type = Variant::NIL; // Native enum types are not Dictionaries. + // Native enum types are not dictionaries. + type.builtin_type = Variant::NIL; + type.is_pseudo_type = true; } List enum_values; @@ -182,10 +184,29 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_enum_n return type; } +static GDScriptParser::DataType make_builtin_enum_type(const StringName &p_enum_name, Variant::Type p_type, bool p_meta = true) { + GDScriptParser::DataType type = make_enum_type(p_enum_name, Variant::get_type_name(p_type), p_meta); + if (p_meta) { + // Built-in enum types are not dictionaries. + type.builtin_type = Variant::NIL; + type.is_pseudo_type = true; + } + + List enum_values; + Variant::get_enumerations_for_enum(p_type, p_enum_name, &enum_values); + + for (const StringName &E : enum_values) { + type.enum_values[E] = Variant::get_enum_value(p_type, p_enum_name, E); + } + + return type; +} + static GDScriptParser::DataType make_global_enum_type(const StringName &p_enum_name, const StringName &p_base, bool p_meta = true) { GDScriptParser::DataType type = make_enum_type(p_enum_name, p_base, p_meta); if (p_meta) { - type.builtin_type = Variant::NIL; // Native enum types are not Dictionaries. + // Global enum types are not dictionaries. + type.builtin_type = Variant::NIL; type.is_pseudo_type = true; } @@ -703,8 +724,8 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type if (first == SNAME("Variant")) { if (p_type->type_chain.size() == 2) { // May be nested enum. - StringName enum_name = p_type->type_chain[1]->name; - StringName qualified_name = String(first) + ENUM_SEPARATOR + String(p_type->type_chain[1]->name); + const StringName enum_name = p_type->type_chain[1]->name; + const StringName qualified_name = String(first) + ENUM_SEPARATOR + String(p_type->type_chain[1]->name); if (CoreConstants::is_global_enum(qualified_name)) { result = make_global_enum_type(enum_name, first, true); return result; @@ -719,21 +740,34 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type result.kind = GDScriptParser::DataType::VARIANT; } else if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) { // Built-in types. - if (p_type->type_chain.size() > 1) { - push_error(R"(Built-in types don't contain nested types.)", p_type->type_chain[1]); + const Variant::Type builtin_type = GDScriptParser::get_builtin_type(first); + + if (p_type->type_chain.size() == 2) { + // May be nested enum. + const StringName enum_name = p_type->type_chain[1]->name; + if (Variant::has_enum(builtin_type, enum_name)) { + result = make_builtin_enum_type(enum_name, builtin_type, true); + return result; + } else { + push_error(vformat(R"(Name "%s" is not a nested type of "%s".)", enum_name, first), p_type->type_chain[1]); + return bad_type; + } + } else if (p_type->type_chain.size() > 2) { + push_error(R"(Built-in types only contain enum types, which do not have nested types.)", p_type->type_chain[2]); return bad_type; } + result.kind = GDScriptParser::DataType::BUILTIN; - result.builtin_type = GDScriptParser::get_builtin_type(first); + result.builtin_type = builtin_type; - if (result.builtin_type == Variant::ARRAY) { + if (builtin_type == Variant::ARRAY) { GDScriptParser::DataType container_type = type_from_metatype(resolve_datatype(p_type->get_container_type_or_null(0))); if (container_type.kind != GDScriptParser::DataType::VARIANT) { container_type.is_constant = false; result.set_container_element_type(0, container_type); } } - if (result.builtin_type == Variant::DICTIONARY) { + if (builtin_type == Variant::DICTIONARY) { GDScriptParser::DataType key_type = type_from_metatype(resolve_datatype(p_type->get_container_type_or_null(0))); if (key_type.kind != GDScriptParser::DataType::VARIANT) { key_type.is_constant = false; @@ -3970,13 +4004,36 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod if (base.kind == GDScriptParser::DataType::BUILTIN) { if (base.is_meta_type) { - bool valid = true; - Variant result = Variant::get_constant_value(base.builtin_type, name, &valid); - if (valid) { + bool valid = false; + + if (Variant::has_constant(base.builtin_type, name)) { + valid = true; + + const Variant constant_value = Variant::get_constant_value(base.builtin_type, name); + p_identifier->is_constant = true; - p_identifier->reduced_value = result; - p_identifier->set_datatype(type_from_variant(result, p_identifier)); - } else if (base.is_hard_type()) { + p_identifier->reduced_value = constant_value; + p_identifier->set_datatype(type_from_variant(constant_value, p_identifier)); + } + + if (!valid) { + const StringName enum_name = Variant::get_enum_for_enumeration(base.builtin_type, name); + if (enum_name != StringName()) { + valid = true; + + p_identifier->is_constant = true; + p_identifier->reduced_value = Variant::get_enum_value(base.builtin_type, enum_name, name); + p_identifier->set_datatype(make_builtin_enum_type(enum_name, base.builtin_type, false)); + } + } + + if (!valid && Variant::has_enum(base.builtin_type, name)) { + valid = true; + + p_identifier->set_datatype(make_builtin_enum_type(name, base.builtin_type, true)); + } + + if (!valid && base.is_hard_type()) { #ifdef SUGGEST_GODOT4_RENAMES String rename_hint; if (GLOBAL_GET(GDScriptWarning::get_settings_path_from_code(GDScriptWarning::RENAMED_IN_GODOT_4_HINT)).booleanize()) { @@ -3985,9 +4042,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod rename_hint = " " + vformat(R"(Did you mean to use "%s"?)", renamed_identifier_name); } } - push_error(vformat(R"(Cannot find constant "%s" on base "%s".%s)", name, base.to_string(), rename_hint), p_identifier); + push_error(vformat(R"(Cannot find member "%s" in base "%s".%s)", name, base.to_string(), rename_hint), p_identifier); #else - push_error(vformat(R"(Cannot find constant "%s" on base "%s".)", name, base.to_string()), p_identifier); + push_error(vformat(R"(Cannot find member "%s" in base "%s".)", name, base.to_string()), p_identifier); #endif // SUGGEST_GODOT4_RENAMES } } else { @@ -4029,9 +4086,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod rename_hint = " " + vformat(R"(Did you mean to use "%s"?)", renamed_identifier_name); } } - push_error(vformat(R"(Cannot find property "%s" on base "%s".%s)", name, base.to_string(), rename_hint), p_identifier); + push_error(vformat(R"(Cannot find member "%s" in base "%s".%s)", name, base.to_string(), rename_hint), p_identifier); #else - push_error(vformat(R"(Cannot find property "%s" on base "%s".)", name, base.to_string()), p_identifier); + push_error(vformat(R"(Cannot find member "%s" in base "%s".)", name, base.to_string()), p_identifier); #endif // SUGGEST_GODOT4_RENAMES } } @@ -5572,7 +5629,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo } else { Vector names = String(p_property.class_name).split(ENUM_SEPARATOR); if (names.size() == 2) { - result = make_native_enum_type(names[1], names[0], false); + result = make_enum_type(names[1], names[0], false); result.is_constant = false; } } diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd new file mode 100644 index 00000000000..6367d50980b --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd @@ -0,0 +1,2 @@ +func test(): + print(Vector3.Axis) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out new file mode 100644 index 00000000000..9c476031f36 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Type "Axis" in base "Vector3" cannot be used on its own. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd new file mode 100644 index 00000000000..badcd3a83cf --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd @@ -0,0 +1,2 @@ +func test(): + print(Variant.Operator) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out new file mode 100644 index 00000000000..191acade730 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Type "Operator" in base "Variant" cannot be used on its own. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd new file mode 100644 index 00000000000..e07998ddf65 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd @@ -0,0 +1,2 @@ +func test(): + print(Node.ProcessMode) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out new file mode 100644 index 00000000000..83671fc493a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Type "ProcessMode" in base "Node" cannot be used on its own. diff --git a/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd new file mode 100644 index 00000000000..4ccd7de994f --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd @@ -0,0 +1,28 @@ +extends Node + +@export var test_type_1 := TYPE_BOOL +@export var test_type_2 := Variant.Type.TYPE_BOOL +@export var test_type_3: Variant.Type + +@export var test_side_1 := SIDE_RIGHT +@export var test_side_2 := Side.SIDE_RIGHT +@export var test_side_3: Side + +@export var test_axis_1 := Vector3.AXIS_Y +@export var test_axis_2 := Vector3.Axis.AXIS_Y +@export var test_axis_3: Vector3.Axis + +@export var test_mode_1 := Node.PROCESS_MODE_ALWAYS +@export var test_mode_2 := Node.ProcessMode.PROCESS_MODE_ALWAYS +@export var test_mode_3: Node.ProcessMode + +func test(): + for property in get_property_list(): + if str(property.name).begins_with("test_"): + Utils.print_property_extended_info(property, self) + +func test_no_exec(): + # GH-99309 + var sprite: Sprite3D = $Sprite3D + sprite.axis = Vector3.AXIS_Y # No warning. + sprite.set_axis(Vector3.AXIS_Y) # No warning. diff --git a/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out new file mode 100644 index 00000000000..6c45dee3232 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out @@ -0,0 +1,25 @@ +GDTEST_OK +var test_type_1: Variant.Type = 1 + hint=ENUM hint_string="Type Nil:0,Type Bool:1,Type Int:2,Type Float:3,Type String:4,Type Vector 2:5,Type Vector 2i:6,Type Rect 2:7,Type Rect 2i:8,Type Vector 3:9,Type Vector 3i:10,Type Transform 2d:11,Type Vector 4:12,Type Vector 4i:13,Type Plane:14,Type Quaternion:15,Type Aabb:16,Type Basis:17,Type Transform 3d:18,Type Projection:19,Type Color:20,Type String Name:21,Type Node Path:22,Type Rid:23,Type Object:24,Type Callable:25,Type Signal:26,Type Dictionary:27,Type Array:28,Type Packed Byte Array:29,Type Packed Int 32 Array:30,Type Packed Int 64 Array:31,Type Packed Float 32 Array:32,Type Packed Float 64 Array:33,Type Packed String Array:34,Type Packed Vector 2 Array:35,Type Packed Vector 3 Array:36,Type Packed Color Array:37,Type Packed Vector 4 Array:38,Type Max:39" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Variant.Type" +var test_type_2: Variant.Type = 1 + hint=ENUM hint_string="Type Nil:0,Type Bool:1,Type Int:2,Type Float:3,Type String:4,Type Vector 2:5,Type Vector 2i:6,Type Rect 2:7,Type Rect 2i:8,Type Vector 3:9,Type Vector 3i:10,Type Transform 2d:11,Type Vector 4:12,Type Vector 4i:13,Type Plane:14,Type Quaternion:15,Type Aabb:16,Type Basis:17,Type Transform 3d:18,Type Projection:19,Type Color:20,Type String Name:21,Type Node Path:22,Type Rid:23,Type Object:24,Type Callable:25,Type Signal:26,Type Dictionary:27,Type Array:28,Type Packed Byte Array:29,Type Packed Int 32 Array:30,Type Packed Int 64 Array:31,Type Packed Float 32 Array:32,Type Packed Float 64 Array:33,Type Packed String Array:34,Type Packed Vector 2 Array:35,Type Packed Vector 3 Array:36,Type Packed Color Array:37,Type Packed Vector 4 Array:38,Type Max:39" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Variant.Type" +var test_type_3: Variant.Type = 0 + hint=ENUM hint_string="Type Nil:0,Type Bool:1,Type Int:2,Type Float:3,Type String:4,Type Vector 2:5,Type Vector 2i:6,Type Rect 2:7,Type Rect 2i:8,Type Vector 3:9,Type Vector 3i:10,Type Transform 2d:11,Type Vector 4:12,Type Vector 4i:13,Type Plane:14,Type Quaternion:15,Type Aabb:16,Type Basis:17,Type Transform 3d:18,Type Projection:19,Type Color:20,Type String Name:21,Type Node Path:22,Type Rid:23,Type Object:24,Type Callable:25,Type Signal:26,Type Dictionary:27,Type Array:28,Type Packed Byte Array:29,Type Packed Int 32 Array:30,Type Packed Int 64 Array:31,Type Packed Float 32 Array:32,Type Packed Float 64 Array:33,Type Packed String Array:34,Type Packed Vector 2 Array:35,Type Packed Vector 3 Array:36,Type Packed Color Array:37,Type Packed Vector 4 Array:38,Type Max:39" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Variant.Type" +var test_side_1: Side = 2 + hint=ENUM hint_string="Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Side" +var test_side_2: Side = 2 + hint=ENUM hint_string="Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Side" +var test_side_3: Side = 0 + hint=ENUM hint_string="Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Side" +var test_axis_1: Vector3.Axis = 1 + hint=ENUM hint_string="Axis X:0,Axis Y:1,Axis Z:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Vector3.Axis" +var test_axis_2: Vector3.Axis = 1 + hint=ENUM hint_string="Axis X:0,Axis Y:1,Axis Z:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Vector3.Axis" +var test_axis_3: Vector3.Axis = 0 + hint=ENUM hint_string="Axis X:0,Axis Y:1,Axis Z:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Vector3.Axis" +var test_mode_1: Node.ProcessMode = 3 + hint=ENUM hint_string="Process Mode Inherit:0,Process Mode Pausable:1,Process Mode When Paused:2,Process Mode Always:3,Process Mode Disabled:4" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Node.ProcessMode" +var test_mode_2: Node.ProcessMode = 3 + hint=ENUM hint_string="Process Mode Inherit:0,Process Mode Pausable:1,Process Mode When Paused:2,Process Mode Always:3,Process Mode Disabled:4" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Node.ProcessMode" +var test_mode_3: Node.ProcessMode = 0 + hint=ENUM hint_string="Process Mode Inherit:0,Process Mode Pausable:1,Process Mode When Paused:2,Process Mode Always:3,Process Mode Disabled:4" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Node.ProcessMode" diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index c54d58d6a01..d0797282dea 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -5040,22 +5040,25 @@ void BindingsGenerator::_populate_global_constants() { } } - // HARDCODED - List hardcoded_enums; - hardcoded_enums.push_back("Vector2.Axis"); - hardcoded_enums.push_back("Vector2I.Axis"); - hardcoded_enums.push_back("Vector3.Axis"); - hardcoded_enums.push_back("Vector3I.Axis"); - for (const StringName &enum_cname : hardcoded_enums) { - // These enums are not generated and must be written manually (e.g.: Vector3.Axis) - // Here, we assume core types do not begin with underscore - TypeInterface enum_itype; - enum_itype.is_enum = true; - enum_itype.name = enum_cname.operator String(); - enum_itype.cname = enum_cname; - enum_itype.proxy_name = pascal_to_pascal_case(enum_itype.name); - TypeInterface::postsetup_enum_type(enum_itype); - enum_types.insert(enum_itype.cname, enum_itype); + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (i == Variant::OBJECT) { + continue; + } + + const Variant::Type type = Variant::Type(i); + + List enum_names; + Variant::get_enums_for_type(type, &enum_names); + + for (const StringName &enum_name : enum_names) { + TypeInterface enum_itype; + enum_itype.is_enum = true; + enum_itype.name = Variant::get_type_name(type) + "." + enum_name; + enum_itype.cname = enum_itype.name; + enum_itype.proxy_name = pascal_to_pascal_case(enum_itype.name); + TypeInterface::postsetup_enum_type(enum_itype); + enum_types.insert(enum_itype.cname, enum_itype); + } } } diff --git a/tests/core/object/test_class_db.h b/tests/core/object/test_class_db.h index 924e93129dc..b38d3d3e614 100644 --- a/tests/core/object/test_class_db.h +++ b/tests/core/object/test_class_db.h @@ -863,16 +863,19 @@ void add_global_enums(Context &r_context) { } } - // HARDCODED - List hardcoded_enums; - hardcoded_enums.push_back("Vector2.Axis"); - hardcoded_enums.push_back("Vector2i.Axis"); - hardcoded_enums.push_back("Vector3.Axis"); - hardcoded_enums.push_back("Vector3i.Axis"); - for (const StringName &E : hardcoded_enums) { - // These enums are not generated and must be written manually (e.g.: Vector3.Axis) - // Here, we assume core types do not begin with underscore - r_context.enum_types.push_back(E); + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (i == Variant::OBJECT) { + continue; + } + + const Variant::Type type = Variant::Type(i); + + List enum_names; + Variant::get_enums_for_type(type, &enum_names); + + for (const StringName &enum_name : enum_names) { + r_context.enum_types.push_back(Variant::get_type_name(type) + "." + enum_name); + } } } From e1fa489f77db7c022c197434e001b76d2835526d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Guedes?= Date: Fri, 22 Nov 2024 12:40:04 +0100 Subject: [PATCH 47/59] Fix wording in LookAtModifier3D docs --- doc/classes/LookAtModifier3D.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/classes/LookAtModifier3D.xml b/doc/classes/LookAtModifier3D.xml index e85da06c3af..b6d106c4c5c 100644 --- a/doc/classes/LookAtModifier3D.xml +++ b/doc/classes/LookAtModifier3D.xml @@ -1,10 +1,10 @@ - The [SkeletonModifier3D] rotates a bone to look a target. + The [LookAtModifier3D] rotates a bone to look at a target. - 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. From bead829fd5d40aa86ff5372b2edff6924bbe01fe Mon Sep 17 00:00:00 2001 From: jtcat Date: Fri, 22 Nov 2024 14:59:40 +0000 Subject: [PATCH 48/59] Fix inspector section iteration in `update_tree` --- editor/editor_inspector.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 6b3c6b462d1..6e837560f6b 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -3648,8 +3648,6 @@ void EditorInspector::update_tree() { for (List::Element *I = sections.back(); I; I = I->prev()) { EditorInspectorSection *section = I->get(); if (section->get_vbox()->get_child_count() == 0) { - I = I->prev(); - sections.erase(section); vbox_per_path[main_vbox].erase(section->get_section()); memdelete(section); From e8a4b45ce4adcbafb78048b207a87f453543fa93 Mon Sep 17 00:00:00 2001 From: Thaddeus Crews Date: Fri, 22 Nov 2024 09:22:15 -0600 Subject: [PATCH 49/59] Style: Add 19.1.0 LLVM options to `.clang-format` --- .clang-format | 43 +++++++++++++++---- core/math/bvh_logic.inc | 1 - core/math/bvh_misc.inc | 1 - core/math/bvh_structs.inc | 1 - .../gles3/shaders/canvas_uniforms_inc.glsl | 1 - misc/utility/.clang-format-glsl | 5 ++- .../CrossPlatformSettings_piece_all.glsl | 1 - modules/betsy/UavCrossPlatform_piece_all.glsl | 1 - modules/lightmapper_rd/lm_common_inc.glsl | 1 - .../shaders/canvas_uniforms_inc.glsl | 1 - .../renderer_rd/shaders/decal_data_inc.glsl | 1 - .../effects/luminance_reduce_raster_inc.glsl | 1 - 12 files changed, 39 insertions(+), 19 deletions(-) diff --git a/.clang-format b/.clang-format index 338ce6b7f39..a6822dc2cdd 100644 --- a/.clang-format +++ b/.clang-format @@ -1,6 +1,6 @@ # Commented out parameters are those with the same value as base LLVM style. # We can uncomment them if we want to change their value, or enforce the -# chosen value in case the base style changes (last sync: Clang 18.1.8). +# chosen value in case the base style changes (last sync: Clang 19.1.0). BasedOnStyle: LLVM AccessModifierOffset: -4 AlignAfterOpenBracket: DontAlign @@ -37,7 +37,29 @@ AlignAfterOpenBracket: DontAlign # Enabled: false # AcrossEmptyLines: false # AcrossComments: false +# AlignCaseArrows: false # AlignCaseColons: false +# AlignConsecutiveTableGenBreakingDAGArgColons: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionPointers: false +# PadOperators: false +# AlignConsecutiveTableGenCondOperatorColons: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionPointers: false +# PadOperators: false +# AlignConsecutiveTableGenDefinitionColons: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionPointers: false +# PadOperators: false # AlignEscapedNewlines: Right AlignOperands: DontAlign AlignTrailingComments: @@ -47,6 +69,7 @@ AlignTrailingComments: AllowAllParametersOfDeclarationOnNextLine: false # AllowBreakBeforeNoexceptSpecifier: Never # AllowShortBlocksOnASingleLine: Never +# AllowShortCaseExpressionOnASingleLine: true # AllowShortCaseLabelsOnASingleLine: false # AllowShortCompoundRequirementOnASingleLine: true # AllowShortEnumsOnASingleLine: true @@ -54,9 +77,7 @@ AllowAllParametersOfDeclarationOnNextLine: false # AllowShortIfStatementsOnASingleLine: Never # AllowShortLambdasOnASingleLine: All # AllowShortLoopsOnASingleLine: false -# AlwaysBreakAfterReturnType: None # AlwaysBreakBeforeMultilineStrings: false -# AlwaysBreakTemplateDeclarations: MultiLine # AttributeMacros: # - __capability # BinPackArguments: true @@ -84,6 +105,7 @@ AllowAllParametersOfDeclarationOnNextLine: false # BreakAdjacentStringLiterals: true # BreakAfterAttributes: Leave # BreakAfterJavaFieldAnnotations: false +# BreakAfterReturnType: None # BreakArrays: true # BreakBeforeBinaryOperators: None # BreakBeforeBraces: Attach @@ -91,8 +113,10 @@ AllowAllParametersOfDeclarationOnNextLine: false # BreakBeforeInlineASMColon: OnlyMultiline # BreakBeforeTernaryOperators: true BreakConstructorInitializers: AfterColon +# BreakFunctionDefinitionParameters: false # BreakInheritanceList: BeforeColon # BreakStringLiterals: true +# BreakTemplateDeclarations: MultiLine ColumnLimit: 0 # CommentPragmas: '^ IWYU pragma:' # CompactNamespaces: false @@ -150,13 +174,16 @@ JavaImportGroups: - javax # JavaScriptQuotes: Leave # JavaScriptWrapImports: true -# KeepEmptyLinesAtEOF: false -KeepEmptyLinesAtTheStartOfBlocks: false +KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: false + AtStartOfFile: false # LambdaBodyIndentation: Signature # Language: Cpp # LineEnding: DeriveLF # MacroBlockBegin: '' # MacroBlockEnd: '' +# MainIncludeChar: Quote # MaxEmptyLinesToKeep: 1 # NamespaceIndentation: None # ObjCBinPackProtocolList: Auto @@ -219,13 +246,12 @@ RemoveSemicolon: true # SpacesBeforeTrailingComments: 1 # SpacesInAngles: Never # SpacesInContainerLiterals: true -## Godot TODO: We'll want to use a min of 1, but we need to see how to fix -## our comment capitalization at the same time. SpacesInLineCommentPrefix: - Minimum: 0 + Minimum: 0 # We want a minimum of 1 for comments, but allow 0 for disabled code. Maximum: -1 # SpacesInParens: Never # SpacesInParensOptions: +# ExceptDoubleParentheses: false # InConditionalStatements: false # InCStyleCasts: false # InEmptyParentheses: false @@ -238,6 +264,7 @@ Standard: c++20 # - Q_UNUSED # - QT_REQUIRE_VERSION TabWidth: 4 +# TableGenBreakInsideDAGArg: DontBreak UseTab: Always # VerilogBreakBetweenInstancePorts: true # WhitespaceSensitiveMacros: diff --git a/core/math/bvh_logic.inc b/core/math/bvh_logic.inc index dd3b135bb56..aaa91bc9d30 100644 --- a/core/math/bvh_logic.inc +++ b/core/math/bvh_logic.inc @@ -1,4 +1,3 @@ - // for slow incremental optimization, we will periodically remove each // item from the tree and reinsert, to give it a chance to find a better position void _logic_item_remove_and_reinsert(uint32_t p_ref_id) { diff --git a/core/math/bvh_misc.inc b/core/math/bvh_misc.inc index 9b35a1d36dc..ef1261a7597 100644 --- a/core/math/bvh_misc.inc +++ b/core/math/bvh_misc.inc @@ -1,4 +1,3 @@ - int _handle_get_tree_id(BVHHandle p_handle) const { if (USE_PAIRS) { return _extra[p_handle.id()].tree_id; diff --git a/core/math/bvh_structs.inc b/core/math/bvh_structs.inc index d40c631ce22..6326cd63ef3 100644 --- a/core/math/bvh_structs.inc +++ b/core/math/bvh_structs.inc @@ -1,4 +1,3 @@ - public: struct ItemRef { uint32_t tnode_id; // -1 is invalid diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl index f6ad2b730ab..d98cbdac544 100644 --- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl +++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl @@ -1,4 +1,3 @@ - #define MAX_LIGHTS_PER_ITEM uint(16) #define M_PI 3.14159265359 diff --git a/misc/utility/.clang-format-glsl b/misc/utility/.clang-format-glsl index 59efa8fa353..c588df0236c 100644 --- a/misc/utility/.clang-format-glsl +++ b/misc/utility/.clang-format-glsl @@ -30,7 +30,10 @@ JavaImportGroups: - com.google - java - javax -KeepEmptyLinesAtTheStartOfBlocks: false +KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: false + AtStartOfFile: false ObjCBlockIndentWidth: 4 PackConstructorInitializers: NextLine RemoveSemicolon: false # Differs from base .clang-format diff --git a/modules/betsy/CrossPlatformSettings_piece_all.glsl b/modules/betsy/CrossPlatformSettings_piece_all.glsl index b7abac7fcc4..001d8e63b23 100644 --- a/modules/betsy/CrossPlatformSettings_piece_all.glsl +++ b/modules/betsy/CrossPlatformSettings_piece_all.glsl @@ -1,4 +1,3 @@ - #define min3(a, b, c) min(a, min(b, c)) #define max3(a, b, c) max(a, max(b, c)) diff --git a/modules/betsy/UavCrossPlatform_piece_all.glsl b/modules/betsy/UavCrossPlatform_piece_all.glsl index 30854df637c..5f074137af9 100644 --- a/modules/betsy/UavCrossPlatform_piece_all.glsl +++ b/modules/betsy/UavCrossPlatform_piece_all.glsl @@ -1,4 +1,3 @@ - #define OGRE_imageLoad2D(inImage, iuv) imageLoad(inImage, int2(iuv)) #define OGRE_imageLoad2DArray(inImage, iuvw) imageLoad(inImage, int3(iuvw)) diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl index 98d11b9e69e..962e4449115 100644 --- a/modules/lightmapper_rd/lm_common_inc.glsl +++ b/modules/lightmapper_rd/lm_common_inc.glsl @@ -1,4 +1,3 @@ - /* SET 0, static data that does not change between any call */ layout(set = 0, binding = 0) uniform BakeParameters { diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index 84017a1fe19..59e0bdfe99b 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl @@ -1,4 +1,3 @@ - #define MAX_LIGHTS_PER_ITEM 16 #define M_PI 3.14159265359 diff --git a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl index 158096d3c7f..3d6eaab8e1a 100644 --- a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl @@ -1,4 +1,3 @@ - struct DecalData { highp mat4 xform; //to decal transform highp vec3 inv_extents; diff --git a/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster_inc.glsl index b8860f65187..fc45b1f8276 100644 --- a/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster_inc.glsl @@ -1,4 +1,3 @@ - layout(push_constant, std430) uniform PushConstant { ivec2 source_size; ivec2 dest_size; From 250de088e3a0f303a393405ebdaa40c7dce62550 Mon Sep 17 00:00:00 2001 From: Michael Alexsander Date: Sun, 15 Sep 2024 19:17:23 -0300 Subject: [PATCH 50/59] Fix `RichTextLabel`'s modified stack being wiped on translation changes --- scene/gui/rich_text_label.cpp | 42 ++++++++++++++++++++++++----------- scene/gui/rich_text_label.h | 3 +++ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index a349d502368..b0886a95d7d 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(BitFieldfirst_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 a01da02b273..ef4d17b8aa3 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -626,6 +626,9 @@ class RichTextLabel : public Control { String text; void _apply_translation(); + bool internal_stack_editing = false; + bool stack_externally_modified = false; + bool fit_content = false; struct ThemeCache { From e0b13004a0f48b61cefdf8e469f6d623c17f1932 Mon Sep 17 00:00:00 2001 From: Micky Date: Sun, 17 Nov 2024 11:53:12 +0100 Subject: [PATCH 51/59] Fix incorrect Z direction for AABB's position --- doc/classes/AABB.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml index ae2de055cb0..57ac241eb22 100644 --- a/doc/classes/AABB.xml +++ b/doc/classes/AABB.xml @@ -345,14 +345,14 @@ - 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]. - 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. 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]. From e210313045cc4de77c654f7cabf4c810c957f3fe Mon Sep 17 00:00:00 2001 From: kobewi Date: Fri, 22 Nov 2024 21:44:27 +0100 Subject: [PATCH 52/59] Fix stringification of Vector4 --- core/math/vector4.cpp | 2 +- .../tests/scripts/runtime/features/stringify.gd | 9 ++++++--- .../tests/scripts/runtime/features/stringify.out | 10 ++++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp index b6b914f36da..8ac2c4bf1f1 100644 --- a/core/math/vector4.cpp +++ b/core/math/vector4.cpp @@ -213,7 +213,7 @@ Vector4 Vector4::clampf(real_t p_min, real_t p_max) const { } Vector4::operator String() const { - return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")"; + return "(" + String::num_real(x, true) + ", " + String::num_real(y, true) + ", " + String::num_real(z, true) + ", " + String::num_real(w, true) + ")"; } static_assert(sizeof(Vector4) == 4 * sizeof(real_t)); diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.gd b/modules/gdscript/tests/scripts/runtime/features/stringify.gd index 8579baf8766..463d207e591 100644 --- a/modules/gdscript/tests/scripts/runtime/features/stringify.gd +++ b/modules/gdscript/tests/scripts/runtime/features/stringify.gd @@ -4,15 +4,18 @@ func test(): print(-1.25, 0.25, 1.25) print("hello world") - print(Vector2(0.25, 0.25)) + print(Vector2(0.25, 1)) print(Vector2i(0, 0)) - print(Rect2(0.25, 0.25, 0.5, 0.5)) + print(Rect2(0.25, 0.25, 0.5, 1)) print(Rect2i(0, 0, 0, 0)) - print(Vector3(0.25, 0.25, 0.25)) + print(Vector3(0.25, 0.25, 1)) print(Vector3i(0, 0, 0)) + print(Vector4(0.25, 0.25, 0.25, 1)) + print(Vector4i(0, 0, 0, 0)) + print(Transform2D.IDENTITY) print(Plane(1, 2, 3, 4)) print(Quaternion(1, 2, 3, 4)) diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.out b/modules/gdscript/tests/scripts/runtime/features/stringify.out index 2463d70ef42..9983366db03 100644 --- a/modules/gdscript/tests/scripts/runtime/features/stringify.out +++ b/modules/gdscript/tests/scripts/runtime/features/stringify.out @@ -3,12 +3,14 @@ truefalse -101 -1.250.251.25 hello world -(0.25, 0.25) +(0.25, 1.0) (0, 0) -[P: (0.25, 0.25), S: (0.5, 0.5)] +[P: (0.25, 0.25), S: (0.5, 1.0)] [P: (0, 0), S: (0, 0)] -(0.25, 0.25, 0.25) +(0.25, 0.25, 1.0) (0, 0, 0) +(0.25, 0.25, 0.25, 1.0) +(0, 0, 0, 0) [X: (1.0, 0.0), Y: (0.0, 1.0), O: (0.0, 0.0)] [N: (1.0, 2.0, 3.0), D: 4] (1, 2, 3, 4) @@ -32,4 +34,4 @@ Node::[signal]property_list_changed [(1.0, 1.0), (0.0, 0.0)] [(1.0, 1.0, 1.0), (0.0, 0.0, 0.0)] [(1.0, 0.0, 0.0, 1.0), (0.0, 0.0, 1.0, 1.0), (0.0, 1.0, 0.0, 1.0)] -[(1, 1, 1, 1), (0, 0, 0, 0)] +[(1.0, 1.0, 1.0, 1.0), (0.0, 0.0, 0.0, 0.0)] From e9b57fce827c8fac5640a8a260dffd8682b660db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?= <7645683+bruvzg@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:26:25 +0200 Subject: [PATCH 53/59] Convert line breaks to `\n` and strip line break from the end of string returned by `OS::read_string_from_stdin`/`OS::get_stdin_string`. --- doc/classes/OS.xml | 1 + drivers/unix/os_unix.cpp | 2 +- platform/windows/os_windows.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 5ab7c27f4f4..2389db1301b 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -721,6 +721,7 @@ - If standard input is console, this method will block until the program receives a line break in standard input (usually by the user pressing [kbd]Enter[/kbd]). - If standard input is pipe, this method will block until a specific amount of data is read or pipe is closed. - If standard input is a file, this method will read a specific amount of data (or less if end-of-file is reached) and return immediately. + [b]Note:[/b] This method automatically replaces [code]\r\n[/code] line breaks with [code]\n[/code] and removes them from the end of the string. Use [method read_buffer_from_stdin] to read the unprocessed data. [b]Note:[/b] This method is implemented on Linux, macOS, and Windows. [b]Note:[/b] On exported Windows builds, run the console wrapper executable to access the terminal. If standard input is console, calling this method without console wrapped will freeze permanently. If standard input is pipe or file, it can be used without console wrapper. If you need a single executable with full console support, use a custom build compiled with the [code]windows_subsystem=console[/code] flag. diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index ffc270cd36e..299ac6536f8 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -191,7 +191,7 @@ String OS_Unix::get_stdin_string(int64_t p_buffer_size) { Vector data; data.resize(p_buffer_size); if (fgets((char *)data.ptrw(), data.size(), stdin)) { - return String::utf8((char *)data.ptr()); + return String::utf8((char *)data.ptr()).replace("\r\n", "\n").rstrip("\n"); } return String(); } diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index a25b7ea4ca7..75b0c9bad9d 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1751,7 +1751,7 @@ String OS_Windows::get_stdin_string(int64_t p_buffer_size) { data.resize(p_buffer_size); DWORD count = 0; if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), data.ptrw(), data.size(), &count, nullptr)) { - return String::utf8((const char *)data.ptr(), count); + return String::utf8((const char *)data.ptr(), count).replace("\r\n", "\n").rstrip("\n"); } return String(); From da191168fe6cd69c6803c7db4804c1c17781409c Mon Sep 17 00:00:00 2001 From: Bad Sector Date: Fri, 22 Nov 2024 21:10:07 +0200 Subject: [PATCH 54/59] Add VoxelGI bake cancelling and progress UI improvement --- editor/plugins/voxel_gi_editor_plugin.cpp | 10 ++-- editor/plugins/voxel_gi_editor_plugin.h | 4 +- scene/3d/voxel_gi.cpp | 49 +++++++++++----- scene/3d/voxel_gi.h | 4 +- scene/3d/voxelizer.cpp | 71 +++++++++++++++++++---- scene/3d/voxelizer.h | 14 ++++- 6 files changed, 116 insertions(+), 36 deletions(-) diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp index 68fe013c089..527138e0608 100644 --- a/editor/plugins/voxel_gi_editor_plugin.cpp +++ b/editor/plugins/voxel_gi_editor_plugin.cpp @@ -146,15 +146,15 @@ void VoxelGIEditorPlugin::make_visible(bool p_visible) { EditorProgress *VoxelGIEditorPlugin::tmp_progress = nullptr; -void VoxelGIEditorPlugin::bake_func_begin(int p_steps) { +void VoxelGIEditorPlugin::bake_func_begin() { ERR_FAIL_COND(tmp_progress != nullptr); - tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake VoxelGI"), p_steps)); + tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake VoxelGI"), 1000, true)); } -void VoxelGIEditorPlugin::bake_func_step(int p_step, const String &p_description) { - ERR_FAIL_NULL(tmp_progress); - tmp_progress->step(p_description, p_step, false); +bool VoxelGIEditorPlugin::bake_func_step(int p_progress, const String &p_description) { + ERR_FAIL_NULL_V(tmp_progress, false); + return tmp_progress->step(p_description, p_progress, false); } void VoxelGIEditorPlugin::bake_func_end() { diff --git a/editor/plugins/voxel_gi_editor_plugin.h b/editor/plugins/voxel_gi_editor_plugin.h index d09822dda61..01a2ab4bd1d 100644 --- a/editor/plugins/voxel_gi_editor_plugin.h +++ b/editor/plugins/voxel_gi_editor_plugin.h @@ -50,8 +50,8 @@ class VoxelGIEditorPlugin : public EditorPlugin { EditorFileDialog *probe_file = nullptr; static EditorProgress *tmp_progress; - static void bake_func_begin(int p_steps); - static void bake_func_step(int p_step, const String &p_description); + static void bake_func_begin(); + static bool bake_func_step(int p_progress, const String &p_description); static void bake_func_end(); void _bake(); diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index 80ff176a98d..5fec7021eb4 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -389,6 +389,17 @@ VoxelGI::BakeBeginFunc VoxelGI::bake_begin_function = nullptr; VoxelGI::BakeStepFunc VoxelGI::bake_step_function = nullptr; VoxelGI::BakeEndFunc VoxelGI::bake_end_function = nullptr; +static int voxelizer_plot_bake_base = 0; +static int voxelizer_plot_bake_total = 0; + +static bool voxelizer_plot_bake_step_function(int current, int) { + return VoxelGI::bake_step_function((voxelizer_plot_bake_base + current) * 500 / voxelizer_plot_bake_total, RTR("Plotting Meshes")); +} + +static bool voxelizer_sdf_bake_step_function(int current, int total) { + return VoxelGI::bake_step_function(500 + current * 500 / total, RTR("Generating Distance Field")); +} + Vector3i VoxelGI::get_estimated_cell_size() const { static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 }; int cell_subdiv = subdiv_value[subdiv]; @@ -432,22 +443,27 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) { _find_meshes(p_from_node, mesh_list); if (bake_begin_function) { - bake_begin_function(mesh_list.size() + 1); + bake_begin_function(); } - int pmc = 0; + Voxelizer::BakeStepFunc voxelizer_step_func = bake_step_function != nullptr ? voxelizer_plot_bake_step_function : nullptr; + voxelizer_plot_bake_total = voxelizer_plot_bake_base = 0; for (PlotMesh &E : mesh_list) { - if (bake_step_function) { - bake_step_function(pmc, RTR("Plotting Meshes") + " " + itos(pmc) + "/" + itos(mesh_list.size())); + voxelizer_plot_bake_total += baker.get_bake_steps(E.mesh); + } + for (PlotMesh &E : mesh_list) { + if (baker.plot_mesh(E.local_xform, E.mesh, E.instance_materials, E.override_material, voxelizer_step_func) != Voxelizer::BAKE_RESULT_OK) { + baker.end_bake(); + if (bake_end_function) { + bake_end_function(); + } + return; } - - pmc++; - - baker.plot_mesh(E.local_xform, E.mesh, E.instance_materials, E.override_material); + voxelizer_plot_bake_base += baker.get_bake_steps(E.mesh); } if (bake_step_function) { - bake_step_function(pmc++, RTR("Finishing Plot")); + bake_step_function(500, RTR("Finishing Plot")); } baker.end_bake(); @@ -476,19 +492,22 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) { } if (bake_step_function) { - bake_step_function(pmc++, RTR("Generating Distance Field")); + bake_step_function(500, RTR("Generating Distance Field")); } - Vector df = baker.get_sdf_3d_image(); + voxelizer_step_func = bake_step_function != nullptr ? voxelizer_sdf_bake_step_function : nullptr; - RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data_new->get_rid(), exposure_normalization); + Vector df; + if (baker.get_sdf_3d_image(df, voxelizer_step_func) == Voxelizer::BAKE_RESULT_OK) { + RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data_new->get_rid(), exposure_normalization); - probe_data_new->allocate(baker.get_to_cell_space_xform(), AABB(-size / 2, size), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count()); + probe_data_new->allocate(baker.get_to_cell_space_xform(), AABB(-size / 2, size), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count()); - set_probe_data(probe_data_new); + set_probe_data(probe_data_new); #ifdef TOOLS_ENABLED - probe_data_new->set_edited(true); //so it gets saved + probe_data_new->set_edited(true); //so it gets saved #endif + } } if (bake_end_function) { diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h index 7d7787f7212..d7e0d74d36a 100644 --- a/scene/3d/voxel_gi.h +++ b/scene/3d/voxel_gi.h @@ -108,8 +108,8 @@ class VoxelGI : public VisualInstance3D { }; - typedef void (*BakeBeginFunc)(int); - typedef void (*BakeStepFunc)(int, const String &); + typedef void (*BakeBeginFunc)(); + typedef bool (*BakeStepFunc)(int, const String &); typedef void (*BakeEndFunc)(); private: diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp index 99392e9ba06..1074cad11e5 100644 --- a/scene/3d/voxelizer.cpp +++ b/scene/3d/voxelizer.cpp @@ -382,8 +382,24 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref p_material return mc; } -void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref &p_mesh, const Vector> &p_materials, const Ref &p_override_material) { - ERR_FAIL_COND_MSG(!p_xform.is_finite(), "Invalid mesh bake transform."); +int Voxelizer::get_bake_steps(Ref &p_mesh) const { + int bake_total = 0; + for (int i = 0; i < p_mesh->get_surface_count(); i++) { + if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) { + continue; // Only triangles. + } + Array a = p_mesh->surface_get_arrays(i); + Vector vertices = a[Mesh::ARRAY_VERTEX]; + Vector index = a[Mesh::ARRAY_INDEX]; + bake_total += (index.size() > 0 ? index.size() : vertices.size()) / 3; + } + return bake_total; +} + +Voxelizer::BakeResult Voxelizer::plot_mesh(const Transform3D &p_xform, Ref &p_mesh, const Vector> &p_materials, const Ref &p_override_material, BakeStepFunc p_bake_step_func) { + ERR_FAIL_COND_V_MSG(!p_xform.is_finite(), BAKE_RESULT_INVALID_PARAMETER, "Invalid mesh bake transform."); + + int bake_total = get_bake_steps(p_mesh), bake_current = 0; for (int i = 0; i < p_mesh->get_surface_count(); i++) { if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) { @@ -428,6 +444,13 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref &p_mesh, const V Vector2 uvs[3]; Vector3 normal[3]; + bake_current++; + if (p_bake_step_func != nullptr && (bake_current & 2047) == 1) { + if (p_bake_step_func(bake_current, bake_total)) { + return BAKE_RESULT_CANCELLED; + } + } + for (int k = 0; k < 3; k++) { vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]); } @@ -460,6 +483,13 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref &p_mesh, const V Vector2 uvs[3]; Vector3 normal[3]; + bake_current++; + if (p_bake_step_func != nullptr && (bake_current & 2047) == 1) { + if (p_bake_step_func(bake_current, bake_total)) { + return BAKE_RESULT_CANCELLED; + } + } + for (int k = 0; k < 3; k++) { vtxs[k] = p_xform.xform(vr[j * 3 + k]); } @@ -487,6 +517,8 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref &p_mesh, const V } max_original_cells = bake_cells.size(); + + return BAKE_RESULT_OK; } void Voxelizer::_sort() { @@ -821,7 +853,7 @@ static void edt(float *f, int stride, int n) { #undef square -Vector Voxelizer::get_sdf_3d_image() const { +Voxelizer::BakeResult Voxelizer::get_sdf_3d_image(Vector &r_image, BakeStepFunc p_bake_step_function) const { Vector3i octree_size = get_voxel_gi_octree_size(); uint32_t float_count = octree_size.x * octree_size.y * octree_size.z; @@ -849,9 +881,17 @@ Vector Voxelizer::get_sdf_3d_image() const { //process in each direction + int bake_total = octree_size.x * 2 + octree_size.y, bake_current = 0; + //xy->z - for (int i = 0; i < octree_size.x; i++) { + for (int i = 0; i < octree_size.x; i++, bake_current++) { + if (p_bake_step_function) { + if (p_bake_step_function(bake_current, bake_total)) { + memdelete_arr(work_memory); + return BAKE_RESULT_CANCELLED; + } + } for (int j = 0; j < octree_size.y; j++) { edt(&work_memory[i + j * y_mult], z_mult, octree_size.z); } @@ -859,23 +899,34 @@ Vector Voxelizer::get_sdf_3d_image() const { //xz->y - for (int i = 0; i < octree_size.x; i++) { + for (int i = 0; i < octree_size.x; i++, bake_current++) { + if (p_bake_step_function) { + if (p_bake_step_function(bake_current, bake_total)) { + memdelete_arr(work_memory); + return BAKE_RESULT_CANCELLED; + } + } for (int j = 0; j < octree_size.z; j++) { edt(&work_memory[i + j * z_mult], y_mult, octree_size.y); } } //yz->x - for (int i = 0; i < octree_size.y; i++) { + for (int i = 0; i < octree_size.y; i++, bake_current++) { + if (p_bake_step_function) { + if (p_bake_step_function(bake_current, bake_total)) { + memdelete_arr(work_memory); + return BAKE_RESULT_CANCELLED; + } + } for (int j = 0; j < octree_size.z; j++) { edt(&work_memory[i * y_mult + j * z_mult], 1, octree_size.x); } } - Vector image3d; - image3d.resize(float_count); + r_image.resize(float_count); { - uint8_t *w = image3d.ptrw(); + uint8_t *w = r_image.ptrw(); for (uint32_t i = 0; i < float_count; i++) { uint32_t d = uint32_t(Math::sqrt(work_memory[i])); if (d == 0) { @@ -888,7 +939,7 @@ Vector Voxelizer::get_sdf_3d_image() const { memdelete_arr(work_memory); - return image3d; + return BAKE_RESULT_OK; } #undef INF diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h index 08d018eee98..41e77673085 100644 --- a/scene/3d/voxelizer.h +++ b/scene/3d/voxelizer.h @@ -34,6 +34,15 @@ #include "scene/resources/multimesh.h" class Voxelizer { +public: + enum BakeResult { + BAKE_RESULT_OK, + BAKE_RESULT_INVALID_PARAMETER, + BAKE_RESULT_CANCELLED, + }; + + typedef bool (*BakeStepFunc)(int, int); + private: enum : uint32_t { CHILD_EMPTY = 0xFFFFFFFF @@ -112,7 +121,8 @@ class Voxelizer { public: void begin_bake(int p_subdiv, const AABB &p_bounds, float p_exposure_normalization); - void plot_mesh(const Transform3D &p_xform, Ref &p_mesh, const Vector> &p_materials, const Ref &p_override_material); + int get_bake_steps(Ref &p_mesh) const; + BakeResult plot_mesh(const Transform3D &p_xform, Ref &p_mesh, const Vector> &p_materials, const Ref &p_override_material, BakeStepFunc p_bake_step_function); void end_bake(); int get_voxel_gi_octree_depth() const; @@ -121,7 +131,7 @@ class Voxelizer { Vector get_voxel_gi_octree_cells() const; Vector get_voxel_gi_data_cells() const; Vector get_voxel_gi_level_cell_count() const; - Vector get_sdf_3d_image() const; + BakeResult get_sdf_3d_image(Vector &r_image, BakeStepFunc p_bake_step_function) const; Ref create_debug_multimesh(); From 0df602afed31954086a54b67e1e2c53672aef7d8 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Sat, 23 Nov 2024 14:57:24 +0100 Subject: [PATCH 55/59] [UPNP] Allow disabling UPNP implementation on the Web Make UPNP classes custom instance, so they can come with empty implementation on the Web (where the would not work anyway) without breaking scripts referencing it. This results in smaller Web builds by not including the library which also results in the emscripten socket wrappers to be stipped away. --- modules/upnp/SCsub | 2 +- modules/upnp/register_types.cpp | 14 +- modules/upnp/upnp.cpp | 299 +---------------------- modules/upnp/upnp.h | 61 +++-- modules/upnp/upnp_device.cpp | 126 +--------- modules/upnp/upnp_device.h | 57 ++--- modules/upnp/upnp_device_miniupnp.cpp | 153 ++++++++++++ modules/upnp/upnp_device_miniupnp.h | 83 +++++++ modules/upnp/upnp_miniupnp.cpp | 334 ++++++++++++++++++++++++++ modules/upnp/upnp_miniupnp.h | 93 +++++++ 10 files changed, 734 insertions(+), 488 deletions(-) create mode 100644 modules/upnp/upnp_device_miniupnp.cpp create mode 100644 modules/upnp/upnp_device_miniupnp.h create mode 100644 modules/upnp/upnp_miniupnp.cpp create mode 100644 modules/upnp/upnp_miniupnp.h diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub index 6657d75caee..ba4a842cb61 100644 --- a/modules/upnp/SCsub +++ b/modules/upnp/SCsub @@ -10,7 +10,7 @@ env_upnp = env_modules.Clone() thirdparty_obj = [] -if env["builtin_miniupnpc"]: +if env["builtin_miniupnpc"] and env["platform"] != "web": thirdparty_dir = "#thirdparty/miniupnpc/" thirdparty_sources = [ "igd_desc_parse.c", diff --git a/modules/upnp/register_types.cpp b/modules/upnp/register_types.cpp index f6a34837a28..fdf39c0b334 100644 --- a/modules/upnp/register_types.cpp +++ b/modules/upnp/register_types.cpp @@ -33,6 +33,11 @@ #include "upnp.h" #include "upnp_device.h" +#ifndef WEB_ENABLED +#include "upnp_device_miniupnp.h" +#include "upnp_miniupnp.h" +#endif + #include "core/error/error_macros.h" void initialize_upnp_module(ModuleInitializationLevel p_level) { @@ -40,8 +45,13 @@ void initialize_upnp_module(ModuleInitializationLevel p_level) { return; } - GDREGISTER_CLASS(UPNP); - GDREGISTER_CLASS(UPNPDevice); + ClassDB::register_custom_instance_class(); + ClassDB::register_custom_instance_class(); + +#ifndef WEB_ENABLED + UPNPMiniUPNP::make_default(); + UPNPDeviceMiniUPNP::make_default(); +#endif } void uninitialize_upnp_module(ModuleInitializationLevel p_level) { diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp index 4305bf842af..5ec0b984fc1 100644 --- a/modules/upnp/upnp.cpp +++ b/modules/upnp/upnp.cpp @@ -30,298 +30,7 @@ #include "upnp.h" -#include -#include - -#include - -bool UPNP::is_common_device(const String &dev) const { - return dev.is_empty() || - dev.contains("InternetGatewayDevice") || - dev.contains("WANIPConnection") || - dev.contains("WANPPPConnection") || - dev.contains("rootdevice"); -} - -int UPNP::discover(int timeout, int ttl, const String &device_filter) { - ERR_FAIL_COND_V_MSG(timeout < 0, UPNP_RESULT_INVALID_PARAM, "The response's wait time can't be negative."); - ERR_FAIL_COND_V_MSG(ttl < 0 || ttl > 255, UPNP_RESULT_INVALID_PARAM, "The time-to-live must be set between 0 and 255 (inclusive)."); - - devices.clear(); - - int error = 0; - struct UPNPDev *devlist; - - CharString cs = discover_multicast_if.utf8(); - const char *m_if = cs.length() ? cs.get_data() : nullptr; - if (is_common_device(device_filter)) { - devlist = upnpDiscover(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error); - } else { - devlist = upnpDiscoverAll(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error); - } - - if (error != UPNPDISCOVER_SUCCESS) { - switch (error) { - case UPNPDISCOVER_SOCKET_ERROR: - return UPNP_RESULT_SOCKET_ERROR; - case UPNPDISCOVER_MEMORY_ERROR: - return UPNP_RESULT_MEM_ALLOC_ERROR; - default: - return UPNP_RESULT_UNKNOWN_ERROR; - } - } - - if (!devlist) { - return UPNP_RESULT_NO_DEVICES; - } - - struct UPNPDev *dev = devlist; - - while (dev) { - if (device_filter.is_empty() || strstr(dev->st, device_filter.utf8().get_data())) { - add_device_to_list(dev, devlist); - } - - dev = dev->pNext; - } - - freeUPNPDevlist(devlist); - - return UPNP_RESULT_SUCCESS; -} - -void UPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) { - Ref new_device; - new_device.instantiate(); - - new_device->set_description_url(dev->descURL); - new_device->set_service_type(dev->st); - - parse_igd(new_device, devlist); - - devices.push_back(new_device); -} - -char *UPNP::load_description(const String &url, int *size, int *status_code) const { - return (char *)miniwget(url.utf8().get_data(), size, 0, status_code); -} - -void UPNP::parse_igd(Ref dev, UPNPDev *devlist) { - int size = 0; - int status_code = -1; - char *xml = load_description(dev->get_description_url(), &size, &status_code); - - if (status_code != 200) { - dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_ERROR); - return; - } - - if (!xml || size < 1) { - dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_EMPTY); - return; - } - - struct UPNPUrls urls = {}; - struct IGDdatas data; - - parserootdesc(xml, size, &data); - free(xml); - xml = nullptr; - - GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0); - - char addr[16]; -#if MINIUPNPC_API_VERSION >= 18 - int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16, nullptr, 0); -#else - int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16); -#endif - - if (i != 1) { - FreeUPNPUrls(&urls); - - switch (i) { - case 0: - dev->set_igd_status(UPNPDevice::IGD_STATUS_NO_IGD); - return; - case 2: - dev->set_igd_status(UPNPDevice::IGD_STATUS_DISCONNECTED); - return; - case 3: - dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_DEVICE); - return; - default: - dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_ERROR); - return; - } - } - - if (urls.controlURL[0] == '\0') { - FreeUPNPUrls(&urls); - dev->set_igd_status(UPNPDevice::IGD_STATUS_INVALID_CONTROL); - return; - } - - dev->set_igd_control_url(urls.controlURL); - dev->set_igd_service_type(data.first.servicetype); - dev->set_igd_our_addr(addr); - dev->set_igd_status(UPNPDevice::IGD_STATUS_OK); - - FreeUPNPUrls(&urls); -} - -int UPNP::upnp_result(int in) { - switch (in) { - case UPNPCOMMAND_SUCCESS: - return UPNP_RESULT_SUCCESS; - case UPNPCOMMAND_UNKNOWN_ERROR: - return UPNP_RESULT_UNKNOWN_ERROR; - case UPNPCOMMAND_INVALID_ARGS: - return UPNP_RESULT_INVALID_ARGS; - case UPNPCOMMAND_HTTP_ERROR: - return UPNP_RESULT_HTTP_ERROR; - case UPNPCOMMAND_INVALID_RESPONSE: - return UPNP_RESULT_INVALID_RESPONSE; - case UPNPCOMMAND_MEM_ALLOC_ERROR: - return UPNP_RESULT_MEM_ALLOC_ERROR; - - case 402: - return UPNP_RESULT_INVALID_ARGS; - case 403: - return UPNP_RESULT_NOT_AUTHORIZED; - case 501: - return UPNP_RESULT_ACTION_FAILED; - case 606: - return UPNP_RESULT_NOT_AUTHORIZED; - case 714: - return UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY; - case 715: - return UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED; - case 716: - return UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED; - case 718: - return UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING; - case 724: - return UPNP_RESULT_SAME_PORT_VALUES_REQUIRED; - case 725: - return UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED; - case 726: - return UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD; - case 727: - return UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD; - case 728: - return UPNP_RESULT_NO_PORT_MAPS_AVAILABLE; - case 729: - return UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM; - case 732: - return UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED; - case 733: - return UPNP_RESULT_INCONSISTENT_PARAMETERS; - } - - return UPNP_RESULT_UNKNOWN_ERROR; -} - -int UPNP::get_device_count() const { - return devices.size(); -} - -Ref UPNP::get_device(int index) const { - ERR_FAIL_INDEX_V(index, devices.size(), nullptr); - - return devices.get(index); -} - -void UPNP::add_device(Ref device) { - ERR_FAIL_COND(device.is_null()); - - devices.push_back(device); -} - -void UPNP::set_device(int index, Ref device) { - ERR_FAIL_INDEX(index, devices.size()); - ERR_FAIL_COND(device.is_null()); - - devices.set(index, device); -} - -void UPNP::remove_device(int index) { - ERR_FAIL_INDEX(index, devices.size()); - - devices.remove_at(index); -} - -void UPNP::clear_devices() { - devices.clear(); -} - -Ref UPNP::get_gateway() const { - ERR_FAIL_COND_V_MSG(devices.is_empty(), nullptr, "Couldn't find any UPNPDevices."); - - for (int i = 0; i < devices.size(); i++) { - Ref dev = get_device(i); - - if (dev.is_valid() && dev->is_valid_gateway()) { - return dev; - } - } - - return nullptr; -} - -void UPNP::set_discover_multicast_if(const String &m_if) { - discover_multicast_if = m_if; -} - -String UPNP::get_discover_multicast_if() const { - return discover_multicast_if; -} - -void UPNP::set_discover_local_port(int port) { - discover_local_port = port; -} - -int UPNP::get_discover_local_port() const { - return discover_local_port; -} - -void UPNP::set_discover_ipv6(bool ipv6) { - discover_ipv6 = ipv6; -} - -bool UPNP::is_discover_ipv6() const { - return discover_ipv6; -} - -String UPNP::query_external_address() const { - Ref dev = get_gateway(); - - if (dev.is_null()) { - return ""; - } - - return dev->query_external_address(); -} - -int UPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { - Ref dev = get_gateway(); - - if (dev.is_null()) { - return UPNP_RESULT_NO_GATEWAY; - } - - return dev->add_port_mapping(port, port_internal, desc, proto, duration); -} - -int UPNP::delete_port_mapping(int port, String proto) const { - Ref dev = get_gateway(); - - if (dev.is_null()) { - return UPNP_RESULT_NO_GATEWAY; - } - - return dev->delete_port_mapping(port, proto); -} +UPNP *(*UPNP::_create)(bool p_notify_postinitialize) = nullptr; void UPNP::_bind_methods() { ClassDB::bind_method(D_METHOD("get_device_count"), &UPNP::get_device_count); @@ -382,9 +91,3 @@ void UPNP::_bind_methods() { BIND_ENUM_CONSTANT(UPNP_RESULT_NO_DEVICES); BIND_ENUM_CONSTANT(UPNP_RESULT_UNKNOWN_ERROR); } - -UPNP::UPNP() { -} - -UPNP::~UPNP() { -} diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h index dc9bbdbc221..566b01ecdcc 100644 --- a/modules/upnp/upnp.h +++ b/modules/upnp/upnp.h @@ -35,26 +35,14 @@ #include "core/object/ref_counted.h" -#include - class UPNP : public RefCounted { GDCLASS(UPNP, RefCounted); -private: - String discover_multicast_if = ""; - int discover_local_port = 0; - bool discover_ipv6 = false; - - Vector> devices; - - bool is_common_device(const String &dev) const; - void add_device_to_list(UPNPDev *dev, UPNPDev *devlist); - void parse_igd(Ref dev, UPNPDev *devlist); - char *load_description(const String &url, int *size, int *status_code) const; - protected: static void _bind_methods(); + static UPNP *(*_create)(bool p_notify_postinitialize); + public: enum UPNPResult { UPNP_RESULT_SUCCESS, @@ -88,35 +76,40 @@ class UPNP : public RefCounted { UPNP_RESULT_UNKNOWN_ERROR, }; - static int upnp_result(int in); + static UPNP *create(bool p_notify_postinitialize = true) { + if (!_create) { + return nullptr; + } + return _create(p_notify_postinitialize); + } - int get_device_count() const; - Ref get_device(int index) const; - void add_device(Ref device); - void set_device(int index, Ref device); - void remove_device(int index); - void clear_devices(); + virtual int get_device_count() const = 0; + virtual Ref get_device(int index) const = 0; + virtual void add_device(Ref device) = 0; + virtual void set_device(int index, Ref device) = 0; + virtual void remove_device(int index) = 0; + virtual void clear_devices() = 0; - Ref get_gateway() const; + virtual Ref get_gateway() const = 0; - int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice"); + virtual int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice") = 0; - String query_external_address() const; + virtual String query_external_address() const = 0; - int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const; - int delete_port_mapping(int port, String proto = "UDP") const; + virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const = 0; + virtual int delete_port_mapping(int port, String proto = "UDP") const = 0; - void set_discover_multicast_if(const String &m_if); - String get_discover_multicast_if() const; + virtual void set_discover_multicast_if(const String &m_if) = 0; + virtual String get_discover_multicast_if() const = 0; - void set_discover_local_port(int port); - int get_discover_local_port() const; + virtual void set_discover_local_port(int port) = 0; + virtual int get_discover_local_port() const = 0; - void set_discover_ipv6(bool ipv6); - bool is_discover_ipv6() const; + virtual void set_discover_ipv6(bool ipv6) = 0; + virtual bool is_discover_ipv6() const = 0; - UPNP(); - ~UPNP(); + UPNP() {} + virtual ~UPNP() {} }; VARIANT_ENUM_CAST(UPNP::UPNPResult) diff --git a/modules/upnp/upnp_device.cpp b/modules/upnp/upnp_device.cpp index 11ee3681afd..45766281f14 100644 --- a/modules/upnp/upnp_device.cpp +++ b/modules/upnp/upnp_device.cpp @@ -30,119 +30,7 @@ #include "upnp_device.h" -#include "upnp.h" - -#include - -String UPNPDevice::query_external_address() const { - ERR_FAIL_COND_V_MSG(!is_valid_gateway(), "", "The Internet Gateway Device must be valid."); - - char addr[16]; - int i = UPNP_GetExternalIPAddress( - igd_control_url.utf8().get_data(), - igd_service_type.utf8().get_data(), - (char *)&addr); - - ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, "", "Couldn't get external IP address."); - - return String(addr); -} - -int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { - ERR_FAIL_COND_V_MSG(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY, "The Internet Gateway Device must be valid."); - ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive)."); - ERR_FAIL_COND_V_MSG(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 0 and 65535 (inclusive)."); // Needs to allow 0 because 0 signifies "use external port as internal port" - ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP."); - ERR_FAIL_COND_V_MSG(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION, "The port mapping's lease duration can't be negative."); - - if (port_internal < 1) { - port_internal = port; - } - - int i = UPNP_AddPortMapping( - igd_control_url.utf8().get_data(), - igd_service_type.utf8().get_data(), - itos(port).utf8().get_data(), - itos(port_internal).utf8().get_data(), - igd_our_addr.utf8().get_data(), - desc.is_empty() ? nullptr : desc.utf8().get_data(), - proto.utf8().get_data(), - nullptr, // Remote host, always nullptr as IGDs don't support it - duration > 0 ? itos(duration).utf8().get_data() : nullptr); - - ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't add port mapping."); - - return UPNP::UPNP_RESULT_SUCCESS; -} - -int UPNPDevice::delete_port_mapping(int port, String proto) const { - ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive)."); - ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP."); - - int i = UPNP_DeletePortMapping( - igd_control_url.utf8().get_data(), - igd_service_type.utf8().get_data(), - itos(port).utf8().get_data(), - proto.utf8().get_data(), - nullptr // Remote host, always nullptr as IGDs don't support it - ); - - ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't delete port mapping."); - - return UPNP::UPNP_RESULT_SUCCESS; -} - -void UPNPDevice::set_description_url(const String &url) { - description_url = url; -} - -String UPNPDevice::get_description_url() const { - return description_url; -} - -void UPNPDevice::set_service_type(const String &type) { - service_type = type; -} - -String UPNPDevice::get_service_type() const { - return service_type; -} - -void UPNPDevice::set_igd_control_url(const String &url) { - igd_control_url = url; -} - -String UPNPDevice::get_igd_control_url() const { - return igd_control_url; -} - -void UPNPDevice::set_igd_service_type(const String &type) { - igd_service_type = type; -} - -String UPNPDevice::get_igd_service_type() const { - return igd_service_type; -} - -void UPNPDevice::set_igd_our_addr(const String &addr) { - igd_our_addr = addr; -} - -String UPNPDevice::get_igd_our_addr() const { - return igd_our_addr; -} - -void UPNPDevice::set_igd_status(IGDStatus status) { - igd_status = status; -} - -UPNPDevice::IGDStatus UPNPDevice::get_igd_status() const { - return igd_status; -} - -bool UPNPDevice::is_valid_gateway() const { - return igd_status == IGD_STATUS_OK; -} +UPNPDevice *(*UPNPDevice::_create)(bool p_notify_postinitialize) = nullptr; void UPNPDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("is_valid_gateway"), &UPNPDevice::is_valid_gateway); @@ -185,15 +73,3 @@ void UPNPDevice::_bind_methods() { BIND_ENUM_CONSTANT(IGD_STATUS_MALLOC_ERROR); BIND_ENUM_CONSTANT(IGD_STATUS_UNKNOWN_ERROR); } - -UPNPDevice::UPNPDevice() { - description_url = ""; - service_type = ""; - igd_control_url = ""; - igd_service_type = ""; - igd_our_addr = ""; - igd_status = IGD_STATUS_UNKNOWN_ERROR; -} - -UPNPDevice::~UPNPDevice() { -} diff --git a/modules/upnp/upnp_device.h b/modules/upnp/upnp_device.h index a49e574890d..fdc5bab1108 100644 --- a/modules/upnp/upnp_device.h +++ b/modules/upnp/upnp_device.h @@ -36,6 +36,11 @@ class UPNPDevice : public RefCounted { GDCLASS(UPNPDevice, RefCounted); +protected: + static void _bind_methods(); + + static UPNPDevice *(*_create)(bool p_notify_postinitialize); + public: enum IGDStatus { IGD_STATUS_OK, @@ -50,42 +55,38 @@ class UPNPDevice : public RefCounted { IGD_STATUS_UNKNOWN_ERROR, }; - void set_description_url(const String &url); - String get_description_url() const; + static UPNPDevice *create(bool p_notify_postinitialize = true) { + if (!_create) { + return nullptr; + } + return _create(p_notify_postinitialize); + } - void set_service_type(const String &type); - String get_service_type() const; + virtual void set_description_url(const String &url) = 0; + virtual String get_description_url() const = 0; - void set_igd_control_url(const String &url); - String get_igd_control_url() const; + virtual void set_service_type(const String &type) = 0; + virtual String get_service_type() const = 0; - void set_igd_service_type(const String &type); - String get_igd_service_type() const; + virtual void set_igd_control_url(const String &url) = 0; + virtual String get_igd_control_url() const = 0; - void set_igd_our_addr(const String &addr); - String get_igd_our_addr() const; + virtual void set_igd_service_type(const String &type) = 0; + virtual String get_igd_service_type() const = 0; - void set_igd_status(IGDStatus status); - IGDStatus get_igd_status() const; + virtual void set_igd_our_addr(const String &addr) = 0; + virtual String get_igd_our_addr() const = 0; - bool is_valid_gateway() const; - String query_external_address() const; - int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const; - int delete_port_mapping(int port, String proto = "UDP") const; + virtual void set_igd_status(IGDStatus status) = 0; + virtual IGDStatus get_igd_status() const = 0; - UPNPDevice(); - ~UPNPDevice(); - -protected: - static void _bind_methods(); + virtual bool is_valid_gateway() const = 0; + virtual String query_external_address() const = 0; + virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const = 0; + virtual int delete_port_mapping(int port, String proto = "UDP") const = 0; -private: - String description_url; - String service_type; - String igd_control_url; - String igd_service_type; - String igd_our_addr; - IGDStatus igd_status; + UPNPDevice() {} + virtual ~UPNPDevice() {} }; VARIANT_ENUM_CAST(UPNPDevice::IGDStatus) diff --git a/modules/upnp/upnp_device_miniupnp.cpp b/modules/upnp/upnp_device_miniupnp.cpp new file mode 100644 index 00000000000..46319f83d35 --- /dev/null +++ b/modules/upnp/upnp_device_miniupnp.cpp @@ -0,0 +1,153 @@ +/**************************************************************************/ +/* upnp_device_miniupnp.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef WEB_ENABLED + +#include "upnp_device_miniupnp.h" + +#include "upnp_miniupnp.h" + +#include + +void UPNPDeviceMiniUPNP::make_default() { + UPNPDevice::_create = UPNPDeviceMiniUPNP::_create; +} + +String UPNPDeviceMiniUPNP::query_external_address() const { + ERR_FAIL_COND_V_MSG(!is_valid_gateway(), "", "The Internet Gateway Device must be valid."); + + char addr[16]; + int i = UPNP_GetExternalIPAddress( + igd_control_url.utf8().get_data(), + igd_service_type.utf8().get_data(), + (char *)&addr); + + ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, "", "Couldn't get external IP address."); + + return String(addr); +} + +int UPNPDeviceMiniUPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { + ERR_FAIL_COND_V_MSG(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY, "The Internet Gateway Device must be valid."); + ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 0 and 65535 (inclusive)."); // Needs to allow 0 because 0 signifies "use external port as internal port" + ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP."); + ERR_FAIL_COND_V_MSG(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION, "The port mapping's lease duration can't be negative."); + + if (port_internal < 1) { + port_internal = port; + } + + int i = UPNP_AddPortMapping( + igd_control_url.utf8().get_data(), + igd_service_type.utf8().get_data(), + itos(port).utf8().get_data(), + itos(port_internal).utf8().get_data(), + igd_our_addr.utf8().get_data(), + desc.is_empty() ? nullptr : desc.utf8().get_data(), + proto.utf8().get_data(), + nullptr, // Remote host, always nullptr as IGDs don't support it + duration > 0 ? itos(duration).utf8().get_data() : nullptr); + + ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNPMiniUPNP::upnp_result(i), "Couldn't add port mapping."); + + return UPNP::UPNP_RESULT_SUCCESS; +} + +int UPNPDeviceMiniUPNP::delete_port_mapping(int port, String proto) const { + ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP."); + + int i = UPNP_DeletePortMapping( + igd_control_url.utf8().get_data(), + igd_service_type.utf8().get_data(), + itos(port).utf8().get_data(), + proto.utf8().get_data(), + nullptr // Remote host, always nullptr as IGDs don't support it + ); + + ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNPMiniUPNP::upnp_result(i), "Couldn't delete port mapping."); + + return UPNP::UPNP_RESULT_SUCCESS; +} + +void UPNPDeviceMiniUPNP::set_description_url(const String &url) { + description_url = url; +} + +String UPNPDeviceMiniUPNP::get_description_url() const { + return description_url; +} + +void UPNPDeviceMiniUPNP::set_service_type(const String &type) { + service_type = type; +} + +String UPNPDeviceMiniUPNP::get_service_type() const { + return service_type; +} + +void UPNPDeviceMiniUPNP::set_igd_control_url(const String &url) { + igd_control_url = url; +} + +String UPNPDeviceMiniUPNP::get_igd_control_url() const { + return igd_control_url; +} + +void UPNPDeviceMiniUPNP::set_igd_service_type(const String &type) { + igd_service_type = type; +} + +String UPNPDeviceMiniUPNP::get_igd_service_type() const { + return igd_service_type; +} + +void UPNPDeviceMiniUPNP::set_igd_our_addr(const String &addr) { + igd_our_addr = addr; +} + +String UPNPDeviceMiniUPNP::get_igd_our_addr() const { + return igd_our_addr; +} + +void UPNPDeviceMiniUPNP::set_igd_status(IGDStatus status) { + igd_status = status; +} + +UPNPDeviceMiniUPNP::IGDStatus UPNPDeviceMiniUPNP::get_igd_status() const { + return igd_status; +} + +bool UPNPDeviceMiniUPNP::is_valid_gateway() const { + return igd_status == IGD_STATUS_OK; +} + +#endif // WEB_ENABLED diff --git a/modules/upnp/upnp_device_miniupnp.h b/modules/upnp/upnp_device_miniupnp.h new file mode 100644 index 00000000000..bea3b1d5424 --- /dev/null +++ b/modules/upnp/upnp_device_miniupnp.h @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* upnp_device_miniupnp.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef UPNP_DEVICE_MINIUPNP_H +#define UPNP_DEVICE_MINIUPNP_H + +#ifndef WEB_ENABLED + +#include "upnp_device.h" + +class UPNPDeviceMiniUPNP : public UPNPDevice { + GDCLASS(UPNPDeviceMiniUPNP, UPNPDevice); + +private: + static UPNPDevice *_create(bool p_notify_postinitialize) { return static_cast(ClassDB::creator(p_notify_postinitialize)); } + + String description_url; + String service_type; + String igd_control_url; + String igd_service_type; + String igd_our_addr; + IGDStatus igd_status = IGD_STATUS_UNKNOWN_ERROR; + +public: + static void make_default(); + + virtual void set_description_url(const String &url) override; + virtual String get_description_url() const override; + + virtual void set_service_type(const String &type) override; + virtual String get_service_type() const override; + + virtual void set_igd_control_url(const String &url) override; + virtual String get_igd_control_url() const override; + + virtual void set_igd_service_type(const String &type) override; + virtual String get_igd_service_type() const override; + + virtual void set_igd_our_addr(const String &addr) override; + virtual String get_igd_our_addr() const override; + + virtual void set_igd_status(IGDStatus status) override; + virtual IGDStatus get_igd_status() const override; + + virtual bool is_valid_gateway() const override; + virtual String query_external_address() const override; + virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const override; + virtual int delete_port_mapping(int port, String proto = "UDP") const override; + + UPNPDeviceMiniUPNP() {} + virtual ~UPNPDeviceMiniUPNP() {} +}; + +#endif // WEB_ENABLED + +#endif // UPNP_DEVICE_MINIUPNP_H diff --git a/modules/upnp/upnp_miniupnp.cpp b/modules/upnp/upnp_miniupnp.cpp new file mode 100644 index 00000000000..0714d56a08f --- /dev/null +++ b/modules/upnp/upnp_miniupnp.cpp @@ -0,0 +1,334 @@ +/**************************************************************************/ +/* upnp_miniupnp.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef WEB_ENABLED + +#include "upnp_miniupnp.h" + +#include "upnp_device_miniupnp.h" + +#include +#include + +#include + +void UPNPMiniUPNP::make_default() { + UPNP::_create = UPNPMiniUPNP::_create; +} + +bool UPNPMiniUPNP::is_common_device(const String &dev) const { + return dev.is_empty() || + dev.contains("InternetGatewayDevice") || + dev.contains("WANIPConnection") || + dev.contains("WANPPPConnection") || + dev.contains("rootdevice"); +} + +int UPNPMiniUPNP::discover(int timeout, int ttl, const String &device_filter) { + ERR_FAIL_COND_V_MSG(timeout < 0, UPNP_RESULT_INVALID_PARAM, "The response's wait time can't be negative."); + ERR_FAIL_COND_V_MSG(ttl < 0 || ttl > 255, UPNP_RESULT_INVALID_PARAM, "The time-to-live must be set between 0 and 255 (inclusive)."); + + devices.clear(); + + int error = 0; + struct UPNPDev *devlist; + + CharString cs = discover_multicast_if.utf8(); + const char *m_if = cs.length() ? cs.get_data() : nullptr; + if (is_common_device(device_filter)) { + devlist = upnpDiscover(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error); + } else { + devlist = upnpDiscoverAll(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error); + } + + if (error != UPNPDISCOVER_SUCCESS) { + switch (error) { + case UPNPDISCOVER_SOCKET_ERROR: + return UPNP_RESULT_SOCKET_ERROR; + case UPNPDISCOVER_MEMORY_ERROR: + return UPNP_RESULT_MEM_ALLOC_ERROR; + default: + return UPNP_RESULT_UNKNOWN_ERROR; + } + } + + if (!devlist) { + return UPNP_RESULT_NO_DEVICES; + } + + struct UPNPDev *dev = devlist; + + while (dev) { + if (device_filter.is_empty() || strstr(dev->st, device_filter.utf8().get_data())) { + add_device_to_list(dev, devlist); + } + + dev = dev->pNext; + } + + freeUPNPDevlist(devlist); + + return UPNP_RESULT_SUCCESS; +} + +void UPNPMiniUPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) { + Ref new_device; + new_device.instantiate(); + + new_device->set_description_url(dev->descURL); + new_device->set_service_type(dev->st); + + parse_igd(new_device, devlist); + + devices.push_back(new_device); +} + +char *UPNPMiniUPNP::load_description(const String &url, int *size, int *status_code) const { + return (char *)miniwget(url.utf8().get_data(), size, 0, status_code); +} + +void UPNPMiniUPNP::parse_igd(Ref dev, UPNPDev *devlist) { + int size = 0; + int status_code = -1; + char *xml = load_description(dev->get_description_url(), &size, &status_code); + + if (status_code != 200) { + dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_ERROR); + return; + } + + if (!xml || size < 1) { + dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_EMPTY); + return; + } + + struct UPNPUrls urls = {}; + struct IGDdatas data; + + parserootdesc(xml, size, &data); + free(xml); + xml = nullptr; + + GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0); + + char addr[16]; +#if MINIUPNPC_API_VERSION >= 18 + int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16, nullptr, 0); +#else + int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16); +#endif + + if (i != 1) { + FreeUPNPUrls(&urls); + + switch (i) { + case 0: + dev->set_igd_status(UPNPDevice::IGD_STATUS_NO_IGD); + return; + case 2: + dev->set_igd_status(UPNPDevice::IGD_STATUS_DISCONNECTED); + return; + case 3: + dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_DEVICE); + return; + default: + dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_ERROR); + return; + } + } + + if (urls.controlURL[0] == '\0') { + FreeUPNPUrls(&urls); + dev->set_igd_status(UPNPDevice::IGD_STATUS_INVALID_CONTROL); + return; + } + + dev->set_igd_control_url(urls.controlURL); + dev->set_igd_service_type(data.first.servicetype); + dev->set_igd_our_addr(addr); + dev->set_igd_status(UPNPDevice::IGD_STATUS_OK); + + FreeUPNPUrls(&urls); +} + +int UPNPMiniUPNP::upnp_result(int in) { + switch (in) { + case UPNPCOMMAND_SUCCESS: + return UPNP_RESULT_SUCCESS; + case UPNPCOMMAND_UNKNOWN_ERROR: + return UPNP_RESULT_UNKNOWN_ERROR; + case UPNPCOMMAND_INVALID_ARGS: + return UPNP_RESULT_INVALID_ARGS; + case UPNPCOMMAND_HTTP_ERROR: + return UPNP_RESULT_HTTP_ERROR; + case UPNPCOMMAND_INVALID_RESPONSE: + return UPNP_RESULT_INVALID_RESPONSE; + case UPNPCOMMAND_MEM_ALLOC_ERROR: + return UPNP_RESULT_MEM_ALLOC_ERROR; + + case 402: + return UPNP_RESULT_INVALID_ARGS; + case 403: + return UPNP_RESULT_NOT_AUTHORIZED; + case 501: + return UPNP_RESULT_ACTION_FAILED; + case 606: + return UPNP_RESULT_NOT_AUTHORIZED; + case 714: + return UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY; + case 715: + return UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED; + case 716: + return UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED; + case 718: + return UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING; + case 724: + return UPNP_RESULT_SAME_PORT_VALUES_REQUIRED; + case 725: + return UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED; + case 726: + return UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD; + case 727: + return UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD; + case 728: + return UPNP_RESULT_NO_PORT_MAPS_AVAILABLE; + case 729: + return UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM; + case 732: + return UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED; + case 733: + return UPNP_RESULT_INCONSISTENT_PARAMETERS; + } + + return UPNP_RESULT_UNKNOWN_ERROR; +} + +int UPNPMiniUPNP::get_device_count() const { + return devices.size(); +} + +Ref UPNPMiniUPNP::get_device(int index) const { + ERR_FAIL_INDEX_V(index, devices.size(), nullptr); + + return devices.get(index); +} + +void UPNPMiniUPNP::add_device(Ref device) { + ERR_FAIL_COND(device.is_null()); + + devices.push_back(device); +} + +void UPNPMiniUPNP::set_device(int index, Ref device) { + ERR_FAIL_INDEX(index, devices.size()); + ERR_FAIL_COND(device.is_null()); + + devices.set(index, device); +} + +void UPNPMiniUPNP::remove_device(int index) { + ERR_FAIL_INDEX(index, devices.size()); + + devices.remove_at(index); +} + +void UPNPMiniUPNP::clear_devices() { + devices.clear(); +} + +Ref UPNPMiniUPNP::get_gateway() const { + ERR_FAIL_COND_V_MSG(devices.is_empty(), nullptr, "Couldn't find any UPNPDevices."); + + for (int i = 0; i < devices.size(); i++) { + Ref dev = get_device(i); + + if (dev.is_valid() && dev->is_valid_gateway()) { + return dev; + } + } + + return nullptr; +} + +void UPNPMiniUPNP::set_discover_multicast_if(const String &m_if) { + discover_multicast_if = m_if; +} + +String UPNPMiniUPNP::get_discover_multicast_if() const { + return discover_multicast_if; +} + +void UPNPMiniUPNP::set_discover_local_port(int port) { + discover_local_port = port; +} + +int UPNPMiniUPNP::get_discover_local_port() const { + return discover_local_port; +} + +void UPNPMiniUPNP::set_discover_ipv6(bool ipv6) { + discover_ipv6 = ipv6; +} + +bool UPNPMiniUPNP::is_discover_ipv6() const { + return discover_ipv6; +} + +String UPNPMiniUPNP::query_external_address() const { + Ref dev = get_gateway(); + + if (dev.is_null()) { + return ""; + } + + return dev->query_external_address(); +} + +int UPNPMiniUPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { + Ref dev = get_gateway(); + + if (dev.is_null()) { + return UPNP_RESULT_NO_GATEWAY; + } + + return dev->add_port_mapping(port, port_internal, desc, proto, duration); +} + +int UPNPMiniUPNP::delete_port_mapping(int port, String proto) const { + Ref dev = get_gateway(); + + if (dev.is_null()) { + return UPNP_RESULT_NO_GATEWAY; + } + + return dev->delete_port_mapping(port, proto); +} + +#endif // WEB_ENABLED diff --git a/modules/upnp/upnp_miniupnp.h b/modules/upnp/upnp_miniupnp.h new file mode 100644 index 00000000000..0c7dba9d0be --- /dev/null +++ b/modules/upnp/upnp_miniupnp.h @@ -0,0 +1,93 @@ +/**************************************************************************/ +/* upnp_miniupnp.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef UPNP_MINIUPNP_H +#define UPNP_MINIUPNP_H + +#ifndef WEB_ENABLED + +#include "upnp.h" + +#include + +class UPNPMiniUPNP : public UPNP { + GDCLASS(UPNPMiniUPNP, UPNP); + +private: + static UPNP *_create(bool p_notify_postinitialize) { return static_cast(ClassDB::creator(p_notify_postinitialize)); } + + String discover_multicast_if = ""; + int discover_local_port = 0; + bool discover_ipv6 = false; + + Vector> devices; + + bool is_common_device(const String &dev) const; + void add_device_to_list(UPNPDev *dev, UPNPDev *devlist); + void parse_igd(Ref dev, UPNPDev *devlist); + char *load_description(const String &url, int *size, int *status_code) const; + +public: + static void make_default(); + + static int upnp_result(int in); + + virtual int get_device_count() const override; + virtual Ref get_device(int index) const override; + virtual void add_device(Ref device) override; + virtual void set_device(int index, Ref device) override; + virtual void remove_device(int index) override; + virtual void clear_devices() override; + + virtual Ref get_gateway() const override; + + virtual int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice") override; + + virtual String query_external_address() const override; + + virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const override; + virtual int delete_port_mapping(int port, String proto = "UDP") const override; + + virtual void set_discover_multicast_if(const String &m_if) override; + virtual String get_discover_multicast_if() const override; + + virtual void set_discover_local_port(int port) override; + virtual int get_discover_local_port() const override; + + virtual void set_discover_ipv6(bool ipv6) override; + virtual bool is_discover_ipv6() const override; + + UPNPMiniUPNP() {} + virtual ~UPNPMiniUPNP() {} +}; + +#endif // WEB_ENABLED + +#endif // UPNP_MINIUPNP_H From 796d943f14178ec1872085624bacaf4b9c18ef48 Mon Sep 17 00:00:00 2001 From: Alexander Hartmann Date: Sun, 24 Nov 2024 00:29:09 +0100 Subject: [PATCH 56/59] Fix missing space after period in error message. --- platform/android/export/export_plugin.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index e20de99c2d0..a7b0879056a 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -2529,7 +2529,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref da = DirAccess::open(java_sdk_path.path_join("bin"), &errn); if (errn != OK) { - err += TTR("Invalid Java SDK path in Editor Settings."); + err += TTR("Invalid Java SDK path in Editor Settings.") + " "; err += TTR("Missing 'bin' directory!"); err += "\n"; valid = false; @@ -2537,7 +2537,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref da = DirAccess::open(sdk_path.path_join("platform-tools"), &errn); if (errn != OK) { - err += TTR("Invalid Android SDK path in Editor Settings."); + err += TTR("Invalid Android SDK path in Editor Settings.") + " "; err += TTR("Missing 'platform-tools' directory!"); err += "\n"; valid = false; @@ -2563,7 +2563,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref build_tools_da = DirAccess::open(sdk_path.path_join("build-tools"), &errn); if (errn != OK) { - err += TTR("Invalid Android SDK path in Editor Settings."); + err += TTR("Invalid Android SDK path in Editor Settings.") + " "; err += TTR("Missing 'build-tools' directory!"); err += "\n"; valid = false; @@ -2585,7 +2585,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref Date: Sun, 24 Nov 2024 15:33:47 +0100 Subject: [PATCH 57/59] [Buildsystem] Fix path format for SCU builds on Windows --- methods.py | 1 + 1 file changed, 1 insertion(+) diff --git a/methods.py b/methods.py index 203f0dd8a53..be290f81280 100644 --- a/methods.py +++ b/methods.py @@ -102,6 +102,7 @@ def add_source_files_scu(self, sources, files, allow_gen=False): subdir = os.path.dirname(files) subdir = subdir if subdir == "" else subdir + "/" section_name = self.Dir(subdir).tpath + section_name = section_name.replace("\\", "/") # win32 # if the section name is in the hash table? # i.e. is it part of the SCU build? global _scu_folders From 13b565c64d25a170c65f00c6716cb41dad9408c3 Mon Sep 17 00:00:00 2001 From: tetrapod00 <145553014+tetrapod00@users.noreply.github.com> Date: Sun, 24 Nov 2024 01:04:57 -0800 Subject: [PATCH 58/59] Docs: Update Control class to properly reflect behavior of Themes on Control Children Document fact that themes only propagate to control children (not Node2D, etc). Wording is copied from Theme docs. Also clarifies line somewhat. Co-Authored-By: Allyson Chan --- doc/classes/Control.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index d455bd7d686..02b167c390e 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -12,7 +12,7 @@ Call [method accept_event] so no other node receives the event. Once you accept an input, it becomes handled so [method Node._unhandled_input] will not process it. Only one [Control] node can be in focus. Only the node in focus will receive events. To get the focus, call [method grab_focus]. [Control] nodes lose focus when another node grabs it, or if you hide the node in focus. Sets [member mouse_filter] to [constant MOUSE_FILTER_IGNORE] to tell a [Control] node to ignore mouse or touch events. You'll need it if you place an icon on top of a button. - [Theme] resources change the Control's appearance. If you change the [Theme] on a [Control] node, it affects all of its children. To override some of the theme's parameters, call one of the [code]add_theme_*_override[/code] methods, like [method add_theme_font_override]. You can override the theme with the Inspector. + [Theme] resources change the control's appearance. The [member theme] of a [Control] node affects all of its direct and indirect children (as long as a chain of controls is uninterrupted). To override some of the theme items, call one of the [code]add_theme_*_override[/code] methods, like [method add_theme_font_override]. You can also override theme items in the Inspector. [b]Note:[/b] Theme items are [i]not[/i] [Object] properties. This means you can't access their values using [method Object.get] and [method Object.set]. Instead, use the [code]get_theme_*[/code] and [code]add_theme_*_override[/code] methods provided by this class. From 8e1a6ea4319e6f38cecc36a06e2e5384678ecf83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Mon, 25 Nov 2024 19:43:21 +0100 Subject: [PATCH 59/59] Revert "Make delay_usec more precise" This reverts commit df3367f3343ec5acc579205479642d7275f3e12b. Fixes #99593. --- platform/windows/os_windows.cpp | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index a25b7ea4ca7..416016b112e 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -817,22 +817,10 @@ double OS_Windows::get_unix_time() const { } void OS_Windows::delay_usec(uint32_t p_usec) const { - constexpr uint32_t tolerance = 1000 + 20; - - uint64_t t0 = get_ticks_usec(); - uint64_t target_time = t0 + p_usec; - - // Calculate sleep duration with a tolerance for fine-tuning. - if (p_usec > tolerance) { - uint32_t coarse_sleep_usec = p_usec - tolerance; - if (coarse_sleep_usec >= 1000) { - Sleep(coarse_sleep_usec / 1000); - } - } - - // Spin-wait until we reach the precise target time. - while (get_ticks_usec() < target_time) { - YieldProcessor(); + if (p_usec < 1000) { + Sleep(1); + } else { + Sleep(p_usec / 1000); } }