summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/config/project_settings.cpp2
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp13
-rw-r--r--editor/editor_asset_installer.cpp2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp144
-rw-r--r--modules/gdscript/gdscript_analyzer.h15
-rw-r--r--modules/gdscript/gdscript_editor.cpp35
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp2
-rw-r--r--platform/macos/export/export_plugin.cpp52
-rw-r--r--platform/macos/export/export_plugin.h4
-rw-r--r--scene/animation/animation_blend_tree.cpp57
-rw-r--r--scene/animation/animation_mixer.cpp42
-rw-r--r--scene/animation/animation_node_state_machine.cpp8
-rw-r--r--scene/animation/animation_player.cpp38
-rw-r--r--scene/animation/animation_tree.h4
-rw-r--r--scene/resources/animation.h16
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp13
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl2
-rw-r--r--servers/rendering/shader_language.cpp28
-rw-r--r--servers/rendering/shader_language.h15
20 files changed, 318 insertions, 176 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index e59f79fcc8..37a2608c10 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1491,7 +1491,7 @@ ProjectSettings::ProjectSettings() {
PackedStringArray extensions;
extensions.push_back("gd");
- if (Engine::get_singleton()->has_singleton("GodotSharp")) {
+ if (ClassDB::class_exists("CSharpScript")) {
extensions.push_back("cs");
}
extensions.push_back("gdshader");
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 941b1a1b28..8e9b0c2f29 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -341,10 +341,15 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
normal_transform.columns[2] = Vector2();
_update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform);
- state_buffer.canvas_modulate[0] = p_modulate.r;
- state_buffer.canvas_modulate[1] = p_modulate.g;
- state_buffer.canvas_modulate[2] = p_modulate.b;
- state_buffer.canvas_modulate[3] = p_modulate.a;
+ bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target);
+ Color modulate = p_modulate;
+ if (use_linear_colors) {
+ modulate = p_modulate.srgb_to_linear();
+ }
+ state_buffer.canvas_modulate[0] = modulate.r;
+ state_buffer.canvas_modulate[1] = modulate.g;
+ state_buffer.canvas_modulate[2] = modulate.b;
+ state_buffer.canvas_modulate[3] = modulate.a;
Size2 render_target_size = texture_storage->render_target_get_size(p_to_render_target);
state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp
index 8662ad75b2..33049b6bc2 100644
--- a/editor/editor_asset_installer.cpp
+++ b/editor/editor_asset_installer.cpp
@@ -632,7 +632,7 @@ void EditorAssetInstaller::_notification(int p_what) {
extension_icon_map["gdshader"] = get_editor_theme_icon(SNAME("Shader"));
extension_icon_map["gdshaderinc"] = get_editor_theme_icon(SNAME("TextFile"));
extension_icon_map["gd"] = get_editor_theme_icon(SNAME("GDScript"));
- if (Engine::get_singleton()->has_singleton("GodotSharp")) {
+ if (ClassDB::class_exists("CSharpScript")) {
extension_icon_map["cs"] = get_editor_theme_icon(SNAME("CSharpScript"));
} else {
// Mark C# support as unavailable.
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index bfc78d2605..990384bcaa 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -312,6 +312,15 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
p_source = p_class;
}
+ Ref<GDScriptParserRef> parser_ref = ensure_cached_parser_for_class(p_class, nullptr, vformat(R"(Trying to resolve class inheritance of "%s" from "%s")", p_class->fqcn, parser->script_path), p_source);
+ Finally finally([&]() {
+ GDScriptParser::ClassNode *look_class = p_class;
+ do {
+ ensure_cached_parser_for_class(look_class->base_type.class_type, look_class, vformat(R"(Trying to resolve class inheritance of "%s" from "%s")", p_class->fqcn, parser->script_path), p_source);
+ look_class = look_class->base_type.class_type;
+ } while (look_class != nullptr);
+ });
+
if (p_class->base_type.is_resolving()) {
push_error(vformat(R"(Could not resolve class "%s": Cyclic reference.)", type_from_metatype(p_class->get_datatype()).to_string()), p_source);
return ERR_PARSE_ERROR;
@@ -323,21 +332,17 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
}
if (!parser->has_class(p_class)) {
- String script_path = p_class->get_datatype().script_path;
- Ref<GDScriptParserRef> parser_ref = parser->get_depended_parser_for(script_path);
if (parser_ref.is_null()) {
- push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
+ // Error already pushed.
return ERR_PARSE_ERROR;
}
Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
if (err) {
- push_error(vformat(R"(Could not parse script "%s": %s.)", script_path, error_names[err]), p_source);
+ push_error(vformat(R"(Could not parse script "%s": %s.)", p_class->get_datatype().script_path, error_names[err]), p_source);
return ERR_PARSE_ERROR;
}
- ERR_FAIL_COND_V_MSG(!parser_ref->get_parser()->has_class(p_class), ERR_PARSE_ERROR, R"(Parser bug: Mismatched external parser.)");
-
GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
GDScriptParser *other_parser = parser_ref->get_parser();
@@ -883,6 +888,11 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
p_source = member.get_source_node();
}
+ Ref<GDScriptParserRef> parser_ref = ensure_cached_parser_for_class(p_class, nullptr, vformat(R"(Trying to resolve class member "%s" of "%s" from "%s")", member.get_name(), p_class->fqcn, parser->script_path), p_source);
+ Finally finally([&]() {
+ ensure_cached_parser_for_class(member.get_datatype().class_type, p_class, vformat(R"(Trying to resolve class member "%s" of "%s" from "%s")", member.get_name(), p_class->fqcn, parser->script_path), p_source);
+ });
+
if (member.get_datatype().is_resolving()) {
push_error(vformat(R"(Could not resolve member "%s": Cyclic reference.)", member.get_name()), p_source);
return;
@@ -892,22 +902,26 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
return;
}
+ // If it's already resolving, that's ok.
+ if (!p_class->base_type.is_resolving()) {
+ Error err = resolve_class_inheritance(p_class);
+ if (err) {
+ return;
+ }
+ }
+
if (!parser->has_class(p_class)) {
- String script_path = p_class->get_datatype().script_path;
- Ref<GDScriptParserRef> parser_ref = parser->get_depended_parser_for(script_path);
if (parser_ref.is_null()) {
- push_error(vformat(R"(Could not find script "%s" (While resolving "%s").)", script_path, member.get_name()), p_source);
+ // Error already pushed.
return;
}
Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
if (err) {
- push_error(vformat(R"(Could not resolve script "%s": %s (While resolving "%s").)", script_path, error_names[err], member.get_name()), p_source);
+ push_error(vformat(R"(Could not parse script "%s": %s (While resolving member "%s").)", p_class->get_datatype().script_path, error_names[err], member.get_name()), p_source);
return;
}
- ERR_FAIL_COND_MSG(!parser_ref->get_parser()->has_class(p_class), R"(Parser bug: Mismatched external parser.)");
-
GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
GDScriptParser *other_parser = parser_ref->get_parser();
@@ -915,19 +929,12 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
other_analyzer->resolve_class_member(p_class, p_index);
if (other_parser->errors.size() > error_count) {
push_error(vformat(R"(Could not resolve member "%s".)", member.get_name()), p_source);
+ return;
}
return;
}
- // If it's already resolving, that's ok.
- if (!p_class->base_type.is_resolving()) {
- Error err = resolve_class_inheritance(p_class);
- if (err) {
- return;
- }
- }
-
GDScriptParser::ClassNode *previous_class = parser->current_class;
parser->current_class = p_class;
@@ -1170,27 +1177,25 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
p_source = p_class;
}
+ Ref<GDScriptParserRef> parser_ref = ensure_cached_parser_for_class(p_class, nullptr, vformat(R"(Trying to resolve class interface of "%s" from "%s")", p_class->fqcn, parser->script_path), p_source);
+
if (!p_class->resolved_interface) {
#ifdef DEBUG_ENABLED
bool has_static_data = p_class->has_static_data;
#endif
if (!parser->has_class(p_class)) {
- String script_path = p_class->get_datatype().script_path;
- Ref<GDScriptParserRef> parser_ref = parser->get_depended_parser_for(script_path);
if (parser_ref.is_null()) {
- push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
+ // Error already pushed.
return;
}
Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
if (err) {
- push_error(vformat(R"(Could not resolve script "%s": %s.)", script_path, error_names[err]), p_source);
+ push_error(vformat(R"(Could not parse script "%s": %s.)", p_class->get_datatype().script_path, error_names[err]), p_source);
return;
}
- ERR_FAIL_COND_MSG(!parser_ref->get_parser()->has_class(p_class), R"(Parser bug: Mismatched external parser.)");
-
GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
GDScriptParser *other_parser = parser_ref->get_parser();
@@ -1198,6 +1203,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
other_analyzer->resolve_class_interface(p_class);
if (other_parser->errors.size() > error_count) {
push_error(vformat(R"(Could not resolve class "%s".)", p_class->fqcn), p_source);
+ return;
}
return;
@@ -1261,26 +1267,24 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class, co
p_source = p_class;
}
+ Ref<GDScriptParserRef> parser_ref = ensure_cached_parser_for_class(p_class, nullptr, vformat(R"(Trying to resolve class body of "%s" from "%s")", p_class->fqcn, parser->script_path), p_source);
+
if (p_class->resolved_body) {
return;
}
if (!parser->has_class(p_class)) {
- String script_path = p_class->get_datatype().script_path;
- Ref<GDScriptParserRef> parser_ref = parser->get_depended_parser_for(script_path);
if (parser_ref.is_null()) {
- push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
+ // Error already pushed.
return;
}
Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
if (err) {
- push_error(vformat(R"(Could not resolve script "%s": %s.)", script_path, error_names[err]), p_source);
+ push_error(vformat(R"(Could not parse script "%s": %s.)", p_class->get_datatype().script_path, error_names[err]), p_source);
return;
}
- ERR_FAIL_COND_MSG(!parser_ref->get_parser()->has_class(p_class), R"(Parser bug: Mismatched external parser.)");
-
GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
GDScriptParser *other_parser = parser_ref->get_parser();
@@ -1288,6 +1292,7 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class, co
other_analyzer->resolve_class_body(p_class);
if (other_parser->errors.size() > error_count) {
push_error(vformat(R"(Could not resolve class "%s".)", p_class->fqcn), p_source);
+ return;
}
return;
@@ -3645,12 +3650,81 @@ GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const Str
}
}
+Ref<GDScriptParserRef> GDScriptAnalyzer::ensure_cached_parser_for_class(const GDScriptParser::ClassNode *p_class, const GDScriptParser::ClassNode *p_from_class, const String &p_context, const GDScriptParser::Node *p_source) {
+ if (p_class == nullptr) {
+ return nullptr;
+ }
+
+ if (parser->has_class(p_class)) {
+ return nullptr;
+ }
+
+ {
+ HashMap<const GDScriptParser::ClassNode *, Ref<GDScriptParserRef>>::Iterator E = external_class_parser_cache.find(p_class);
+ if (E) {
+ return E->value;
+ }
+ }
+
+ Ref<GDScriptParserRef> parser_ref;
+ Ref<GDScriptParserRef> dependant_parser_ref;
+ GDScriptParser *dependant_parser = parser;
+ do {
+ if (HashMap<const GDScriptParser::ClassNode *, Ref<GDScriptParserRef>>::Iterator E = external_class_parser_cache.find(p_from_class)) {
+ dependant_parser_ref = E->value;
+ dependant_parser = E->value->get_parser();
+
+ // Silently ensure it's parsed.
+ dependant_parser_ref->raise_status(GDScriptParserRef::PARSED);
+ }
+
+ if (dependant_parser == nullptr) {
+ continue;
+ }
+
+ if (dependant_parser_ref.is_valid() && dependant_parser->has_class(p_class)) {
+ external_class_parser_cache.insert(p_class, dependant_parser_ref);
+ parser_ref = dependant_parser_ref;
+ break;
+ }
+
+ String script_path = p_class->get_datatype().script_path;
+ HashMap<String, Ref<GDScriptParserRef>>::Iterator E = dependant_parser->depended_parsers.find(script_path);
+ if (E) {
+ // Silently ensure it's parsed.
+ E->value->raise_status(GDScriptParserRef::PARSED);
+ if (E->value->get_parser()->has_class(p_class)) {
+ external_class_parser_cache.insert(p_class, E->value);
+ parser_ref = E->value;
+ break;
+ }
+ }
+
+ dependant_parser_ref = Ref<GDScriptParserRef>();
+ dependant_parser = nullptr;
+ p_from_class = p_from_class->base_type.class_type;
+ } while (p_from_class != nullptr);
+
+ if (parser_ref.is_null()) {
+ push_error(vformat(R"(Parser bug: Could not find external parser. (%s))", p_context), p_source);
+ }
+
+ return parser_ref;
+}
+
+Ref<GDScript> GDScriptAnalyzer::get_depended_shallow_script(const String &p_path, Error &r_error) {
+ // To keep a local cache of the parser for resolving external nodes later.
+ parser->get_depended_parser_for(p_path);
+ Ref<GDScript> scr = GDScriptCache::get_shallow_script(p_path, r_error, parser->script_path);
+ return scr;
+}
+
void GDScriptAnalyzer::reduce_identifier_from_base_set_class(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType p_identifier_datatype) {
ERR_FAIL_NULL(p_identifier);
p_identifier->set_datatype(p_identifier_datatype);
Error err = OK;
- Ref<GDScript> scr = GDScriptCache::get_shallow_script(p_identifier_datatype.script_path, err, parser->script_path);
+ Ref<GDScript> scr = get_depended_shallow_script(p_identifier_datatype.script_path, err);
if (err) {
push_error(vformat(R"(Error while getting cache for script "%s".)", p_identifier_datatype.script_path), p_identifier);
return;
@@ -4340,7 +4414,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
const String &res_type = ResourceLoader::get_resource_type(p_preload->resolved_path);
if (res_type == "GDScript") {
Error err = OK;
- Ref<GDScript> res = GDScriptCache::get_shallow_script(p_preload->resolved_path, err, parser->script_path);
+ Ref<GDScript> res = get_depended_shallow_script(p_preload->resolved_path, err);
p_preload->resource = res;
if (err != OK) {
push_error(vformat(R"(Could not preload resource script "%s".)", p_preload->resolved_path), p_preload->path);
@@ -4916,7 +4990,7 @@ Array GDScriptAnalyzer::make_array_from_element_datatype(const GDScriptParser::D
Ref<Script> script_type = p_element_datatype.script_type;
if (p_element_datatype.kind == GDScriptParser::DataType::CLASS && script_type.is_null()) {
Error err = OK;
- Ref<GDScript> scr = GDScriptCache::get_shallow_script(p_element_datatype.script_path, err, parser->script_path);
+ Ref<GDScript> scr = get_depended_shallow_script(p_element_datatype.script_path, err);
if (err) {
push_error(vformat(R"(Error while getting cache for script "%s".)", p_element_datatype.script_path), p_source_node);
return array;
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 922000df52..35e20f40d4 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -41,9 +41,22 @@
class GDScriptAnalyzer {
GDScriptParser *parser = nullptr;
+ template <typename Fn>
+ class Finally {
+ Fn fn;
+
+ public:
+ Finally(Fn p_fn) :
+ fn(p_fn) {}
+ ~Finally() {
+ fn();
+ }
+ };
+
const GDScriptParser::EnumNode *current_enum = nullptr;
GDScriptParser::LambdaNode *current_lambda = nullptr;
List<GDScriptParser::LambdaNode *> pending_body_resolution_lambdas;
+ HashMap<const GDScriptParser::ClassNode *, Ref<GDScriptParserRef>> external_class_parser_cache;
bool static_context = false;
// Tests for detecting invalid overloading of script members
@@ -132,6 +145,8 @@ class GDScriptAnalyzer {
void resolve_pending_lambda_bodies();
bool class_exists(const StringName &p_class) const;
void reduce_identifier_from_base_set_class(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType p_identifier_datatype);
+ Ref<GDScriptParserRef> ensure_cached_parser_for_class(const GDScriptParser::ClassNode *p_class, const GDScriptParser::ClassNode *p_from_class, const String &p_context, const GDScriptParser::Node *p_source);
+ Ref<GDScript> get_depended_shallow_script(const String &p_path, Error &r_error);
#ifdef DEBUG_ENABLED
void is_shadowing(GDScriptParser::IdentifierNode *p_identifier, const String &p_context, const bool p_in_local_scope);
#endif
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index b1ffc02e4b..28a030e492 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -796,7 +796,7 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
case GDScriptParser::Node::CALL: {
const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(par->initializer);
if (call->is_constant && call->reduced) {
- def_val = call->function_name.operator String() + call->reduced_value.operator String();
+ def_val = call->reduced_value.get_construct_string();
} else {
def_val = call->function_name.operator String() + (call->arguments.is_empty() ? "()" : "(...)");
}
@@ -804,7 +804,7 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
case GDScriptParser::Node::ARRAY: {
const GDScriptParser::ArrayNode *arr = static_cast<const GDScriptParser::ArrayNode *>(par->initializer);
if (arr->is_constant && arr->reduced) {
- def_val = arr->reduced_value.operator String();
+ def_val = arr->reduced_value.get_construct_string();
} else {
def_val = arr->elements.is_empty() ? "[]" : "[...]";
}
@@ -812,24 +812,17 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
case GDScriptParser::Node::DICTIONARY: {
const GDScriptParser::DictionaryNode *dict = static_cast<const GDScriptParser::DictionaryNode *>(par->initializer);
if (dict->is_constant && dict->reduced) {
- def_val = dict->reduced_value.operator String();
+ def_val = dict->reduced_value.get_construct_string();
} else {
def_val = dict->elements.is_empty() ? "{}" : "{...}";
}
} break;
case GDScriptParser::Node::SUBSCRIPT: {
const GDScriptParser::SubscriptNode *sub = static_cast<const GDScriptParser::SubscriptNode *>(par->initializer);
- if (sub->is_constant) {
- if (sub->datatype.kind == GDScriptParser::DataType::ENUM) {
- def_val = sub->get_datatype().to_string();
- } else if (sub->reduced) {
- const Variant::Type vt = sub->reduced_value.get_type();
- if (vt == Variant::Type::NIL || vt == Variant::Type::FLOAT || vt == Variant::Type::INT || vt == Variant::Type::STRING || vt == Variant::Type::STRING_NAME || vt == Variant::Type::BOOL || vt == Variant::Type::NODE_PATH) {
- def_val = sub->reduced_value.operator String();
- } else {
- def_val = sub->get_datatype().to_string() + sub->reduced_value.operator String();
- }
- }
+ if (sub->is_attribute && sub->datatype.kind == GDScriptParser::DataType::ENUM && !sub->datatype.is_meta_type) {
+ def_val = sub->get_datatype().to_string() + "." + sub->attribute->name;
+ } else if (sub->is_constant && sub->reduced) {
+ def_val = sub->reduced_value.get_construct_string();
}
} break;
default:
@@ -2759,6 +2752,20 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
base_type = base_type.class_type->base_type;
} break;
+ case GDScriptParser::DataType::SCRIPT: {
+ if (base_type.script_type->is_valid() && base_type.script_type->has_method(p_method)) {
+ r_arghint = _make_arguments_hint(base_type.script_type->get_method_info(p_method), p_argidx);
+ return;
+ }
+ Ref<Script> base_script = base_type.script_type->get_base_script();
+ if (base_script.is_valid()) {
+ base_type.script_type = base_script;
+ } else {
+ base_type.kind = GDScriptParser::DataType::NATIVE;
+ base_type.builtin_type = Variant::OBJECT;
+ base_type.native_type = base_type.script_type->get_instance_base_type();
+ }
+ } break;
case GDScriptParser::DataType::NATIVE: {
StringName class_name = base_type.native_type;
if (!ClassDB::class_exists(class_name)) {
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index fbfa4a0a79..025fcbd32a 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -622,7 +622,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) {
enable_stdout();
result.status = GDTEST_COMPILER_ERROR;
result.output = get_text_for_status(result.status) + "\n";
- result.output = compiler.get_error();
+ result.output += compiler.get_error() + "\n";
if (!p_is_generating) {
result.passed = check_output(result.output);
}
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index a934e991a1..2ff02d2e74 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -141,7 +141,7 @@ String EditorExportPlatformMacOS::get_export_option_warning(const EditorExportPr
if (p_name == "codesign/codesign") {
if (dist_type == 2) {
- if (codesign_tool == 2 && Engine::get_singleton()->has_singleton("GodotSharp")) {
+ if (codesign_tool == 2 && ClassDB::class_exists("CSharpScript")) {
return TTR("'rcodesign' doesn't support signing applications with embedded dynamic libraries (GDExtension or .NET).");
}
if (codesign_tool == 0) {
@@ -333,7 +333,7 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP
}
// These entitlements are required to run managed code, and are always enabled in Mono builds.
- if (Engine::get_singleton()->has_singleton("GodotSharp")) {
+ if (ClassDB::class_exists("CSharpScript")) {
if (p_option == "codesign/entitlements/allow_jit_code_execution" || p_option == "codesign/entitlements/allow_unsigned_executable_memory" || p_option == "codesign/entitlements/allow_dyld_environment_variables") {
return false;
}
@@ -1064,7 +1064,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
return OK;
}
-Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn, bool p_set_id) {
+void EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn, bool p_set_id) {
int codesign_tool = p_preset->get("codesign/codesign");
switch (codesign_tool) {
case 1: { // built-in ad-hoc
@@ -1074,7 +1074,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
Error err = CodeSign::codesign(false, true, p_path, p_ent_path, error_msg);
if (err != OK) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Built-in CodeSign failed with error \"%s\"."), error_msg));
- return Error::FAILED;
+ return;
}
#else
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Built-in CodeSign require regex module."));
@@ -1086,7 +1086,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
String rcodesign = EDITOR_GET("export/macos/rcodesign").operator String();
if (rcodesign.is_empty()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Xrcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign)."));
- return Error::FAILED;
+ return;
}
List<String> args;
@@ -1124,13 +1124,13 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
Error err = OS::get_singleton()->execute(rcodesign, args, &str, &exitcode, true);
if (err != OK) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start rcodesign executable."));
- return err;
+ return;
}
if (exitcode != 0) {
print_line("rcodesign (" + p_path + "):\n" + str);
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Code signing failed, see editor log for details."));
- return Error::FAILED;
+ return;
} else {
print_verbose("rcodesign (" + p_path + "):\n" + str);
}
@@ -1141,7 +1141,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
if (!FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Xcode command line tools are not installed."));
- return Error::FAILED;
+ return;
}
bool ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
@@ -1190,13 +1190,13 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
Error err = OS::get_singleton()->execute("codesign", args, &str, &exitcode, true);
if (err != OK) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed."));
- return err;
+ return;
}
if (exitcode != 0) {
print_line("codesign (" + p_path + "):\n" + str);
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Code signing failed, see editor log for details."));
- return Error::FAILED;
+ return;
} else {
print_verbose("codesign (" + p_path + "):\n" + str);
}
@@ -1205,11 +1205,9 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
default: {
};
}
-
- return OK;
}
-Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path,
+void EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path,
const String &p_ent_path, const String &p_helper_ent_path, bool p_should_error_on_non_code) {
static Vector<String> extensions_to_sign;
@@ -1224,7 +1222,8 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
Ref<DirAccess> dir_access{ DirAccess::open(p_path, &dir_access_error) };
if (dir_access_error != OK) {
- return dir_access_error;
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Cannot sign directory %s."), p_path));
+ return;
}
dir_access->list_dir_begin();
@@ -1247,28 +1246,19 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
set_bundle_id = true;
}
}
- Error code_sign_error{ _code_sign(p_preset, current_file_path, ent_path, false, set_bundle_id) };
- if (code_sign_error != OK) {
- return code_sign_error;
- }
+ _code_sign(p_preset, current_file_path, ent_path, false, set_bundle_id);
if (is_executable(current_file_path)) {
// chmod with 0755 if the file is executable.
FileAccess::set_unix_permissions(current_file_path, 0755);
}
} else if (dir_access->current_is_dir()) {
- Error code_sign_error{ _code_sign_directory(p_preset, current_file_path, p_ent_path, p_helper_ent_path, p_should_error_on_non_code) };
- if (code_sign_error != OK) {
- return code_sign_error;
- }
+ _code_sign_directory(p_preset, current_file_path, p_ent_path, p_helper_ent_path, p_should_error_on_non_code);
} else if (p_should_error_on_non_code) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Cannot sign file %s."), current_file));
- return Error::FAILED;
}
current_file = dir_access->get_next();
}
-
- return OK;
}
Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path,
@@ -1364,7 +1354,7 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
if (err == OK && p_sign_enabled) {
if (dir_access->dir_exists(p_src_path) && p_src_path.get_extension().is_empty()) {
// If it is a directory, find and sign all dynamic libraries.
- err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_helper_ent_path, p_should_error_on_non_code_sign);
+ _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_helper_ent_path, p_should_error_on_non_code_sign);
} else {
if (extensions_to_sign.has(p_in_app_path.get_extension())) {
String ent_path = p_ent_path;
@@ -1376,7 +1366,7 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
set_bundle_id = true;
}
}
- err = _code_sign(p_preset, p_in_app_path, ent_path, false, set_bundle_id);
+ _code_sign(p_preset, p_in_app_path, ent_path, false, set_bundle_id);
}
if (dir_access->file_exists(p_in_app_path) && is_executable(p_in_app_path)) {
// chmod with 0755 if the file is executable.
@@ -1989,7 +1979,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
ent_f->store_line("<plist version=\"1.0\">");
ent_f->store_line("<dict>");
- if (Engine::get_singleton()->has_singleton("GodotSharp")) {
+ if (ClassDB::class_exists("CSharpScript")) {
// These entitlements are required to run managed code, and are always enabled in Mono builds.
ent_f->store_line("<key>com.apple.security.cs.allow-jit</key>");
ent_f->store_line("<true/>");
@@ -2157,7 +2147,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
String hlp_path = helpers[i];
err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file());
if (err == OK && sign_enabled) {
- err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path, false, true);
+ _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path, false, true);
}
FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755);
}
@@ -2202,7 +2192,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
if (ep.step(TTR("Code signing bundle"), 2)) {
return ERR_SKIP;
}
- err = _code_sign(p_preset, tmp_app_path_name, ent_path, true, false);
+ _code_sign(p_preset, tmp_app_path_name, ent_path, true, false);
}
String noto_path = p_path;
@@ -2220,7 +2210,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
if (ep.step(TTR("Code signing DMG"), 3)) {
return ERR_SKIP;
}
- err = _code_sign(p_preset, p_path, ent_path, false, false);
+ _code_sign(p_preset, p_path, ent_path, false, false);
}
} else if (export_format == "pkg") {
// Create a Installer.
diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h
index 1929fc8d5f..062a2e5f95 100644
--- a/platform/macos/export/export_plugin.h
+++ b/platform/macos/export/export_plugin.h
@@ -90,8 +90,8 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
void _make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
- Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true, bool p_set_id = false);
- Error _code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, const String &p_helper_ent_path, bool p_should_error_on_non_code = true);
+ void _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true, bool p_set_id = false);
+ void _code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, const String &p_helper_ent_path, bool p_should_error_on_non_code = true);
Error _copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path, const String &p_in_app_path,
bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path, const String &p_helper_ent_path,
bool p_should_error_on_non_code_sign, bool p_sandbox);
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 6e33a1b27c..59ebf38253 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -144,7 +144,7 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
if (cur_loop_mode != Animation::LOOP_NONE) {
if (cur_loop_mode == Animation::LOOP_LINEAR) {
if (!Math::is_zero_approx(cur_len)) {
- if (prev_time <= cur_len && cur_time > cur_len) {
+ if (Animation::is_less_or_equal_approx(prev_time, cur_len) && Animation::is_greater_approx(cur_time, cur_len)) {
is_just_looped = true; // Don't break with negative timescale since remain will not be 0.
}
cur_time = Math::fposmod(cur_time, cur_len);
@@ -152,9 +152,9 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
backward = false;
} else {
if (!Math::is_zero_approx(cur_len)) {
- if (prev_time >= 0 && cur_time < 0) {
+ if (Animation::is_greater_or_equal_approx(prev_time, 0) && Animation::is_less_approx(cur_time, 0)) {
backward = !backward;
- } else if (prev_time <= cur_len && cur_time > cur_len) {
+ } else if (Animation::is_less_or_equal_approx(prev_time, cur_len) && Animation::is_greater_approx(cur_time, cur_len)) {
backward = !backward;
is_just_looped = true; // Don't break with negative timescale since remain will not be 0.
}
@@ -162,10 +162,10 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
}
}
} else {
- if (cur_time < 0) {
+ if (Animation::is_less_approx(cur_time, 0)) {
cur_delta += cur_time;
cur_time = 0;
- } else if (cur_time > cur_len) {
+ } else if (Animation::is_greater_approx(cur_time, cur_len)) {
cur_delta += cur_time - cur_len;
cur_time = cur_len;
}
@@ -173,11 +173,11 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
// If ended, don't progress AnimationNode. So set delta to 0.
if (!Math::is_zero_approx(cur_delta)) {
if (play_mode == PLAY_MODE_FORWARD) {
- if (prev_time >= cur_len) {
+ if (Animation::is_greater_or_equal_approx(prev_time, cur_len)) {
cur_delta = 0;
}
} else {
- if (prev_time <= 0) {
+ if (Animation::is_less_or_equal_approx(prev_time, 0)) {
cur_delta = 0;
}
}
@@ -197,6 +197,7 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
double cur_playback_time = cur_time + start_offset;
if (stretch_time_scale) {
double mlt = anim_size / cur_len;
+ prev_playback_time *= mlt;
cur_playback_time *= mlt;
cur_delta *= mlt;
}
@@ -204,31 +205,31 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
if (!Math::is_zero_approx(anim_size)) {
prev_playback_time = Math::fposmod(prev_playback_time, anim_size);
cur_playback_time = Math::fposmod(cur_playback_time, anim_size);
- if (prev_playback_time >= 0 && cur_playback_time < 0) {
+ if (Animation::is_greater_or_equal_approx(prev_playback_time, 0) && Animation::is_less_approx(cur_playback_time, 0)) {
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
}
- if (prev_playback_time <= anim_size && cur_playback_time > anim_size) {
+ if (Animation::is_less_or_equal_approx(prev_playback_time, anim_size) && Animation::is_greater_approx(cur_playback_time, anim_size)) {
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
}
}
} else if (cur_loop_mode == Animation::LOOP_PINGPONG) {
if (!Math::is_zero_approx(anim_size)) {
- if (Math::fposmod(cur_playback_time, anim_size * 2.0) >= anim_size) {
+ if (Animation::is_greater_or_equal_approx(Math::fposmod(cur_playback_time, anim_size * 2.0), anim_size)) {
cur_delta = -cur_delta; // Needed for retrieving discrete keys correctly.
}
prev_playback_time = Math::pingpong(prev_playback_time, anim_size);
cur_playback_time = Math::pingpong(cur_playback_time, anim_size);
- if (prev_playback_time >= 0 && cur_playback_time < 0) {
+ if (Animation::is_greater_or_equal_approx(prev_playback_time, 0) && Animation::is_less_approx(cur_playback_time, 0)) {
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
}
- if (prev_playback_time <= anim_size && cur_playback_time > anim_size) {
+ if (Animation::is_less_or_equal_approx(prev_playback_time, anim_size) && Animation::is_greater_approx(cur_playback_time, anim_size)) {
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
}
}
} else {
- if (cur_playback_time < 0) {
+ if (Animation::is_less_approx(cur_playback_time, 0)) {
cur_playback_time = 0;
- } else if (cur_playback_time > anim_size) {
+ } else if (Animation::is_greater_approx(cur_playback_time, anim_size)) {
cur_playback_time = anim_size;
}
@@ -236,11 +237,11 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
// We should use call_deferred since the track keys are still being processed.
if (process_state->tree && !p_test_only) {
// AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection.
- if (p_seek && !p_is_external_seeking && cur_playback_time == 0) {
+ if (p_seek && !p_is_external_seeking && Math::is_zero_approx(cur_playback_time)) {
process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_started), animation);
}
// Finished.
- if (prev_time + start_offset < anim_size && cur_playback_time >= anim_size) {
+ if (Animation::is_less_approx(prev_playback_time, anim_size) && Animation::is_greater_or_equal_approx(cur_playback_time, anim_size)) {
process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_finished), animation);
}
}
@@ -522,7 +523,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
bool p_seek = p_playback_info.seeked;
bool p_is_external_seeking = p_playback_info.is_external_seeking;
- if (p_time == 0 && p_seek && !p_is_external_seeking) {
+ if (Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking) {
clear_remaining_fade = true; // Reset occurs.
}
@@ -545,9 +546,9 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
set_parameter(internal_active, false);
set_parameter(time_to_restart, -1);
} else if (!do_start && !cur_active) {
- if (cur_time_to_restart >= 0.0 && !p_seek) {
+ if (Animation::is_greater_or_equal_approx(cur_time_to_restart, 0) && !p_seek) {
cur_time_to_restart -= abs_delta;
- if (cur_time_to_restart < 0) {
+ if (Animation::is_less_approx(cur_time_to_restart, 0)) {
do_start = true; // Restart.
}
set_parameter(time_to_restart, cur_time_to_restart);
@@ -590,8 +591,8 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
real_t blend = 1.0;
bool use_blend = sync;
- if (cur_fade_in_remaining > 0) {
- if (fade_in > 0) {
+ if (Animation::is_greater_approx(cur_fade_in_remaining, 0)) {
+ if (Animation::is_greater_approx(fade_in, 0)) {
use_blend = true;
blend = (fade_in - cur_fade_in_remaining) / fade_in;
if (fade_in_curve.is_valid()) {
@@ -604,7 +605,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
if (is_fading_out) {
use_blend = true;
- if (fade_out > 0) {
+ if (Animation::is_greater_approx(fade_out, 0)) {
blend = cur_fade_out_remaining / fade_out;
if (fade_out_curve.is_valid()) {
blend = 1.0 - fade_out_curve->sample(1.0 - blend);
@@ -636,7 +637,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
NodeTimeInfo os_nti = blend_input(1, pi, FILTER_PASS, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
- if (cur_fade_in_remaining <= 0 && !do_start && !is_fading_out && os_nti.get_remain(break_loop_at_end) <= fade_out) {
+ if (Animation::is_less_or_equal_approx(cur_fade_in_remaining, 0) && !do_start && !is_fading_out && Animation::is_less_or_equal_approx(os_nti.get_remain(break_loop_at_end), fade_out)) {
is_fading_out = true;
cur_fade_out_remaining = os_nti.get_remain(break_loop_at_end);
cur_fade_in_remaining = 0;
@@ -644,7 +645,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
}
if (!p_seek) {
- if (os_nti.get_remain(break_loop_at_end) <= 0 || (is_fading_out && cur_fade_out_remaining <= 0)) {
+ if (Animation::is_less_or_equal_approx(os_nti.get_remain(break_loop_at_end), 0) || (is_fading_out && Animation::is_less_or_equal_approx(cur_fade_out_remaining, 0))) {
set_parameter(internal_active, false);
set_parameter(active, false);
if (auto_restart) {
@@ -1007,7 +1008,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer
AnimationMixer::PlaybackInfo pi = p_playback_info;
pi.weight = 1.0;
- if (cur_seek_pos >= 0) {
+ if (Animation::is_greater_or_equal_approx(cur_seek_pos, 0)) {
pi.time = cur_seek_pos;
pi.seeked = true;
pi.is_external_seeking = true;
@@ -1252,7 +1253,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(const AnimationMix
bool p_seek = p_playback_info.seeked;
bool p_is_external_seeking = p_playback_info.is_external_seeking;
- if (p_time == 0 && p_seek && !p_is_external_seeking) {
+ if (Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking) {
clear_remaining_fade = true; // Reset occurs.
}
@@ -1317,7 +1318,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(const AnimationMix
if (cur_prev_index < 0) { // Process current animation, check for transition.
pi.weight = 1.0;
cur_nti = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only);
- if (input_data[cur_current_index].auto_advance && cur_nti.get_remain(input_data[cur_current_index].break_loop_at_end) <= xfade_time) {
+ if (input_data[cur_current_index].auto_advance && Animation::is_less_or_equal_approx(cur_nti.get_remain(input_data[cur_current_index].break_loop_at_end), xfade_time)) {
set_parameter(transition_request, get_input_name((cur_current_index + 1) % get_input_count()));
}
} else { // Cross-fading from prev to current.
@@ -1349,7 +1350,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(const AnimationMix
pi.weight = blend;
blend_input(cur_prev_index, pi, FILTER_IGNORE, true, p_test_only);
if (!p_seek) {
- if (cur_prev_xfading <= 0) {
+ if (Animation::is_less_or_equal_approx(cur_prev_xfading, 0)) {
set_parameter(prev_index, -1);
}
cur_prev_xfading -= Math::abs(p_playback_info.delta);
diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp
index e7626b3c2d..e57be69eaf 100644
--- a/scene/animation/animation_mixer.cpp
+++ b/scene/animation/animation_mixer.cpp
@@ -1049,7 +1049,7 @@ void AnimationMixer::blend_capture(double p_delta) {
}
capture_cache.remain -= p_delta * capture_cache.step;
- if (capture_cache.remain <= 0.0) {
+ if (Animation::is_less_or_equal_approx(capture_cache.remain, 0)) {
capture_cache.clear();
return;
}
@@ -1156,7 +1156,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (track->root_motion && calc_root) {
double prev_time = time - delta;
if (!backward) {
- if (prev_time < 0) {
+ if (Animation::is_less_approx(prev_time, 0)) {
switch (a->get_loop_mode()) {
case Animation::LOOP_NONE: {
prev_time = 0;
@@ -1172,7 +1172,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
}
} else {
- if (prev_time > a->get_length()) {
+ if (Animation::is_greater_approx(prev_time, (double)a->get_length())) {
switch (a->get_loop_mode()) {
case Animation::LOOP_NONE: {
prev_time = (double)a->get_length();
@@ -1190,7 +1190,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
Vector3 loc[2];
if (!backward) {
- if (prev_time > time) {
+ if (Animation::is_greater_approx(prev_time, time)) {
Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
if (err != OK) {
continue;
@@ -1202,7 +1202,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
prev_time = 0;
}
} else {
- if (prev_time < time) {
+ if (Animation::is_less_approx(prev_time, time)) {
Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
if (err != OK) {
continue;
@@ -1244,7 +1244,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (track->root_motion && calc_root) {
double prev_time = time - delta;
if (!backward) {
- if (prev_time < 0) {
+ if (Animation::is_less_approx(prev_time, 0)) {
switch (a->get_loop_mode()) {
case Animation::LOOP_NONE: {
prev_time = 0;
@@ -1260,7 +1260,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
}
} else {
- if (prev_time > a->get_length()) {
+ if (Animation::is_greater_approx(prev_time, (double)a->get_length())) {
switch (a->get_loop_mode()) {
case Animation::LOOP_NONE: {
prev_time = (double)a->get_length();
@@ -1278,7 +1278,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
Quaternion rot[2];
if (!backward) {
- if (prev_time > time) {
+ if (Animation::is_greater_approx(prev_time, time)) {
Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);
if (err != OK) {
continue;
@@ -1290,7 +1290,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
prev_time = 0;
}
} else {
- if (prev_time < time) {
+ if (Animation::is_less_approx(prev_time, time)) {
Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);
if (err != OK) {
continue;
@@ -1331,7 +1331,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (track->root_motion && calc_root) {
double prev_time = time - delta;
if (!backward) {
- if (prev_time < 0) {
+ if (Animation::is_less_approx(prev_time, 0)) {
switch (a->get_loop_mode()) {
case Animation::LOOP_NONE: {
prev_time = 0;
@@ -1347,7 +1347,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
}
} else {
- if (prev_time > a->get_length()) {
+ if (Animation::is_greater_approx(prev_time, (double)a->get_length())) {
switch (a->get_loop_mode()) {
case Animation::LOOP_NONE: {
prev_time = (double)a->get_length();
@@ -1365,7 +1365,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
Vector3 scale[2];
if (!backward) {
- if (prev_time > time) {
+ if (Animation::is_greater_approx(prev_time, time)) {
Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);
if (err != OK) {
continue;
@@ -1377,7 +1377,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
prev_time = 0;
}
} else {
- if (prev_time < time) {
+ if (Animation::is_less_approx(prev_time, time)) {
Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);
if (err != OK) {
continue;
@@ -1635,7 +1635,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
PlayingAudioStreamInfo pasi;
pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs, 0, 1.0, t->playback_type, t->bus);
pasi.start = time;
- if (len && end_ofs > 0) { // Force an end at a time.
+ if (len && Animation::is_greater_approx(end_ofs, 0)) { // Force an end at a time.
pasi.len = len - start_ofs - end_ofs;
} else {
pasi.len = 0;
@@ -1671,7 +1671,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
double at_anim_pos = 0.0;
switch (anim->get_loop_mode()) {
case Animation::LOOP_NONE: {
- if (!is_external_seeking && ((!backward && time >= pos + (double)anim->get_length()) || (backward && time <= pos))) {
+ if (!is_external_seeking && ((!backward && Animation::is_greater_or_equal_approx(time, pos + (double)anim->get_length())) || (backward && Animation::is_less_or_equal_approx(time, pos)))) {
continue; // Do nothing if current time is outside of length when started.
}
at_anim_pos = MIN((double)anim->get_length(), time - pos); // Seek to end.
@@ -1841,23 +1841,23 @@ void AnimationMixer::_blend_apply() {
}
if (!track_info.loop) {
if (!track_info.backward) {
- if (track_info.time < pasi.start) {
+ if (Animation::is_less_approx(track_info.time, pasi.start)) {
stop = true;
}
} else if (track_info.backward) {
- if (track_info.time > pasi.start) {
+ if (Animation::is_greater_approx(track_info.time, pasi.start)) {
stop = true;
}
}
}
- if (pasi.len > 0) {
+ if (Animation::is_greater_approx(pasi.len, 0)) {
double len = 0.0;
if (!track_info.backward) {
- len = pasi.start > track_info.time ? (track_info.length - pasi.start) + track_info.time : track_info.time - pasi.start;
+ len = Animation::is_greater_approx(pasi.start, track_info.time) ? (track_info.length - pasi.start) + track_info.time : track_info.time - pasi.start;
} else {
- len = pasi.start < track_info.time ? (track_info.length - track_info.time) + pasi.start : pasi.start - track_info.time;
+ len = Animation::is_less_approx(pasi.start, track_info.time) ? (track_info.length - track_info.time) + pasi.start : pasi.start - track_info.time;
}
- if (len > pasi.len) {
+ if (Animation::is_greater_approx(len, pasi.len)) {
stop = true;
}
}
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 8b497abd8c..ecf4054e23 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -702,7 +702,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
bool p_is_external_seeking = p_playback_info.is_external_seeking;
// Check seek to 0 (means reset) by parent AnimationNode.
- if (p_time == 0 && p_seek && !p_is_external_seeking) {
+ if (Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking) {
if (p_state_machine->state_machine_type != AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED || is_end() || !playing) {
// Restart state machine.
if (p_state_machine->get_state_machine_type() != AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) {
@@ -873,7 +873,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
}
fadeing_from_nti = p_state_machine->blend_node(p_state_machine->states[fading_from].node, fading_from, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
- if (fading_pos >= fading_time) {
+ if (Animation::is_greater_or_equal_approx(fading_pos, fading_time)) {
// Finish fading.
fading_from = StringName();
fadeing_from_nti = AnimationNode::NodeTimeInfo();
@@ -887,7 +887,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
if (will_end || ((p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) && !p_state_machine->has_transition_from(current))) {
// There is no next transition.
if (fading_from != StringName()) {
- return current_nti.get_remain() > fadeing_from_nti.get_remain() ? current_nti : fadeing_from_nti;
+ return Animation::is_greater_approx(current_nti.get_remain(), fadeing_from_nti.get_remain()) ? current_nti : fadeing_from_nti;
}
return current_nti;
}
@@ -1015,7 +1015,7 @@ bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p
}
if (current != AnimationNodeStateMachine::START_NODE && p_next.switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_AT_END) {
- return current_nti.get_remain(p_next.break_loop_at_end) <= p_next.xfade;
+ return Animation::is_less_or_equal_approx(current_nti.get_remain(p_next.break_loop_at_end), p_next.xfade);
}
return true;
}
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index bd8c7ff882..19229f405a 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -164,35 +164,35 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f
double delta = p_started ? 0 : p_delta * speed;
double next_pos = cd.pos + delta;
- real_t len = cd.from->animation->get_length();
+ double len = cd.from->animation->get_length();
Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
switch (cd.from->animation->get_loop_mode()) {
case Animation::LOOP_NONE: {
- if (next_pos < 0) {
+ if (Animation::is_less_approx(next_pos, 0)) {
next_pos = 0;
- } else if (next_pos > len) {
+ } else if (Animation::is_greater_approx(next_pos, len)) {
next_pos = len;
}
delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here).
} break;
case Animation::LOOP_LINEAR: {
- if (next_pos < 0 && cd.pos >= 0) {
+ if (Animation::is_less_approx(next_pos, 0) && Animation::is_greater_or_equal_approx(cd.pos, 0)) {
looped_flag = Animation::LOOPED_FLAG_START;
}
- if (next_pos > len && cd.pos <= len) {
+ if (Animation::is_greater_approx(next_pos, len) && Animation::is_less_or_equal_approx(cd.pos, len)) {
looped_flag = Animation::LOOPED_FLAG_END;
}
next_pos = Math::fposmod(next_pos, (double)len);
} break;
case Animation::LOOP_PINGPONG: {
- if (next_pos < 0 && cd.pos >= 0) {
+ if (Animation::is_less_approx(next_pos, 0) && Animation::is_greater_or_equal_approx(cd.pos, 0)) {
cd.speed_scale *= -1.0;
looped_flag = Animation::LOOPED_FLAG_START;
}
- if (next_pos > len && cd.pos <= len) {
+ if (Animation::is_greater_approx(next_pos, len) && Animation::is_less_or_equal_approx(cd.pos, len)) {
cd.speed_scale *= -1.0;
looped_flag = Animation::LOOPED_FLAG_END;
}
@@ -209,16 +209,16 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f
// End detection.
if (p_is_current) {
if (cd.from->animation->get_loop_mode() == Animation::LOOP_NONE) {
- if (!backwards && prev_pos <= len && next_pos == len) {
+ if (!backwards && Animation::is_less_or_equal_approx(prev_pos, len) && Math::is_equal_approx(next_pos, len)) {
// Playback finished.
end_reached = true;
- end_notify = prev_pos < len; // Notify only if not already at the end.
+ end_notify = Animation::is_less_approx(prev_pos, len); // Notify only if not already at the end.
p_blend = 1.0;
}
- if (backwards && prev_pos >= 0 && next_pos == 0) {
+ if (backwards && Animation::is_greater_or_equal_approx(prev_pos, 0) && Math::is_equal_approx(next_pos, 0)) {
// Playback finished.
end_reached = true;
- end_notify = prev_pos > 0; // Notify only if not already at the beginning.
+ end_notify = Animation::is_greater_approx(prev_pos, 0); // Notify only if not already at the beginning.
p_blend = 1.0;
}
}
@@ -277,7 +277,7 @@ void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) {
for (List<Blend>::Element *E = c.blend.front(); E; E = E->next()) {
Blend &b = E->get();
b.blend_left = MAX(0, b.blend_left - Math::absf(speed_scale * p_delta) / b.blend_time);
- if (b.blend_left <= 0) {
+ if (Animation::is_less_or_equal_approx(b.blend_left, 0)) {
to_erase.push_back(E);
b.blend_left = CMP_EPSILON; // May want to play last frame.
}
@@ -401,7 +401,7 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo
bk.from = c.current.from->name;
bk.to = name;
- if (p_custom_blend >= 0) {
+ if (Animation::is_greater_or_equal_approx(p_custom_blend, 0)) {
blend_time = p_custom_blend;
} else if (blend_times.has(bk)) {
blend_time = blend_times[bk];
@@ -419,10 +419,10 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo
}
}
- if (p_custom_blend < 0 && blend_time == 0 && default_blend_time) {
+ if (Animation::is_less_approx(p_custom_blend, 0) && Math::is_zero_approx(blend_time) && default_blend_time) {
blend_time = default_blend_time;
}
- if (blend_time > 0) {
+ if (Animation::is_greater_approx(blend_time, 0)) {
Blend b;
b.data = c.current;
b.blend_left = get_current_blend_amount();
@@ -449,10 +449,10 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo
c.assigned = name;
emit_signal(SNAME("current_animation_changed"), c.assigned);
} else {
- if (p_from_end && c.current.pos == 0) {
+ if (p_from_end && Math::is_zero_approx(c.current.pos)) {
// Animation reset but played backwards, set position to the end.
seek_internal(c.current.from->animation->get_length(), true, true, true);
- } else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) {
+ } else if (!p_from_end && Math::is_equal_approx(c.current.pos, (double)c.current.from->animation->get_length())) {
// Animation resumed but already ended, set position to the beginning.
seek_internal(0, true, true, true);
} else if (playing) {
@@ -585,7 +585,7 @@ void AnimationPlayer::seek_internal(double p_time, bool p_update, bool p_update_
return;
}
- bool is_backward = p_time < playback.current.pos;
+ bool is_backward = Animation::is_less_approx(p_time, playback.current.pos);
_check_immediately_after_start();
@@ -708,7 +708,7 @@ void AnimationPlayer::set_blend_time(const StringName &p_animation1, const Strin
BlendKey bk;
bk.from = p_animation1;
bk.to = p_animation2;
- if (p_time == 0) {
+ if (Math::is_zero_approx(p_time)) {
blend_times.erase(bk);
} else {
blend_times[bk] = p_time;
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 62a01b758f..6698427233 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -87,6 +87,10 @@ public:
if (p_break_loop && is_just_looped) {
return 0;
}
+ double remain = length - position;
+ if (Math::is_zero_approx(remain)) {
+ return 0;
+ }
return length - position;
}
};
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index cb12b12c0e..d5daaac58a 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -527,6 +527,22 @@ public:
static Variant interpolate_variant(const Variant &a, const Variant &b, float c, bool p_snap_array_element = false);
static Variant cubic_interpolate_in_time_variant(const Variant &pre_a, const Variant &a, const Variant &b, const Variant &post_b, float c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t, bool p_snap_array_element = false);
+ static bool is_less_or_equal_approx(double a, double b) {
+ return a < b || Math::is_equal_approx(a, b);
+ }
+
+ static bool is_less_approx(double a, double b) {
+ return a < b && !Math::is_equal_approx(a, b);
+ }
+
+ static bool is_greater_or_equal_approx(double a, double b) {
+ return a > b || Math::is_equal_approx(a, b);
+ }
+
+ static bool is_greater_approx(double a, double b) {
+ return a > b && !Math::is_equal_approx(a, b);
+ }
+
static TrackType get_cache_type(TrackType p_type);
Animation();
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index e58e45f13e..5c68fb82b1 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1451,10 +1451,15 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
normal_transform.columns[2] = Vector2();
_update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform);
- state_buffer.canvas_modulate[0] = p_modulate.r;
- state_buffer.canvas_modulate[1] = p_modulate.g;
- state_buffer.canvas_modulate[2] = p_modulate.b;
- state_buffer.canvas_modulate[3] = p_modulate.a;
+ bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target);
+ Color modulate = p_modulate;
+ if (use_linear_colors) {
+ modulate = p_modulate.srgb_to_linear();
+ }
+ state_buffer.canvas_modulate[0] = modulate.r;
+ state_buffer.canvas_modulate[1] = modulate.g;
+ state_buffer.canvas_modulate[2] = modulate.b;
+ state_buffer.canvas_modulate[3] = modulate.a;
Size2 render_target_size = texture_storage->render_target_get_size(p_to_render_target);
state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 20b080da4d..4a630b0b0a 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -352,7 +352,7 @@ void vertex_shader(vec3 vertex_input,
}
#ifdef OVERRIDE_POSITION
- vec4 position;
+ vec4 position = vec4(1.0);
#endif
#ifdef USE_MULTIVIEW
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index a64b2e10ea..530a7a37db 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -352,7 +352,7 @@ void main() {
}
#ifdef OVERRIDE_POSITION
- vec4 position;
+ vec4 position = vec4(1.0);
#endif
#ifdef USE_MULTIVIEW
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index e35fde406f..745dcf5392 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -4664,9 +4664,18 @@ bool ShaderLanguage::_validate_restricted_func(const StringName &p_name, const C
}
}
- if (!p_func_info->uses_restricted_functions.is_empty()) {
- const Pair<StringName, TkPos> &first_element = p_func_info->uses_restricted_functions.get(0);
- _set_tkpos(first_element.second);
+ if (!p_func_info->uses_restricted_items.is_empty()) {
+ const Pair<StringName, CallInfo::Item> &first_element = p_func_info->uses_restricted_items.get(0);
+
+ if (first_element.second.type == CallInfo::Item::ITEM_TYPE_VARYING) {
+ const ShaderNode::Varying &varying = shader->varyings[first_element.first];
+
+ if (varying.stage == ShaderNode::Varying::STAGE_VERTEX) {
+ return true;
+ }
+ }
+
+ _set_tkpos(first_element.second.pos);
if (is_in_restricted_function) {
_set_error(vformat(RTR("'%s' cannot be used within the '%s' processor function."), first_element.first, "vertex"));
@@ -5352,7 +5361,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
// Register usage of the restricted function.
- calls_info[current_function].uses_restricted_functions.push_back(Pair<StringName, TkPos>(name, _get_tkpos()));
+ calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos())));
is_builtin = true;
break;
}
@@ -5469,10 +5478,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (shader->varyings.has(varname)) {
switch (shader->varyings[varname].stage) {
- case ShaderNode::Varying::STAGE_UNKNOWN: {
- _set_error(vformat(RTR("Varying '%s' must be assigned in the 'vertex' or 'fragment' function first."), varname));
- return nullptr;
- }
+ case ShaderNode::Varying::STAGE_UNKNOWN:
+ if (is_out_arg) {
+ error = true;
+ }
+ break;
case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT:
[[fallthrough]];
case ShaderNode::Varying::STAGE_VERTEX:
@@ -5672,6 +5682,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
_set_tkpos(prev_pos);
ShaderNode::Varying &var = shader->varyings[identifier];
+ calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(identifier, CallInfo::Item(CallInfo::Item::ITEM_TYPE_VARYING, prev_pos)));
+
String error;
if (is_token_operator_assign(next_token.type)) {
if (!_validate_varying_assign(shader->varyings[identifier], &error)) {
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 076bd8def4..bc0aa0558a 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -917,8 +917,21 @@ private:
// Additional function information (eg. call hierarchy). No need to expose it to compiler.
struct CallInfo {
+ struct Item {
+ enum ItemType {
+ ITEM_TYPE_BUILTIN,
+ ITEM_TYPE_VARYING,
+ } type;
+
+ TkPos pos;
+
+ Item() {}
+ Item(ItemType p_type, TkPos p_pos) :
+ type(p_type), pos(p_pos) {}
+ };
+
StringName name;
- List<Pair<StringName, TkPos>> uses_restricted_functions;
+ List<Pair<StringName, Item>> uses_restricted_items;
List<CallInfo *> calls;
};