diff options
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; }; |