diff options
Diffstat (limited to 'modules')
48 files changed, 404 insertions, 186 deletions
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index c241f1cabd..4c217dac28 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -953,12 +953,12 @@ void CSGMesh3D::set_mesh(const Ref<Mesh> &p_mesh) { return; } if (mesh.is_valid()) { - mesh->disconnect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed)); + mesh->disconnect_changed(callable_mp(this, &CSGMesh3D::_mesh_changed)); } mesh = p_mesh; if (mesh.is_valid()) { - mesh->connect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed)); + mesh->connect_changed(callable_mp(this, &CSGMesh3D::_mesh_changed)); } _mesh_changed(); diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index e6523e3d09..8a3a36e84b 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -31,6 +31,7 @@ #include "texture_loader_dds.h" #include "core/io/file_access.h" +#include "scene/resources/image_texture.h" #define PF_FOURCC(s) ((uint32_t)(((s)[3] << 24U) | ((s)[2] << 16U) | ((s)[1] << 8U) | ((s)[0]))) diff --git a/modules/dds/texture_loader_dds.h b/modules/dds/texture_loader_dds.h index dc3df1fcee..3763700ff1 100644 --- a/modules/dds/texture_loader_dds.h +++ b/modules/dds/texture_loader_dds.h @@ -32,7 +32,6 @@ #define TEXTURE_LOADER_DDS_H #include "core/io/resource_loader.h" -#include "scene/resources/texture.h" class ResourceFormatDDS : public ResourceFormatLoader { public: diff --git a/modules/enet/enet_packet_peer.cpp b/modules/enet/enet_packet_peer.cpp index f64704c67d..a131841a07 100644 --- a/modules/enet/enet_packet_peer.cpp +++ b/modules/enet/enet_packet_peer.cpp @@ -76,7 +76,7 @@ void ENetPacketPeer::throttle_configure(int p_interval, int p_acceleration, int void ENetPacketPeer::set_timeout(int p_timeout, int p_timeout_min, int p_timeout_max) { ERR_FAIL_COND_MSG(peer == nullptr, "Peer not connected"); - ERR_FAIL_COND_MSG(p_timeout > p_timeout_min || p_timeout_min > p_timeout_max, "Timeout limit must be less than minimum timeout, which itself must be less then maximum timeout"); + ERR_FAIL_COND_MSG(p_timeout > p_timeout_min || p_timeout_min > p_timeout_max, "Timeout limit must be less than minimum timeout, which itself must be less than maximum timeout"); enet_peer_timeout(peer, p_timeout, p_timeout_min, p_timeout_max); } diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 3d6d133579..7117337827 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -787,11 +787,11 @@ Error GDScript::reload(bool p_keep_state) { err = compiler.compile(&parser, this, p_keep_state); if (err) { + _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), false, ERR_HANDLER_SCRIPT); if (can_run) { if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error()); } - _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), false, ERR_HANDLER_SCRIPT); reloading = false; return ERR_COMPILATION_FAILED; } else { diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index d3445b8cc0..78337a6245 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -4517,6 +4517,10 @@ Variant GDScriptAnalyzer::make_variable_default_value(GDScriptParser::VariableNo return result; } +const HashMap<String, Ref<GDScriptParserRef>> &GDScriptAnalyzer::get_depended_parsers() { + return depended_parsers; +} + GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source) { GDScriptParser::DataType result; result.is_constant = true; diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index 195e23b503..4b6b0fbe26 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -144,6 +144,7 @@ public: Error analyze(); Variant make_variable_default_value(GDScriptParser::VariableNode *p_variable); + const HashMap<String, Ref<GDScriptParserRef>> &get_depended_parsers(); GDScriptAnalyzer(GDScriptParser *p_parser); }; diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index e5bb93e3c8..d191bd0224 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -294,8 +294,12 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro if (p_update_from_disk) { r_error = script->load_source_code(p_path); + if (r_error) { + return script; + } } + r_error = script->reload(true); if (r_error) { return script; } @@ -303,7 +307,6 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro singleton->full_gdscript_cache[p_path] = script; singleton->shallow_gdscript_cache.erase(p_path); - script->reload(true); return script; } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 004af80a91..3f571602e8 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2579,9 +2579,9 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri } } else if (!base->is_valid()) { Error err = OK; - Ref<GDScript> base_root = GDScriptCache::get_full_script(base->path, err, p_script->path); + Ref<GDScript> base_root = GDScriptCache::get_shallow_script(base->path, err, p_script->path); if (err) { - _set_error(vformat(R"(Could not compile base class "%s" from "%s": %s)", base->fully_qualified_name, base->path, error_names[err]), nullptr); + _set_error(vformat(R"(Could not parse base class "%s" from "%s": %s)", base->fully_qualified_name, base->path, error_names[err]), nullptr); return err; } if (base_root.is_valid()) { @@ -2591,7 +2591,12 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri _set_error(vformat(R"(Could not find class "%s" in "%s".)", base->fully_qualified_name, base->path), nullptr); return ERR_COMPILATION_FAILED; } - ERR_FAIL_COND_V(!base->is_valid() && !base->reloading, ERR_BUG); + + err = _populate_class_members(base.ptr(), p_class->base_type.class_type, p_keep_state); + if (err) { + _set_error(vformat(R"(Could not populate class members of base class "%s" in "%s".)", base->fully_qualified_name, base->path), nullptr); + return err; + } } p_script->base = base; @@ -2968,7 +2973,7 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri GDScriptCache::add_static_script(p_script); } - return GDScriptCache::finish_compiling(main_script->get_path()); + return GDScriptCache::finish_compiling(main_script->path); } String GDScriptCompiler::get_error() const { diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index cd34feb8b3..2a7346940b 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -143,14 +143,26 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li #endif if (err) { if (r_errors) { - for (const GDScriptParser::ParserError &E : parser.get_errors()) { - const GDScriptParser::ParserError &pe = E; + for (const GDScriptParser::ParserError &pe : parser.get_errors()) { ScriptLanguage::ScriptError e; + e.path = p_path; e.line = pe.line; e.column = pe.column; e.message = pe.message; r_errors->push_back(e); } + + for (KeyValue<String, Ref<GDScriptParserRef>> E : analyzer.get_depended_parsers()) { + GDScriptParser *depended_parser = E.value->get_parser(); + for (const GDScriptParser::ParserError &pe : depended_parser->get_errors()) { + ScriptLanguage::ScriptError e; + e.path = E.key; + e.line = pe.line; + e.column = pe.column; + e.message = pe.message; + r_errors->push_back(e); + } + } } return false; } else { @@ -1435,11 +1447,11 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, } break; case GDScriptParser::Node::SELF: { if (p_context.current_class) { - r_type.type.kind = GDScriptParser::DataType::CLASS; - r_type.type.type_source = GDScriptParser::DataType::INFERRED; - r_type.type.is_constant = true; - r_type.type.class_type = p_context.current_class; - r_type.value = p_context.base; + if (p_context.type != GDScriptParser::COMPLETION_SUPER_METHOD) { + r_type.type = p_context.current_class->get_datatype(); + } else { + r_type.type = p_context.current_class->base_type; + } found = true; } } break; diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index e23bd50b8b..605e82be6e 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -98,7 +98,7 @@ public: return; } - virtual String _get_name() const override { return "GDScript"; } + virtual String get_name() const override { return "GDScript"; } }; static void _editor_init() { diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd index 38c2faa859..8709b89b54 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd +++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd @@ -1,2 +1,2 @@ func test(): - CanvasItem.new() + InstancePlaceholder.new() diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out index 9eff912b59..36224c6b6f 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out @@ -1,2 +1,2 @@ GDTEST_ANALYZER_ERROR -Native class "CanvasItem" cannot be constructed as it is abstract. +Native class "InstancePlaceholder" cannot be constructed as it is abstract. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd index 118e7e8a45..be67182efb 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd +++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd @@ -1,4 +1,4 @@ -class A extends CanvasItem: +class A extends InstancePlaceholder: func _init(): print('no') diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out index 8b956f5974..260f062555 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out @@ -1,2 +1,2 @@ GDTEST_ANALYZER_ERROR -Class "abstract_script_instantiate.gd::B" cannot be constructed as it is based on abstract native class "CanvasItem". +Class "abstract_script_instantiate.gd::B" cannot be constructed as it is based on abstract native class "InstancePlaceholder". diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 0bbc2bbf74..d828363e03 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -49,6 +49,8 @@ #include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/multimesh_instance_3d.h" +#include "scene/resources/image_texture.h" +#include "scene/resources/portable_compressed_texture.h" #include "scene/resources/skin.h" #include "scene/resources/surface_tool.h" @@ -3769,6 +3771,12 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { extensions["KHR_materials_unlit"] = mat_unlit; p_state->add_used_extension("KHR_materials_unlit"); } + if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION) && !Math::is_equal_approx(base_material->get_emission_energy_multiplier(), 1.0f)) { + Dictionary mat_emissive_strength; + mat_emissive_strength["emissiveStrength"] = base_material->get_emission_energy_multiplier(); + extensions["KHR_materials_emissive_strength"] = mat_emissive_strength; + p_state->add_used_extension("KHR_materials_emissive_strength"); + } d["extensions"] = extensions; materials.push_back(d); @@ -3789,35 +3797,35 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) { const Array &materials = p_state->json["materials"]; for (GLTFMaterialIndex i = 0; i < materials.size(); i++) { - const Dictionary &d = materials[i]; + const Dictionary &material_dict = materials[i]; Ref<StandardMaterial3D> material; material.instantiate(); - if (d.has("name") && !String(d["name"]).is_empty()) { - material->set_name(d["name"]); + if (material_dict.has("name") && !String(material_dict["name"]).is_empty()) { + material->set_name(material_dict["name"]); } else { material->set_name(vformat("material_%s", itos(i))); } material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - Dictionary pbr_spec_gloss_extensions; - if (d.has("extensions")) { - pbr_spec_gloss_extensions = d["extensions"]; + Dictionary material_extensions; + if (material_dict.has("extensions")) { + material_extensions = material_dict["extensions"]; } - if (pbr_spec_gloss_extensions.has("KHR_materials_unlit")) { + if (material_extensions.has("KHR_materials_unlit")) { material->set_shading_mode(BaseMaterial3D::SHADING_MODE_UNSHADED); } - if (pbr_spec_gloss_extensions.has("KHR_materials_emissive_strength")) { - Dictionary emissive_strength = pbr_spec_gloss_extensions["KHR_materials_emissive_strength"]; + if (material_extensions.has("KHR_materials_emissive_strength")) { + Dictionary emissive_strength = material_extensions["KHR_materials_emissive_strength"]; if (emissive_strength.has("emissiveStrength")) { material->set_emission_energy_multiplier(emissive_strength["emissiveStrength"]); } } - if (pbr_spec_gloss_extensions.has("KHR_materials_pbrSpecularGlossiness")) { + if (material_extensions.has("KHR_materials_pbrSpecularGlossiness")) { WARN_PRINT("Material uses a specular and glossiness workflow. Textures will be converted to roughness and metallic workflow, which may not be 100% accurate."); - Dictionary sgm = pbr_spec_gloss_extensions["KHR_materials_pbrSpecularGlossiness"]; + Dictionary sgm = material_extensions["KHR_materials_pbrSpecularGlossiness"]; Ref<GLTFSpecGloss> spec_gloss; spec_gloss.instantiate(); @@ -3865,8 +3873,8 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) { } spec_gloss_to_rough_metal(spec_gloss, material); - } else if (d.has("pbrMetallicRoughness")) { - const Dictionary &mr = d["pbrMetallicRoughness"]; + } else if (material_dict.has("pbrMetallicRoughness")) { + const Dictionary &mr = material_dict["pbrMetallicRoughness"]; if (mr.has("baseColorFactor")) { const Array &arr = mr["baseColorFactor"]; ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR); @@ -3918,8 +3926,8 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) { } } - if (d.has("normalTexture")) { - const Dictionary &bct = d["normalTexture"]; + if (material_dict.has("normalTexture")) { + const Dictionary &bct = material_dict["normalTexture"]; if (bct.has("index")) { material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(p_state, bct["index"], TEXTURE_TYPE_NORMAL)); material->set_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING, true); @@ -3928,8 +3936,8 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) { material->set_normal_scale(bct["scale"]); } } - if (d.has("occlusionTexture")) { - const Dictionary &bct = d["occlusionTexture"]; + if (material_dict.has("occlusionTexture")) { + const Dictionary &bct = material_dict["occlusionTexture"]; if (bct.has("index")) { material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(p_state, bct["index"], TEXTURE_TYPE_GENERIC)); material->set_ao_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_RED); @@ -3937,8 +3945,8 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) { } } - if (d.has("emissiveFactor")) { - const Array &arr = d["emissiveFactor"]; + if (material_dict.has("emissiveFactor")) { + const Array &arr = material_dict["emissiveFactor"]; ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR); const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb(); material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true); @@ -3946,8 +3954,8 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) { material->set_emission(c); } - if (d.has("emissiveTexture")) { - const Dictionary &bct = d["emissiveTexture"]; + if (material_dict.has("emissiveTexture")) { + const Dictionary &bct = material_dict["emissiveTexture"]; if (bct.has("index")) { material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(p_state, bct["index"], TEXTURE_TYPE_GENERIC)); material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true); @@ -3955,20 +3963,20 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) { } } - if (d.has("doubleSided")) { - const bool ds = d["doubleSided"]; + if (material_dict.has("doubleSided")) { + const bool ds = material_dict["doubleSided"]; if (ds) { material->set_cull_mode(BaseMaterial3D::CULL_DISABLED); } } - if (d.has("alphaMode")) { - const String &am = d["alphaMode"]; + if (material_dict.has("alphaMode")) { + const String &am = material_dict["alphaMode"]; if (am == "BLEND") { material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS); } else if (am == "MASK") { material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR); - if (d.has("alphaCutoff")) { - material->set_alpha_scissor_threshold(d["alphaCutoff"]); + if (material_dict.has("alphaCutoff")) { + material->set_alpha_scissor_threshold(material_dict["alphaCutoff"]); } else { material->set_alpha_scissor_threshold(0.5f); } diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 6973bd3cd8..f9c3ca476a 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -138,11 +138,11 @@ Returns the position of a grid cell in the GridMap's local coordinate space. To convert the returned value into global coordinates, use [method Node3D.to_global]. See also [method map_to_local]. </description> </method> - <method name="resource_changed"> + <method name="resource_changed" is_deprecated="true"> <return type="void" /> <param index="0" name="resource" type="Resource" /> <description> - Notifies the [GridMap] about changed resource and recreates octant data. + [i]Obsoleted.[/i] Use [signal Resource.changed] instead. </description> </method> <method name="set_cell_item"> diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index c77fa98be2..f1e2218434 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -258,11 +258,11 @@ RID GridMap::get_navigation_map() const { void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) { if (!mesh_library.is_null()) { - mesh_library->unregister_owner(this); + mesh_library->disconnect_changed(callable_mp(this, &GridMap::_recreate_octant_data)); } mesh_library = p_mesh_library; if (!mesh_library.is_null()) { - mesh_library->register_owner(this); + mesh_library->connect_changed(callable_mp(this, &GridMap::_recreate_octant_data)); } _recreate_octant_data(); @@ -1005,9 +1005,10 @@ void GridMap::clear() { clear_baked_meshes(); } +#ifndef DISABLE_DEPRECATED void GridMap::resource_changed(const Ref<Resource> &p_res) { - _recreate_octant_data(); } +#endif void GridMap::_update_octants_callback() { if (!awaiting_update) { @@ -1079,7 +1080,9 @@ void GridMap::_bind_methods() { ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &GridMap::map_to_local); ClassDB::bind_method(D_METHOD("_update_octants_callback"), &GridMap::_update_octants_callback); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &GridMap::resource_changed); +#endif ClassDB::bind_method(D_METHOD("set_center_x", "enable"), &GridMap::set_center_x); ClassDB::bind_method(D_METHOD("get_center_x"), &GridMap::get_center_x); @@ -1336,10 +1339,6 @@ void GridMap::_navigation_map_changed(RID p_map) { #endif // DEBUG_ENABLED GridMap::~GridMap() { - if (!mesh_library.is_null()) { - mesh_library->unregister_owner(this); - } - clear(); #ifdef DEBUG_ENABLED NavigationServer3D::get_singleton()->disconnect("map_changed", callable_mp(this, &GridMap::_navigation_map_changed)); diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 18c3f90269..e05979efbc 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -203,7 +203,9 @@ class GridMap : public Node3D { void _queue_octants_dirty(); void _update_octants_callback(); +#ifndef DISABLE_DEPRECATED void resource_changed(const Ref<Resource> &p_res); +#endif void _clear_internal(); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs index 8be1151142..72614dd7e0 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs @@ -384,5 +384,65 @@ namespace Godot.SourceGenerators typeArgumentSyntax.GetLocation(), typeArgumentSyntax.SyntaxTree.FilePath)); } + + public static readonly DiagnosticDescriptor GlobalClassMustDeriveFromGodotObjectRule = + new DiagnosticDescriptor(id: "GD0401", + title: "The class must derive from GodotObject or a derived class", + messageFormat: "The class '{0}' must derive from GodotObject or a derived class.", + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + "The class must derive from GodotObject or a derived class. Change the base class or remove the '[GlobalClass]' attribute."); + + public static void ReportGlobalClassMustDeriveFromGodotObject( + SyntaxNodeAnalysisContext context, + SyntaxNode classSyntax, + ISymbol typeSymbol) + { + string message = $"The class '{typeSymbol.ToDisplayString()}' must derive from GodotObject or a derived class"; + + string description = $"{message}. Change the base class or remove the '[GlobalClass]' attribute."; + + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor(id: "GD0401", + title: message, + messageFormat: message, + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description), + classSyntax.GetLocation(), + classSyntax.SyntaxTree.FilePath)); + } + + public static readonly DiagnosticDescriptor GlobalClassMustNotBeGenericRule = + new DiagnosticDescriptor(id: "GD0402", + title: "The class must not contain generic arguments", + messageFormat: "The class '{0}' must not contain generic arguments", + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + "The class must be a non-generic type. Remove the generic arguments or the '[GlobalClass]' attribute."); + + public static void ReportGlobalClassMustNotBeGeneric( + SyntaxNodeAnalysisContext context, + SyntaxNode classSyntax, + ISymbol typeSymbol) + { + string message = $"The class '{typeSymbol.ToDisplayString()}' must not contain generic arguments"; + + string description = $"{message}. Remove the generic arguments or the '[GlobalClass]' attribute."; + + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor(id: "GD0402", + title: message, + messageFormat: message, + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description), + classSyntax.GetLocation(), + classSyntax.SyntaxTree.FilePath)); + } } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs index b2a3c046e5..b6ea4b8e88 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -81,7 +81,7 @@ namespace Godot.SourceGenerators return godotClassName ?? nativeType.Name; } - private static bool IsGodotScriptClass( + private static bool TryGetGodotScriptClass( this ClassDeclarationSyntax cds, Compilation compilation, out INamedTypeSymbol? symbol ) @@ -108,7 +108,7 @@ namespace Godot.SourceGenerators { foreach (var cds in source) { - if (cds.IsGodotScriptClass(compilation, out var symbol)) + if (cds.TryGetGodotScriptClass(compilation, out var symbol)) yield return (cds, symbol!); } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GlobalClassAnalyzer.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GlobalClassAnalyzer.cs new file mode 100644 index 0000000000..bcb35dae8a --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GlobalClassAnalyzer.cs @@ -0,0 +1,42 @@ +using System.Collections.Immutable; +using System.Linq; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Godot.SourceGenerators +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class GlobalClassAnalyzer : DiagnosticAnalyzer + { + public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics + => ImmutableArray.Create( + Common.GlobalClassMustDeriveFromGodotObjectRule, + Common.GlobalClassMustNotBeGenericRule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration); + } + + private void AnalyzeNode(SyntaxNodeAnalysisContext context) + { + var typeClassDecl = (ClassDeclarationSyntax)context.Node; + + // Return if not a type symbol or the type is not a global class. + if (context.ContainingSymbol is not INamedTypeSymbol typeSymbol || + !typeSymbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotGlobalClassAttribute() ?? false)) + return; + + if (typeSymbol.IsGenericType) + Common.ReportGlobalClassMustNotBeGeneric(context, typeClassDecl, typeSymbol); + + if (!typeSymbol.InheritsFrom("GodotSharp", GodotClasses.GodotObject)) + Common.ReportGlobalClassMustDeriveFromGodotObject(context, typeClassDecl, typeSymbol); + } + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs index 3e6858485d..09a4ab538f 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs @@ -620,7 +620,7 @@ namespace Godot.SourceGenerators bool isPresetHint = false; - if (elementVariantType == VariantType.String) + if (elementVariantType == VariantType.String || elementVariantType == VariantType.StringName) isPresetHint = GetStringArrayEnumHint(elementVariantType, exportAttr, out hintString); if (!isPresetHint) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 36f5d8e2ab..74425c9835 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using System.ComponentModel; namespace Godot { @@ -623,21 +624,31 @@ namespace Godot /// </summary> /// <param name="target">The position to look at.</param> /// <param name="up">The relative up direction.</param> + /// <param name="useModelFront"> + /// If true, then the model is oriented in reverse, + /// towards the model front axis (+Z, Vector3.ModelFront), + /// which is more useful for orienting 3D models. + /// </param> /// <returns>The resulting basis matrix.</returns> - public static Basis LookingAt(Vector3 target, Vector3 up) + public static Basis LookingAt(Vector3 target, Vector3? up = null, bool useModelFront = false) { + up ??= Vector3.Up; #if DEBUG if (target.IsZeroApprox()) { throw new ArgumentException("The vector can't be zero.", nameof(target)); } - if (up.IsZeroApprox()) + if (up.Value.IsZeroApprox()) { throw new ArgumentException("The vector can't be zero.", nameof(up)); } #endif - Vector3 column2 = -target.Normalized(); - Vector3 column0 = up.Cross(column2); + Vector3 column2 = target.Normalized(); + if (!useModelFront) + { + column2 = -column2; + } + Vector3 column0 = up.Value.Cross(column2); #if DEBUG if (column0.IsZeroApprox()) { @@ -649,6 +660,13 @@ namespace Godot return new Basis(column0, column1, column2); } + /// <inheritdoc cref="LookingAt(Vector3, Nullable{Vector3}, bool)"/> + [EditorBrowsable(EditorBrowsableState.Never)] + public static Basis LookingAt(Vector3 target, Vector3 up) + { + return LookingAt(target, up, false); + } + /// <summary> /// Returns the orthonormalized version of the basis matrix (useful to /// call occasionally to avoid rounding errors for orthogonal matrices). diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 1e2aaa299f..ae2c025137 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using System.ComponentModel; namespace Godot { @@ -175,14 +176,26 @@ namespace Godot /// </summary> /// <param name="target">The object to look at.</param> /// <param name="up">The relative up direction.</param> + /// <param name="useModelFront"> + /// If true, then the model is oriented in reverse, + /// towards the model front axis (+Z, Vector3.ModelFront), + /// which is more useful for orienting 3D models. + /// </param> /// <returns>The resulting transform.</returns> - public readonly Transform3D LookingAt(Vector3 target, Vector3 up) + public readonly Transform3D LookingAt(Vector3 target, Vector3? up = null, bool useModelFront = false) { Transform3D t = this; - t.SetLookAt(Origin, target, up); + t.SetLookAt(Origin, target, up ?? Vector3.Up, useModelFront); return t; } + /// <inheritdoc cref="LookingAt(Vector3, Nullable{Vector3}, bool)"/> + [EditorBrowsable(EditorBrowsableState.Never)] + public readonly Transform3D LookingAt(Vector3 target, Vector3 up) + { + return LookingAt(target, up, false); + } + /// <summary> /// Returns the transform with the basis orthogonal (90 degrees), /// and normalized axis vectors (scale of 1 or -1). @@ -247,9 +260,9 @@ namespace Godot return new Transform3D(Basis * tmpBasis, Origin); } - private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up) + private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up, bool useModelFront = false) { - Basis = Basis.LookingAt(target - eye, up); + Basis = Basis.LookingAt(target - eye, up, useModelFront); Origin = eye; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index c773c0fda6..d929b5c6ab 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -660,6 +660,13 @@ namespace Godot private static readonly Vector3 _forward = new Vector3(0, 0, -1); private static readonly Vector3 _back = new Vector3(0, 0, 1); + private static readonly Vector3 _modelLeft = new Vector3(1, 0, 0); + private static readonly Vector3 _modelRight = new Vector3(-1, 0, 0); + private static readonly Vector3 _modelTop = new Vector3(0, 1, 0); + private static readonly Vector3 _modelBottom = new Vector3(0, -1, 0); + private static readonly Vector3 _modelFront = new Vector3(0, 0, 1); + private static readonly Vector3 _modelRear = new Vector3(0, 0, -1); + /// <summary> /// Zero vector, a vector with all components set to <c>0</c>. /// </summary> @@ -712,6 +719,31 @@ namespace Godot public static Vector3 Back { get { return _back; } } /// <summary> + /// Unit vector pointing towards the left side of imported 3D assets. + /// </summary> + public static Vector3 ModelLeft { get { return _modelLeft; } } + /// <summary> + /// Unit vector pointing towards the right side of imported 3D assets. + /// </summary> + public static Vector3 ModelRight { get { return _modelRight; } } + /// <summary> + /// Unit vector pointing towards the top side (up) of imported 3D assets. + /// </summary> + public static Vector3 ModelTop { get { return _modelTop; } } + /// <summary> + /// Unit vector pointing towards the bottom side (down) of imported 3D assets. + /// </summary> + public static Vector3 ModelBottom { get { return _modelBottom; } } + /// <summary> + /// Unit vector pointing towards the front side (facing forward) of imported 3D assets. + /// </summary> + public static Vector3 ModelFront { get { return _modelFront; } } + /// <summary> + /// Unit vector pointing towards the rear side (back) of imported 3D assets. + /// </summary> + public static Vector3 ModelRear { get { return _modelRear; } } + + /// <summary> /// Constructs a new <see cref="Vector3"/> with the given components. /// </summary> /// <param name="x">The vector's X component.</param> diff --git a/modules/multiplayer/multiplayer_synchronizer.cpp b/modules/multiplayer/multiplayer_synchronizer.cpp index e5207fdae2..9c2d281f72 100644 --- a/modules/multiplayer/multiplayer_synchronizer.cpp +++ b/modules/multiplayer/multiplayer_synchronizer.cpp @@ -157,7 +157,7 @@ Error MultiplayerSynchronizer::get_state(const List<NodePath> &p_properties, Obj bool valid = false; const Object *obj = _get_prop_target(p_obj, prop); ERR_FAIL_COND_V(!obj, FAILED); - r_variant.write[i] = obj->get(prop.get_concatenated_subnames(), &valid); + r_variant.write[i] = obj->get_indexed(prop.get_subnames(), &valid); r_variant_ptrs.write[i] = &r_variant[i]; ERR_FAIL_COND_V_MSG(!valid, ERR_INVALID_DATA, vformat("Property '%s' not found.", prop)); i++; @@ -171,7 +171,7 @@ Error MultiplayerSynchronizer::set_state(const List<NodePath> &p_properties, Obj for (const NodePath &prop : p_properties) { Object *obj = _get_prop_target(p_obj, prop); ERR_FAIL_COND_V(!obj, FAILED); - obj->set(prop.get_concatenated_subnames(), p_state[i]); + obj->set_indexed(prop.get_subnames(), p_state[i]); i += 1; } return OK; diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp index 867cf5d8fc..9c0ce3e71e 100644 --- a/modules/navigation/nav_region.cpp +++ b/modules/navigation/nav_region.cpp @@ -115,11 +115,11 @@ void NavRegion::update_polygons() { #ifdef DEBUG_ENABLED if (!Math::is_equal_approx(double(map->get_cell_size()), double(mesh->get_cell_size()))) { - ERR_PRINT_ONCE("Navigation map synchronization error. Attempted to update a navigation region with a navigation mesh that uses a different `cell_size` than the `cell_size` set on the navigation map."); + ERR_PRINT_ONCE(vformat("Navigation map synchronization error. Attempted to update a navigation region with a navigation mesh that uses a `cell_size` of %s while assigned to a navigation map set to a `cell_size` of %s. The cell size for navigation maps can be changed by using the NavigationServer map_set_cell_size() function. The cell size for default navigation maps can also be changed in the ProjectSettings.", double(map->get_cell_size()), double(mesh->get_cell_size()))); } if (!Math::is_equal_approx(double(map->get_cell_height()), double(mesh->get_cell_height()))) { - ERR_PRINT_ONCE("Navigation map synchronization error. Attempted to update a navigation region with a navigation mesh that uses a different `cell_height` than the `cell_height` set on the navigation map."); + ERR_PRINT_ONCE(vformat("Navigation map synchronization error. Attempted to update a navigation region with a navigation mesh that uses a `cell_height` of %s while assigned to a navigation map set to a `cell_height` of %s. The cell height for navigation maps can be changed by using the NavigationServer map_set_cell_height() function. The cell height for default navigation maps can also be changed in the ProjectSettings.", double(map->get_cell_height()), double(mesh->get_cell_height()))); } if (map && Math::rad_to_deg(map->get_up().angle_to(transform.basis.get_column(1))) >= 90.0f) { diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp index a7176e0816..1b0c5cb9e3 100644 --- a/modules/noise/noise_texture_2d.cpp +++ b/modules/noise/noise_texture_2d.cpp @@ -32,8 +32,6 @@ #include "noise.h" -#include "core/core_string_names.h" - NoiseTexture2D::NoiseTexture2D() { noise = Ref<Noise>(); @@ -223,11 +221,11 @@ void NoiseTexture2D::set_noise(Ref<Noise> p_noise) { return; } if (noise.is_valid()) { - noise->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update)); + noise->disconnect_changed(callable_mp(this, &NoiseTexture2D::_queue_update)); } noise = p_noise; if (noise.is_valid()) { - noise->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update)); + noise->connect_changed(callable_mp(this, &NoiseTexture2D::_queue_update)); } _queue_update(); } @@ -347,11 +345,11 @@ void NoiseTexture2D::set_color_ramp(const Ref<Gradient> &p_gradient) { return; } if (color_ramp.is_valid()) { - color_ramp->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update)); + color_ramp->disconnect_changed(callable_mp(this, &NoiseTexture2D::_queue_update)); } color_ramp = p_gradient; if (color_ramp.is_valid()) { - color_ramp->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update)); + color_ramp->connect_changed(callable_mp(this, &NoiseTexture2D::_queue_update)); } _queue_update(); } diff --git a/modules/noise/noise_texture_3d.cpp b/modules/noise/noise_texture_3d.cpp index f6c67b0f2d..ed242e7faa 100644 --- a/modules/noise/noise_texture_3d.cpp +++ b/modules/noise/noise_texture_3d.cpp @@ -32,8 +32,6 @@ #include "noise.h" -#include "core/core_string_names.h" - NoiseTexture3D::NoiseTexture3D() { noise = Ref<Noise>(); @@ -214,11 +212,11 @@ void NoiseTexture3D::set_noise(Ref<Noise> p_noise) { return; } if (noise.is_valid()) { - noise->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture3D::_queue_update)); + noise->disconnect_changed(callable_mp(this, &NoiseTexture3D::_queue_update)); } noise = p_noise; if (noise.is_valid()) { - noise->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture3D::_queue_update)); + noise->connect_changed(callable_mp(this, &NoiseTexture3D::_queue_update)); } _queue_update(); } @@ -297,11 +295,11 @@ void NoiseTexture3D::set_color_ramp(const Ref<Gradient> &p_gradient) { return; } if (color_ramp.is_valid()) { - color_ramp->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture3D::_queue_update)); + color_ramp->disconnect_changed(callable_mp(this, &NoiseTexture3D::_queue_update)); } color_ramp = p_gradient; if (color_ramp.is_valid()) { - color_ramp->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture3D::_queue_update)); + color_ramp->connect_changed(callable_mp(this, &NoiseTexture3D::_queue_update)); } _queue_update(); } diff --git a/modules/noise/tests/test_noise_texture_2d.h b/modules/noise/tests/test_noise_texture_2d.h index e2ec39ef48..938e8fd6ab 100644 --- a/modules/noise/tests/test_noise_texture_2d.h +++ b/modules/noise/tests/test_noise_texture_2d.h @@ -210,7 +210,7 @@ TEST_CASE("[NoiseTexture2D][SceneTree] Generating a basic noise texture with mip noise_texture->set_generate_mipmaps(true); Ref<NoiseTextureTester> tester = memnew(NoiseTextureTester(noise_texture.ptr())); - noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTextureTester::check_mip_and_color_ramp)); + noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTextureTester::check_mip_and_color_ramp)); MessageQueue::get_singleton()->flush(); } @@ -227,7 +227,7 @@ TEST_CASE("[NoiseTexture2D][SceneTree] Generating a normal map without mipmaps") noise_texture->set_generate_mipmaps(false); Ref<NoiseTextureTester> tester = memnew(NoiseTextureTester(noise_texture.ptr())); - noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTextureTester::check_normal_map)); + noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTextureTester::check_normal_map)); MessageQueue::get_singleton()->flush(); } @@ -245,7 +245,7 @@ TEST_CASE("[NoiseTexture2D][SceneTree] Generating a seamless noise texture") { SUBCASE("Grayscale(L8) 16x16, with seamless blend skirt of 0.05") { noise_texture->set_seamless_blend_skirt(0.05); - noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTextureTester::check_seamless_texture_grayscale)); + noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTextureTester::check_seamless_texture_grayscale)); MessageQueue::get_singleton()->flush(); } @@ -257,7 +257,7 @@ TEST_CASE("[NoiseTexture2D][SceneTree] Generating a seamless noise texture") { gradient->set_points(points); noise_texture->set_color_ramp(gradient); noise_texture->set_seamless_blend_skirt(1.0); - noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTextureTester::check_seamless_texture_rgba)); + noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTextureTester::check_seamless_texture_rgba)); MessageQueue::get_singleton()->flush(); } } diff --git a/modules/noise/tests/test_noise_texture_3d.h b/modules/noise/tests/test_noise_texture_3d.h index a612f2920a..b708eac43b 100644 --- a/modules/noise/tests/test_noise_texture_3d.h +++ b/modules/noise/tests/test_noise_texture_3d.h @@ -194,7 +194,7 @@ TEST_CASE("[NoiseTexture3D][SceneTree] Generating a basic noise texture with mip noise_texture->set_depth(16); Ref<NoiseTexture3DTester> tester = memnew(NoiseTexture3DTester(noise_texture.ptr())); - noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTexture3DTester::check_mip_and_color_ramp)); + noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTexture3DTester::check_mip_and_color_ramp)); MessageQueue::get_singleton()->flush(); } @@ -213,7 +213,7 @@ TEST_CASE("[NoiseTexture3D][SceneTree] Generating a seamless noise texture") { SUBCASE("Grayscale(L8) 16x16x16, with seamless blend skirt of 0.05") { noise_texture->set_seamless_blend_skirt(0.05); - noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTexture3DTester::check_seamless_texture_grayscale)); + noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTexture3DTester::check_seamless_texture_grayscale)); MessageQueue::get_singleton()->flush(); } @@ -225,7 +225,7 @@ TEST_CASE("[NoiseTexture3D][SceneTree] Generating a seamless noise texture") { gradient->set_points(points); noise_texture->set_color_ramp(gradient); noise_texture->set_seamless_blend_skirt(1.0); - noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTexture3DTester::check_seamless_texture_rgba)); + noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTexture3DTester::check_seamless_texture_rgba)); MessageQueue::get_singleton()->flush(); } } diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp index 6fffa1ed07..65559afed0 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp @@ -134,6 +134,10 @@ void OpenXRHandTrackingExtension::on_process() { // process our hands const XrTime time = OpenXRAPI::get_singleton()->get_next_frame_time(); // This data will be used for the next frame we render + if (time == 0) { + // we don't have timing info yet, or we're skipping a frame... + return; + } XrResult result; diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp index 69fbf87483..eee0de967e 100644 --- a/modules/raycast/raycast_occlusion_cull.cpp +++ b/modules/raycast/raycast_occlusion_cull.cpp @@ -355,41 +355,14 @@ void RaycastOcclusionCull::Scenario::_update_dirty_instance(int p_idx, RID *p_in // Embree requires the last element to be readable by a 16-byte SSE load instruction, so we add padding to be safe. occ_inst->xformed_vertices.resize(vertices_size + 1); - const Vector3 *read_ptr = occ->vertices.ptr(); - Vector3 *write_ptr = occ_inst->xformed_vertices.ptr(); - - if (vertices_size > 1024) { - TransformThreadData td; - td.xform = occ_inst->xform; - td.read = read_ptr; - td.write = write_ptr; - td.vertex_count = vertices_size; - td.thread_count = WorkerThreadPool::get_singleton()->get_thread_count(); - WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &Scenario::_transform_vertices_thread, &td, td.thread_count, -1, true, SNAME("RaycastOcclusionCull")); - WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); - - } else { - _transform_vertices_range(read_ptr, write_ptr, occ_inst->xform, 0, vertices_size); - } + for_range(0, vertices_size, vertices_size > 1024, SNAME("RaycastOcclusionCull"), [&](const int i) { + occ_inst->xformed_vertices[i] = occ_inst->xform.xform(occ->vertices[i]); + }); occ_inst->indices.resize(occ->indices.size()); memcpy(occ_inst->indices.ptr(), occ->indices.ptr(), occ->indices.size() * sizeof(int32_t)); } -void RaycastOcclusionCull::Scenario::_transform_vertices_thread(uint32_t p_thread, TransformThreadData *p_data) { - uint32_t vertex_total = p_data->vertex_count; - uint32_t total_threads = p_data->thread_count; - uint32_t from = p_thread * vertex_total / total_threads; - uint32_t to = (p_thread + 1 == total_threads) ? vertex_total : ((p_thread + 1) * vertex_total / total_threads); - _transform_vertices_range(p_data->read, p_data->write, p_data->xform, from, to); -} - -void RaycastOcclusionCull::Scenario::_transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform3D &p_xform, int p_from, int p_to) { - for (int i = p_from; i < p_to; i++) { - p_write[i] = p_xform.xform(p_read[i]); - } -} - void RaycastOcclusionCull::Scenario::_commit_scene(void *p_ud) { Scenario *scenario = (Scenario *)p_ud; int commit_idx = 1 - (scenario->current_scene_idx); diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h index c4e733b664..7a5346878b 100644 --- a/modules/raycast/raycast_occlusion_cull.h +++ b/modules/raycast/raycast_occlusion_cull.h @@ -121,14 +121,6 @@ private: const uint32_t *masks; }; - struct TransformThreadData { - uint32_t thread_count; - uint32_t vertex_count; - Transform3D xform; - const Vector3 *read; - Vector3 *write = nullptr; - }; - Thread *commit_thread = nullptr; bool commit_done = true; bool dirty = false; @@ -144,8 +136,6 @@ private: void _update_dirty_instance_thread(int p_idx, RID *p_instances); void _update_dirty_instance(int p_idx, RID *p_instances); - void _transform_vertices_thread(uint32_t p_thread, TransformThreadData *p_data); - void _transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform3D &p_xform, int p_from, int p_to); static void _commit_scene(void *p_ud); bool update(); diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index b8010e6692..13d8a2c17a 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -52,6 +52,7 @@ using namespace godot; #include "core/object/worker_thread_pool.h" #include "core/string/print_string.h" #include "core/string/translation.h" +#include "scene/resources/image_texture.h" #include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg. diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index aba727edaa..44700e045b 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -85,7 +85,7 @@ using namespace godot; #include "core/object/worker_thread_pool.h" #include "core/templates/hash_map.h" #include "core/templates/rid_owner.h" -#include "scene/resources/texture.h" +#include "scene/resources/image_texture.h" #include "servers/text/text_server_extension.h" #include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg. diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index d81b50779e..54311caaf9 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -83,7 +83,7 @@ using namespace godot; #include "core/object/worker_thread_pool.h" #include "core/templates/hash_map.h" #include "core/templates/rid_owner.h" -#include "scene/resources/texture.h" +#include "scene/resources/image_texture.h" #include "servers/text/text_server_extension.h" #include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg. diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index 6c961813b4..d964fd7627 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/os/os.h" +#include "scene/resources/image_texture.h" #ifdef _MSC_VER #pragma warning(push) diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index 32adc28a88..21d4caef45 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -43,6 +43,8 @@ #include <theora/theoradec.h> #include <vorbis/codec.h> +class ImageTexture; + //#define THEORA_USE_THREAD_STREAMING class VideoStreamPlaybackTheora : public VideoStreamPlayback { diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index fcd717cfec..b54335b724 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -33,6 +33,7 @@ #include "core/io/file_access.h" #include "core/variant/typed_array.h" +#include "modules/vorbis/resource_importer_ogg_vorbis.h" #include <ogg/ogg.h> int AudioStreamPlaybackOggVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) { @@ -520,6 +521,9 @@ bool AudioStreamOggVorbis::is_monophonic() const { } void AudioStreamOggVorbis::_bind_methods() { + ClassDB::bind_static_method("AudioStreamOggVorbis", D_METHOD("load_from_buffer", "buffer"), &AudioStreamOggVorbis::load_from_buffer); + ClassDB::bind_static_method("AudioStreamOggVorbis", D_METHOD("load_from_file", "path"), &AudioStreamOggVorbis::load_from_file); + ClassDB::bind_method(D_METHOD("set_packet_sequence", "packet_sequence"), &AudioStreamOggVorbis::set_packet_sequence); ClassDB::bind_method(D_METHOD("get_packet_sequence"), &AudioStreamOggVorbis::get_packet_sequence); @@ -549,3 +553,11 @@ void AudioStreamOggVorbis::_bind_methods() { AudioStreamOggVorbis::AudioStreamOggVorbis() {} AudioStreamOggVorbis::~AudioStreamOggVorbis() {} + +Ref<AudioStreamOggVorbis> AudioStreamOggVorbis::load_from_buffer(const Vector<uint8_t> &file_data) { + return ResourceImporterOggVorbis::load_from_buffer(file_data); +} + +Ref<AudioStreamOggVorbis> AudioStreamOggVorbis::load_from_file(const String &p_path) { + return ResourceImporterOggVorbis::load_from_file(p_path); +} diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h index c76df7f84d..41ce942eec 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.h +++ b/modules/vorbis/audio_stream_ogg_vorbis.h @@ -125,6 +125,8 @@ protected: static void _bind_methods(); public: + static Ref<AudioStreamOggVorbis> load_from_file(const String &p_path); + static Ref<AudioStreamOggVorbis> load_from_buffer(const Vector<uint8_t> &file_data); void set_loop(bool p_enable); virtual bool has_loop() const override; diff --git a/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml b/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml index 4f920e2e04..7e3af6688a 100644 --- a/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml +++ b/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml @@ -1,11 +1,29 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="AudioStreamOggVorbis" inherits="AudioStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> + A class representing an Ogg Vorbis audio stream. </brief_description> <description> + The AudioStreamOggVorbis class is a specialized [AudioStream] for handling Ogg Vorbis file formats. It offers functionality for loading and playing back Ogg Vorbis files, as well as managing looping and other playback properties. This class is part of the audio stream system, which also supports WAV files through the [AudioStreamWAV] class. </description> <tutorials> </tutorials> + <methods> + <method name="load_from_buffer" qualifiers="static"> + <return type="AudioStreamOggVorbis" /> + <param index="0" name="buffer" type="PackedByteArray" /> + <description> + Creates a new AudioStreamOggVorbis instance from the given buffer. The buffer must contain Ogg Vorbis data. + </description> + </method> + <method name="load_from_file" qualifiers="static"> + <return type="AudioStreamOggVorbis" /> + <param index="0" name="path" type="String" /> + <description> + Creates a new AudioStreamOggVorbis instance from the given file path. The file must be in Ogg Vorbis format. + </description> + </method> + </methods> <members> <member name="bar_beats" type="int" setter="set_bar_beats" getter="get_bar_beats" default="4"> </member> diff --git a/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml b/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml index ccedb9c98e..10c87b899f 100644 --- a/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml +++ b/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml @@ -6,6 +6,22 @@ </description> <tutorials> </tutorials> + <methods> + <method name="load_from_buffer" qualifiers="static"> + <return type="AudioStreamOggVorbis" /> + <param index="0" name="buffer" type="PackedByteArray" /> + <description> + This method loads audio data from a PackedByteArray buffer into an AudioStreamOggVorbis object. + </description> + </method> + <method name="load_from_file" qualifiers="static"> + <return type="AudioStreamOggVorbis" /> + <param index="0" name="path" type="String" /> + <description> + This method loads audio data from a file into an AudioStreamOggVorbis object. The file path is provided as a string. + </description> + </method> + </methods> <members> <member name="bar_beats" type="int" setter="" getter="" default="4"> </member> diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp index 028b7a3086..26af912999 100644 --- a/modules/vorbis/register_types.cpp +++ b/modules/vorbis/register_types.cpp @@ -31,7 +31,10 @@ #include "register_types.h" #include "audio_stream_ogg_vorbis.h" + +#ifdef TOOLS_ENABLED #include "resource_importer_ogg_vorbis.h" +#endif void initialize_vorbis_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp index 8392750798..b42cd20589 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp @@ -81,18 +81,50 @@ void ResourceImporterOggVorbis::get_import_options(const String &p_path, List<Im r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "bar_beats", PROPERTY_HINT_RANGE, "2,32,or_greater"), 4)); } -Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const String &p_path) { - Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(f.is_null(), Ref<AudioStreamOggVorbis>(), "Cannot open file '" + p_path + "'."); +#ifdef TOOLS_ENABLED + +bool ResourceImporterOggVorbis::has_advanced_options() const { + return true; +} + +void ResourceImporterOggVorbis::show_advanced_options(const String &p_path) { + Ref<AudioStreamOggVorbis> ogg_stream = load_from_file(p_path); + if (ogg_stream.is_valid()) { + AudioStreamImportSettings::get_singleton()->edit(p_path, "oggvorbisstr", ogg_stream); + } +} +#endif + +Error ResourceImporterOggVorbis::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { + bool loop = p_options["loop"]; + float loop_offset = p_options["loop_offset"]; + double bpm = p_options["bpm"]; + int beat_count = p_options["beat_count"]; + int bar_beats = p_options["bar_beats"]; - uint64_t len = f->get_length(); + Ref<AudioStreamOggVorbis> ogg_vorbis_stream = load_from_file(p_source_file); + if (ogg_vorbis_stream.is_null()) { + return ERR_CANT_OPEN; + } - Vector<uint8_t> file_data; - file_data.resize(len); - uint8_t *w = file_data.ptrw(); + ogg_vorbis_stream->set_loop(loop); + ogg_vorbis_stream->set_loop_offset(loop_offset); + ogg_vorbis_stream->set_bpm(bpm); + ogg_vorbis_stream->set_beat_count(beat_count); + ogg_vorbis_stream->set_bar_beats(bar_beats); + + return ResourceSaver::save(ogg_vorbis_stream, p_save_path + ".oggvorbisstr"); +} - f->get_buffer(w, len); +ResourceImporterOggVorbis::ResourceImporterOggVorbis() { +} + +void ResourceImporterOggVorbis::_bind_methods() { + ClassDB::bind_static_method("ResourceImporterOggVorbis", D_METHOD("load_from_buffer", "buffer"), &ResourceImporterOggVorbis::load_from_buffer); + ClassDB::bind_static_method("ResourceImporterOggVorbis", D_METHOD("load_from_file", "path"), &ResourceImporterOggVorbis::load_from_file); +} +Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::load_from_buffer(const Vector<uint8_t> &file_data) { Ref<AudioStreamOggVorbis> ogg_vorbis_stream; ogg_vorbis_stream.instantiate(); @@ -114,7 +146,7 @@ Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const Str err = ogg_sync_check(&sync_state); ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); while (ogg_sync_pageout(&sync_state, &page) != 1) { - if (cursor >= len) { + if (cursor >= size_t(file_data.size())) { done = true; break; } @@ -123,8 +155,8 @@ Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const Str char *sync_buf = ogg_sync_buffer(&sync_state, OGG_SYNC_BUFFER_SIZE); err = ogg_sync_check(&sync_state); ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); - ERR_FAIL_COND_V(cursor > len, Ref<AudioStreamOggVorbis>()); - size_t copy_size = len - cursor; + ERR_FAIL_COND_V(cursor > size_t(file_data.size()), Ref<AudioStreamOggVorbis>()); + size_t copy_size = file_data.size() - cursor; if (copy_size > OGG_SYNC_BUFFER_SIZE) { copy_size = OGG_SYNC_BUFFER_SIZE; } @@ -201,40 +233,8 @@ Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const Str return ogg_vorbis_stream; } -#ifdef TOOLS_ENABLED - -bool ResourceImporterOggVorbis::has_advanced_options() const { - return true; -} - -void ResourceImporterOggVorbis::show_advanced_options(const String &p_path) { - Ref<AudioStreamOggVorbis> ogg_stream = import_ogg_vorbis(p_path); - if (ogg_stream.is_valid()) { - AudioStreamImportSettings::get_singleton()->edit(p_path, "oggvorbisstr", ogg_stream); - } -} -#endif - -Error ResourceImporterOggVorbis::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { - bool loop = p_options["loop"]; - float loop_offset = p_options["loop_offset"]; - double bpm = p_options["bpm"]; - int beat_count = p_options["beat_count"]; - int bar_beats = p_options["bar_beats"]; - - Ref<AudioStreamOggVorbis> ogg_vorbis_stream = import_ogg_vorbis(p_source_file); - if (ogg_vorbis_stream.is_null()) { - return ERR_CANT_OPEN; - } - - ogg_vorbis_stream->set_loop(loop); - ogg_vorbis_stream->set_loop_offset(loop_offset); - ogg_vorbis_stream->set_bpm(bpm); - ogg_vorbis_stream->set_beat_count(beat_count); - ogg_vorbis_stream->set_bar_beats(bar_beats); - - return ResourceSaver::save(ogg_vorbis_stream, p_save_path + ".oggvorbisstr"); -} - -ResourceImporterOggVorbis::ResourceImporterOggVorbis() { +Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::load_from_file(const String &p_path) { + Vector<uint8_t> file_data = FileAccess::get_file_as_bytes(p_path); + ERR_FAIL_COND_V_MSG(file_data.is_empty(), Ref<AudioStreamOggVorbis>(), "Cannot open file '" + p_path + "'."); + return load_from_buffer(file_data); } diff --git a/modules/vorbis/resource_importer_ogg_vorbis.h b/modules/vorbis/resource_importer_ogg_vorbis.h index 4874419834..59ae3378a0 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.h +++ b/modules/vorbis/resource_importer_ogg_vorbis.h @@ -42,16 +42,17 @@ class ResourceImporterOggVorbis : public ResourceImporter { OGG_SYNC_BUFFER_SIZE = 8192, }; -private: - // virtual int get_samples_in_packet(Vector<uint8_t> p_packet) = 0; - - static Ref<AudioStreamOggVorbis> import_ogg_vorbis(const String &p_path); +protected: + static void _bind_methods(); public: #ifdef TOOLS_ENABLED virtual bool has_advanced_options() const override; virtual void show_advanced_options(const String &p_path) override; #endif + + static Ref<AudioStreamOggVorbis> load_from_file(const String &p_path); + static Ref<AudioStreamOggVorbis> load_from_buffer(const Vector<uint8_t> &file_data); virtual void get_recognized_extensions(List<String> *p_extensions) const override; virtual String get_save_extension() const override; virtual String get_resource_type() const override; diff --git a/modules/webp/resource_saver_webp.cpp b/modules/webp/resource_saver_webp.cpp index 92285e2eab..52289334f8 100644 --- a/modules/webp/resource_saver_webp.cpp +++ b/modules/webp/resource_saver_webp.cpp @@ -34,7 +34,7 @@ #include "core/io/file_access.h" #include "core/io/image.h" -#include "scene/resources/texture.h" +#include "scene/resources/image_texture.h" Error ResourceSaverWebP::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) { Ref<ImageTexture> texture = p_resource; |