summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--SConstruct20
-rw-r--r--core/object/class_db.cpp63
-rw-r--r--core/object/class_db.h1
-rw-r--r--core/variant/array.cpp8
-rw-r--r--core/variant/variant.h2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp4
-rw-r--r--editor/animation_track_editor.cpp2
-rw-r--r--editor/import/3d/resource_importer_obj.cpp8
-rw-r--r--editor/scene_tree_dock.cpp11
-rw-r--r--modules/gdscript/gdscript_vm.cpp19
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/typed_array_assign_wrong_to_typed.out1
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.gd7
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.out2
-rw-r--r--platform/ios/keyboard_input_view.mm30
-rw-r--r--platform/linuxbsd/joypad_linux.cpp6
-rw-r--r--platform/linuxbsd/joypad_linux.h15
-rw-r--r--platform/web/detect.py1
-rw-r--r--scene/2d/parallax_2d.cpp7
-rw-r--r--scene/gui/rich_text_label.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp22
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h2
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp20
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp1
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp16
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h3
-rw-r--r--servers/rendering/shader_language.cpp22
-rw-r--r--servers/rendering/shader_language.h2
-rw-r--r--thirdparty/README.md2
-rw-r--r--thirdparty/thorvg/inc/config.h2
-rw-r--r--thirdparty/thorvg/inc/thorvg.h2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h1
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp78
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp48
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp3
-rw-r--r--thirdparty/thorvg/src/renderer/tvgCanvas.h2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgRender.h2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgShape.h1
-rwxr-xr-xthirdparty/thorvg/update-thorvg.sh2
39 files changed, 332 insertions, 112 deletions
diff --git a/SConstruct b/SConstruct
index 3fabc4706f..8e9a536bdc 100644
--- a/SConstruct
+++ b/SConstruct
@@ -200,7 +200,10 @@ opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectur
opts.Add(BoolVariable("dev_build", "Developer build with dev-only debugging code (DEV_ENABLED)", False))
opts.Add(
EnumVariable(
- "optimize", "Optimization level", "speed_trace", ("none", "custom", "debug", "speed", "speed_trace", "size")
+ "optimize",
+ "Optimization level (by default inferred from 'target' and 'dev_build')",
+ "auto",
+ ("auto", "none", "custom", "debug", "speed", "speed_trace", "size"),
)
)
opts.Add(BoolVariable("debug_symbols", "Build with debugging symbols", False))
@@ -466,14 +469,15 @@ env.editor_build = env["target"] == "editor"
env.dev_build = env["dev_build"]
env.debug_features = env["target"] in ["editor", "template_debug"]
-if env.dev_build:
- opt_level = "none"
-elif env.debug_features:
- opt_level = "speed_trace"
-else: # Release
- opt_level = "speed"
+if env["optimize"] == "auto":
+ if env.dev_build:
+ opt_level = "none"
+ elif env.debug_features:
+ opt_level = "speed_trace"
+ else: # Release
+ opt_level = "speed"
+ env["optimize"] = ARGUMENTS.get("optimize", opt_level)
-env["optimize"] = ARGUMENTS.get("optimize", opt_level)
env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", env.dev_build)
if env.editor_build:
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index fe4345aa0d..24cf0a29c5 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -76,6 +76,21 @@ class PlaceholderExtensionInstance {
StringName class_name;
HashMap<StringName, Variant> properties;
+ // Checks if a property is from a runtime class, and not a non-runtime base class.
+ bool is_runtime_property(const StringName &p_property_name) {
+ StringName current_class_name = class_name;
+
+ while (ClassDB::is_class_runtime(current_class_name)) {
+ if (ClassDB::has_property(current_class_name, p_property_name, true)) {
+ return true;
+ }
+
+ current_class_name = ClassDB::get_parent_class(current_class_name);
+ }
+
+ return false;
+ }
+
public:
PlaceholderExtensionInstance(const StringName &p_class_name) {
class_name = p_class_name;
@@ -83,27 +98,24 @@ public:
~PlaceholderExtensionInstance() {}
- void set(const StringName &p_name, const Variant &p_value) {
- bool is_default_valid = false;
- Variant default_value = ClassDB::class_get_default_property_value(class_name, p_name, &is_default_valid);
-
- // If there's a default value, then we know it's a valid property.
- if (is_default_valid) {
+ void set(const StringName &p_name, const Variant &p_value, bool &r_valid) {
+ r_valid = is_runtime_property(p_name);
+ if (r_valid) {
properties[p_name] = p_value;
}
}
- Variant get(const StringName &p_name) {
+ Variant get(const StringName &p_name, bool &r_valid) {
const Variant *value = properties.getptr(p_name);
Variant ret;
if (value) {
ret = *value;
+ r_valid = true;
} else {
- bool is_default_valid = false;
- Variant default_value = ClassDB::class_get_default_property_value(class_name, p_name, &is_default_valid);
- if (is_default_valid) {
- ret = default_value;
+ r_valid = is_runtime_property(p_name);
+ if (r_valid) {
+ ret = ClassDB::class_get_default_property_value(class_name, p_name);
}
}
@@ -115,10 +127,10 @@ public:
const StringName &name = *(StringName *)p_name;
const Variant &value = *(const Variant *)p_value;
- self->set(name, value);
+ bool valid = false;
+ self->set(name, value, valid);
- // We have to return true so Godot doesn't try to call the real setter function.
- return true;
+ return valid;
}
static GDExtensionBool placeholder_instance_get(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) {
@@ -126,10 +138,10 @@ public:
const StringName &name = *(StringName *)p_name;
Variant *value = (Variant *)r_ret;
- *value = self->get(name);
+ bool valid = false;
+ *value = self->get(name, valid);
- // We have to return true so Godot doesn't try to call the real getter function.
- return true;
+ return valid;
}
static const GDExtensionPropertyInfo *placeholder_instance_get_property_list(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) {
@@ -172,9 +184,9 @@ public:
static GDExtensionObjectPtr placeholder_class_create_instance(void *p_class_userdata) {
ClassDB::ClassInfo *ti = (ClassDB::ClassInfo *)p_class_userdata;
- // Find the closest native parent.
+ // Find the closest native parent, that isn't a runtime class.
ClassDB::ClassInfo *native_parent = ti->inherits_ptr;
- while (native_parent->gdextension) {
+ while (native_parent->gdextension || native_parent->is_runtime) {
native_parent = native_parent->inherits_ptr;
}
ERR_FAIL_NULL_V(native_parent->creation_func, nullptr);
@@ -1952,6 +1964,14 @@ bool ClassDB::is_class_reloadable(const StringName &p_class) {
return ti->reloadable;
}
+bool ClassDB::is_class_runtime(const StringName &p_class) {
+ OBJTYPE_RLOCK;
+
+ ClassInfo *ti = classes.getptr(p_class);
+ ERR_FAIL_NULL_V_MSG(ti, false, "Cannot get class '" + String(p_class) + "'.");
+ return ti->is_runtime;
+}
+
void ClassDB::add_resource_base_extension(const StringName &p_extension, const StringName &p_class) {
if (resource_base_extensions.has(p_extension)) {
return;
@@ -2063,6 +2083,11 @@ void ClassDB::register_extension_class(ObjectGDExtension *p_extension) {
ClassInfo *parent = classes.getptr(p_extension->parent_class_name);
+#ifdef TOOLS_ENABLED
+ // @todo This is a limitation of the current implementation, but it should be possible to remove.
+ ERR_FAIL_COND_MSG(p_extension->is_runtime && parent->gdextension && !parent->is_runtime, "Extension runtime class " + String(p_extension->class_name) + " cannot descend from " + parent->name + " which isn't also a runtime class");
+#endif
+
ClassInfo c;
c.api = p_extension->editor_class ? API_EDITOR_EXTENSION : API_EXTENSION;
c.gdextension = p_extension;
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 37a864c109..fb671bdc84 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -460,6 +460,7 @@ public:
static bool is_class_exposed(const StringName &p_class);
static bool is_class_reloadable(const StringName &p_class);
+ static bool is_class_runtime(const StringName &p_class);
static void add_resource_base_extension(const StringName &p_extension, const StringName &p_class);
static void get_resource_base_extensions(List<String> *p_extensions);
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 3685515db5..54cd1eda2f 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -235,7 +235,7 @@ void Array::assign(const Array &p_array) {
for (int i = 0; i < size; i++) {
const Variant &element = source[i];
if (element.get_type() != Variant::NIL && (element.get_type() != Variant::OBJECT || !typed.validate_object(element, "assign"))) {
- ERR_FAIL_MSG(vformat(R"(Unable to convert array index %i from "%s" to "%s".)", i, Variant::get_type_name(element.get_type()), Variant::get_type_name(typed.type)));
+ ERR_FAIL_MSG(vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(element.get_type()), Variant::get_type_name(typed.type)));
}
}
_p->array = p_array._p->array;
@@ -258,11 +258,11 @@ void Array::assign(const Array &p_array) {
continue;
}
if (!Variant::can_convert_strict(value->get_type(), typed.type)) {
- ERR_FAIL_MSG("Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(value->get_type()) + "' to '" + Variant::get_type_name(typed.type) + "'.");
+ ERR_FAIL_MSG(vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
}
Callable::CallError ce;
Variant::construct(typed.type, data[i], &value, 1, ce);
- ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert array index %i from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
+ ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
}
} else if (Variant::can_convert_strict(source_typed.type, typed.type)) {
// from primitives to different convertible primitives
@@ -270,7 +270,7 @@ void Array::assign(const Array &p_array) {
const Variant *value = source + i;
Callable::CallError ce;
Variant::construct(typed.type, data[i], &value, 1, ce);
- ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert array index %i from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
+ ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
}
} else {
ERR_FAIL_MSG(vformat(R"(Cannot assign contents of "Array[%s]" to "Array[%s]".)", Variant::get_type_name(source_typed.type), Variant::get_type_name(typed.type)));
diff --git a/core/variant/variant.h b/core/variant/variant.h
index f352af24da..1cb3580c01 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -857,7 +857,7 @@ String vformat(const String &p_text, const VarArgs... p_args) {
bool error = false;
String fmt = p_text.sprintf(args_array, &error);
- ERR_FAIL_COND_V_MSG(error, String(), fmt);
+ ERR_FAIL_COND_V_MSG(error, String(), String("Formatting error in string \"") + p_text + "\": " + fmt + ".");
return fmt;
}
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 8e89889fd1..a6796a1a6b 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -2499,7 +2499,9 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
glColorMask(0, 0, 0, 0);
RasterizerGLES3::clear_depth(0.0);
glClear(GL_DEPTH_BUFFER_BIT);
- glDrawBuffers(0, nullptr);
+ // Some desktop GL implementations fall apart when using Multiview with GL_NONE.
+ GLuint db = p_camera_data->view_count > 1 ? GL_COLOR_ATTACHMENT0 : GL_NONE;
+ glDrawBuffers(1, &db);
uint64_t spec_constant = SceneShaderGLES3::DISABLE_FOG | SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL |
SceneShaderGLES3::DISABLE_LIGHTMAP | SceneShaderGLES3::DISABLE_LIGHT_OMNI |
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index baf2c6502f..b6636ca576 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -4429,7 +4429,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
for (int i = 0; i < subindices.size(); i++) {
InsertData id = p_id;
id.type = Animation::TYPE_BEZIER;
- id.value = p_id.value.get(subindices[i].substr(1, subindices[i].length()));
+ id.value = subindices[i].is_empty() ? p_id.value : p_id.value.get(subindices[i].substr(1, subindices[i].length()));
id.path = String(p_id.path) + subindices[i];
p_next_tracks = _confirm_insert(id, p_next_tracks, p_reset_wanted, p_reset_anim, false);
}
diff --git a/editor/import/3d/resource_importer_obj.cpp b/editor/import/3d/resource_importer_obj.cpp
index 6d68e93c75..a0c05598a2 100644
--- a/editor/import/3d/resource_importer_obj.cpp
+++ b/editor/import/3d/resource_importer_obj.cpp
@@ -425,9 +425,13 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
}
if (!current_material.is_empty()) {
- mesh->set_surface_name(mesh->get_surface_count() - 1, current_material.get_basename());
+ if (mesh->get_surface_count() >= 1) {
+ mesh->set_surface_name(mesh->get_surface_count() - 1, current_material.get_basename());
+ }
} else if (!current_group.is_empty()) {
- mesh->set_surface_name(mesh->get_surface_count() - 1, current_group);
+ if (mesh->get_surface_count() >= 1) {
+ mesh->set_surface_name(mesh->get_surface_count() - 1, current_group);
+ }
}
Array array = surf_tool->commit_to_arrays();
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 94bd3e16d3..25de9facb2 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -2276,6 +2276,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
Vector<StringName> former_names;
int inc = 0;
+ bool need_edit = false;
for (int ni = 0; ni < p_nodes.size(); ni++) {
// No undo implemented for this yet.
@@ -2296,7 +2297,11 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
inc--; // If the child will generate a gap when moved, adjust.
}
- if (!same_parent) {
+ if (same_parent) {
+ // When node is reparented to the same parent, EditorSelection does not change.
+ // After hovering another node, the inspector has to be manually updated in this case.
+ need_edit = select_node_hovered_at_end_of_drag;
+ } else {
undo_redo->add_do_method(node->get_parent(), "remove_child", node);
undo_redo->add_do_method(new_parent, "add_child", node, true);
}
@@ -2401,6 +2406,10 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
perform_node_renames(nullptr, &path_renames);
undo_redo->commit_action();
+
+ if (need_edit) {
+ EditorNode::get_singleton()->edit_current();
+ }
}
void SceneTreeDock::_script_created(Ref<Script> p_script) {
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 5d1805696d..912367764b 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -550,9 +550,22 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
return _get_default_variant_for_data_type(return_type);
}
if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
- Variant arg;
- Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err);
- memnew_placement(&stack[i + 3], Variant(arg));
+ if (argument_types[i].builtin_type == Variant::ARRAY && argument_types[i].has_container_element_type(0)) {
+ const GDScriptDataType &arg_type = argument_types[i].container_element_types[0];
+ Array array(p_args[i]->operator Array(), arg_type.builtin_type, arg_type.native_type, arg_type.script_type);
+ memnew_placement(&stack[i + 3], Variant(array));
+ } else {
+ Variant variant;
+ Variant::construct(argument_types[i].builtin_type, variant, &p_args[i], 1, r_err);
+ if (unlikely(r_err.error)) {
+ r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_err.argument = i;
+ r_err.expected = argument_types[i].builtin_type;
+ call_depth--;
+ return _get_default_variant_for_data_type(return_type);
+ }
+ memnew_placement(&stack[i + 3], Variant(variant));
+ }
} else {
memnew_placement(&stack[i + 3], Variant(*p_args[i]));
}
diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_array_assign_wrong_to_typed.out b/modules/gdscript/tests/scripts/runtime/errors/typed_array_assign_wrong_to_typed.out
index 7b9f1066b0..9b38957101 100644
--- a/modules/gdscript/tests/scripts/runtime/errors/typed_array_assign_wrong_to_typed.out
+++ b/modules/gdscript/tests/scripts/runtime/errors/typed_array_assign_wrong_to_typed.out
@@ -1,4 +1,5 @@
GDTEST_RUNTIME_ERROR
>> ERROR
>> Method/function failed.
+>> Unable to convert array index 0 from "Object" to "Object".
not ok
diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.gd b/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.gd
new file mode 100644
index 0000000000..13f2c3b956
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.gd
@@ -0,0 +1,7 @@
+# GH-93990
+
+func test_param(array: Array[String]) -> void:
+ print(array.get_typed_builtin() == TYPE_STRING)
+
+func test() -> void:
+ test_param(PackedStringArray())
diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.out b/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.out
new file mode 100644
index 0000000000..55482c2b52
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+true
diff --git a/platform/ios/keyboard_input_view.mm b/platform/ios/keyboard_input_view.mm
index 8b614662b7..4067701a41 100644
--- a/platform/ios/keyboard_input_view.mm
+++ b/platform/ios/keyboard_input_view.mm
@@ -149,23 +149,18 @@
return;
}
+ NSString *substringToDelete = nil;
if (self.previousSelectedRange.length == 0) {
- // We are deleting all text before cursor if no range was selected.
- // This way any inserted or changed text will be updated.
- NSString *substringToDelete = [self.previousText substringToIndex:self.previousSelectedRange.location];
- [self deleteText:substringToDelete.length];
+ // Get previous text to delete.
+ substringToDelete = [self.previousText substringToIndex:self.previousSelectedRange.location];
} else {
- // If text was previously selected
- // we are sending only one `backspace`.
- // It will remove all text from text input.
+ // If text was previously selected we are sending only one `backspace`. It will remove all text from text input.
[self deleteText:1];
}
- NSString *substringToEnter;
-
+ NSString *substringToEnter = nil;
if (self.selectedRange.length == 0) {
- // If previous cursor had a selection
- // we have to calculate an inserted text.
+ // If previous cursor had a selection we have to calculate an inserted text.
if (self.previousSelectedRange.length != 0) {
NSInteger rangeEnd = self.selectedRange.location + self.selectedRange.length;
NSInteger rangeStart = MIN(self.previousSelectedRange.location, self.selectedRange.location);
@@ -187,7 +182,18 @@
substringToEnter = [self.text substringWithRange:self.selectedRange];
}
- [self enterText:substringToEnter];
+ NSInteger skip = 0;
+ if (substringToDelete != nil) {
+ for (NSInteger i = 0; i < MIN([substringToDelete length], [substringToEnter length]); i++) {
+ if ([substringToDelete characterAtIndex:i] == [substringToEnter characterAtIndex:i]) {
+ skip++;
+ } else {
+ break;
+ }
+ }
+ [self deleteText:[substringToDelete length] - skip]; // Delete changed part of previous text.
+ }
+ [self enterText:[substringToEnter substringFromIndex:skip]]; // Enter changed part of new text.
self.previousText = self.text;
self.previousSelectedRange = self.selectedRange;
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index 3534c1afee..a67428b9a4 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -374,6 +374,12 @@ void JoypadLinux::open_joypad(const char *p_path) {
name = namebuf;
}
+ for (const String &word : name.to_lower().split(" ")) {
+ if (banned_words.has(word)) {
+ return;
+ }
+ }
+
if (ioctl(fd, EVIOCGID, &inpid) < 0) {
close(fd);
return;
diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h
index 26a9908d4e..bf24d8e5a5 100644
--- a/platform/linuxbsd/joypad_linux.h
+++ b/platform/linuxbsd/joypad_linux.h
@@ -94,6 +94,21 @@ private:
Vector<String> attached_devices;
+ // List of lowercase words that will prevent the controller from being recognized if its name matches.
+ // This is done to prevent trackpads, graphics tablets and motherboard LED controllers from being
+ // recognized as controllers (and taking up controller ID slots as a result).
+ // Only whole words are matched within the controller name string. The match is case-insensitive.
+ const Vector<String> banned_words = {
+ "touchpad", // Matches e.g. "SynPS/2 Synaptics TouchPad", "Sony Interactive Entertainment DualSense Wireless Controller Touchpad"
+ "trackpad",
+ "clickpad",
+ "keyboard", // Matches e.g. "PG-90215 Keyboard", "Usb Keyboard Usb Keyboard Consumer Control"
+ "mouse", // Matches e.g. "Mouse passthrough"
+ "pen", // Matches e.g. "Wacom One by Wacom S Pen"
+ "finger", // Matches e.g. "Wacom HID 495F Finger"
+ "led", // Matches e.g. "ASRock LED Controller"
+ };
+
static void monitor_joypads_thread_func(void *p_user);
void monitor_joypads_thread_run();
diff --git a/platform/web/detect.py b/platform/web/detect.py
index cb4dac1125..79485ea28a 100644
--- a/platform/web/detect.py
+++ b/platform/web/detect.py
@@ -78,6 +78,7 @@ def get_flags():
# -Os reduces file size by around 5 MiB over -O3. -Oz only saves about
# 100 KiB over -Os, which does not justify the negative impact on
# run-time performance.
+ # Note that this overrides the "auto" behavior for target/dev_build.
"optimize": "size",
}
diff --git a/scene/2d/parallax_2d.cpp b/scene/2d/parallax_2d.cpp
index b3586a1da0..9dd9d4a376 100644
--- a/scene/2d/parallax_2d.cpp
+++ b/scene/2d/parallax_2d.cpp
@@ -31,6 +31,7 @@
#include "parallax_2d.h"
#include "core/config/project_settings.h"
+#include "scene/main/viewport.h"
void Parallax2D::_notification(int p_what) {
switch (p_what) {
@@ -72,7 +73,11 @@ void Parallax2D::_validate_property(PropertyInfo &p_property) const {
void Parallax2D::_camera_moved(const Transform2D &p_transform, const Point2 &p_screen_offset, const Point2 &p_adj_screen_pos) {
if (!ignore_camera_scroll) {
- set_screen_offset(p_adj_screen_pos);
+ if (get_viewport() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) {
+ set_screen_offset((p_adj_screen_pos + Vector2(0.5, 0.5)).floor());
+ } else {
+ set_screen_offset(p_adj_screen_pos);
+ }
}
}
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 8ffa0f8c63..74978416c4 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -4947,10 +4947,10 @@ void RichTextLabel::append_text(const String &p_bbcode) {
tag_stack.push_front("outline_size");
} else if (bbcode_name == "fade") {
- int start_index = 0;
+ int start_index = brk_pos;
OptionMap::Iterator start_option = bbcode_options.find("start");
if (start_option) {
- start_index = start_option->value.to_int();
+ start_index += start_option->value.to_int();
}
int length = 10;
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 536fc7a04a..f97ed3d215 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -587,7 +587,7 @@ void RenderForwardClustered::_render_list_with_draw_list(RenderListParameters *p
RD::get_singleton()->draw_list_end();
}
-void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_apply_alpha_multiplier, bool p_pancake_shadows, int p_index) {
+void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_apply_alpha_multiplier, bool p_pancake_shadows, int p_index) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers;
@@ -603,7 +603,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
}
}
- p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers, p_apply_alpha_multiplier);
+ p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers, p_apply_alpha_multiplier);
// now do implementation UBO
@@ -1732,7 +1732,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
_setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform);
_setup_voxelgis(*p_render_data->voxel_gi_instances);
- _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
+ _setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, false);
// May have changed due to the above (light buffer enlarged, as an example).
_update_render_base_uniform_set();
@@ -1995,7 +1995,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
// Shadow pass can change the base uniform set samplers.
_update_render_base_uniform_set();
- _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, true, using_motion_pass);
+ _setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, true, using_motion_pass);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, samplers, true);
@@ -2209,7 +2209,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, samplers, true);
- _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
+ _setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, false);
{
uint32_t transparent_color_pass_flags = (color_pass_flags | COLOR_PASS_FLAG_TRANSPARENT) & ~(COLOR_PASS_FLAG_SEPARATE_SPECULAR);
@@ -2562,6 +2562,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
SceneState::ShadowPass shadow_pass;
RenderSceneDataRD scene_data;
+ scene_data.flip_y = !p_flip_y; // Q: Why is this inverted? Do we assume flip in shadow logic?
scene_data.cam_projection = p_projection;
scene_data.cam_transform = p_transform;
scene_data.view_projection[0] = p_projection;
@@ -2581,7 +2582,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
render_data.instances = &p_instances;
render_data.render_info = p_render_info;
- _setup_environment(&render_data, true, p_viewport_size, !p_flip_y, Color(), false, false, p_use_pancake, shadow_pass_index);
+ _setup_environment(&render_data, true, p_viewport_size, Color(), false, false, p_use_pancake, shadow_pass_index);
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
scene_data.screen_mesh_lod_threshold = 0.0;
@@ -2654,6 +2655,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
RenderSceneDataRD scene_data;
+ scene_data.flip_y = true;
scene_data.cam_projection = p_cam_projection;
scene_data.cam_transform = p_cam_transform;
scene_data.view_projection[0] = p_cam_projection;
@@ -2673,7 +2675,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
_update_render_base_uniform_set();
- _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false, false);
+ _setup_environment(&render_data, true, Vector2(1, 1), Color(), false, false, false);
PassMode pass_mode = PASS_MODE_SHADOW;
@@ -2720,7 +2722,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform
_update_render_base_uniform_set();
- _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+ _setup_environment(&render_data, true, Vector2(1, 1), Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
@@ -2771,7 +2773,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance
_update_render_base_uniform_set();
- _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+ _setup_environment(&render_data, true, Vector2(1, 1), Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
@@ -2887,7 +2889,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
RendererRD::MaterialStorage::store_transform(to_bounds.affine_inverse() * scene_data.cam_transform, scene_state.ubo.sdf_to_bounds);
scene_data.emissive_exposure_normalization = p_exposure_normalization;
- _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+ _setup_environment(&render_data, true, Vector2(1, 1), Color());
RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture, RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index ae9e5e7c10..0aa4a0667e 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -361,7 +361,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
static RenderForwardClustered *singleton;
- void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_apply_alpha_multiplier = false, bool p_pancake_shadows = false, int p_index = 0);
+ void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_apply_alpha_multiplier = false, bool p_pancake_shadows = false, int p_index = 0);
void _setup_voxelgis(const PagedArray<RID> &p_voxelgis);
void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 194a70dc22..0d83264bfb 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -804,7 +804,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_begin_label("Render Setup");
_setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform);
- _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
+ _setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, false);
// May have changed due to the above (light buffer enlarged, as an example).
_update_render_base_uniform_set();
@@ -953,7 +953,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// Shadow pass can change the base uniform set samplers.
_update_render_base_uniform_set();
- _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, p_render_data->render_buffers.is_valid());
+ _setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, p_render_data->render_buffers.is_valid());
if (merge_transparent_pass && using_subpass_post_process) {
RENDER_TIMESTAMP("Render Opaque + Transparent + Tonemap");
@@ -1075,7 +1075,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, samplers, true);
// this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation
- //_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
+ //_setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, false);
RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
render_list_params.framebuffer_format = fb_format;
@@ -1310,6 +1310,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
}
RenderSceneDataRD scene_data;
+ scene_data.flip_y = !p_flip_y; // Q: Why is this inverted? Do we assume flip in shadow logic?
scene_data.cam_projection = p_projection;
scene_data.cam_transform = p_transform;
scene_data.view_projection[0] = p_projection;
@@ -1327,7 +1328,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
render_data.instances = &p_instances;
render_data.render_info = p_render_info;
- _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index);
+ _setup_environment(&render_data, true, Vector2(1, 1), Color(), false, p_use_pancake, shadow_pass_index);
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
scene_data.screen_mesh_lod_threshold = 0.0;
@@ -1415,7 +1416,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
- _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+ _setup_environment(&render_data, true, Vector2(1, 1), Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
@@ -1460,7 +1461,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
- _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+ _setup_environment(&render_data, true, Vector2(1, 1), Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
@@ -1526,6 +1527,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
_update_render_base_uniform_set();
RenderSceneDataRD scene_data;
+ scene_data.flip_y = true;
scene_data.cam_projection = p_cam_projection;
scene_data.cam_transform = p_cam_transform;
scene_data.view_projection[0] = p_cam_projection;
@@ -1541,7 +1543,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
- _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false);
+ _setup_environment(&render_data, true, Vector2(1, 1), Color(), false, false);
PassMode pass_mode = PASS_MODE_SHADOW;
@@ -1974,7 +1976,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
}
}
-void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
+void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID();
RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? RendererRD::LightStorage::get_singleton()->reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID();
@@ -1987,7 +1989,7 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
}
}
- p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers, false);
+ p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers, false);
}
/// RENDERING ///
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index aa1b8f34b2..b0fe552449 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -197,7 +197,7 @@ private:
void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false);
- void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
+ void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
RID render_base_uniform_set;
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 96bcd72099..0ebed49ee9 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -1124,6 +1124,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
scene_data.camera_visible_layers = p_camera_data->visible_layers;
scene_data.taa_jitter = p_camera_data->taa_jitter;
scene_data.main_cam_transform = p_camera_data->main_transform;
+ scene_data.flip_y = !p_reflection_probe.is_valid();
scene_data.view_count = p_camera_data->view_count;
for (uint32_t v = 0; v < p_camera_data->view_count; v++) {
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
index dc1e64ddcc..ba8aafda6d 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
@@ -42,7 +42,11 @@ Transform3D RenderSceneDataRD::get_cam_transform() const {
}
Projection RenderSceneDataRD::get_cam_projection() const {
- return cam_projection;
+ Projection correction;
+ correction.set_depth_correction(flip_y);
+ correction.add_jitter_offset(taa_jitter);
+
+ return correction * cam_projection;
}
uint32_t RenderSceneDataRD::get_view_count() const {
@@ -58,14 +62,18 @@ Vector3 RenderSceneDataRD::get_view_eye_offset(uint32_t p_view) const {
Projection RenderSceneDataRD::get_view_projection(uint32_t p_view) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_view, view_count, Projection());
- return view_projection[p_view];
+ Projection correction;
+ correction.set_depth_correction(flip_y);
+ correction.add_jitter_offset(taa_jitter);
+
+ return correction * view_projection[p_view];
}
RID RenderSceneDataRD::create_uniform_buffer() {
return RD::get_singleton()->uniform_buffer_create(sizeof(UBODATA));
}
-void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers, bool p_apply_alpha_multiplier) {
+void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers, bool p_apply_alpha_multiplier) {
RendererSceneRenderRD *render_scene_render = RendererSceneRenderRD::get_singleton();
UBODATA ubo_data;
@@ -76,7 +84,7 @@ void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p
UBO &prev_ubo = ubo_data.prev_ubo;
Projection correction;
- correction.set_depth_correction(p_flip_y);
+ correction.set_depth_correction(flip_y);
correction.add_jitter_offset(taa_jitter);
Projection projection = correction * cam_projection;
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
index f6785942ed..5579a97792 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
@@ -50,6 +50,7 @@ public:
Vector2 taa_jitter;
uint32_t camera_visible_layers;
bool cam_orthogonal = false;
+ bool flip_y = false;
// For billboards to cast correct shadows.
Transform3D main_cam_transform;
@@ -90,7 +91,7 @@ public:
virtual Projection get_view_projection(uint32_t p_view) const override;
RID create_uniform_buffer();
- void update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers, bool p_apply_alpha_multiplier);
+ void update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers, bool p_apply_alpha_multiplier);
virtual RID get_uniform_buffer() const override;
private:
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index f5e0b811a2..0b1595d988 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -39,6 +39,8 @@
#define HAS_WARNING(flag) (warning_flags & flag)
+int ShaderLanguage::instance_counter = 0;
+
String ShaderLanguage::get_operator_text(Operator p_op) {
static const char *op_names[OP_MAX] = { "==",
"!=",
@@ -10812,17 +10814,16 @@ ShaderLanguage::ShaderLanguage() {
nodes = nullptr;
completion_class = TAG_GLOBAL;
- int idx = 0;
- while (builtin_func_defs[idx].name) {
- if (builtin_func_defs[idx].tag == SubClassTag::TAG_GLOBAL) {
- const StringName &name = StringName(builtin_func_defs[idx].name);
-
- if (!global_func_set.has(name)) {
- global_func_set.insert(name);
+ if (instance_counter == 0) {
+ int idx = 0;
+ while (builtin_func_defs[idx].name) {
+ if (builtin_func_defs[idx].tag == SubClassTag::TAG_GLOBAL) {
+ global_func_set.insert(builtin_func_defs[idx].name);
}
+ idx++;
}
- idx++;
}
+ instance_counter++;
#ifdef DEBUG_ENABLED
warnings_check_map.insert(ShaderWarning::UNUSED_CONSTANT, &used_constants);
@@ -10837,5 +10838,8 @@ ShaderLanguage::ShaderLanguage() {
ShaderLanguage::~ShaderLanguage() {
clear();
- global_func_set.clear();
+ instance_counter--;
+ if (instance_counter == 0) {
+ global_func_set.clear();
+ }
}
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index edac819a1e..076bd8def4 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -800,6 +800,8 @@ public:
static bool is_control_flow_keyword(String p_keyword);
static void get_builtin_funcs(List<String> *r_keywords);
+ static int instance_counter;
+
struct BuiltInInfo {
DataType type = TYPE_VOID;
bool constant = false;
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 4572687be2..5bc76026c7 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -882,7 +882,7 @@ instead of `miniz.h` as an external dependency.
## thorvg
- Upstream: https://github.com/thorvg/thorvg
-- Version: 0.14.0 (ae4e9d003c93325f1eba64319fa9852a0d764b4c, 2024)
+- Version: 0.14.1 (70b2f2dad158316dd08166d613b425248b36fd27, 2024)
- License: MIT
Files extracted from upstream source:
diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h
index 6218c18e68..4be7e3936d 100644
--- a/thirdparty/thorvg/inc/config.h
+++ b/thirdparty/thorvg/inc/config.h
@@ -15,5 +15,5 @@
// For internal debugging:
//#define THORVG_LOG_ENABLED
-#define THORVG_VERSION_STRING "0.14.0"
+#define THORVG_VERSION_STRING "0.14.1"
#endif
diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h
index 0b7e9771b9..20f1942a57 100644
--- a/thirdparty/thorvg/inc/thorvg.h
+++ b/thirdparty/thorvg/inc/thorvg.h
@@ -631,6 +631,8 @@ public:
* The Canvas rendering can be performed asynchronously. To make sure that rendering is finished,
* the sync() must be called after the draw() regardless of threading.
*
+ * @retval Result::InsufficientCondition: The canvas is either already in sync condition or in a damaged condition (a draw is required before syncing).
+ *
* @see Canvas::draw()
*/
virtual Result sync() noexcept;
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h
index 231410cdac..05cbdc7f3a 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h
@@ -23,6 +23,7 @@
#ifndef _TVG_SW_COMMON_H_
#define _TVG_SW_COMMON_H_
+#include <algorithm>
#include "tvgCommon.h"
#include "tvgRender.h"
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp
index be1662daeb..bd0b5ffdcb 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp
@@ -63,6 +63,66 @@ static void _calculateCoefficients(const SwFill* fill, uint32_t x, uint32_t y, f
}
+static uint32_t _estimateAAMargin(const Fill* fdata)
+{
+ constexpr float marginScalingFactor = 800.0f;
+ if (fdata->identifier() == TVG_CLASS_ID_RADIAL) {
+ auto radius = P(static_cast<const RadialGradient*>(fdata))->r;
+ return mathZero(radius) ? 0 : static_cast<uint32_t>(marginScalingFactor / radius);
+ }
+ auto grad = P(static_cast<const LinearGradient*>(fdata));
+ Point p1 {grad->x1, grad->y1};
+ Point p2 {grad->x2, grad->y2};
+ auto length = mathLength(&p1, &p2);
+ return mathZero(length) ? 0 : static_cast<uint32_t>(marginScalingFactor / length);
+}
+
+
+static void _adjustAAMargin(uint32_t& iMargin, uint32_t index)
+{
+ constexpr float threshold = 0.1f;
+ constexpr uint32_t iMarginMax = 40;
+
+ auto iThreshold = static_cast<uint32_t>(index * threshold);
+ if (iMargin > iThreshold) iMargin = iThreshold;
+ if (iMargin > iMarginMax) iMargin = iMarginMax;
+}
+
+
+static inline uint32_t _alphaUnblend(uint32_t c)
+{
+ auto a = (c >> 24);
+ if (a == 255 || a == 0) return c;
+ auto invA = 255.0f / static_cast<float>(a);
+ auto c0 = static_cast<uint8_t>(static_cast<float>((c >> 16) & 0xFF) * invA);
+ auto c1 = static_cast<uint8_t>(static_cast<float>((c >> 8) & 0xFF) * invA);
+ auto c2 = static_cast<uint8_t>(static_cast<float>(c & 0xFF) * invA);
+
+ return (a << 24) | (c0 << 16) | (c1 << 8) | c2;
+}
+
+
+static void _applyAA(const SwFill* fill, uint32_t begin, uint32_t end)
+{
+ if (begin == 0 || end == 0) return;
+
+ auto i = GRADIENT_STOP_SIZE - end;
+ auto rgbaEnd = _alphaUnblend(fill->ctable[i]);
+ auto rgbaBegin = _alphaUnblend(fill->ctable[begin]);
+
+ auto dt = 1.0f / (begin + end + 1.0f);
+ float t = dt;
+ while (i != begin) {
+ auto dist = 255 - static_cast<int32_t>(255 * t);
+ auto color = INTERPOLATE(rgbaEnd, rgbaBegin, dist);
+ fill->ctable[i++] = ALPHA_BLEND((color | 0xff000000), (color >> 24));
+
+ if (i == GRADIENT_STOP_SIZE) i = 0;
+ t += dt;
+ }
+}
+
+
static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* surface, uint8_t opacity)
{
if (!fill->ctable) {
@@ -88,6 +148,11 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface*
auto pos = 1.5f * inc;
uint32_t i = 0;
+ //If repeat is true, anti-aliasing must be applied between the last and the first colors.
+ auto repeat = fill->spread == FillSpread::Repeat;
+ uint32_t iAABegin = repeat ? _estimateAAMargin(fdata) : 0;
+ uint32_t iAAEnd = 0;
+
fill->ctable[i++] = ALPHA_BLEND(rgba | 0xff000000, a);
while (pos <= pColors->offset) {
@@ -97,6 +162,11 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface*
}
for (uint32_t j = 0; j < cnt - 1; ++j) {
+ if (repeat && j == cnt - 2 && iAAEnd == 0) {
+ iAAEnd = iAABegin;
+ _adjustAAMargin(iAAEnd, GRADIENT_STOP_SIZE - i);
+ }
+
auto curr = colors + j;
auto next = curr + 1;
auto delta = 1.0f / (next->offset - curr->offset);
@@ -118,14 +188,18 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface*
}
rgba = rgba2;
a = a2;
+
+ if (repeat && j == 0) _adjustAAMargin(iAABegin, i - 1);
}
rgba = ALPHA_BLEND((rgba | 0xff000000), a);
for (; i < GRADIENT_STOP_SIZE; ++i)
fill->ctable[i] = rgba;
- //Make sure the last color stop is represented at the end of the table
- fill->ctable[GRADIENT_STOP_SIZE - 1] = rgba;
+ //For repeat fill spread apply anti-aliasing between the last and first colors,
+ //othewise make sure the last color stop is represented at the end of the table.
+ if (repeat) _applyAA(fill, iAABegin, iAAEnd);
+ else fill->ctable[GRADIENT_STOP_SIZE - 1] = rgba;
return true;
}
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp
index 04f36c727f..b3507acdc3 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp
@@ -1087,6 +1087,7 @@ static bool _rasterDirectScaledMaskedImage(SwSurface* surface, const SwImage* im
static bool _rasterScaledMaskedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
{
+ TVGERR("SW_ENGINE", "Not supported ScaledMaskedImage!");
#if 0 //Enable it when GRAYSCALE image is supported
TVGLOG("SW_ENGINE", "Scaled Masked(%d) Image [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y);
@@ -1100,6 +1101,11 @@ static bool _rasterScaledMaskedImage(SwSurface* surface, const SwImage* image, c
static bool _rasterScaledMattedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
{
+ if (surface->channelSize == sizeof(uint8_t)) {
+ TVGERR("SW_ENGINE", "Not supported grayscale scaled matted image!");
+ return false;
+ }
+
auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
auto csize = surface->compositor->image.channelSize;
auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize;
@@ -1130,6 +1136,11 @@ static bool _rasterScaledMattedImage(SwSurface* surface, const SwImage* image, c
static bool _rasterScaledBlendingImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
{
+ if (surface->channelSize == sizeof(uint8_t)) {
+ TVGERR("SW_ENGINE", "Not supported grayscale scaled blending image!");
+ return false;
+ }
+
auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
auto sampleSize = _sampleSize(image->scale);
@@ -1152,19 +1163,33 @@ static bool _rasterScaledBlendingImage(SwSurface* surface, const SwImage* image,
static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
{
- auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
auto sampleSize = _sampleSize(image->scale);
int32_t miny = 0, maxy = 0;
- for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
- SCALED_IMAGE_RANGE_Y(y)
- auto dst = dbuffer;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
- SCALED_IMAGE_RANGE_X
- auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
- if (opacity < 255) src = ALPHA_BLEND(src, opacity);
- *dst = src + ALPHA_BLEND(*dst, IA(src));
+ //32bits channels
+ if (surface->channelSize == sizeof(uint32_t)) {
+ auto buffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
+ for (auto y = region.min.y; y < region.max.y; ++y, buffer += surface->stride) {
+ SCALED_IMAGE_RANGE_Y(y)
+ auto dst = buffer;
+ for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
+ SCALED_IMAGE_RANGE_X
+ auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
+ if (opacity < 255) src = ALPHA_BLEND(src, opacity);
+ *dst = src + ALPHA_BLEND(*dst, IA(src));
+ }
+ }
+ } else if (surface->channelSize == sizeof(uint8_t)) {
+ auto buffer = surface->buf8 + (region.min.y * surface->stride + region.min.x);
+ for (auto y = region.min.y; y < region.max.y; ++y, buffer += surface->stride) {
+ SCALED_IMAGE_RANGE_Y(y)
+ auto dst = buffer;
+ for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
+ SCALED_IMAGE_RANGE_X
+ auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
+ *dst = MULTIPLY(A(src), opacity);
+ }
}
}
return true;
@@ -1173,11 +1198,6 @@ static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const M
static bool _scaledImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity)
{
- if (surface->channelSize == sizeof(uint8_t)) {
- TVGERR("SW_ENGINE", "Not supported grayscale Textmap polygon mesh!");
- return false;
- }
-
Matrix itransform;
if (transform) {
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
index 0a3f5ef7e7..350f333405 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
@@ -20,6 +20,7 @@
* SOFTWARE.
*/
+#include <algorithm>
#include "tvgMath.h"
#include "tvgSwCommon.h"
#include "tvgTaskScheduler.h"
@@ -86,7 +87,7 @@ struct SwShapeTask : SwTask
Additionally, the stroke style should not be dashed. */
bool antialiasing(float strokeWidth)
{
- return strokeWidth < 2.0f || rshape->stroke->dashCnt > 0 || rshape->stroke->strokeFirst || rshape->strokeTrim();
+ return strokeWidth < 2.0f || rshape->stroke->dashCnt > 0 || rshape->stroke->strokeFirst || rshape->strokeTrim() || rshape->stroke->color[3] < 255;;
}
float validStrokeWidth()
diff --git a/thirdparty/thorvg/src/renderer/tvgCanvas.h b/thirdparty/thorvg/src/renderer/tvgCanvas.h
index 9d216e2f30..81fd1b7d6f 100644
--- a/thirdparty/thorvg/src/renderer/tvgCanvas.h
+++ b/thirdparty/thorvg/src/renderer/tvgCanvas.h
@@ -129,7 +129,7 @@ struct Canvas::Impl
return Result::Success;
}
- return Result::InsufficientCondition;
+ return Result::Unknown;
}
Result viewport(int32_t x, int32_t y, int32_t w, int32_t h)
diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h
index 8f28d37dbc..a915d68fec 100644
--- a/thirdparty/thorvg/src/renderer/tvgRender.h
+++ b/thirdparty/thorvg/src/renderer/tvgRender.h
@@ -103,7 +103,7 @@ struct RenderRegion
void intersect(const RenderRegion& rhs);
void add(const RenderRegion& rhs);
- bool operator==(const RenderRegion& rhs)
+ bool operator==(const RenderRegion& rhs) const
{
if (x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h) return true;
return false;
diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h
index c45995a64d..ecc58b6cc0 100644
--- a/thirdparty/thorvg/src/renderer/tvgShape.h
+++ b/thirdparty/thorvg/src/renderer/tvgShape.h
@@ -296,6 +296,7 @@ struct Shape::Impl
if (!rs.stroke) rs.stroke = new RenderStroke();
if (rs.stroke->fill && rs.stroke->fill != p) delete(rs.stroke->fill);
rs.stroke->fill = p;
+ rs.stroke->color[3] = 0;
flag |= RenderUpdateFlag::Stroke;
flag |= RenderUpdateFlag::GradientStroke;
diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh
index d08158bfe7..e964e5ab6d 100755
--- a/thirdparty/thorvg/update-thorvg.sh
+++ b/thirdparty/thorvg/update-thorvg.sh
@@ -1,6 +1,6 @@
#!/bin/bash -e
-VERSION=0.14.0
+VERSION=0.14.1
cd thirdparty/thorvg/ || true
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/