summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/csg/csg_shape.cpp9
-rw-r--r--modules/csg/icons/CSGBox3D.svg2
-rw-r--r--modules/csg/icons/CSGCapsule3D.svg2
-rw-r--r--modules/csg/icons/CSGCylinder3D.svg2
-rw-r--r--modules/csg/icons/CSGPolygon3D.svg2
-rw-r--r--modules/csg/icons/CSGSphere3D.svg2
-rw-r--r--modules/csg/icons/CSGTorus3D.svg2
-rw-r--r--modules/gdscript/SCsub2
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp2
-rw-r--r--modules/gdscript/gdscript.cpp109
-rw-r--r--modules/gdscript/gdscript.h14
-rw-r--r--modules/gdscript/gdscript_cache.cpp25
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp4
-rw-r--r--modules/gdscript/gdscript_lambda_callable.h4
-rw-r--r--modules/gdscript/gdscript_parser.h4
-rw-r--r--modules/gdscript/gdscript_vm.cpp8
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp4
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.cpp15
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.h1
-rw-r--r--modules/gltf/gltf_document.cpp70
-rw-r--r--modules/gltf/gltf_document.h3
-rw-r--r--modules/gltf/gltf_state.cpp2
-rw-r--r--modules/jpg/image_loader_jpegd.cpp6
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp4
-rw-r--r--modules/mono/csharp_script.cpp31
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs25
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs18
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs11
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs15
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs8
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp6
-rw-r--r--modules/navigation/nav_map.cpp4
-rw-r--r--modules/navigation/nav_mesh_generator_2d.cpp29
-rw-r--r--modules/navigation/nav_mesh_generator_3d.cpp76
-rw-r--r--modules/noise/fastnoise_lite.cpp4
-rw-r--r--modules/noise/noise.cpp6
-rw-r--r--modules/openxr/SCsub1
-rw-r--r--modules/openxr/openxr_api.cpp7
-rw-r--r--modules/text_server_adv/gdextension_build/methods.py4
-rw-r--r--modules/text_server_adv/text_server_adv.cpp21
-rw-r--r--modules/text_server_adv/text_server_adv.h7
-rw-r--r--modules/text_server_fb/gdextension_build/methods.py4
-rw-r--r--modules/text_server_fb/text_server_fb.cpp8
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.cpp6
-rw-r--r--modules/webp/webp_common.cpp4
49 files changed, 440 insertions, 173 deletions
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 0656f8224c..9c178997c5 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -488,7 +488,9 @@ bool CSGShape3D::_is_debug_collision_shape_visible() {
}
void CSGShape3D::_update_debug_collision_shape() {
- // NOTE: This is called only for the root shape with collision, when root_collision_shape is valid.
+ if (!use_collision || !is_root_shape() || !root_collision_shape.is_valid() || !_is_debug_collision_shape_visible()) {
+ return;
+ }
ERR_FAIL_NULL(RenderingServer::get_singleton());
@@ -573,6 +575,11 @@ void CSGShape3D::_notification(int p_what) {
// Update this node's parent only if its own visibility has changed, not the visibility of parent nodes
parent_shape->_make_dirty();
}
+ if (is_visible()) {
+ _update_debug_collision_shape();
+ } else {
+ _clear_debug_collision_shape();
+ }
last_visible = is_visible();
} break;
diff --git a/modules/csg/icons/CSGBox3D.svg b/modules/csg/icons/CSGBox3D.svg
index bb3a1f357a..d425180cf5 100644
--- a/modules/csg/icons/CSGBox3D.svg
+++ b/modules/csg/icons/CSGBox3D.svg
@@ -1 +1 @@
-<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="m8 2 6 3v6l-6 3-6-3V5zm0 12V8l6-3M8 8 2 5" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
+<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="m8 2 6 3v6l-6 3-6-3V5zm0 12V8l6-3M8 8 2 5" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
diff --git a/modules/csg/icons/CSGCapsule3D.svg b/modules/csg/icons/CSGCapsule3D.svg
index 33a2d4a115..3c2657999c 100644
--- a/modules/csg/icons/CSGCapsule3D.svg
+++ b/modules/csg/icons/CSGCapsule3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M4 6a4 4 0 0 1 8 0v4a4 4 0 0 1-8 0zm0 1.25a2.5 1 0 0 0 8 0m-4-5v12" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M4 6a4 4 0 0 1 8 0v4a4 4 0 0 1-8 0zm0 1.25a2.5 1 0 0 0 8 0m-4-5v12" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
diff --git a/modules/csg/icons/CSGCylinder3D.svg b/modules/csg/icons/CSGCylinder3D.svg
index 29d658dc46..19e48b4dba 100644
--- a/modules/csg/icons/CSGCylinder3D.svg
+++ b/modules/csg/icons/CSGCylinder3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M2 4v8a6 2 0 0 0 12 0V4A6 2 0 0 0 2 4a6 2 0 0 0 12 0" stroke-width="2" fill="none" stroke="#fc7f7f" mask="url(#a)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M2 4v8a6 2 0 0 0 12 0V4A6 2 0 0 0 2 4a6 2 0 0 0 12 0" stroke-width="2" fill="none" stroke="#fc7f7f" mask="url(#a)"/></svg>
diff --git a/modules/csg/icons/CSGPolygon3D.svg b/modules/csg/icons/CSGPolygon3D.svg
index 8d4b61e039..090047248b 100644
--- a/modules/csg/icons/CSGPolygon3D.svg
+++ b/modules/csg/icons/CSGPolygon3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="m8 2 6 3.5v5L8 14l-6-3.5v-5h6zm6 3.5L8 9 2 5.5M8 9v5" fill="none" stroke-linejoin="round" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="m8 2 6 3.5v5L8 14l-6-3.5v-5h6zm6 3.5L8 9 2 5.5M8 9v5" fill="none" stroke-linejoin="round" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
diff --git a/modules/csg/icons/CSGSphere3D.svg b/modules/csg/icons/CSGSphere3D.svg
index 16d45b3c99..a677ffaf5c 100644
--- a/modules/csg/icons/CSGSphere3D.svg
+++ b/modules/csg/icons/CSGSphere3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M8 2a6 6 0 0 0 0 12A6 6 0 0 0 8 2v12M2.05 7.4a6 2 0 0 0 11.9 0" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M8 2a6 6 0 0 0 0 12A6 6 0 0 0 8 2v12M2.05 7.4a6 2 0 0 0 11.9 0" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
diff --git a/modules/csg/icons/CSGTorus3D.svg b/modules/csg/icons/CSGTorus3D.svg
index 27a6b422f9..60c56bd1ca 100644
--- a/modules/csg/icons/CSGTorus3D.svg
+++ b/modules/csg/icons/CSGTorus3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><g fill="none" stroke="#fc7f7f" mask="url(#a)"><path d="M2.5 10a6 4 0 0 0 11 0 4 4 0 0 0 0-4 6 4 0 0 0-11 0 4 4 0 0 0 0 4z" stroke-width="2"/><path d="M6.2 7.2a2 1 0 1 0 3.6 0" stroke-width="1.75" stroke-linecap="round"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><g fill="none" stroke="#fc7f7f" mask="url(#a)"><path d="M2.5 10a6 4 0 0 0 11 0 4 4 0 0 0 0-4 6 4 0 0 0-11 0 4 4 0 0 0 0 4z" stroke-width="2"/><path d="M6.2 7.2a2 1 0 1 0 3.6 0" stroke-width="1.75" stroke-linecap="round"/></g></svg>
diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub
index 1dc4768186..61accd4fc9 100644
--- a/modules/gdscript/SCsub
+++ b/modules/gdscript/SCsub
@@ -19,6 +19,8 @@ if env.editor_build:
# Using a define in the disabled case, to avoid having an extra define
# in regular builds where all modules are enabled.
env_gdscript.Append(CPPDEFINES=["GDSCRIPT_NO_LSP"])
+ # Also needed in main env to unexpose --lsp-port option.
+ env.Append(CPPDEFINES=["GDSCRIPT_NO_LSP"])
if env["tests"]:
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
index becc2876f9..9128f104b8 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -40,7 +40,7 @@ void GDScriptEditorTranslationParserPlugin::get_recognized_extensions(List<Strin
}
Error GDScriptEditorTranslationParserPlugin::parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) {
- // Extract all translatable strings using the parsed tree from GDSriptParser.
+ // Extract all translatable strings using the parsed tree from GDScriptParser.
// The strategy is to find all ExpressionNode and AssignmentNode from the tree and extract strings if relevant, i.e
// Search strings in ExpressionNode -> CallNode -> tr(), set_text(), set_placeholder() etc.
// Search strings in AssignmentNode -> text = "__", tooltip_text = "__" etc.
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 6245cc85a0..4accdb4d21 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -992,6 +992,7 @@ void GDScript::set_path(const String &p_path, bool p_take_over) {
String old_path = path;
path = p_path;
+ path_valid = true;
GDScriptCache::move_script(old_path, p_path);
for (KeyValue<StringName, Ref<GDScript>> &kv : subclasses) {
@@ -1000,6 +1001,9 @@ void GDScript::set_path(const String &p_path, bool p_take_over) {
}
String GDScript::get_script_path() const {
+ if (!path_valid && !get_path().is_empty()) {
+ return get_path();
+ }
return path;
}
@@ -1035,6 +1039,7 @@ Error GDScript::load_source_code(const String &p_path) {
source = s;
path = p_path;
+ path_valid = true;
#ifdef TOOLS_ENABLED
source_changed_cache = true;
set_edited(false);
@@ -1387,33 +1392,106 @@ String GDScript::debug_get_script_name(const Ref<Script> &p_script) {
#endif
thread_local GDScript::UpdatableFuncPtr GDScript::func_ptrs_to_update_thread_local;
+GDScript::UpdatableFuncPtr *GDScript::func_ptrs_to_update_main_thread = &func_ptrs_to_update_thread_local;
+
+GDScript::UpdatableFuncPtrElement *GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) {
+ MutexLock lock(func_ptrs_to_update_mutex);
-GDScript::UpdatableFuncPtrElement GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) {
- UpdatableFuncPtrElement result = {};
+ List<UpdatableFuncPtrElement>::Element *result = func_ptrs_to_update_elems.push_back(UpdatableFuncPtrElement());
{
- MutexLock lock(func_ptrs_to_update_thread_local.mutex);
- result.element = func_ptrs_to_update_thread_local.ptrs.push_back(p_func_ptr_ptr);
- result.mutex = &func_ptrs_to_update_thread_local.mutex;
+ MutexLock lock2(func_ptrs_to_update_thread_local.mutex);
+ result->get().element = func_ptrs_to_update_thread_local.ptrs.push_back(p_func_ptr_ptr);
+ result->get().mutex = &func_ptrs_to_update_thread_local.mutex;
if (likely(func_ptrs_to_update_thread_local.initialized)) {
- return result;
+ return &result->get();
}
func_ptrs_to_update_thread_local.initialized = true;
}
- MutexLock lock(func_ptrs_to_update_mutex);
func_ptrs_to_update.push_back(&func_ptrs_to_update_thread_local);
- return result;
+ return &result->get();
+}
+
+void GDScript::_remove_func_ptr_to_update(const UpdatableFuncPtrElement *p_func_ptr_element) {
+ // None of these checks should ever fail, unless there's a bug.
+ // They can be removed once we are sure they never catch anything.
+ // Left here now due to extra safety needs late in the release cycle.
+ ERR_FAIL_NULL(p_func_ptr_element);
+ MutexLock lock(*p_func_ptr_element->mutex);
+ ERR_FAIL_NULL(p_func_ptr_element->element);
+ ERR_FAIL_NULL(p_func_ptr_element->mutex);
+ p_func_ptr_element->element->erase();
}
-void GDScript::_remove_func_ptr_to_update(const UpdatableFuncPtrElement p_func_ptr_element) {
- ERR_FAIL_NULL(p_func_ptr_element.element);
- ERR_FAIL_NULL(p_func_ptr_element.mutex);
- MutexLock lock(*p_func_ptr_element.mutex);
- p_func_ptr_element.element->erase();
+void GDScript::_fixup_thread_function_bookkeeping() {
+ // Transfer the ownership of these update items to the main thread,
+ // because the current one is dying, leaving theirs orphan, dangling.
+
+ HashSet<GDScript *> scripts;
+
+ DEV_ASSERT(!Thread::is_main_thread());
+ MutexLock lock(func_ptrs_to_update_main_thread->mutex);
+
+ {
+ MutexLock lock2(func_ptrs_to_update_thread_local.mutex);
+
+ while (!func_ptrs_to_update_thread_local.ptrs.is_empty()) {
+ // Transfer the thread-to-script records from the dying thread to the main one.
+
+ List<GDScriptFunction **>::Element *E = func_ptrs_to_update_thread_local.ptrs.front();
+ List<GDScriptFunction **>::Element *new_E = func_ptrs_to_update_main_thread->ptrs.push_front(E->get());
+
+ GDScript *script = (*E->get())->get_script();
+ if (!scripts.has(script)) {
+ scripts.insert(script);
+
+ // Replace dying thread by the main thread in the script-to-thread records.
+
+ MutexLock lock3(script->func_ptrs_to_update_mutex);
+ DEV_ASSERT(script->func_ptrs_to_update.find(&func_ptrs_to_update_thread_local));
+ {
+ for (List<UpdatableFuncPtrElement>::Element *F = script->func_ptrs_to_update_elems.front(); F; F = F->next()) {
+ bool is_dying_thread_entry = F->get().mutex == &func_ptrs_to_update_thread_local.mutex;
+ if (is_dying_thread_entry) {
+ // This may lead to multiple main-thread entries, but that's not a problem
+ // and allows to reuse the element, which is needed, since it's tracked by pointer.
+ F->get().element = new_E;
+ F->get().mutex = &func_ptrs_to_update_main_thread->mutex;
+ }
+ }
+ }
+ }
+
+ E->erase();
+ }
+ }
+ func_ptrs_to_update_main_thread->initialized = true;
+
+ {
+ // Remove orphan thread-to-script entries from every script.
+ // FIXME: This involves iterating through every script whenever a thread dies.
+ // While it's OK that thread creation/destruction are heavy operations,
+ // additional bookkeeping can be used to outperform this brute-force approach.
+
+ GDScriptLanguage *gd_lang = GDScriptLanguage::get_singleton();
+
+ MutexLock lock2(gd_lang->mutex);
+
+ for (SelfList<GDScript> *s = gd_lang->script_list.first(); s; s = s->next()) {
+ GDScript *script = s->self();
+ for (List<UpdatableFuncPtr *>::Element *E = script->func_ptrs_to_update.front(); E; E = E->next()) {
+ bool is_dying_thread_entry = &E->get()->mutex == &func_ptrs_to_update_thread_local.mutex;
+ if (is_dying_thread_entry) {
+ E->erase();
+ break;
+ }
+ }
+ }
+ }
}
void GDScript::clear(ClearData *p_clear_data) {
@@ -1441,6 +1519,7 @@ void GDScript::clear(ClearData *p_clear_data) {
*func_ptr_ptr = nullptr;
}
}
+ func_ptrs_to_update_elems.clear();
}
RBSet<GDScript *> must_clear_dependencies = get_must_clear_dependencies();
@@ -2060,6 +2139,10 @@ void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) {
named_globals.erase(p_name);
}
+void GDScriptLanguage::thread_exit() {
+ GDScript::_fixup_thread_function_bookkeeping();
+}
+
void GDScriptLanguage::init() {
//populate global constants
int gcc = CoreConstants::get_global_constant_count();
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 04b0a1d786..9b99f5ca0b 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -128,11 +128,16 @@ class GDScript : public Script {
Mutex *mutex = nullptr;
};
static thread_local UpdatableFuncPtr func_ptrs_to_update_thread_local;
+ static thread_local LocalVector<List<UpdatableFuncPtr *>::Element> func_ptrs_to_update_entries_thread_local;
+ static UpdatableFuncPtr *func_ptrs_to_update_main_thread;
List<UpdatableFuncPtr *> func_ptrs_to_update;
+ List<UpdatableFuncPtrElement> func_ptrs_to_update_elems;
Mutex func_ptrs_to_update_mutex;
- UpdatableFuncPtrElement _add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr);
- static void _remove_func_ptr_to_update(const UpdatableFuncPtrElement p_func_ptr_element);
+ UpdatableFuncPtrElement *_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr);
+ static void _remove_func_ptr_to_update(const UpdatableFuncPtrElement *p_func_ptr_element);
+
+ static void _fixup_thread_function_bookkeeping();
#ifdef TOOLS_ENABLED
// For static data storage during hot-reloading.
@@ -171,6 +176,7 @@ class GDScript : public Script {
//exported members
String source;
String path;
+ bool path_valid = false; // False if using default path.
StringName local_name; // Inner class identifier or `class_name`.
StringName global_name; // `class_name`.
String fully_qualified_name;
@@ -553,6 +559,10 @@ public:
virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value) override;
virtual void remove_named_global_constant(const StringName &p_name) override;
+ /* MULTITHREAD FUNCTIONS */
+
+ virtual void thread_exit() override;
+
/* DEBUGGER FUNCTIONS */
virtual String debug_get_error() const override;
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index 26f01ec218..76f4e69ab9 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -364,28 +364,33 @@ void GDScriptCache::remove_static_script(const String &p_fqcn) {
Ref<PackedScene> GDScriptCache::get_packed_scene(const String &p_path, Error &r_error, const String &p_owner) {
MutexLock lock(singleton->mutex);
- if (singleton->packed_scene_cache.has(p_path)) {
- singleton->packed_scene_dependencies[p_path].insert(p_owner);
- return singleton->packed_scene_cache[p_path];
+ String path = p_path;
+ if (path.begins_with("uid://")) {
+ path = ResourceUID::get_singleton()->get_id_path(ResourceUID::get_singleton()->text_to_id(path));
}
- Ref<PackedScene> scene = ResourceCache::get_ref(p_path);
+ if (singleton->packed_scene_cache.has(path)) {
+ singleton->packed_scene_dependencies[path].insert(p_owner);
+ return singleton->packed_scene_cache[path];
+ }
+
+ Ref<PackedScene> scene = ResourceCache::get_ref(path);
if (scene.is_valid()) {
- singleton->packed_scene_cache[p_path] = scene;
- singleton->packed_scene_dependencies[p_path].insert(p_owner);
+ singleton->packed_scene_cache[path] = scene;
+ singleton->packed_scene_dependencies[path].insert(p_owner);
return scene;
}
scene.instantiate();
r_error = OK;
- if (p_path.is_empty()) {
+ if (path.is_empty()) {
r_error = ERR_FILE_BAD_PATH;
return scene;
}
- scene->set_path(p_path);
- singleton->packed_scene_cache[p_path] = scene;
- singleton->packed_scene_dependencies[p_path].insert(p_owner);
+ scene->set_path(path);
+ singleton->packed_scene_cache[path] = scene;
+ singleton->packed_scene_dependencies[path].insert(p_owner);
scene->reload_from_file();
return scene;
diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp
index 547f5607d3..339d1ac08e 100644
--- a/modules/gdscript/gdscript_lambda_callable.cpp
+++ b/modules/gdscript/gdscript_lambda_callable.cpp
@@ -296,5 +296,7 @@ GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptF
}
GDScriptLambdaSelfCallable::~GDScriptLambdaSelfCallable() {
- GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element);
+ if (updatable_func_ptr_element) {
+ GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element);
+ }
}
diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h
index ee7d547544..d961f18852 100644
--- a/modules/gdscript/gdscript_lambda_callable.h
+++ b/modules/gdscript/gdscript_lambda_callable.h
@@ -45,7 +45,7 @@ class GDScriptLambdaCallable : public CallableCustom {
GDScriptFunction *function = nullptr;
Ref<GDScript> script;
uint32_t h;
- GDScript::UpdatableFuncPtrElement updatable_func_ptr_element;
+ GDScript::UpdatableFuncPtrElement *updatable_func_ptr_element = nullptr;
Vector<Variant> captures;
@@ -72,7 +72,7 @@ class GDScriptLambdaSelfCallable : public CallableCustom {
Ref<RefCounted> reference; // For objects that are RefCounted, keep a reference.
Object *object = nullptr; // For non RefCounted objects, use a direct pointer.
uint32_t h;
- GDScript::UpdatableFuncPtrElement updatable_func_ptr_element;
+ GDScript::UpdatableFuncPtrElement *updatable_func_ptr_element = nullptr;
Vector<Variant> captures;
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 9067864dfe..4b46b98baa 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -178,11 +178,11 @@ public:
bool operator==(const DataType &p_other) const {
if (type_source == UNDETECTED || p_other.type_source == UNDETECTED) {
- return true; // Can be consireded equal for parsing purposes.
+ return true; // Can be considered equal for parsing purposes.
}
if (type_source == INFERRED || p_other.type_source == INFERRED) {
- return true; // Can be consireded equal for parsing purposes.
+ return true; // Can be considered equal for parsing purposes.
}
if (kind != p_other.kind) {
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index b723ecc185..d31411b26b 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -662,6 +662,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
uint32_t op_signature = _code_ptr[ip + 5];
uint32_t actual_signature = (a->get_type() << 8) | (b->get_type());
+#ifdef DEBUG_ENABLED
+ if (op == Variant::OP_DIVIDE || op == Variant::OP_MODULE) {
+ // Don't optimize division and modulo since there's not check for division by zero with validated calls.
+ op_signature = 0xFFFF;
+ _code_ptr[ip + 5] = op_signature;
+ }
+#endif
+
// Check if this is the first run. If so, store the current signature for the optimized path.
if (unlikely(op_signature == 0)) {
static Mutex initializer_mutex;
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
index cb45a6589e..2fad475e92 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.cpp
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -130,8 +130,9 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
// Get global paths for source and sink.
// Escape paths to be valid Python strings to embed in the script.
const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape();
+ const String blend_basename = p_path.get_file().get_basename();
const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
- vformat("%s-%s.gltf", p_path.get_file().get_basename(), p_path.md5_text()));
+ vformat("%s-%s.gltf", blend_basename, p_path.md5_text()));
const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape();
// Handle configuration options.
@@ -282,6 +283,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
if (p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")]) {
base_dir = sink.get_base_dir();
}
+ state->set_scene_name(blend_basename);
err = gltf->append_from_file(sink.get_basename() + ".gltf", state, p_flags, base_dir);
if (err != OK) {
if (r_err) {
diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp
index b63a938e64..e35c0e9b9b 100644
--- a/modules/gltf/editor/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp
@@ -51,6 +51,10 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t
gltf.instantiate();
Ref<GLTFState> state;
state.instantiate();
+ if (p_options.has("gltf/naming_version")) {
+ int naming_version = p_options["gltf/naming_version"];
+ gltf->set_naming_version(naming_version);
+ }
if (p_options.has("gltf/embedded_image_handling")) {
int32_t enum_option = p_options["gltf/embedded_image_handling"];
state->set_handle_binary_image(enum_option);
@@ -77,7 +81,16 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t
void EditorSceneFormatImporterGLTF::get_import_options(const String &p_path,
List<ResourceImporter::ImportOption> *r_options) {
- r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed As Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES));
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/naming_version", PROPERTY_HINT_ENUM, "Godot 4.1 or 4.0,Godot 4.2 or later"), 1));
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES));
+}
+
+void EditorSceneFormatImporterGLTF::handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const {
+ if (!p_import_params.has("gltf/naming_version")) {
+ // If an existing import file is missing the glTF
+ // compatibility version, we need to use version 0.
+ p_import_params["gltf/naming_version"] = 0;
+ }
}
#endif // TOOLS_ENABLED
diff --git a/modules/gltf/editor/editor_scene_importer_gltf.h b/modules/gltf/editor/editor_scene_importer_gltf.h
index ed57ec8cdb..7726c845bf 100644
--- a/modules/gltf/editor/editor_scene_importer_gltf.h
+++ b/modules/gltf/editor/editor_scene_importer_gltf.h
@@ -49,6 +49,7 @@ public:
List<String> *r_missing_deps, Error *r_err = nullptr) override;
virtual void get_import_options(const String &p_path,
List<ResourceImporter::ImportOption> *r_options) override;
+ virtual void handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const override;
};
#endif // TOOLS_ENABLED
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 47fc58fe43..4060f7f626 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -573,9 +573,12 @@ Error GLTFDocument::_parse_scenes(Ref<GLTFState> p_state) {
// Determine what to use for the scene name.
if (scene_dict.has("name") && !String(scene_dict["name"]).is_empty() && !((String)scene_dict["name"]).begins_with("Scene")) {
p_state->scene_name = scene_dict["name"];
- } else {
+ } else if (p_state->scene_name.is_empty()) {
p_state->scene_name = p_state->filename;
}
+ if (_naming_version == 0) {
+ p_state->scene_name = _gen_unique_name(p_state, p_state->scene_name);
+ }
}
return OK;
@@ -2797,9 +2800,26 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
array[Mesh::ARRAY_INDEX] = indices;
}
- bool generate_tangents = p_state->force_generate_tangents && (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL"));
+ bool generate_tangents = p_state->force_generate_tangents && (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("NORMAL"));
+
+ if (generate_tangents && !a.has("TEXCOORD_0")) {
+ // If we don't have UVs we provide a dummy tangent array.
+ Vector<float> tangents;
+ tangents.resize(vertex_num * 4);
+ float *tangentsw = tangents.ptrw();
+
+ Vector<Vector3> normals = array[Mesh::ARRAY_NORMAL];
+ for (int k = 0; k < vertex_num; k++) {
+ Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normals[k]);
+ tangentsw[k * 4 + 0] = tan.x;
+ tangentsw[k * 4 + 1] = tan.y;
+ tangentsw[k * 4 + 2] = tan.z;
+ tangentsw[k * 4 + 3] = 1.0;
+ }
+ array[Mesh::ARRAY_TANGENT] = tangents;
+ }
- if (p_state->force_disable_compression || !a.has("POSITION") || !a.has("NORMAL") || !(a.has("TANGENT") || generate_tangents) || p.has("targets") || (a.has("JOINTS_0") || a.has("JOINTS_1"))) {
+ if (p_state->force_disable_compression || !a.has("POSITION") || !a.has("NORMAL") || p.has("targets") || (a.has("JOINTS_0") || a.has("JOINTS_1"))) {
flags &= ~RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES;
}
@@ -2810,7 +2830,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
mesh_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
}
mesh_surface_tool->index();
- if (generate_tangents) {
+ if (generate_tangents && a.has("TEXCOORD_0")) {
//must generate mikktspace tangents.. ergh..
mesh_surface_tool->generate_tangents();
}
@@ -3006,6 +3026,14 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
return OK;
}
+void GLTFDocument::set_naming_version(int p_version) {
+ _naming_version = p_version;
+}
+
+int GLTFDocument::get_naming_version() const {
+ return _naming_version;
+}
+
void GLTFDocument::set_image_format(const String &p_image_format) {
_image_format = p_image_format;
}
@@ -5341,12 +5369,22 @@ void GLTFDocument::_assign_node_names(Ref<GLTFState> p_state) {
}
String gltf_node_name = gltf_node->get_name();
if (gltf_node_name.is_empty()) {
- if (gltf_node->mesh >= 0) {
- gltf_node_name = "Mesh";
- } else if (gltf_node->camera >= 0) {
- gltf_node_name = "Camera";
+ if (_naming_version == 0) {
+ if (gltf_node->mesh >= 0) {
+ gltf_node_name = _gen_unique_name(p_state, "Mesh");
+ } else if (gltf_node->camera >= 0) {
+ gltf_node_name = _gen_unique_name(p_state, "Camera3D");
+ } else {
+ gltf_node_name = _gen_unique_name(p_state, "Node");
+ }
} else {
- gltf_node_name = "Node";
+ if (gltf_node->mesh >= 0) {
+ gltf_node_name = "Mesh";
+ } else if (gltf_node->camera >= 0) {
+ gltf_node_name = "Camera";
+ } else {
+ gltf_node_name = "Node";
+ }
}
}
gltf_node->set_name(_gen_unique_name(p_state, gltf_node_name));
@@ -5846,6 +5884,10 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> p_state, const GLTFNodeIn
BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, gltf_node->parent);
p_scene_parent->add_child(bone_attachment, true);
+
+ // Find the correct bone_idx so we can properly serialize it.
+ bone_attachment->set_bone_idx(active_skeleton->find_bone(gltf_node->get_name()));
+
bone_attachment->set_owner(p_scene_root);
// There is no gltf_node that represent this, so just directly create a unique name
@@ -5949,6 +5991,10 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> p_state, const GL
BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, p_node_index);
p_scene_parent->add_child(bone_attachment, true);
+
+ // Find the correct bone_idx so we can properly serialize it.
+ bone_attachment->set_bone_idx(active_skeleton->find_bone(gltf_node->get_name()));
+
bone_attachment->set_owner(p_scene_root);
// There is no gltf_node that represent this, so just directly create a unique name
@@ -7380,7 +7426,11 @@ Node *GLTFDocument::_generate_scene_node_tree(Ref<GLTFState> p_state) {
if (unlikely(p_state->scene_name.is_empty())) {
p_state->scene_name = single_root->get_name();
} else if (single_root->get_name() == StringName()) {
- single_root->set_name(_gen_unique_name(p_state, p_state->scene_name));
+ if (_naming_version == 0) {
+ single_root->set_name(p_state->scene_name);
+ } else {
+ single_root->set_name(_gen_unique_name(p_state, p_state->scene_name));
+ }
}
return single_root;
}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 828d650cff..7e378fe94d 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -73,6 +73,7 @@ public:
private:
const float BAKE_FPS = 30.0f;
+ int _naming_version = 1;
String _image_format = "PNG";
float _lossy_quality = 0.75f;
Ref<GLTFDocumentExtension> _image_save_extension;
@@ -86,6 +87,8 @@ public:
static void unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension);
static void unregister_all_gltf_document_extensions();
+ void set_naming_version(int p_version);
+ int get_naming_version() const;
void set_image_format(const String &p_image_format);
String get_image_format() const;
void set_lossy_quality(float p_lossy_quality);
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index c0ec004fd6..766fe41257 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -124,7 +124,7 @@ void GLTFState::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skeletons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeletons", "get_skeletons"); // Vector<Ref<GLTFSkeleton>>
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "create_animations"), "set_create_animations", "get_create_animations"); // bool
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>>
- ADD_PROPERTY(PropertyInfo(Variant::INT, "handle_binary_image", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed As Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_handle_binary_image", "get_handle_binary_image"); // enum
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "handle_binary_image", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_handle_binary_image", "get_handle_binary_image"); // enum
BIND_CONSTANT(HANDLE_BINARY_DISCARD_TEXTURES);
BIND_CONSTANT(HANDLE_BINARY_EXTRACT_TEXTURES);
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index 0b9fcf4455..e7fa909706 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -156,7 +156,11 @@ public:
static Error _jpgd_save_to_output_stream(jpge::output_stream *p_output_stream, const Ref<Image> &p_img, float p_quality) {
ERR_FAIL_COND_V(p_img.is_null() || p_img->is_empty(), ERR_INVALID_PARAMETER);
- Ref<Image> image = p_img;
+ Ref<Image> image = p_img->duplicate();
+ if (image->is_compressed()) {
+ Error error = image->decompress();
+ ERR_FAIL_COND_V_MSG(error != OK, error, "Couldn't decompress image.");
+ }
if (image->get_format() != Image::FORMAT_RGB8) {
image->convert(Image::FORMAT_RGB8);
}
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index fe919953c1..a4ecb767a7 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -877,7 +877,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise_oidn(RenderingDevice *p_rd, RID
if (err != OK || exitcode != 0) {
da->remove(fname_out);
print_verbose(str);
- ERR_FAIL_V_MSG(BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, vformat(TTR("OIDN denoiser failed, return code: %d"), exitcode));
+ ERR_FAIL_V_MSG(BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, vformat("OIDN denoiser failed, return code: %d", exitcode));
}
Ref<Image> img = _read_pfm(fname_out);
@@ -988,7 +988,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
oidn_path = oidn_path.path_join("oidnDenoise");
}
}
- ERR_FAIL_COND_V_MSG(oidn_path.is_empty() || !da->file_exists(oidn_path), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, TTR("OIDN denoiser is selected in the project settings, but no or invalid OIDN executable path is configured in the editor settings."));
+ ERR_FAIL_COND_V_MSG(oidn_path.is_empty() || !da->file_exists(oidn_path), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, "OIDN denoiser is selected in the project settings, but no or invalid OIDN executable path is configured in the editor settings.");
}
if (p_step_function) {
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 44bcd4cfe4..56e4fa53d0 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -142,6 +142,10 @@ void CSharpLanguage::finalize() {
return;
}
+ if (gdmono && gdmono->is_runtime_initialized() && GDMonoCache::godot_api_cache_updated) {
+ GDMonoCache::managed_callbacks.DisposablesTracker_OnGodotShuttingDown();
+ }
+
finalizing = true;
// Make sure all script binding gchandles are released before finalizing GDMono
@@ -1985,24 +1989,31 @@ const Variant CSharpInstance::get_rpc_config() const {
void CSharpInstance::notification(int p_notification, bool p_reversed) {
if (p_notification == Object::NOTIFICATION_PREDELETE) {
- // When NOTIFICATION_PREDELETE is sent, we also take the chance to call Dispose().
- // It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE is guaranteed
+ if (base_ref_counted) {
+ // At this point, Dispose() was already called (manually or from the finalizer).
+ // The RefCounted wouldn't have reached 0 otherwise, since the managed side
+ // references it and Dispose() needs to be called to release it.
+ // However, this means C# RefCounted scripts can't receive NOTIFICATION_PREDELETE, but
+ // this is likely the case with GDScript as well: https://github.com/godotengine/godot/issues/6784
+ return;
+ }
+ } else if (p_notification == Object::NOTIFICATION_PREDELETE_CLEANUP) {
+ // When NOTIFICATION_PREDELETE_CLEANUP is sent, we also take the chance to call Dispose().
+ // It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE_CLEANUP is guaranteed
// to be sent at least once, which happens right before the call to the destructor.
predelete_notified = true;
if (base_ref_counted) {
- // It's not safe to proceed if the owner derives RefCounted and the refcount reached 0.
- // At this point, Dispose() was already called (manually or from the finalizer) so
- // that's not a problem. The refcount wouldn't have reached 0 otherwise, since the
- // managed side references it and Dispose() needs to be called to release it.
- // However, this means C# RefCounted scripts can't receive NOTIFICATION_PREDELETE, but
- // this is likely the case with GDScript as well: https://github.com/godotengine/godot/issues/6784
+ // At this point, Dispose() was already called (manually or from the finalizer).
+ // The RefCounted wouldn't have reached 0 otherwise, since the managed side
+ // references it and Dispose() needs to be called to release it.
return;
}
- _call_notification(p_notification, p_reversed);
-
+ // NOTIFICATION_PREDELETE_CLEANUP is not sent to scripts.
+ // After calling Dispose() the C# instance can no longer be used,
+ // so it should be the last thing we do.
GDMonoCache::managed_callbacks.CSharpInstanceBridge_CallDispose(
gchandle.get_intptr(), /* okIfNull */ false);
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
index df35091596..147ef852b3 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
@@ -230,6 +230,31 @@ namespace Godot.SourceGenerators
location?.SourceTree?.FilePath));
}
+ public static void ReportOnlyNodesShouldExportNodes(
+ GeneratorExecutionContext context,
+ ISymbol exportedMemberSymbol
+ )
+ {
+ var locations = exportedMemberSymbol.Locations;
+ var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
+ bool isField = exportedMemberSymbol is IFieldSymbol;
+
+ string message = $"Types not derived from Node should not export Node {(isField ? "fields" : "properties")}";
+
+ string description = $"{message}. Node export is only supported in Node-derived classes.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0107",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ location,
+ location?.SourceTree?.FilePath));
+ }
+
public static void ReportSignalDelegateMissingSuffix(
GeneratorExecutionContext context,
INamedTypeSymbol delegateSymbol)
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index 5866db5144..c7fd45238d 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -32,7 +32,7 @@ namespace Godot.SourceGenerators
disabledGenerators != null &&
disabledGenerators.Split(';').Contains(generatorName));
- public static bool InheritsFrom(this INamedTypeSymbol? symbol, string assemblyName, string typeFullName)
+ public static bool InheritsFrom(this ITypeSymbol? symbol, string assemblyName, string typeFullName)
{
while (symbol != null)
{
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
index fc0bfbf084..253e24f092 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -170,6 +170,15 @@ namespace Godot.SourceGenerators
continue;
}
+ if (marshalType == MarshalType.GodotObjectOrDerived)
+ {
+ if (!symbol.InheritsFrom("GodotSharp", "Godot.Node") &&
+ propertyType.InheritsFrom("GodotSharp", "Godot.Node"))
+ {
+ Common.ReportOnlyNodesShouldExportNodes(context, property);
+ }
+ }
+
var propertyDeclarationSyntax = property.DeclaringSyntaxReferences
.Select(r => r.GetSyntax() as PropertyDeclarationSyntax).FirstOrDefault();
@@ -265,6 +274,15 @@ namespace Godot.SourceGenerators
continue;
}
+ if (marshalType == MarshalType.GodotObjectOrDerived)
+ {
+ if (!symbol.InheritsFrom("GodotSharp", "Godot.Node") &&
+ fieldType.InheritsFrom("GodotSharp", "Godot.Node"))
+ {
+ Common.ReportOnlyNodesShouldExportNodes(context, field);
+ }
+ }
+
EqualsValueClauseSyntax? initializer = field.DeclaringSyntaxReferences
.Select(r => r.GetSyntax())
.OfType<VariableDeclaratorSyntax>()
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
index 7b1d5c228a..1d17f3d4f5 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
@@ -1,5 +1,7 @@
using System;
+using System.Linq;
using Microsoft.Build.Construction;
+using Microsoft.Build.Locator;
namespace GodotTools.ProjectEditor
{
@@ -19,15 +21,18 @@ namespace GodotTools.ProjectEditor
public static class ProjectUtils
{
- public static void MSBuildLocatorRegisterDefaults(out Version version, out string path)
+ public static void MSBuildLocatorRegisterLatest(out Version version, out string path)
{
- var instance = Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults();
+ var instance = MSBuildLocator.QueryVisualStudioInstances()
+ .OrderByDescending(x => x.Version)
+ .First();
+ MSBuildLocator.RegisterInstance(instance);
version = instance.Version;
path = instance.MSBuildPath;
}
public static void MSBuildLocatorRegisterMSBuildPath(string msbuildPath)
- => Microsoft.Build.Locator.MSBuildLocator.RegisterMSBuildPath(msbuildPath);
+ => MSBuildLocator.RegisterMSBuildPath(msbuildPath);
public static MSBuildProject Open(string path)
{
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index a00c812c79..650afb4cdf 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -456,7 +456,7 @@ namespace GodotTools
var dotNetSdkSearchVersion = Environment.Version;
// First we try to find the .NET Sdk ourselves to make sure we get the
- // correct version first (`RegisterDefaults` always picks the latest).
+ // correct version first, otherwise pick the latest.
if (DotNetFinder.TryFindDotNetSdk(dotNetSdkSearchVersion, out var sdkVersion, out string sdkPath))
{
if (Godot.OS.IsStdOutVerbose())
@@ -468,7 +468,7 @@ namespace GodotTools
{
try
{
- ProjectUtils.MSBuildLocatorRegisterDefaults(out sdkVersion, out sdkPath);
+ ProjectUtils.MSBuildLocatorRegisterLatest(out sdkVersion, out sdkPath);
if (Godot.OS.IsStdOutVerbose())
Console.WriteLine($"Found .NET Sdk version '{sdkVersion}': {sdkPath}");
}
@@ -497,7 +497,10 @@ namespace GodotTools
AddChild(new HotReloadAssemblyWatcher { Name = "HotReloadAssemblyWatcher" });
- _menuPopup = new PopupMenu();
+ _menuPopup = new PopupMenu
+ {
+ Name = "CSharpTools",
+ };
_menuPopup.Hide();
AddToolSubmenuItem("C#", _menuPopup);
@@ -626,6 +629,12 @@ namespace GodotTools
_editorSettings.SettingsChanged -= OnSettingsChanged;
}
+ public override void _ExitTree()
+ {
+ _errorDialog?.QueueFree();
+ _confirmCreateSlnDialog?.QueueFree();
+ }
+
private void OnSettingsChanged()
{
// We want to force NoConsoleLogging to true when the VerbosityLevel is at Detailed or above.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
index 93a83b701b..0cc89d78af 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
@@ -259,7 +259,7 @@ namespace Godot.NativeInterop
}
return new godot_callable(method /* Takes ownership of disposable */,
- p_managed_callable.Target.GetInstanceId());
+ p_managed_callable.Target?.GetInstanceId() ?? 0);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
index 4ee452455e..215bb4df8c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
@@ -182,8 +182,8 @@ namespace Godot
}
// Constants
- private static readonly Vector2I _min = new Vector2I(int.MinValue, int.MinValue);
- private static readonly Vector2I _max = new Vector2I(int.MaxValue, int.MaxValue);
+ private static readonly Vector2I _minValue = new Vector2I(int.MinValue, int.MinValue);
+ private static readonly Vector2I _maxValue = new Vector2I(int.MaxValue, int.MaxValue);
private static readonly Vector2I _zero = new Vector2I(0, 0);
private static readonly Vector2I _one = new Vector2I(1, 1);
@@ -197,12 +197,12 @@ namespace Godot
/// Min vector, a vector with all components equal to <see cref="int.MinValue"/>. Can be used as a negative integer equivalent of <see cref="Vector2.Inf"/>.
/// </summary>
/// <value>Equivalent to <c>new Vector2I(int.MinValue, int.MinValue)</c>.</value>
- public static Vector2I Min { get { return _min; } }
+ public static Vector2I MinValue { get { return _minValue; } }
/// <summary>
/// Max vector, a vector with all components equal to <see cref="int.MaxValue"/>. Can be used as an integer equivalent of <see cref="Vector2.Inf"/>.
/// </summary>
/// <value>Equivalent to <c>new Vector2I(int.MaxValue, int.MaxValue)</c>.</value>
- public static Vector2I Max { get { return _max; } }
+ public static Vector2I MaxValue { get { return _maxValue; } }
/// <summary>
/// Zero vector, a vector with all components set to <c>0</c>.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
index db8ceb30e9..fe74ec8884 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
@@ -193,8 +193,8 @@ namespace Godot
}
// Constants
- private static readonly Vector3I _min = new Vector3I(int.MinValue, int.MinValue, int.MinValue);
- private static readonly Vector3I _max = new Vector3I(int.MaxValue, int.MaxValue, int.MaxValue);
+ private static readonly Vector3I _minValue = new Vector3I(int.MinValue, int.MinValue, int.MinValue);
+ private static readonly Vector3I _maxValue = new Vector3I(int.MaxValue, int.MaxValue, int.MaxValue);
private static readonly Vector3I _zero = new Vector3I(0, 0, 0);
private static readonly Vector3I _one = new Vector3I(1, 1, 1);
@@ -210,12 +210,12 @@ namespace Godot
/// Min vector, a vector with all components equal to <see cref="int.MinValue"/>. Can be used as a negative integer equivalent of <see cref="Vector3.Inf"/>.
/// </summary>
/// <value>Equivalent to <c>new Vector3I(int.MinValue, int.MinValue, int.MinValue)</c>.</value>
- public static Vector3I Min { get { return _min; } }
+ public static Vector3I MinValue { get { return _minValue; } }
/// <summary>
/// Max vector, a vector with all components equal to <see cref="int.MaxValue"/>. Can be used as an integer equivalent of <see cref="Vector3.Inf"/>.
/// </summary>
/// <value>Equivalent to <c>new Vector3I(int.MaxValue, int.MaxValue, int.MaxValue)</c>.</value>
- public static Vector3I Max { get { return _max; } }
+ public static Vector3I MaxValue { get { return _maxValue; } }
/// <summary>
/// Zero vector, a vector with all components set to <c>0</c>.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
index e75e996b04..a0a4393523 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
@@ -228,8 +228,8 @@ namespace Godot
}
// Constants
- private static readonly Vector4I _min = new Vector4I(int.MinValue, int.MinValue, int.MinValue, int.MinValue);
- private static readonly Vector4I _max = new Vector4I(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue);
+ private static readonly Vector4I _minValue = new Vector4I(int.MinValue, int.MinValue, int.MinValue, int.MinValue);
+ private static readonly Vector4I _maxValue = new Vector4I(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue);
private static readonly Vector4I _zero = new Vector4I(0, 0, 0, 0);
private static readonly Vector4I _one = new Vector4I(1, 1, 1, 1);
@@ -238,12 +238,12 @@ namespace Godot
/// Min vector, a vector with all components equal to <see cref="int.MinValue"/>. Can be used as a negative integer equivalent of <see cref="Vector4.Inf"/>.
/// </summary>
/// <value>Equivalent to <c>new Vector4I(int.MinValue, int.MinValue, int.MinValue, int.MinValue)</c>.</value>
- public static Vector4I Min { get { return _min; } }
+ public static Vector4I MinValue { get { return _minValue; } }
/// <summary>
/// Max vector, a vector with all components equal to <see cref="int.MaxValue"/>. Can be used as an integer equivalent of <see cref="Vector4.Inf"/>.
/// </summary>
/// <value>Equivalent to <c>new Vector4I(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)</c>.</value>
- public static Vector4I Max { get { return _max; } }
+ public static Vector4I MaxValue { get { return _maxValue; } }
/// <summary>
/// Zero vector, a vector with all components set to <c>0</c>.
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index ca2ad315a7..3eb746677d 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -556,12 +556,6 @@ GDMono::GDMono() {
GDMono::~GDMono() {
finalizing_scripts_domain = true;
- if (is_runtime_initialized()) {
- if (GDMonoCache::godot_api_cache_updated) {
- GDMonoCache::managed_callbacks.DisposablesTracker_OnGodotShuttingDown();
- }
- }
-
if (hostfxr_dll_handle) {
OS::get_singleton()->close_dynamic_library(hostfxr_dll_handle);
}
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 5ef0298eb4..ca1034dcc0 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -1125,6 +1125,7 @@ void NavMap::_update_rvo_obstacles_tree_2d() {
rvo_2d_vertices.reserve(_obstacle_vertices.size());
uint32_t _obstacle_avoidance_layers = obstacle->get_avoidance_layers();
+ real_t _obstacle_height = obstacle->get_height();
for (const Vector3 &_obstacle_vertex : _obstacle_vertices) {
rvo_2d_vertices.push_back(RVO2D::Vector2(_obstacle_vertex.x + _obstacle_position.x, _obstacle_vertex.z + _obstacle_position.z));
@@ -1135,6 +1136,9 @@ void NavMap::_update_rvo_obstacles_tree_2d() {
for (size_t i = 0; i < rvo_2d_vertices.size(); i++) {
RVO2D::Obstacle2D *rvo_2d_obstacle = new RVO2D::Obstacle2D();
rvo_2d_obstacle->point_ = rvo_2d_vertices[i];
+ rvo_2d_obstacle->height_ = _obstacle_height;
+ rvo_2d_obstacle->elevation_ = _obstacle_position.y;
+
rvo_2d_obstacle->avoidance_layers_ = _obstacle_avoidance_layers;
if (i != 0) {
diff --git a/modules/navigation/nav_mesh_generator_2d.cpp b/modules/navigation/nav_mesh_generator_2d.cpp
index 089744c8bd..f8c12935b4 100644
--- a/modules/navigation/nav_mesh_generator_2d.cpp
+++ b/modules/navigation/nav_mesh_generator_2d.cpp
@@ -587,6 +587,9 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo
const Vector2i &cell = used_cells[used_cell_index];
const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false);
+ if (tile_data == nullptr) {
+ continue;
+ }
Transform2D tile_transform;
tile_transform.set_origin(tilemap->map_to_local(cell));
@@ -597,10 +600,19 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo
Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer);
if (navigation_polygon.is_valid()) {
for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
- Vector<Vector2> traversable_outline = navigation_polygon->get_outline(outline_index);
+ const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index);
+ if (navigation_polygon_outline.size() == 0) {
+ continue;
+ }
+
+ Vector<Vector2> traversable_outline;
+ traversable_outline.resize(navigation_polygon_outline.size());
+
+ const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr();
+ Vector2 *traversable_outline_ptrw = traversable_outline.ptrw();
for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) {
- traversable_outline.write[traversable_outline_index] = tile_transform_offset.xform(traversable_outline[traversable_outline_index]);
+ traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]);
}
p_source_geometry_data->_add_traversable_outline(traversable_outline);
@@ -610,10 +622,19 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo
if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) {
for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) {
- Vector<Vector2> obstruction_outline = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
+ const Vector<Vector2> &collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
+ if (collision_polygon_points.size() == 0) {
+ continue;
+ }
+
+ Vector<Vector2> obstruction_outline;
+ obstruction_outline.resize(collision_polygon_points.size());
+
+ const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr();
+ Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw();
for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) {
- obstruction_outline.write[obstruction_outline_index] = tile_transform_offset.xform(obstruction_outline[obstruction_outline_index]);
+ obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]);
}
p_source_geometry_data->_add_obstruction_outline(obstruction_outline);
diff --git a/modules/navigation/nav_mesh_generator_3d.cpp b/modules/navigation/nav_mesh_generator_3d.cpp
index 5de1c4cba9..8719801c72 100644
--- a/modules/navigation/nav_mesh_generator_3d.cpp
+++ b/modules/navigation/nav_mesh_generator_3d.cpp
@@ -384,33 +384,23 @@ void NavMeshGenerator3D::generator_parse_staticbody3d_node(const Ref<NavigationM
const Vector<real_t> &map_data = heightmap_shape->get_map_data();
Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1);
- Vector2 start = heightmap_gridsize * -0.5;
+ Vector3 start = Vector3(heightmap_gridsize.x, 0, heightmap_gridsize.y) * -0.5;
Vector<Vector3> vertex_array;
vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6);
- int map_data_current_index = 0;
-
- for (int d = 0; d < heightmap_depth; d++) {
- for (int w = 0; w < heightmap_width; w++) {
- if (map_data_current_index + 1 + heightmap_depth < map_data.size()) {
- float top_left_height = map_data[map_data_current_index];
- float top_right_height = map_data[map_data_current_index + 1];
- float bottom_left_height = map_data[map_data_current_index + heightmap_depth];
- float bottom_right_height = map_data[map_data_current_index + 1 + heightmap_depth];
-
- Vector3 top_left = Vector3(start.x + w, top_left_height, start.y + d);
- Vector3 top_right = Vector3(start.x + w + 1.0, top_right_height, start.y + d);
- Vector3 bottom_left = Vector3(start.x + w, bottom_left_height, start.y + d + 1.0);
- Vector3 bottom_right = Vector3(start.x + w + 1.0, bottom_right_height, start.y + d + 1.0);
-
- vertex_array.push_back(top_right);
- vertex_array.push_back(bottom_left);
- vertex_array.push_back(top_left);
- vertex_array.push_back(top_right);
- vertex_array.push_back(bottom_right);
- vertex_array.push_back(bottom_left);
- }
- map_data_current_index += 1;
+ Vector3 *vertex_array_ptrw = vertex_array.ptrw();
+ const real_t *map_data_ptr = map_data.ptr();
+ int vertex_index = 0;
+
+ for (int d = 0; d < heightmap_depth - 1; d++) {
+ for (int w = 0; w < heightmap_width - 1; w++) {
+ vertex_array_ptrw[vertex_index] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + w], d);
+ vertex_array_ptrw[vertex_index + 1] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d);
+ vertex_array_ptrw[vertex_index + 2] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1);
+ vertex_array_ptrw[vertex_index + 3] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d);
+ vertex_array_ptrw[vertex_index + 4] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + heightmap_width + w + 1], d + 1);
+ vertex_array_ptrw[vertex_index + 5] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1);
+ vertex_index += 6;
}
}
if (vertex_array.size() > 0) {
@@ -540,33 +530,23 @@ void NavMeshGenerator3D::generator_parse_gridmap_node(const Ref<NavigationMesh>
const Vector<real_t> &map_data = dict["heights"];
Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1);
- Vector2 start = heightmap_gridsize * -0.5;
+ Vector3 start = Vector3(heightmap_gridsize.x, 0, heightmap_gridsize.y) * -0.5;
Vector<Vector3> vertex_array;
vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6);
- int map_data_current_index = 0;
-
- for (int d = 0; d < heightmap_depth; d++) {
- for (int w = 0; w < heightmap_width; w++) {
- if (map_data_current_index + 1 + heightmap_depth < map_data.size()) {
- float top_left_height = map_data[map_data_current_index];
- float top_right_height = map_data[map_data_current_index + 1];
- float bottom_left_height = map_data[map_data_current_index + heightmap_depth];
- float bottom_right_height = map_data[map_data_current_index + 1 + heightmap_depth];
-
- Vector3 top_left = Vector3(start.x + w, top_left_height, start.y + d);
- Vector3 top_right = Vector3(start.x + w + 1.0, top_right_height, start.y + d);
- Vector3 bottom_left = Vector3(start.x + w, bottom_left_height, start.y + d + 1.0);
- Vector3 bottom_right = Vector3(start.x + w + 1.0, bottom_right_height, start.y + d + 1.0);
-
- vertex_array.push_back(top_right);
- vertex_array.push_back(bottom_left);
- vertex_array.push_back(top_left);
- vertex_array.push_back(top_right);
- vertex_array.push_back(bottom_right);
- vertex_array.push_back(bottom_left);
- }
- map_data_current_index += 1;
+ Vector3 *vertex_array_ptrw = vertex_array.ptrw();
+ const real_t *map_data_ptr = map_data.ptr();
+ int vertex_index = 0;
+
+ for (int d = 0; d < heightmap_depth - 1; d++) {
+ for (int w = 0; w < heightmap_width - 1; w++) {
+ vertex_array_ptrw[vertex_index] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + w], d);
+ vertex_array_ptrw[vertex_index + 1] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d);
+ vertex_array_ptrw[vertex_index + 2] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1);
+ vertex_array_ptrw[vertex_index + 3] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d);
+ vertex_array_ptrw[vertex_index + 4] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + heightmap_width + w + 1], d + 1);
+ vertex_array_ptrw[vertex_index + 5] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1);
+ vertex_index += 6;
}
}
if (vertex_array.size() > 0) {
diff --git a/modules/noise/fastnoise_lite.cpp b/modules/noise/fastnoise_lite.cpp
index 4aea98c4de..1b0ef6506b 100644
--- a/modules/noise/fastnoise_lite.cpp
+++ b/modules/noise/fastnoise_lite.cpp
@@ -416,8 +416,8 @@ void FastNoiseLite::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Smooth,Cellular,Perlin,Value Cubic,Value"), "set_noise_type", "get_noise_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".0001,1,.0001"), "set_frequency", "get_frequency");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-999999999,999999999,0.01"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".0001,1,.0001,exp"), "set_frequency", "get_frequency");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_offset", "get_offset");
ADD_GROUP("Fractal", "fractal_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM, "None,FBM,Ridged,Ping-Pong"), "set_fractal_type", "get_fractal_type");
diff --git a/modules/noise/noise.cpp b/modules/noise/noise.cpp
index 1115d92f58..9b9fd640f4 100644
--- a/modules/noise/noise.cpp
+++ b/modules/noise/noise.cpp
@@ -54,6 +54,9 @@ Vector<Ref<Image>> Noise::_get_seamless_image(int p_width, int p_height, int p_d
Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, real_t p_blend_skirt, bool p_normalize) const {
Vector<Ref<Image>> images = _get_seamless_image(p_width, p_height, 1, p_invert, p_in_3d_space, p_blend_skirt, p_normalize);
+ if (images.size() == 0) {
+ return Ref<Image>();
+ }
return images[0];
}
@@ -163,6 +166,9 @@ Vector<Ref<Image>> Noise::_get_image(int p_width, int p_height, int p_depth, boo
Ref<Image> Noise::get_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, bool p_normalize) const {
Vector<Ref<Image>> images = _get_image(p_width, p_height, 1, p_invert, p_in_3d_space, p_normalize);
+ if (images.is_empty()) {
+ return Ref<Image>();
+ }
return images[0];
}
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index 2ccfe46062..c64b6de78c 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -70,7 +70,6 @@ if env["builtin_openxr"]:
# On Android the openxr_loader is provided by separate plugins for each device
# Build the engine using object files
khrloader_obj = []
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c")
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table_core.c")
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp")
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index d0e958164d..3c606de670 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -289,7 +289,7 @@ bool OpenXRAPI::create_instance() {
for (KeyValue<String, bool *> &requested_extension : requested_extensions) {
if (!is_extension_supported(requested_extension.key)) {
if (requested_extension.value == nullptr) {
- // Null means this is a manditory extension so we fail.
+ // Null means this is a mandatory extension so we fail.
ERR_FAIL_V_MSG(false, String("OpenXR: OpenXR Runtime does not support ") + requested_extension.key + String(" extension!"));
} else {
// Set this extension as not supported.
@@ -804,6 +804,7 @@ bool OpenXRAPI::create_swapchains() {
*/
Size2 recommended_size = get_recommended_target_size();
+ uint32_t sample_count = 1;
// We start with our color swapchain...
{
@@ -827,7 +828,7 @@ bool OpenXRAPI::create_swapchains() {
print_verbose(String("Using color swap chain format:") + get_swapchain_format_name(swapchain_format_to_use));
}
- if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain, &swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data)) {
+ if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, sample_count, view_count, swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain, &swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data)) {
return false;
}
}
@@ -863,7 +864,7 @@ bool OpenXRAPI::create_swapchains() {
// Note, if VK_FORMAT_D32_SFLOAT is used here but we're using the forward+ renderer, we should probably output a warning.
- if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain, &swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data)) {
+ if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, sample_count, view_count, swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain, &swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data)) {
return false;
}
diff --git a/modules/text_server_adv/gdextension_build/methods.py b/modules/text_server_adv/gdextension_build/methods.py
index 3c5229462c..e58bc3abec 100644
--- a/modules/text_server_adv/gdextension_build/methods.py
+++ b/modules/text_server_adv/gdextension_build/methods.py
@@ -99,8 +99,8 @@ def make_icu_data(target, source, env):
def write_macos_plist(target, binary_name, identifier, name):
- os.makedirs(f"{target}/Resourece/", exist_ok=True)
- f = open(f"{target}/Resourece/Info.plist", "w")
+ os.makedirs(f"{target}/Resource/", exist_ok=True)
+ f = open(f"{target}/Resource/Info.plist", "w")
f.write(f'<?xml version="1.0" encoding="UTF-8"?>\n')
f.write(f'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n')
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 16046ef053..6d0a398218 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -338,6 +338,7 @@ _FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) {
/*************************************************************************/
bool TextServerAdvanced::icu_data_loaded = false;
+PackedByteArray TextServerAdvanced::icu_data;
bool TextServerAdvanced::_has_feature(Feature p_feature) const {
switch (p_feature) {
@@ -438,7 +439,7 @@ bool TextServerAdvanced::_load_support_data(const String &p_filename) {
return false;
}
uint64_t len = f->get_length();
- PackedByteArray icu_data = f->get_buffer(len);
+ icu_data = f->get_buffer(len);
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(icu_data.ptr(), &err);
@@ -476,10 +477,10 @@ bool TextServerAdvanced::_save_support_data(const String &p_filename) const {
return false;
}
- PackedByteArray icu_data;
- icu_data.resize(U_ICUDATA_SIZE);
- memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
- f->store_buffer(icu_data);
+ PackedByteArray icu_data_static;
+ icu_data_static.resize(U_ICUDATA_SIZE);
+ memcpy(icu_data_static.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
+ f->store_buffer(icu_data_static);
return true;
#else
@@ -1112,14 +1113,14 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
case FT_PIXEL_MODE_LCD: {
int ofs_color = i * bitmap.pitch + (j * 3);
if (p_bgra) {
- wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
- wr[ofs + 2] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
wr[ofs + 3] = 255;
} else {
- wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
- wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 2];
wr[ofs + 3] = 255;
}
} break;
@@ -4311,6 +4312,8 @@ bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const V
sd->width += gl.advance * gl.repeat;
}
}
+ sd->sort_valid = false;
+ sd->glyphs_logical.clear();
_realign(sd);
}
return true;
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index f1932d9c50..cbd2911aaf 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -158,6 +158,7 @@ class TextServerAdvanced : public TextServerExtension {
// ICU support data.
static bool icu_data_loaded;
+ static PackedByteArray icu_data;
mutable USet *allowed = nullptr;
mutable USpoofChecker *sc_spoof = nullptr;
mutable USpoofChecker *sc_conf = nullptr;
@@ -680,11 +681,7 @@ class TextServerAdvanced : public TextServerExtension {
_FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const {
if (l.start == r.start) {
if (l.count == r.count) {
- if ((l.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) {
- return false;
- } else {
- return true;
- }
+ return (l.flags & TextServer::GRAPHEME_IS_VIRTUAL) < (r.flags & TextServer::GRAPHEME_IS_VIRTUAL);
}
return l.count > r.count; // Sort first glyph with count & flags, order of the rest are irrelevant.
} else {
diff --git a/modules/text_server_fb/gdextension_build/methods.py b/modules/text_server_fb/gdextension_build/methods.py
index 3c5229462c..e58bc3abec 100644
--- a/modules/text_server_fb/gdextension_build/methods.py
+++ b/modules/text_server_fb/gdextension_build/methods.py
@@ -99,8 +99,8 @@ def make_icu_data(target, source, env):
def write_macos_plist(target, binary_name, identifier, name):
- os.makedirs(f"{target}/Resourece/", exist_ok=True)
- f = open(f"{target}/Resourece/Info.plist", "w")
+ os.makedirs(f"{target}/Resource/", exist_ok=True)
+ f = open(f"{target}/Resource/Info.plist", "w")
f.write(f'<?xml version="1.0" encoding="UTF-8"?>\n')
f.write(f'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n')
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index eb247cdcbe..f12275d10c 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -548,14 +548,14 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
case FT_PIXEL_MODE_LCD: {
int ofs_color = i * bitmap.pitch + (j * 3);
if (p_bgra) {
- wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
- wr[ofs + 2] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
wr[ofs + 3] = 255;
} else {
- wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
- wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 2];
wr[ofs + 3] = 255;
}
} break;
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp
index 8a265ffaf3..7ec0b697bf 100644
--- a/modules/vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp
@@ -144,7 +144,7 @@ int AudioStreamPlaybackOggVorbis::_mix_internal(AudioFrame *p_buffer, int p_fram
}
int AudioStreamPlaybackOggVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p_frames) {
- ERR_FAIL_COND_V(!ready, 0);
+ ERR_FAIL_COND_V(!ready, p_frames);
if (!have_samples_left) {
ogg_packet *packet = nullptr;
int err;
@@ -156,10 +156,10 @@ int AudioStreamPlaybackOggVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p
}
err = vorbis_synthesis(&block, packet);
- ERR_FAIL_COND_V_MSG(err != 0, 0, "Error during vorbis synthesis " + itos(err));
+ ERR_FAIL_COND_V_MSG(err != 0, p_frames, "Error during vorbis synthesis " + itos(err));
err = vorbis_synthesis_blockin(&dsp_state, &block);
- ERR_FAIL_COND_V_MSG(err != 0, 0, "Error during vorbis block processing " + itos(err));
+ ERR_FAIL_COND_V_MSG(err != 0, p_frames, "Error during vorbis block processing " + itos(err));
have_packets_left = !packet->e_o_s;
}
diff --git a/modules/webp/webp_common.cpp b/modules/webp/webp_common.cpp
index bc34a25733..3a2ac5a90e 100644
--- a/modules/webp/webp_common.cpp
+++ b/modules/webp/webp_common.cpp
@@ -59,6 +59,10 @@ Vector<uint8_t> _webp_packer(const Ref<Image> &p_image, float p_quality, bool p_
compression_method = CLAMP(compression_method, 0, 6);
Ref<Image> img = p_image->duplicate();
+ if (img->is_compressed()) {
+ Error error = img->decompress();
+ ERR_FAIL_COND_V_MSG(error != OK, Vector<uint8_t>(), "Couldn't decompress image.");
+ }
if (img->detect_alpha()) {
img->convert(Image::FORMAT_RGBA8);
} else {