diff options
29 files changed, 410 insertions, 53 deletions
diff --git a/core/object/object.cpp b/core/object/object.cpp index 147e8f2136..056334c8e1 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -666,8 +666,16 @@ bool Object::has_method(const StringName &p_method) const { } MethodBind *method = ClassDB::get_method(get_class_name(), p_method); + if (method != nullptr) { + return true; + } - return method != nullptr; + const Script *scr = Object::cast_to<Script>(this); + if (scr != nullptr) { + return scr->has_static_method(p_method); + } + + return false; } Variant Object::getvar(const Variant &p_key, bool *r_valid) const { diff --git a/core/object/script_language.h b/core/object/script_language.h index ca08e9837a..5ff7cd8582 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -145,7 +145,10 @@ public: virtual PropertyInfo get_class_category() const; #endif // TOOLS_ENABLED + // TODO: In the next compat breakage rename to `*_script_*` to disambiguate from `Object::has_method()`. virtual bool has_method(const StringName &p_method) const = 0; + virtual bool has_static_method(const StringName &p_method) const { return false; } + virtual MethodInfo get_method_info(const StringName &p_method) const = 0; virtual bool is_tool() const = 0; diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp index ce1109781a..a07bf63a02 100644 --- a/core/object/script_language_extension.cpp +++ b/core/object/script_language_extension.cpp @@ -55,6 +55,7 @@ void ScriptExtension::_bind_methods() { GDVIRTUAL_BIND(_get_class_icon_path); GDVIRTUAL_BIND(_has_method, "method"); + GDVIRTUAL_BIND(_has_static_method, "method"); GDVIRTUAL_BIND(_get_method_info, "method"); GDVIRTUAL_BIND(_is_tool); diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h index beb8064a33..89bba80b90 100644 --- a/core/object/script_language_extension.h +++ b/core/object/script_language_extension.h @@ -99,6 +99,7 @@ public: #endif // TOOLS_ENABLED EXBIND1RC(bool, has_method, const StringName &) + EXBIND1RC(bool, has_static_method, const StringName &) GDVIRTUAL1RC(Dictionary, _get_method_info, const StringName &) virtual MethodInfo get_method_info(const StringName &p_method) const override { diff --git a/doc/classes/ScriptExtension.xml b/doc/classes/ScriptExtension.xml index 9e96a81f7b..51958a2a2a 100644 --- a/doc/classes/ScriptExtension.xml +++ b/doc/classes/ScriptExtension.xml @@ -123,6 +123,12 @@ <description> </description> </method> + <method name="_has_static_method" qualifiers="virtual const"> + <return type="bool" /> + <param index="0" name="method" type="StringName" /> + <description> + </description> + </method> <method name="_inherits_script" qualifiers="virtual const"> <return type="bool" /> <param index="0" name="script" type="Script" /> diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 2894f4164f..fcd3af8d62 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -1420,6 +1420,13 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) { glEnableVertexAttribArray(5); glVertexAttribIPointer(5, 4, GL_UNSIGNED_INT, instance_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(instance_color_offset * sizeof(float))); glVertexAttribDivisor(5, 1); + } else { + // Set all default instance color and custom data values to 1.0 or 0.0 using a compressed format. + uint16_t zero = Math::make_half_float(0.0f); + uint16_t one = Math::make_half_float(1.0f); + GLuint default_color = (uint32_t(one) << 16) | one; + GLuint default_custom = (uint32_t(zero) << 16) | zero; + glVertexAttribI4ui(5, default_color, default_color, default_custom, default_custom); } } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 1f8e9180e3..22bb772e4f 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2962,7 +2962,15 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, glEnableVertexAttribArray(15); glVertexAttribIPointer(15, 4, GL_UNSIGNED_INT, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(color_custom_offset * sizeof(float))); glVertexAttribDivisor(15, 1); + } else { + // Set all default instance color and custom data values to 1.0 or 0.0 using a compressed format. + uint16_t zero = Math::make_half_float(0.0f); + uint16_t one = Math::make_half_float(1.0f); + GLuint default_color = (uint32_t(one) << 16) | one; + GLuint default_custom = (uint32_t(zero) << 16) | zero; + glVertexAttribI4ui(15, default_color, default_color, default_custom, default_custom); } + if (use_index_buffer) { glDrawElementsInstanced(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count); } else { diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 56e405bfcf..64467bc254 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -368,6 +368,9 @@ void FindReplaceBar::_update_results_count() { int col_pos = 0; + bool searched_start_is_symbol = is_symbol(searched[0]); + bool searched_end_is_symbol = is_symbol(searched[searched.length() - 1]); + while (true) { col_pos = is_case_sensitive() ? line_text.find(searched, col_pos) : line_text.findn(searched, col_pos); @@ -376,11 +379,11 @@ void FindReplaceBar::_update_results_count() { } if (is_whole_words()) { - if (col_pos > 0 && !is_symbol(line_text[col_pos - 1])) { + if (!searched_start_is_symbol && col_pos > 0 && !is_symbol(line_text[col_pos - 1])) { col_pos += searched.length(); continue; } - if (col_pos + searched.length() < line_text.length() && !is_symbol(line_text[col_pos + searched.length()])) { + if (!searched_end_is_symbol && col_pos + searched.length() < line_text.length() && !is_symbol(line_text[col_pos + searched.length()])) { col_pos += searched.length(); continue; } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 5d07ba7568..6004591bb2 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -471,7 +471,7 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview class_desc->add_text(" = "); class_desc->pop(); class_desc->push_color(theme_cache.value_color); - _add_text(_fix_constant(p_method.arguments[j].default_value)); + class_desc->add_text(_fix_constant(p_method.arguments[j].default_value)); class_desc->pop(); } @@ -1073,7 +1073,7 @@ void EditorHelp::_update_doc() { class_desc->pop(); class_desc->push_color(theme_cache.value_color); - _add_text(_fix_constant(cd.properties[i].default_value)); + class_desc->add_text(_fix_constant(cd.properties[i].default_value)); class_desc->pop(); class_desc->push_color(theme_cache.symbol_color); @@ -1249,7 +1249,7 @@ void EditorHelp::_update_doc() { class_desc->add_text(" [" + TTR("default:") + " "); class_desc->pop(); class_desc->push_color(theme_cache.value_color); - _add_text(_fix_constant(cd.theme_properties[i].default_value)); + class_desc->add_text(_fix_constant(cd.theme_properties[i].default_value)); class_desc->pop(); class_desc->push_color(theme_cache.symbol_color); class_desc->add_text("]"); @@ -1465,7 +1465,7 @@ void EditorHelp::_update_doc() { class_desc->add_text(" = "); class_desc->pop(); class_desc->push_color(theme_cache.value_color); - _add_text(_fix_constant(enum_list[i].value)); + class_desc->add_text(_fix_constant(enum_list[i].value)); class_desc->pop(); if (enum_list[i].is_deprecated) { @@ -1541,7 +1541,7 @@ void EditorHelp::_update_doc() { class_desc->add_text(" = "); class_desc->pop(); class_desc->push_color(theme_cache.value_color); - _add_text(_fix_constant(constants[i].value)); + class_desc->add_text(_fix_constant(constants[i].value)); class_desc->pop(); if (constants[i].is_deprecated) { @@ -1722,7 +1722,7 @@ void EditorHelp::_update_doc() { class_desc->pop(); // color class_desc->push_color(theme_cache.value_color); - _add_text(_fix_constant(cd.properties[i].default_value)); + class_desc->add_text(_fix_constant(cd.properties[i].default_value)); class_desc->pop(); // color class_desc->push_color(theme_cache.symbol_color); diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp index 0b440274c0..cffd661261 100644 --- a/modules/gdscript/editor/gdscript_docgen.cpp +++ b/modules/gdscript/editor/gdscript_docgen.cpp @@ -32,14 +32,11 @@ #include "../gdscript.h" -using GDP = GDScriptParser; -using GDType = GDP::DataType; - -static String _get_script_path(const String &p_path) { +String GDScriptDocGen::_get_script_path(const String &p_path) { return p_path.trim_prefix("res://").quote(); } -static String _get_class_name(const GDP::ClassNode &p_class) { +String GDScriptDocGen::_get_class_name(const GDP::ClassNode &p_class) { const GDP::ClassNode *curr_class = &p_class; if (!curr_class->identifier) { // All inner classes have an identifier, so this is the outer class. return _get_script_path(curr_class->fqcn); @@ -56,7 +53,7 @@ static String _get_class_name(const GDP::ClassNode &p_class) { return full_name; } -static void _doctype_from_gdtype(const GDType &p_gdtype, String &r_type, String &r_enum, bool p_is_return = false) { +void GDScriptDocGen::_doctype_from_gdtype(const GDType &p_gdtype, String &r_type, String &r_enum, bool p_is_return) { if (!p_gdtype.is_hard_type()) { r_type = "Variant"; return; @@ -82,9 +79,18 @@ static void _doctype_from_gdtype(const GDType &p_gdtype, String &r_type, String r_type = Variant::get_type_name(p_gdtype.builtin_type); return; case GDType::NATIVE: + if (p_gdtype.is_meta_type) { + //r_type = GDScriptNativeClass::get_class_static(); + r_type = "Object"; // "GDScriptNativeClass" refers to a blank page. + return; + } r_type = p_gdtype.native_type; return; case GDType::SCRIPT: + if (p_gdtype.is_meta_type) { + r_type = p_gdtype.script_type.is_valid() ? p_gdtype.script_type->get_class() : Script::get_class_static(); + return; + } if (p_gdtype.script_type.is_valid()) { if (p_gdtype.script_type->get_global_name() != StringName()) { r_type = p_gdtype.script_type->get_global_name(); @@ -102,9 +108,17 @@ static void _doctype_from_gdtype(const GDType &p_gdtype, String &r_type, String r_type = "Object"; return; case GDType::CLASS: + if (p_gdtype.is_meta_type) { + r_type = GDScript::get_class_static(); + return; + } r_type = _get_class_name(*p_gdtype.class_type); return; case GDType::ENUM: + if (p_gdtype.is_meta_type) { + r_type = "Dictionary"; + return; + } r_type = "int"; r_enum = String(p_gdtype.native_type).replace("::", "."); if (r_enum.begins_with("res://")) { @@ -123,6 +137,90 @@ static void _doctype_from_gdtype(const GDType &p_gdtype, String &r_type, String } } +String GDScriptDocGen::_docvalue_from_variant(const Variant &p_variant, int p_recursion_level) { + constexpr int MAX_RECURSION_LEVEL = 2; + + switch (p_variant.get_type()) { + case Variant::STRING: + return String(p_variant).c_escape().quote(); + case Variant::OBJECT: + return "<Object>"; + case Variant::DICTIONARY: { + const Dictionary dict = p_variant; + + if (dict.is_empty()) { + return "{}"; + } + + if (p_recursion_level > MAX_RECURSION_LEVEL) { + return "{...}"; + } + + List<Variant> keys; + dict.get_key_list(&keys); + keys.sort(); + + String data; + for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { + if (E->prev()) { + data += ", "; + } + data += _docvalue_from_variant(E->get(), p_recursion_level + 1) + ": " + _docvalue_from_variant(dict[E->get()], p_recursion_level + 1); + } + + return "{" + data + "}"; + } break; + case Variant::ARRAY: { + const Array array = p_variant; + String result; + + if (array.get_typed_builtin() != Variant::NIL) { + result += "Array["; + + Ref<Script> script = array.get_typed_script(); + if (script.is_valid()) { + if (script->get_global_name() != StringName()) { + result += script->get_global_name(); + } else if (!script->get_path().get_file().is_empty()) { + result += script->get_path().get_file(); + } else { + result += array.get_typed_class_name(); + } + } else if (array.get_typed_class_name() != StringName()) { + result += array.get_typed_class_name(); + } else { + result += Variant::get_type_name((Variant::Type)array.get_typed_builtin()); + } + + result += "]("; + } + + if (array.is_empty()) { + result += "[]"; + } else if (p_recursion_level > MAX_RECURSION_LEVEL) { + result += "[...]"; + } else { + result += "["; + for (int i = 0; i < array.size(); i++) { + if (i > 0) { + result += ", "; + } + result += _docvalue_from_variant(array[i], p_recursion_level + 1); + } + result += "]"; + } + + if (array.get_typed_builtin() != Variant::NIL) { + result += ")"; + } + + return result; + } break; + default: + return p_variant.get_construct_string(); + } +} + void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_class) { p_script->_clear_doc(); @@ -183,7 +281,10 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c p_script->member_lines[const_name] = m_const->start_line; DocData::ConstantDoc const_doc; - DocData::constant_doc_from_variant(const_doc, const_name, m_const->initializer->reduced_value, m_const->doc_data.description); + const_doc.name = const_name; + const_doc.value = _docvalue_from_variant(m_const->initializer->reduced_value); + const_doc.is_value_valid = true; + const_doc.description = m_const->doc_data.description; const_doc.is_deprecated = m_const->doc_data.is_deprecated; const_doc.is_experimental = m_const->doc_data.is_experimental; doc.constants.push_back(const_doc); @@ -217,7 +318,7 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c _doctype_from_gdtype(p->get_datatype(), arg_doc.type, arg_doc.enumeration); if (p->initializer != nullptr) { if (p->initializer->is_constant) { - arg_doc.default_value = p->initializer->reduced_value.get_construct_string().replace("\n", "\\n"); + arg_doc.default_value = _docvalue_from_variant(p->initializer->reduced_value); } else { arg_doc.default_value = "<unknown>"; } @@ -286,7 +387,7 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c if (m_var->initializer) { if (m_var->initializer->is_constant) { - prop_doc.default_value = m_var->initializer->reduced_value.get_construct_string().replace("\n", "\\n"); + prop_doc.default_value = _docvalue_from_variant(m_var->initializer->reduced_value); } else { prop_doc.default_value = "<unknown>"; } @@ -312,7 +413,7 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c for (const GDP::EnumNode::Value &val : m_enum->values) { DocData::ConstantDoc const_doc; const_doc.name = val.identifier->name; - const_doc.value = String(Variant(val.value)); + const_doc.value = _docvalue_from_variant(val.value); const_doc.is_value_valid = true; const_doc.enumeration = name; const_doc.description = val.doc_data.description; @@ -331,8 +432,11 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c p_script->member_lines[name] = m_enum_val.identifier->start_line; DocData::ConstantDoc const_doc; - DocData::constant_doc_from_variant(const_doc, name, m_enum_val.value, m_enum_val.doc_data.description); + const_doc.name = name; + const_doc.value = _docvalue_from_variant(m_enum_val.value); + const_doc.is_value_valid = true; const_doc.enumeration = "@unnamed_enums"; + const_doc.description = m_enum_val.doc_data.description; const_doc.is_deprecated = m_enum_val.doc_data.is_deprecated; const_doc.is_experimental = m_enum_val.doc_data.is_experimental; doc.constants.push_back(const_doc); diff --git a/modules/gdscript/editor/gdscript_docgen.h b/modules/gdscript/editor/gdscript_docgen.h index 3357fb680c..a326c02c5f 100644 --- a/modules/gdscript/editor/gdscript_docgen.h +++ b/modules/gdscript/editor/gdscript_docgen.h @@ -36,8 +36,16 @@ #include "core/doc_data.h" class GDScriptDocGen { + using GDP = GDScriptParser; + using GDType = GDP::DataType; + + static String _get_script_path(const String &p_path); + static String _get_class_name(const GDP::ClassNode &p_class); + static void _doctype_from_gdtype(const GDType &p_gdtype, String &r_type, String &r_enum, bool p_is_return = false); + static String _docvalue_from_variant(const Variant &p_variant, int p_recursion_level = 1); + public: - static void generate_docs(GDScript *p_script, const GDScriptParser::ClassNode *p_class); + static void generate_docs(GDScript *p_script, const GDP::ClassNode *p_class); }; #endif // GDSCRIPT_DOCGEN_H diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index f10ed0df29..a0213f05dd 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -346,6 +346,10 @@ bool GDScript::has_method(const StringName &p_method) const { return member_functions.has(p_method); } +bool GDScript::has_static_method(const StringName &p_method) const { + return member_functions.has(p_method) && member_functions[p_method]->is_static(); +} + MethodInfo GDScript::get_method_info(const StringName &p_method) const { HashMap<StringName, GDScriptFunction *>::ConstIterator E = member_functions.find(p_method); if (!E) { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 50ccfabcc1..eb8e95025a 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -266,6 +266,7 @@ public: virtual void get_script_method_list(List<MethodInfo> *p_list) const override; virtual bool has_method(const StringName &p_method) const override; + virtual bool has_static_method(const StringName &p_method) const override; virtual MethodInfo get_method_info(const StringName &p_method) const override; virtual void get_script_property_list(List<PropertyInfo> *p_list) const override; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 0d06597bc0..cdeaa70e5f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -386,6 +386,7 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c if (!p_class->extends_used) { result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; result.kind = GDScriptParser::DataType::NATIVE; + result.builtin_type = Variant::OBJECT; result.native_type = SNAME("RefCounted"); } else { result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; @@ -464,6 +465,7 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c return ERR_PARSE_ERROR; } base.kind = GDScriptParser::DataType::NATIVE; + base.builtin_type = Variant::OBJECT; base.native_type = name; } else { // Look for other classes in script. @@ -2800,6 +2802,9 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o } if (!left_type.is_set() || !right_type.is_set()) { + GDScriptParser::DataType dummy; + dummy.kind = GDScriptParser::DataType::VARIANT; + p_binary_op->set_datatype(dummy); return; } @@ -3965,8 +3970,10 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident if (autoload.is_singleton) { // Singleton exists, so it's at least a Node. GDScriptParser::DataType result; - result.kind = GDScriptParser::DataType::NATIVE; result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; + result.kind = GDScriptParser::DataType::NATIVE; + result.builtin_type = Variant::OBJECT; + result.native_type = SNAME("Node"); if (ResourceLoader::get_resource_type(autoload.path) == "GDScript") { Ref<GDScriptParserRef> singl_parser = get_parser_for(autoload.path); if (singl_parser.is_valid()) { @@ -4839,7 +4846,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo } else if (class_exists(elem_type_name)) { elem_type.kind = GDScriptParser::DataType::NATIVE; elem_type.builtin_type = Variant::OBJECT; - elem_type.native_type = p_property.hint_string; + elem_type.native_type = elem_type_name; } else if (ScriptServer::is_global_class(elem_type_name)) { // Just load this as it shouldn't be a GDScript. Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(elem_type_name)); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 2f26069281..9cd3560063 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1122,6 +1122,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base base_type.script_type = base_script; } else { base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.builtin_type = Variant::OBJECT; base_type.native_type = scr->get_instance_base_type(); } } else { @@ -1626,6 +1627,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, native_type.script_type = parent; } else { native_type.kind = GDScriptParser::DataType::NATIVE; + native_type.builtin_type = Variant::OBJECT; native_type.native_type = native_type.script_type->get_instance_base_type(); if (!ClassDB::class_exists(native_type.native_type)) { native_type.kind = GDScriptParser::DataType::UNRESOLVED; @@ -2155,6 +2157,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, if (ClassDB::class_exists(p_identifier->name) && ClassDB::is_class_exposed(p_identifier->name)) { r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; r_type.type.kind = GDScriptParser::DataType::NATIVE; + r_type.type.builtin_type = Variant::OBJECT; r_type.type.native_type = p_identifier->name; r_type.type.is_constant = true; if (Engine::get_singleton()->has_singleton(p_identifier->name)) { @@ -2281,6 +2284,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext & base_type.script_type = parent; } else { base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.builtin_type = Variant::OBJECT; base_type.native_type = scr->get_instance_base_type(); } } else { @@ -2450,6 +2454,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex base_type.script_type = base_script; } else { base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.builtin_type = Variant::OBJECT; base_type.native_type = scr->get_instance_base_type(); } } else { @@ -2705,8 +2710,8 @@ static bool _get_subscript_type(GDScriptParser::CompletionContext &p_context, co } r_base_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; r_base_type.kind = GDScriptParser::DataType::NATIVE; - r_base_type.native_type = node->get_class_name(); r_base_type.builtin_type = Variant::OBJECT; + r_base_type.native_type = node->get_class_name(); return true; } } @@ -3260,6 +3265,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co base_type.script_type = base_script; } else { base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.builtin_type = Variant::OBJECT; base_type.native_type = scr->get_instance_base_type(); } } else { diff --git a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd new file mode 100644 index 0000000000..f6aa58737f --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd @@ -0,0 +1,12 @@ +# GH-79521 + +class_name TestStaticMethodAsCallable + +static func static_func() -> String: + return "Test" + +func test(): + var a: Callable = TestStaticMethodAsCallable.static_func + var b: Callable = static_func + prints(a.call(), a.is_valid()) + prints(b.call(), b.is_valid()) diff --git a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out new file mode 100644 index 0000000000..e6d461b8f9 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out @@ -0,0 +1,3 @@ +GDTEST_OK +Test true +Test true diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml index c7c666dc2f..131246fe57 100644 --- a/modules/openxr/doc_classes/OpenXRInterface.xml +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -31,6 +31,14 @@ If handtracking is enabled, returns the angular velocity of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is relative to [XROrigin3D]! </description> </method> + <method name="get_hand_joint_flags" qualifiers="const"> + <return type="int" enum="OpenXRInterface.HandJointFlags" is_bitfield="true" /> + <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" /> + <param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" /> + <description> + If handtracking is enabled, returns flags that inform us of the validity of the tracking data. + </description> + </method> <method name="get_hand_joint_linear_velocity" qualifiers="const"> <return type="Vector3" /> <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" /> @@ -91,6 +99,13 @@ [b]Note:[/b] This feature is only available on the compatibility renderer and currently only available on some stand alone headsets. For Vulkan set [member Viewport.vrs_mode] to [code]VRS_XR[/code] on desktop. </description> </method> + <method name="is_hand_tracking_supported"> + <return type="bool" /> + <description> + Returns [code]true[/code] if OpenXRs hand tracking is supported and enabled. + [b]Note:[/b] This only returns a valid value after OpenXR has been initialized. + </description> + </method> <method name="set_action_set_active"> <return type="void" /> <param index="0" name="name" type="String" /> @@ -246,5 +261,26 @@ <constant name="HAND_JOINT_MAX" value="26" enum="HandJoints"> Maximum value for the hand joint enum. </constant> + <constant name="HAND_JOINT_NONE" value="0" enum="HandJointFlags" is_bitfield="true"> + No flags are set. + </constant> + <constant name="HAND_JOINT_ORIENTATION_VALID" value="1" enum="HandJointFlags" is_bitfield="true"> + If set, the orientation data is valid, otherwise, the orientation data is unreliable and should not be used. + </constant> + <constant name="HAND_JOINT_ORIENTATION_TRACKED" value="2" enum="HandJointFlags" is_bitfield="true"> + If set, the orientation data comes from tracking data, otherwise, the orientation data contains predicted data. + </constant> + <constant name="HAND_JOINT_POSITION_VALID" value="4" enum="HandJointFlags" is_bitfield="true"> + If set, the positional data is valid, otherwise, the positional data is unreliable and should not be used. + </constant> + <constant name="HAND_JOINT_POSITION_TRACKED" value="8" enum="HandJointFlags" is_bitfield="true"> + If set, the positional data comes from tracking data, otherwise, the positional data contains predicted data. + </constant> + <constant name="HAND_JOINT_LINEAR_VELOCITY_VALID" value="16" enum="HandJointFlags" is_bitfield="true"> + If set, our linear velocity data is valid, otherwise, the linear velocity data is unreliable and should not be used. + </constant> + <constant name="HAND_JOINT_ANGULAR_VELOCITY_VALID" value="32" enum="HandJointFlags" is_bitfield="true"> + If set, our angular velocity data is valid, otherwise, the angular velocity data is unreliable and should not be used. + </constant> </constants> </class> diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp index caf97ca2e0..0d667b56c6 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp @@ -245,6 +245,18 @@ void OpenXRHandTrackingExtension::set_motion_range(HandTrackedHands p_hand, XrHa hand_trackers[p_hand].motion_range = p_motion_range; } +XrSpaceLocationFlags OpenXRHandTrackingExtension::get_hand_joint_location_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const { + ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, XrSpaceLocationFlags(0)); + ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, XrSpaceLocationFlags(0)); + + if (!hand_trackers[p_hand].is_initialized) { + return XrSpaceLocationFlags(0); + } + + const XrHandJointLocationEXT &location = hand_trackers[p_hand].joint_locations[p_joint]; + return location.locationFlags; +} + Quaternion OpenXRHandTrackingExtension::get_hand_joint_rotation(HandTrackedHands p_hand, XrHandJointEXT p_joint) const { ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, Quaternion()); ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Quaternion()); @@ -280,6 +292,18 @@ float OpenXRHandTrackingExtension::get_hand_joint_radius(HandTrackedHands p_hand return hand_trackers[p_hand].joint_locations[p_joint].radius; } +XrSpaceVelocityFlags OpenXRHandTrackingExtension::get_hand_joint_velocity_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const { + ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, XrSpaceVelocityFlags(0)); + ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, XrSpaceVelocityFlags(0)); + + if (!hand_trackers[p_hand].is_initialized) { + return XrSpaceVelocityFlags(0); + } + + const XrHandJointVelocityEXT &velocity = hand_trackers[p_hand].joint_velocities[p_joint]; + return velocity.velocityFlags; +} + Vector3 OpenXRHandTrackingExtension::get_hand_joint_linear_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const { ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, Vector3()); ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3()); diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.h b/modules/openxr/extensions/openxr_hand_tracking_extension.h index 5ca0ff60d3..f9b26fd604 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.h +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.h @@ -77,10 +77,12 @@ public: XrHandJointsMotionRangeEXT get_motion_range(HandTrackedHands p_hand) const; void set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range); + XrSpaceLocationFlags get_hand_joint_location_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; Quaternion get_hand_joint_rotation(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; Vector3 get_hand_joint_position(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; float get_hand_joint_radius(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; + XrSpaceVelocityFlags get_hand_joint_velocity_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; Vector3 get_hand_joint_linear_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; Vector3 get_hand_joint_angular_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index d0b01c5771..8ce76a5fad 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -77,6 +77,8 @@ void OpenXRInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("set_motion_range", "hand", "motion_range"), &OpenXRInterface::set_motion_range); ClassDB::bind_method(D_METHOD("get_motion_range", "hand"), &OpenXRInterface::get_motion_range); + ClassDB::bind_method(D_METHOD("get_hand_joint_flags", "hand", "joint"), &OpenXRInterface::get_hand_joint_flags); + ClassDB::bind_method(D_METHOD("get_hand_joint_rotation", "hand", "joint"), &OpenXRInterface::get_hand_joint_rotation); ClassDB::bind_method(D_METHOD("get_hand_joint_position", "hand", "joint"), &OpenXRInterface::get_hand_joint_position); ClassDB::bind_method(D_METHOD("get_hand_joint_radius", "hand", "joint"), &OpenXRInterface::get_hand_joint_radius); @@ -84,6 +86,9 @@ void OpenXRInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("get_hand_joint_linear_velocity", "hand", "joint"), &OpenXRInterface::get_hand_joint_linear_velocity); ClassDB::bind_method(D_METHOD("get_hand_joint_angular_velocity", "hand", "joint"), &OpenXRInterface::get_hand_joint_angular_velocity); + ClassDB::bind_method(D_METHOD("is_hand_tracking_supported"), &OpenXRInterface::is_hand_tracking_supported); + ClassDB::bind_method(D_METHOD("is_eye_gaze_interaction_supported"), &OpenXRInterface::is_eye_gaze_interaction_supported); + BIND_ENUM_CONSTANT(HAND_LEFT); BIND_ENUM_CONSTANT(HAND_RIGHT); BIND_ENUM_CONSTANT(HAND_MAX); @@ -120,7 +125,13 @@ void OpenXRInterface::_bind_methods() { BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_TIP); BIND_ENUM_CONSTANT(HAND_JOINT_MAX); - ClassDB::bind_method(D_METHOD("is_eye_gaze_interaction_supported"), &OpenXRInterface::is_eye_gaze_interaction_supported); + BIND_BITFIELD_FLAG(HAND_JOINT_NONE); + BIND_BITFIELD_FLAG(HAND_JOINT_ORIENTATION_VALID); + BIND_BITFIELD_FLAG(HAND_JOINT_ORIENTATION_TRACKED); + BIND_BITFIELD_FLAG(HAND_JOINT_POSITION_VALID); + BIND_BITFIELD_FLAG(HAND_JOINT_POSITION_TRACKED); + BIND_BITFIELD_FLAG(HAND_JOINT_LINEAR_VELOCITY_VALID); + BIND_BITFIELD_FLAG(HAND_JOINT_ANGULAR_VELOCITY_VALID); } StringName OpenXRInterface::get_name() const { @@ -709,6 +720,21 @@ Array OpenXRInterface::get_available_display_refresh_rates() const { } } +bool OpenXRInterface::is_hand_tracking_supported() { + if (openxr_api == nullptr) { + return false; + } else if (!openxr_api->is_initialized()) { + return false; + } else { + OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); + if (hand_tracking_ext == nullptr) { + return false; + } else { + return hand_tracking_ext->get_active(); + } + } +} + bool OpenXRInterface::is_eye_gaze_interaction_supported() { if (openxr_api == nullptr) { return false; @@ -912,15 +938,39 @@ void OpenXRInterface::handle_hand_tracking(const String &p_path, OpenXRHandTrack if (hand_tracking_ext && hand_tracking_ext->get_active()) { OpenXRInterface::Tracker *tracker = find_tracker(p_path); if (tracker && tracker->positional_tracker.is_valid()) { - // TODO add in confidence! Requires PR #82715 + XrSpaceLocationFlags location_flags = hand_tracking_ext->get_hand_joint_location_flags(p_hand, XR_HAND_JOINT_PALM_EXT); - Transform3D transform; - transform.basis = Basis(hand_tracking_ext->get_hand_joint_rotation(p_hand, XR_HAND_JOINT_PALM_EXT)); - transform.origin = hand_tracking_ext->get_hand_joint_position(p_hand, XR_HAND_JOINT_PALM_EXT); - Vector3 linear_velocity = hand_tracking_ext->get_hand_joint_linear_velocity(p_hand, XR_HAND_JOINT_PALM_EXT); - Vector3 angular_velocity = hand_tracking_ext->get_hand_joint_angular_velocity(p_hand, XR_HAND_JOINT_PALM_EXT); + if (location_flags & (XR_SPACE_LOCATION_ORIENTATION_VALID_BIT + XR_SPACE_LOCATION_POSITION_VALID_BIT)) { + static const XrSpaceLocationFlags all_location_flags = XR_SPACE_LOCATION_ORIENTATION_VALID_BIT + XR_SPACE_LOCATION_POSITION_VALID_BIT + XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT + XR_SPACE_LOCATION_POSITION_TRACKED_BIT; + XRPose::TrackingConfidence confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW; + Transform3D transform; + Vector3 linear_velocity; + Vector3 angular_velocity; + + if ((location_flags & all_location_flags) == all_location_flags) { + // All flags set? confidence is high! + confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH; + } - tracker->positional_tracker->set_pose("skeleton", transform, linear_velocity, angular_velocity, XRPose::XR_TRACKING_CONFIDENCE_HIGH); + if (location_flags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) { + transform.basis = Basis(hand_tracking_ext->get_hand_joint_rotation(p_hand, XR_HAND_JOINT_PALM_EXT)); + } + if (location_flags & XR_SPACE_LOCATION_POSITION_VALID_BIT) { + transform.origin = hand_tracking_ext->get_hand_joint_position(p_hand, XR_HAND_JOINT_PALM_EXT); + } + + XrSpaceVelocityFlags velocity_flags = hand_tracking_ext->get_hand_joint_location_flags(p_hand, XR_HAND_JOINT_PALM_EXT); + if (velocity_flags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) { + linear_velocity = hand_tracking_ext->get_hand_joint_linear_velocity(p_hand, XR_HAND_JOINT_PALM_EXT); + } + if (velocity_flags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) { + angular_velocity = hand_tracking_ext->get_hand_joint_angular_velocity(p_hand, XR_HAND_JOINT_PALM_EXT); + } + + tracker->positional_tracker->set_pose("skeleton", transform, linear_velocity, angular_velocity, confidence); + } else { + tracker->positional_tracker->invalidate_pose("skeleton"); + } } } } @@ -1183,6 +1233,37 @@ OpenXRInterface::HandMotionRange OpenXRInterface::get_motion_range(const Hand p_ return HAND_MOTION_RANGE_MAX; } +BitField<OpenXRInterface::HandJointFlags> OpenXRInterface::get_hand_joint_flags(Hand p_hand, HandJoints p_joint) const { + BitField<OpenXRInterface::HandJointFlags> bits; + + OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); + if (hand_tracking_ext && hand_tracking_ext->get_active()) { + XrSpaceLocationFlags location_flags = hand_tracking_ext->get_hand_joint_location_flags(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint)); + if (location_flags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) { + bits.set_flag(HAND_JOINT_ORIENTATION_VALID); + } + if (location_flags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT) { + bits.set_flag(HAND_JOINT_ORIENTATION_TRACKED); + } + if (location_flags & XR_SPACE_LOCATION_POSITION_VALID_BIT) { + bits.set_flag(HAND_JOINT_POSITION_VALID); + } + if (location_flags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT) { + bits.set_flag(HAND_JOINT_POSITION_TRACKED); + } + + XrSpaceVelocityFlags velocity_flags = hand_tracking_ext->get_hand_joint_velocity_flags(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint)); + if (velocity_flags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) { + bits.set_flag(HAND_JOINT_LINEAR_VELOCITY_VALID); + } + if (velocity_flags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) { + bits.set_flag(HAND_JOINT_ANGULAR_VELOCITY_VALID); + } + } + + return bits; +} + Quaternion OpenXRInterface::get_hand_joint_rotation(Hand p_hand, HandJoints p_joint) const { OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); if (hand_tracking_ext && hand_tracking_ext->get_active()) { diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index 8e24c8dce9..51ef4ea228 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -111,6 +111,7 @@ public: virtual PackedStringArray get_suggested_tracker_names() const override; virtual TrackingStatus get_tracking_status() const override; + bool is_hand_tracking_supported(); bool is_eye_gaze_interaction_supported(); bool initialize_on_startup() const; @@ -222,6 +223,17 @@ public: HAND_JOINT_MAX = 26, }; + enum HandJointFlags { + HAND_JOINT_NONE = 0, + HAND_JOINT_ORIENTATION_VALID = 1, + HAND_JOINT_ORIENTATION_TRACKED = 2, + HAND_JOINT_POSITION_VALID = 4, + HAND_JOINT_POSITION_TRACKED = 8, + HAND_JOINT_LINEAR_VELOCITY_VALID = 16, + HAND_JOINT_ANGULAR_VELOCITY_VALID = 32, + }; + + BitField<HandJointFlags> get_hand_joint_flags(Hand p_hand, HandJoints p_joint) const; Quaternion get_hand_joint_rotation(Hand p_hand, HandJoints p_joint) const; Vector3 get_hand_joint_position(Hand p_hand, HandJoints p_joint) const; float get_hand_joint_radius(Hand p_hand, HandJoints p_joint) const; @@ -236,5 +248,6 @@ public: VARIANT_ENUM_CAST(OpenXRInterface::Hand) VARIANT_ENUM_CAST(OpenXRInterface::HandMotionRange) VARIANT_ENUM_CAST(OpenXRInterface::HandJoints) +VARIANT_BITFIELD_CAST(OpenXRInterface::HandJointFlags) #endif // OPENXR_INTERFACE_H diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp index 3a245460b4..fd4bcf92be 100644 --- a/platform/linuxbsd/crash_handler_linuxbsd.cpp +++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp @@ -49,6 +49,10 @@ #include <stdlib.h> static void handle_crash(int sig) { + signal(SIGSEGV, SIG_DFL); + signal(SIGFPE, SIG_DFL); + signal(SIGILL, SIG_DFL); + if (OS::get_singleton() == nullptr) { abort(); } @@ -156,9 +160,9 @@ void CrashHandler::disable() { } #ifdef CRASH_HANDLER_ENABLED - signal(SIGSEGV, nullptr); - signal(SIGFPE, nullptr); - signal(SIGILL, nullptr); + signal(SIGSEGV, SIG_DFL); + signal(SIGFPE, SIG_DFL); + signal(SIGILL, SIG_DFL); #endif disabled = true; diff --git a/platform/macos/crash_handler_macos.mm b/platform/macos/crash_handler_macos.mm index 7f9a88121e..7c0cab0210 100644 --- a/platform/macos/crash_handler_macos.mm +++ b/platform/macos/crash_handler_macos.mm @@ -72,6 +72,10 @@ static uint64_t load_address() { } static void handle_crash(int sig) { + signal(SIGSEGV, SIG_DFL); + signal(SIGFPE, SIG_DFL); + signal(SIGILL, SIG_DFL); + if (OS::get_singleton() == nullptr) { abort(); } @@ -186,9 +190,9 @@ void CrashHandler::disable() { } #ifdef CRASH_HANDLER_ENABLED - signal(SIGSEGV, nullptr); - signal(SIGFPE, nullptr); - signal(SIGILL, nullptr); + signal(SIGSEGV, SIG_DFL); + signal(SIGFPE, SIG_DFL); + signal(SIGILL, SIG_DFL); #endif disabled = true; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 1642d19b67..3d426b8bf3 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -4112,6 +4112,9 @@ Point2i TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_fro int line = p_from_line; int pos = -1; + bool key_start_is_symbol = is_symbol(p_key[0]); + bool key_end_is_symbol = is_symbol(p_key[p_key.length() - 1]); + for (int i = 0; i < text.size() + 1; i++) { if (line < 0) { line = text.size() - 1; @@ -4175,9 +4178,9 @@ Point2i TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_fro if (pos != -1 && (p_search_flags & SEARCH_WHOLE_WORDS)) { // Validate for whole words. - if (pos > 0 && !is_symbol(text_line[pos - 1])) { + if (!key_start_is_symbol && pos > 0 && !is_symbol(text_line[pos - 1])) { is_match = false; - } else if (pos + p_key.length() < text_line.length() && !is_symbol(text_line[pos + p_key.length()])) { + } else if (!key_end_is_symbol && pos + p_key.length() < text_line.length() && !is_symbol(text_line[pos + p_key.length()])) { is_match = false; } } @@ -7022,6 +7025,9 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc p_from_column = 0; } + bool key_start_is_symbol = is_symbol(p_key[0]); + bool key_end_is_symbol = is_symbol(p_key[p_key.length() - 1]); + while (col == -1 && p_from_column <= p_search.length()) { if (p_search_flags & SEARCH_MATCH_CASE) { col = p_search.find(p_key, p_from_column); @@ -7038,9 +7044,9 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc if (col != -1 && p_search_flags & SEARCH_WHOLE_WORDS) { p_from_column = col; - if (col > 0 && !is_symbol(p_search[col - 1])) { + if (!key_start_is_symbol && col > 0 && !is_symbol(p_search[col - 1])) { col = -1; - } else if ((col + p_key.length()) < p_search.length() && !is_symbol(p_search[col + p_key.length()])) { + } else if (!key_end_is_symbol && (col + p_key.length()) < p_search.length() && !is_symbol(p_search[col + p_key.length()])) { col = -1; } } diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index fd65b739ab..3bd35c53cc 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -931,11 +931,11 @@ void MaterialStorage::MaterialData::update_textures(const HashMap<StringName, Va roughness_detect_texture = tex; roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R); } +#endif // TOOLS_ENABLED if (tex->render_target) { tex->render_target->was_used = true; render_target_cache.push_back(tex->render_target); } -#endif } if (rd_texture.is_null()) { rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_WHITE); diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 9c7bcbb54f..cb7eb3cd59 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -1061,7 +1061,7 @@ void MeshStorage::update_mesh_instances() { RD::get_singleton()->compute_list_end(); } -void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis) { +void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) { Vector<RD::VertexAttribute> attributes; Vector<RID> buffers; @@ -1134,7 +1134,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V } if (mis) { - buffer = mis->vertex_buffer[mis->current_buffer]; + buffer = mis->vertex_buffer[p_current_buffer]; } else { buffer = s->vertex_buffer; } @@ -1146,7 +1146,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V stride += sizeof(uint16_t) * 2; if (mis) { - buffer = mis->vertex_buffer[mis->current_buffer]; + buffer = mis->vertex_buffer[p_current_buffer]; } else { buffer = s->vertex_buffer; } @@ -1157,7 +1157,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V stride += sizeof(uint16_t) * 2; if (mis) { - buffer = mis->vertex_buffer[mis->current_buffer]; + buffer = mis->vertex_buffer[p_current_buffer]; } else { buffer = s->vertex_buffer; } @@ -1241,7 +1241,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V if (int(vd.location) != i) { if (mis && buffer != mesh_default_rd_buffers[i]) { - buffer = mis->vertex_buffer[mis->previous_buffer]; + buffer = mis->vertex_buffer[p_previous_buffer]; } attributes.push_back(vd); @@ -1267,8 +1267,8 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V } v.input_mask = p_input_mask; - v.current_buffer = mis ? mis->current_buffer : 0; - v.previous_buffer = mis ? mis->previous_buffer : 0; + v.current_buffer = p_current_buffer; + v.previous_buffer = p_previous_buffer; v.input_motion_vectors = p_input_motion_vectors; v.vertex_format = RD::get_singleton()->vertex_format_create(attributes); v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers); diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h index 86e81d56cc..1e1db9c47d 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h @@ -190,7 +190,7 @@ private: weight_update_list(this), array_update_list(this) {} }; - void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr); + void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr, uint32_t p_current_buffer = 0, uint32_t p_previous_buffer = 0); void _mesh_instance_clear(MeshInstance *mi); void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface); @@ -523,7 +523,7 @@ public: mis->version_count++; mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count); - _mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, p_input_motion_vectors, mis); + _mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, p_input_motion_vectors, mis, current_buffer, previous_buffer); r_vertex_format = mis->versions[version].vertex_format; r_vertex_array_rd = mis->versions[version].vertex_array; diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h index 7e9b472af1..840a04becf 100644 --- a/tests/scene/test_text_edit.h +++ b/tests/scene/test_text_edit.h @@ -3193,7 +3193,7 @@ TEST_CASE("[SceneTree][TextEdit] search") { TextEdit *text_edit = memnew(TextEdit); SceneTree::get_singleton()->get_root()->add_child(text_edit); - text_edit->set_text("hay needle, hay\nHAY NEEDLE, HAY"); + text_edit->set_text("hay needle, hay\nHAY NEEDLE, HAY\nwordword.word.word"); int length = text_edit->get_line(1).length(); CHECK(text_edit->search("test", 0, 0, 0) == Point2i(-1, -1)); @@ -3225,6 +3225,11 @@ TEST_CASE("[SceneTree][TextEdit] search") { CHECK(text_edit->search("need", TextEdit::SEARCH_WHOLE_WORDS | TextEdit::SEARCH_MATCH_CASE, 0, 0) == Point2i(-1, -1)); CHECK(text_edit->search("need", TextEdit::SEARCH_WHOLE_WORDS | TextEdit::SEARCH_MATCH_CASE | TextEdit::SEARCH_BACKWARDS, 0, 0) == Point2i(-1, -1)); + CHECK(text_edit->search("word", TextEdit::SEARCH_WHOLE_WORDS, 2, 0) == Point2i(9, 2)); + CHECK(text_edit->search("word", TextEdit::SEARCH_WHOLE_WORDS, 2, 10) == Point2i(14, 2)); + CHECK(text_edit->search(".word", TextEdit::SEARCH_WHOLE_WORDS, 2, 0) == Point2i(8, 2)); + CHECK(text_edit->search("word.", TextEdit::SEARCH_WHOLE_WORDS, 2, 0) == Point2i(9, 2)); + ERR_PRINT_OFF; CHECK(text_edit->search("", 0, 0, 0) == Point2i(-1, -1)); CHECK(text_edit->search("needle", 0, -1, 0) == Point2i(-1, -1)); |