diff options
35 files changed, 1652 insertions, 812 deletions
diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml index 90629204e6..0c21576517 100644 --- a/.github/workflows/windows_builds.yml +++ b/.github/workflows/windows_builds.yml @@ -30,6 +30,14 @@ jobs: # Skip debug symbols, they're way too big with MSVC. sconsflags: debug_symbols=no vsproj=yes vsproj_gen_only=no windows_subsystem=console bin: "./bin/godot.windows.editor.x86_64.exe" + artifact: true + + - name: Editor w/ clang-cl (target=editor, tests=yes, use_llvm=yes) + cache-name: windows-editor-clang + target: editor + tests: true + sconsflags: debug_symbols=no windows_subsystem=console use_llvm=yes + bin: ./bin/godot.windows.editor.x86_64.llvm.exe - name: Template (target=template_release) cache-name: windows-template @@ -37,6 +45,7 @@ jobs: tests: true sconsflags: debug_symbols=no tests=yes bin: "./bin/godot.windows.template_release.x86_64.console.exe" + artifact: true steps: - uses: actions/checkout@v4 @@ -84,10 +93,12 @@ jobs: continue-on-error: true - name: Prepare artifact + if: ${{ matrix.artifact }} run: | Remove-Item bin/* -Include *.exp,*.lib,*.pdb -Force - name: Upload artifact + if: ${{ matrix.artifact }} uses: ./.github/actions/upload-artifact with: name: ${{ matrix.cache-name }} diff --git a/SConstruct b/SConstruct index e1c943bd45..0297cd6e61 100644 --- a/SConstruct +++ b/SConstruct @@ -803,7 +803,7 @@ elif env.msvc: env.Append(CXXFLAGS=["/EHsc"]) # Configure compiler warnings -if env.msvc: # MSVC +if env.msvc and not methods.using_clang(env): # MSVC if env["warnings"] == "no": env.Append(CCFLAGS=["/w"]) else: @@ -853,8 +853,11 @@ else: # GCC, Clang # for putting them in `Set` or `Map`. We don't mind about unreliable ordering. common_warnings += ["-Wno-ordered-compare-function-pointers"] + # clang-cl will interpret `-Wall` as `-Weverything`, workaround with compatibility cast + W_ALL = "-Wall" if not env.msvc else "-W3" + if env["warnings"] == "extra": - env.Append(CCFLAGS=["-Wall", "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings) + env.Append(CCFLAGS=[W_ALL, "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings) env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"]) if methods.using_gcc(env): env.Append( @@ -876,9 +879,9 @@ else: # GCC, Clang elif methods.using_clang(env) or methods.using_emcc(env): env.Append(CCFLAGS=["-Wimplicit-fallthrough"]) elif env["warnings"] == "all": - env.Append(CCFLAGS=["-Wall"] + common_warnings) + env.Append(CCFLAGS=[W_ALL] + common_warnings) elif env["warnings"] == "moderate": - env.Append(CCFLAGS=["-Wall", "-Wno-unused"] + common_warnings) + env.Append(CCFLAGS=[W_ALL, "-Wno-unused"] + common_warnings) else: # 'no' env.Append(CCFLAGS=["-w"]) @@ -1032,7 +1035,9 @@ if env["vsproj"]: if env["compiledb"]: if env.scons_version < (4, 0, 0): # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later. - print_error("The `compiledb=yes` option requires SCons 4.0 or later, but your version is %s." % scons_raw_version) + print_error( + "The `compiledb=yes` option requires SCons 4.0 or later, but your version is %s." % scons_raw_version + ) Exit(255) env.Tool("compilation_db") diff --git a/core/io/packed_data_container.h b/core/io/packed_data_container.h index cc9996101e..f4ffa09022 100644 --- a/core/io/packed_data_container.h +++ b/core/io/packed_data_container.h @@ -36,7 +36,7 @@ class PackedDataContainer : public Resource { GDCLASS(PackedDataContainer, Resource); - enum { + enum : uint32_t { TYPE_DICT = 0xFFFFFFFF, TYPE_ARRAY = 0xFFFFFFFE, }; diff --git a/doc/classes/VehicleWheel3D.xml b/doc/classes/VehicleWheel3D.xml index 92b2297bf4..7b4952580c 100644 --- a/doc/classes/VehicleWheel3D.xml +++ b/doc/classes/VehicleWheel3D.xml @@ -18,6 +18,18 @@ Returns [code]null[/code] if the wheel is not in contact with a surface, or the contact body is not a [PhysicsBody3D]. </description> </method> + <method name="get_contact_normal" qualifiers="const"> + <return type="Vector3" /> + <description> + Returns the normal of the suspension's collision in world space if the wheel is in contact. If the wheel isn't in contact with anything, returns a vector pointing directly along the suspension axis toward the vehicle in world space. + </description> + </method> + <method name="get_contact_point" qualifiers="const"> + <return type="Vector3" /> + <description> + Returns the point of the suspension's collision in world space if the wheel is in contact. If the wheel isn't in contact with anything, returns the maximum point of the wheel's ray cast in world space, which is defined by [code]wheel_rest_length + wheel_radius[/code]. + </description> + </method> <method name="get_rpm" qualifiers="const"> <return type="float" /> <description> diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index 81e7220439..ed00dd235f 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -203,7 +203,7 @@ struct LightmapInstance { class LightStorage : public RendererLightStorage { public: - enum ShadowAtlastQuadrant { + enum ShadowAtlastQuadrant : uint32_t { QUADRANT_SHIFT = 27, OMNI_LIGHT_FLAG = 1 << 26, SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1, diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index ff5bc6ba87..eb97337b37 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -134,18 +134,38 @@ void EditorHelpSearch::_native_action_cb(const String &p_item_string) { } void EditorHelpSearch::_update_results() { - String term = search_box->get_text(); + const String term = search_box->get_text().strip_edges(); int search_flags = filter_combo->get_selected_id(); - if (case_sensitive_button->is_pressed()) { - search_flags |= SEARCH_CASE_SENSITIVE; - } - if (hierarchy_button->is_pressed()) { - search_flags |= SEARCH_SHOW_HIERARCHY; - } - search = Ref<Runner>(memnew(Runner(results_tree, results_tree, &tree_cache, term, search_flags))); - set_process(true); + // Process separately if term is not short, or is "@" for annotations. + if (term.length() > 1 || term == "@") { + case_sensitive_button->set_disabled(false); + hierarchy_button->set_disabled(false); + + if (case_sensitive_button->is_pressed()) { + search_flags |= SEARCH_CASE_SENSITIVE; + } + if (hierarchy_button->is_pressed()) { + search_flags |= SEARCH_SHOW_HIERARCHY; + } + + search = Ref<Runner>(memnew(Runner(results_tree, results_tree, &tree_cache, term, search_flags))); + + // Clear old search flags to force rebuild on short term. + old_search_flags = 0; + set_process(true); + } else { + // Disable hierarchy and case sensitive options, not used for short searches. + case_sensitive_button->set_disabled(true); + hierarchy_button->set_disabled(true); + + // Always show hierarchy for short searches. + search = Ref<Runner>(memnew(Runner(results_tree, results_tree, &tree_cache, term, search_flags | SEARCH_SHOW_HIERARCHY))); + + old_search_flags = search_flags; + set_process(true); + } } void EditorHelpSearch::_search_box_gui_input(const Ref<InputEvent> &p_event) { @@ -205,6 +225,8 @@ void EditorHelpSearch::_notification(int p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { if (!is_visible()) { tree_cache.clear(); + results_tree->get_vscroll_bar()->set_value(0); + search = Ref<Runner>(); callable_mp(results_tree, &Tree::clear).call_deferred(); // Wait for the Tree's mouse event propagation. get_ok_button()->set_disabled(true); EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "search_help", Rect2(get_position(), get_size())); @@ -278,6 +300,7 @@ void EditorHelpSearch::popup_dialog(const String &p_term) { popup_centered_ratio(0.5F); } + old_search_flags = 0; if (p_term.is_empty()) { search_box->clear(); } else { @@ -401,6 +424,237 @@ bool EditorHelpSearch::Runner::_is_class_disabled_by_feature_profile(const Strin return false; } +bool EditorHelpSearch::Runner::_fill() { + bool phase_done = false; + switch (phase) { + case PHASE_MATCH_CLASSES_INIT: + phase_done = _phase_fill_classes_init(); + break; + case PHASE_MATCH_CLASSES: + phase_done = _phase_fill_classes(); + break; + case PHASE_CLASS_ITEMS_INIT: + case PHASE_CLASS_ITEMS: + phase_done = true; + break; + case PHASE_MEMBER_ITEMS_INIT: + phase_done = _phase_fill_member_items_init(); + break; + case PHASE_MEMBER_ITEMS: + phase_done = _phase_fill_member_items(); + break; + case PHASE_SELECT_MATCH: + phase_done = _phase_select_match(); + break; + case PHASE_MAX: + return true; + default: + WARN_PRINT("Invalid or unhandled phase in EditorHelpSearch::Runner, aborting search."); + return true; + } + + if (phase_done) { + phase++; + } + return false; +} + +bool EditorHelpSearch::Runner::_phase_fill_classes_init() { + // Initialize fill. + iterator_stack.clear(); + matched_classes.clear(); + matched_item = nullptr; + match_highest_score = 0; + + // Initialize stack of iterators to fill, in reverse. + iterator_stack.push_back(EditorHelp::get_doc_data()->inheriting[""].back()); + + return true; +} + +bool EditorHelpSearch::Runner::_phase_fill_classes() { + if (iterator_stack.is_empty()) { + return true; + } + + if (iterator_stack[iterator_stack.size() - 1]) { + DocData::ClassDoc *class_doc = EditorHelp::get_doc_data()->class_list.getptr(iterator_stack[iterator_stack.size() - 1]->get()); + + // Decrement stack. + iterator_stack[iterator_stack.size() - 1] = iterator_stack[iterator_stack.size() - 1]->prev(); + + // Drop last element of stack if empty. + if (!iterator_stack[iterator_stack.size() - 1]) { + iterator_stack.resize(iterator_stack.size() - 1); + } + + if (!class_doc || class_doc->name.is_empty()) { + return false; + } + + // If class matches the flags, add it to the matched stack. + const bool class_matched = + (search_flags & SEARCH_CLASSES) || + ((search_flags & SEARCH_CONSTRUCTORS) && !class_doc->constructors.is_empty()) || + ((search_flags & SEARCH_METHODS) && !class_doc->methods.is_empty()) || + ((search_flags & SEARCH_OPERATORS) && !class_doc->operators.is_empty()) || + ((search_flags & SEARCH_SIGNALS) && !class_doc->signals.is_empty()) || + ((search_flags & SEARCH_CONSTANTS) && !class_doc->constants.is_empty()) || + ((search_flags & SEARCH_PROPERTIES) && !class_doc->properties.is_empty()) || + ((search_flags & SEARCH_THEME_ITEMS) && !class_doc->theme_properties.is_empty()) || + ((search_flags & SEARCH_ANNOTATIONS) && !class_doc->annotations.is_empty()); + + if (class_matched) { + if (term.is_empty() || class_doc->name.containsn(term)) { + matched_classes.push_back(Pair<DocData::ClassDoc *, String>(class_doc, String())); + } else if (String keyword = _match_keywords(term, class_doc->keywords); !keyword.is_empty()) { + matched_classes.push_back(Pair<DocData::ClassDoc *, String>(class_doc, keyword)); + } + } + + // Add inheriting classes, in reverse. + if (class_doc && EditorHelp::get_doc_data()->inheriting.has(class_doc->name)) { + iterator_stack.push_back(EditorHelp::get_doc_data()->inheriting[class_doc->name].back()); + } + + return false; + } + + // Drop last element of stack if empty. + if (!iterator_stack[iterator_stack.size() - 1]) { + iterator_stack.resize(iterator_stack.size() - 1); + } + + return iterator_stack.is_empty(); +} + +bool EditorHelpSearch::Runner::_phase_fill_member_items_init() { + // Prepare tree. + class_items.clear(); + _populate_cache(); + + return true; +} + +TreeItem *EditorHelpSearch::Runner::_create_category_item(TreeItem *p_parent, const String &p_class, const StringName &p_icon, const String &p_metatype, const String &p_text) { + const String item_meta = "class_" + p_metatype + ":" + p_class; + + TreeItem *item = nullptr; + if (_find_or_create_item(p_parent, item_meta, item)) { + item->set_icon(0, ui_service->get_editor_theme_icon(p_icon)); + item->set_text(0, p_text); + item->set_metadata(0, item_meta); + } + item->set_collapsed(true); + + return item; +} + +bool EditorHelpSearch::Runner::_phase_fill_member_items() { + if (matched_classes.is_empty()) { + return true; + } + + // Pop working item from stack. + Pair<DocData::ClassDoc *, String> match = matched_classes[matched_classes.size() - 1]; + DocData::ClassDoc *class_doc = match.first; + const String &keyword = match.second; + matched_classes.resize(matched_classes.size() - 1); + + if (class_doc) { + TreeItem *item = _create_class_hierarchy(class_doc, keyword, !(search_flags & SEARCH_CLASSES)); + + // If the class has no inheriting classes, fold its item. + item->set_collapsed(!item->get_first_child()); + + if (search_flags & SEARCH_CLASSES) { + item->clear_custom_color(0); + item->clear_custom_color(1); + } else { + item->set_custom_color(0, disabled_color); + item->set_custom_color(1, disabled_color); + } + + // Create common header if required. + const bool search_all = (search_flags & SEARCH_ALL) == SEARCH_ALL; + + if ((search_flags & SEARCH_CONSTRUCTORS) && !class_doc->constructors.is_empty()) { + TreeItem *parent_item = item; + if (search_all) { + parent_item = _create_category_item(parent_item, class_doc->name, SNAME("MemberConstructor"), TTRC("Constructors"), "constructors"); + } + for (const DocData::MethodDoc &constructor_doc : class_doc->constructors) { + _create_constructor_item(parent_item, class_doc, &constructor_doc); + } + } + if ((search_flags & SEARCH_METHODS) && !class_doc->methods.is_empty()) { + TreeItem *parent_item = item; + if (search_all) { + parent_item = _create_category_item(parent_item, class_doc->name, SNAME("MemberMethod"), TTRC("Methods"), "methods"); + } + for (const DocData::MethodDoc &method_doc : class_doc->methods) { + _create_method_item(parent_item, class_doc, &method_doc); + } + } + if ((search_flags & SEARCH_OPERATORS) && !class_doc->operators.is_empty()) { + TreeItem *parent_item = item; + if (search_all) { + parent_item = _create_category_item(parent_item, class_doc->name, SNAME("MemberOperator"), TTRC("Operators"), "operators"); + } + for (const DocData::MethodDoc &operator_doc : class_doc->operators) { + _create_operator_item(parent_item, class_doc, &operator_doc); + } + } + if ((search_flags & SEARCH_SIGNALS) && !class_doc->signals.is_empty()) { + TreeItem *parent_item = item; + if (search_all) { + parent_item = _create_category_item(parent_item, class_doc->name, SNAME("MemberSignal"), TTRC("Signals"), "signals"); + } + for (const DocData::MethodDoc &signal_doc : class_doc->signals) { + _create_signal_item(parent_item, class_doc, &signal_doc); + } + } + if ((search_flags & SEARCH_CONSTANTS) && !class_doc->constants.is_empty()) { + TreeItem *parent_item = item; + if (search_all) { + parent_item = _create_category_item(parent_item, class_doc->name, SNAME("MemberConstant"), TTRC("Constants"), "constants"); + } + for (const DocData::ConstantDoc &constant_doc : class_doc->constants) { + _create_constant_item(parent_item, class_doc, &constant_doc); + } + } + if ((search_flags & SEARCH_PROPERTIES) && !class_doc->properties.is_empty()) { + TreeItem *parent_item = item; + if (search_all) { + parent_item = _create_category_item(parent_item, class_doc->name, SNAME("MemberProperty"), TTRC("Prtoperties"), "propertiess"); + } + for (const DocData::PropertyDoc &property_doc : class_doc->properties) { + _create_property_item(parent_item, class_doc, &property_doc); + } + } + if ((search_flags & SEARCH_THEME_ITEMS) && !class_doc->theme_properties.is_empty()) { + TreeItem *parent_item = item; + if (search_all) { + parent_item = _create_category_item(parent_item, class_doc->name, SNAME("MemberTheme"), TTRC("Theme Properties"), "theme_items"); + } + for (const DocData::ThemeItemDoc &theme_property_doc : class_doc->theme_properties) { + _create_theme_property_item(parent_item, class_doc, &theme_property_doc); + } + } + if ((search_flags & SEARCH_ANNOTATIONS) && !class_doc->annotations.is_empty()) { + TreeItem *parent_item = item; + if (search_all) { + parent_item = _create_category_item(parent_item, class_doc->name, SNAME("MemberAnnotation"), TTRC("Annotations"), "annotations"); + } + for (const DocData::MethodDoc &annotation_doc : class_doc->annotations) { + _create_annotation_item(parent_item, class_doc, &annotation_doc); + } + } + } + + return matched_classes.is_empty(); +} + bool EditorHelpSearch::Runner::_slice() { bool phase_done = false; switch (phase) { @@ -430,7 +684,7 @@ bool EditorHelpSearch::Runner::_slice() { default: WARN_PRINT("Invalid or unhandled phase in EditorHelpSearch::Runner, aborting search."); return true; - }; + } if (phase_done) { phase++; @@ -450,9 +704,11 @@ bool EditorHelpSearch::Runner::_phase_match_classes_init() { matched_item = nullptr; match_highest_score = 0; - terms = term.split_spaces(); - if (terms.is_empty()) { - terms.append(term); + if (!term.is_empty()) { + terms = term.split_spaces(); + if (terms.is_empty()) { + terms.append(term); + } } return true; @@ -480,78 +736,71 @@ bool EditorHelpSearch::Runner::_phase_match_classes() { // Match class name. if (search_flags & SEARCH_CLASSES) { - // If the search term is empty, add any classes which are not script docs or which don't start with - // a double-quotation. This will ensure that only C++ classes and explicitly named classes will - // be added. - match.name = (term.is_empty() && (!class_doc->is_script_doc || class_doc->name[0] != '\"')) || _match_string(term, class_doc->name); + match.name = _match_string(term, class_doc->name); match.keyword = _match_keywords(term, class_doc->keywords); } - // Match members only if the term is long enough, to avoid slow performance from building a large tree. - // Make an exception for annotations, since there are not that many of them. - if (term.length() > 1 || term == "@") { - if (search_flags & SEARCH_CONSTRUCTORS) { - _match_method_name_and_push_back(class_doc->constructors, &match.constructors); - } - if (search_flags & SEARCH_METHODS) { - _match_method_name_and_push_back(class_doc->methods, &match.methods); - } - if (search_flags & SEARCH_OPERATORS) { - _match_method_name_and_push_back(class_doc->operators, &match.operators); - } - if (search_flags & SEARCH_SIGNALS) { - for (int i = 0; i < class_doc->signals.size(); i++) { - MemberMatch<DocData::MethodDoc> signal; - signal.name = _all_terms_in_name(class_doc->signals[i].name); - signal.keyword = _match_keywords_in_all_terms(class_doc->signals[i].keywords); - if (signal.name || !signal.keyword.is_empty()) { - signal.doc = const_cast<DocData::MethodDoc *>(&class_doc->signals[i]); - match.signals.push_back(signal); - } + if (search_flags & SEARCH_CONSTRUCTORS) { + _match_method_name_and_push_back(class_doc->constructors, &match.constructors); + } + if (search_flags & SEARCH_METHODS) { + _match_method_name_and_push_back(class_doc->methods, &match.methods); + } + if (search_flags & SEARCH_OPERATORS) { + _match_method_name_and_push_back(class_doc->operators, &match.operators); + } + if (search_flags & SEARCH_SIGNALS) { + for (const DocData::MethodDoc &signal_doc : class_doc->signals) { + MemberMatch<DocData::MethodDoc> signal; + signal.name = _all_terms_in_name(signal_doc.name); + signal.keyword = _match_keywords_in_all_terms(signal_doc.keywords); + if (signal.name || !signal.keyword.is_empty()) { + signal.doc = &signal_doc; + match.signals.push_back(signal); } } - if (search_flags & SEARCH_CONSTANTS) { - for (int i = 0; i < class_doc->constants.size(); i++) { - MemberMatch<DocData::ConstantDoc> constant; - constant.name = _all_terms_in_name(class_doc->constants[i].name); - constant.keyword = _match_keywords_in_all_terms(class_doc->constants[i].keywords); - if (constant.name || !constant.keyword.is_empty()) { - constant.doc = const_cast<DocData::ConstantDoc *>(&class_doc->constants[i]); - match.constants.push_back(constant); - } + } + if (search_flags & SEARCH_CONSTANTS) { + for (const DocData::ConstantDoc &constant_doc : class_doc->constants) { + MemberMatch<DocData::ConstantDoc> constant; + constant.name = _all_terms_in_name(constant_doc.name); + constant.keyword = _match_keywords_in_all_terms(constant_doc.keywords); + if (constant.name || !constant.keyword.is_empty()) { + constant.doc = &constant_doc; + match.constants.push_back(constant); } } - if (search_flags & SEARCH_PROPERTIES) { - for (int i = 0; i < class_doc->properties.size(); i++) { - MemberMatch<DocData::PropertyDoc> property; - property.name = _all_terms_in_name(class_doc->properties[i].name); - property.keyword = _match_keywords_in_all_terms(class_doc->properties[i].keywords); - if (property.name || !property.keyword.is_empty()) { - property.doc = const_cast<DocData::PropertyDoc *>(&class_doc->properties[i]); - match.properties.push_back(property); - } + } + if (search_flags & SEARCH_PROPERTIES) { + for (const DocData::PropertyDoc &property_doc : class_doc->properties) { + MemberMatch<DocData::PropertyDoc> property; + property.name = _all_terms_in_name(property_doc.name); + property.keyword = _match_keywords_in_all_terms(property_doc.keywords); + if (property.name || !property.keyword.is_empty()) { + property.doc = &property_doc; + match.properties.push_back(property); } } - if (search_flags & SEARCH_THEME_ITEMS) { - for (int i = 0; i < class_doc->theme_properties.size(); i++) { - MemberMatch<DocData::ThemeItemDoc> theme_property; - theme_property.name = _all_terms_in_name(class_doc->theme_properties[i].name); - theme_property.keyword = _match_keywords_in_all_terms(class_doc->theme_properties[i].keywords); - if (theme_property.name || !theme_property.keyword.is_empty()) { - theme_property.doc = const_cast<DocData::ThemeItemDoc *>(&class_doc->theme_properties[i]); - match.theme_properties.push_back(theme_property); - } + } + if (search_flags & SEARCH_THEME_ITEMS) { + for (const DocData::ThemeItemDoc &theme_property_doc : class_doc->theme_properties) { + MemberMatch<DocData::ThemeItemDoc> theme_property; + theme_property.name = _all_terms_in_name(theme_property_doc.name); + theme_property.keyword = _match_keywords_in_all_terms(theme_property_doc.keywords); + if (theme_property.name || !theme_property.keyword.is_empty()) { + theme_property.doc = &theme_property_doc; + match.theme_properties.push_back(theme_property); } } - if (search_flags & SEARCH_ANNOTATIONS) { - for (int i = 0; i < class_doc->annotations.size(); i++) { - MemberMatch<DocData::MethodDoc> annotation; - annotation.name = _all_terms_in_name(class_doc->annotations[i].name); - annotation.keyword = _match_keywords_in_all_terms(class_doc->annotations[i].keywords); - if (annotation.name || !annotation.keyword.is_empty()) { - annotation.doc = const_cast<DocData::MethodDoc *>(&class_doc->annotations[i]); - match.annotations.push_back(annotation); - } + } + if (search_flags & SEARCH_ANNOTATIONS) { + for (const DocData::MethodDoc &annotation_doc : class_doc->annotations) { + MemberMatch<DocData::MethodDoc> annotation; + annotation.name = _all_terms_in_name(annotation_doc.name); + annotation.keyword = _match_keywords_in_all_terms(annotation_doc.keywords); + if (annotation.name || !annotation.keyword.is_empty()) { + annotation.doc = &annotation_doc; + match.annotations.push_back(annotation); } } } @@ -564,9 +813,11 @@ bool EditorHelpSearch::Runner::_phase_match_classes() { } if (!iterator_stack.is_empty()) { + // Iterate on stack. if (iterator_stack[iterator_stack.size() - 1]) { iterator_stack[iterator_stack.size() - 1] = iterator_stack[iterator_stack.size() - 1]->next(); } + // Drop last element of stack. if (!iterator_stack[iterator_stack.size() - 1]) { iterator_stack.resize(iterator_stack.size() - 1); } @@ -661,36 +912,32 @@ bool EditorHelpSearch::Runner::_phase_member_items() { return false; } + // Pick appropriate parent item if showing hierarchy, otherwise pick root. TreeItem *parent_item = (search_flags & SEARCH_SHOW_HIERARCHY) ? class_items[match.doc->name] : root_item; - bool constructor_created = false; - for (int i = 0; i < match.methods.size(); i++) { - String text = match.methods[i].doc->name; - if (!constructor_created) { - if (match.doc->name == match.methods[i].doc->name) { - text += " " + TTR("(constructors)"); - constructor_created = true; - } - } else { - if (match.doc->name == match.methods[i].doc->name) { - continue; - } - } - _create_method_item(parent_item, match.doc, text, match.methods[i]); + + for (const MemberMatch<DocData::MethodDoc> &constructor_item : match.constructors) { + _create_constructor_item(parent_item, match.doc, constructor_item); } - for (int i = 0; i < match.signals.size(); i++) { - _create_signal_item(parent_item, match.doc, match.signals[i]); + for (const MemberMatch<DocData::MethodDoc> &method_item : match.methods) { + _create_method_item(parent_item, match.doc, method_item); } - for (int i = 0; i < match.constants.size(); i++) { - _create_constant_item(parent_item, match.doc, match.constants[i]); + for (const MemberMatch<DocData::MethodDoc> &operator_item : match.operators) { + _create_operator_item(parent_item, match.doc, operator_item); } - for (int i = 0; i < match.properties.size(); i++) { - _create_property_item(parent_item, match.doc, match.properties[i]); + for (const MemberMatch<DocData::MethodDoc> &signal_item : match.signals) { + _create_signal_item(parent_item, match.doc, signal_item); } - for (int i = 0; i < match.theme_properties.size(); i++) { - _create_theme_property_item(parent_item, match.doc, match.theme_properties[i]); + for (const MemberMatch<DocData::ConstantDoc> &constant_item : match.constants) { + _create_constant_item(parent_item, match.doc, constant_item); } - for (int i = 0; i < match.annotations.size(); i++) { - _create_annotation_item(parent_item, match.doc, match.annotations[i]); + for (const MemberMatch<DocData::PropertyDoc> &property_item : match.properties) { + _create_property_item(parent_item, match.doc, property_item); + } + for (const MemberMatch<DocData::ThemeItemDoc> &theme_property_item : match.theme_properties) { + _create_theme_property_item(parent_item, match.doc, theme_property_item); + } + for (const MemberMatch<DocData::MethodDoc> &annotation_item : match.annotations) { + _create_annotation_item(parent_item, match.doc, annotation_item); } ++iterator_match; @@ -704,7 +951,7 @@ bool EditorHelpSearch::Runner::_phase_select_match() { return true; } -void EditorHelpSearch::Runner::_match_method_name_and_push_back(Vector<DocData::MethodDoc> &p_methods, Vector<MemberMatch<DocData::MethodDoc>> *r_match_methods) { +void EditorHelpSearch::Runner::_match_method_name_and_push_back(Vector<DocData::MethodDoc> &p_methods, LocalVector<MemberMatch<DocData::MethodDoc>> *r_match_methods) { // Constructors, Methods, Operators... for (int i = 0; i < p_methods.size(); i++) { String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? p_methods[i].name : p_methods[i].name.to_lower(); @@ -765,12 +1012,12 @@ void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_tex return; } - float inverse_length = 1.f / float(p_text.length()); + float inverse_length = 1.0f / float(p_text.length()); // Favor types where search term is a substring close to the start of the type. float w = 0.5f; int pos = p_text.findn(term); - float score = (pos > -1) ? 1.0f - w * MIN(1, 3 * pos * inverse_length) : MAX(0.f, .9f - w); + float score = (pos > -1) ? 1.0f - w * MIN(1, 3 * pos * inverse_length) : MAX(0.0f, 0.9f - w); // Favor shorter items: they resemble the search term more. w = 0.1f; @@ -781,7 +1028,8 @@ void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_tex score *= 0.9f; } - if (match_highest_score == 0 || score > match_highest_score) { + // Replace current match if term is short as we are searching in reverse. + if (match_highest_score == 0 || score > match_highest_score || (score == match_highest_score && term.length() == 1)) { matched_item = p_item; match_highest_score = score; } @@ -820,6 +1068,29 @@ String EditorHelpSearch::Runner::_build_keywords_tooltip(const String &p_keyword return tooltip.left(-2); } +TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const DocData::ClassDoc *p_class_doc, const String &p_matching_keyword, bool p_gray) { + if (p_class_doc->name.is_empty()) { + return nullptr; + } + if (TreeItem **found = class_items.getptr(p_class_doc->name)) { + return *found; + } + + // Ensure parent nodes are created first. + TreeItem *parent_item = root_item; + if (!p_class_doc->inherits.is_empty()) { + if (class_items.has(p_class_doc->inherits)) { + parent_item = class_items[p_class_doc->inherits]; + } else if (const DocData::ClassDoc *found = EditorHelp::get_doc_data()->class_list.getptr(p_class_doc->inherits)) { + parent_item = _create_class_hierarchy(found, String(), true); + } + } + + TreeItem *class_item = _create_class_item(parent_item, p_class_doc, p_gray, p_matching_keyword); + class_items[p_class_doc->name] = class_item; + return class_item; +} + TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_match) { if (p_match.doc->name.is_empty()) { return nullptr; @@ -887,6 +1158,8 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const item->add_button(0, warning_icon, 0, false, TTR("This class is marked as experimental.")); } } + // Cached item might be collapsed. + item->set_collapsed(false); if (p_gray) { item->set_custom_color(0, disabled_color); @@ -902,7 +1175,9 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const item->set_text(0, p_doc->name + " - " + TTR(vformat("Matches the \"%s\" keyword.", p_matching_keyword))); } - _match_item(item, p_doc->name); + if (!term.is_empty()) { + _match_item(item, p_doc->name); + } for (const String &keyword : p_doc->keywords.split(",")) { _match_item(item, keyword.strip_edges(), true); } @@ -910,44 +1185,73 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const return item; } -TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const MemberMatch<DocData::MethodDoc> &p_match) { +TreeItem *EditorHelpSearch::Runner::_create_constructor_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match) { + String tooltip = p_class_doc->name + "("; + String text = p_class_doc->name + "("; + for (int i = 0; i < p_match.doc->arguments.size(); i++) { + const DocData::ArgumentDoc &arg = p_match.doc->arguments[i]; + tooltip += arg.type + " " + arg.name; + text += arg.type; + if (!arg.default_value.is_empty()) { + tooltip += " = " + arg.default_value; + } + if (i < p_match.doc->arguments.size() - 1) { + tooltip += ", "; + text += ", "; + } + } + tooltip += ")"; + tooltip += _build_keywords_tooltip(p_match.doc->keywords); + text += ")"; + return _create_member_item(p_parent, p_class_doc->name, SNAME("MemberConstructor"), p_match.doc->name, text, TTRC("Constructor"), "method", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); +} + +TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match) { String tooltip = _build_method_tooltip(p_class_doc, p_match.doc); - return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_match.doc->name, p_text, TTRC("Method"), "method", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); + return _create_member_item(p_parent, p_class_doc->name, SNAME("MemberMethod"), p_match.doc->name, p_match.doc->name, TTRC("Method"), "method", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); +} + +TreeItem *EditorHelpSearch::Runner::_create_operator_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match) { + String tooltip = _build_method_tooltip(p_class_doc, p_match.doc); + String text = p_match.doc->name; + if (!p_match.doc->arguments.is_empty()) { + text += "(" + p_match.doc->arguments[0].type + ")"; + } + return _create_member_item(p_parent, p_class_doc->name, SNAME("MemberOperator"), p_match.doc->name, text, TTRC("Operator"), "method", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); } TreeItem *EditorHelpSearch::Runner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match) { String tooltip = _build_method_tooltip(p_class_doc, p_match.doc); - return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_match.doc->name, p_match.doc->name, TTRC("Signal"), "signal", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); + return _create_member_item(p_parent, p_class_doc->name, SNAME("MemberSignal"), p_match.doc->name, p_match.doc->name, TTRC("Signal"), "signal", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); } TreeItem *EditorHelpSearch::Runner::_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match) { String tooltip = _build_method_tooltip(p_class_doc, p_match.doc); // Hide the redundant leading @ symbol. String text = p_match.doc->name.substr(1); - return _create_member_item(p_parent, p_class_doc->name, "MemberAnnotation", p_match.doc->name, text, TTRC("Annotation"), "annotation", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); + return _create_member_item(p_parent, p_class_doc->name, SNAME("MemberAnnotation"), p_match.doc->name, text, TTRC("Annotation"), "annotation", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); } TreeItem *EditorHelpSearch::Runner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::ConstantDoc> &p_match) { String tooltip = p_class_doc->name + "." + p_match.doc->name; tooltip += _build_keywords_tooltip(p_match.doc->keywords); - return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_match.doc->name, p_match.doc->name, TTRC("Constant"), "constant", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); + return _create_member_item(p_parent, p_class_doc->name, SNAME("MemberConstant"), p_match.doc->name, p_match.doc->name, TTRC("Constant"), "constant", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); } TreeItem *EditorHelpSearch::Runner::_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::PropertyDoc> &p_match) { String tooltip = p_match.doc->type + " " + p_class_doc->name + "." + p_match.doc->name; tooltip += "\n " + p_class_doc->name + "." + p_match.doc->setter + "(value) setter"; tooltip += "\n " + p_class_doc->name + "." + p_match.doc->getter + "() getter"; - tooltip += _build_keywords_tooltip(p_match.doc->keywords); - return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_match.doc->name, p_match.doc->name, TTRC("Property"), "property", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); + return _create_member_item(p_parent, p_class_doc->name, SNAME("MemberProperty"), p_match.doc->name, p_match.doc->name, TTRC("Property"), "property", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); } TreeItem *EditorHelpSearch::Runner::_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::ThemeItemDoc> &p_match) { String tooltip = p_match.doc->type + " " + p_class_doc->name + "." + p_match.doc->name; tooltip += _build_keywords_tooltip(p_match.doc->keywords); - return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_match.doc->name, p_match.doc->name, TTRC("Theme Property"), "theme_item", p_match.doc->keywords, tooltip, false, false, p_match.name ? String() : p_match.keyword); + return _create_member_item(p_parent, p_class_doc->name, SNAME("MemberTheme"), p_match.doc->name, p_match.doc->name, TTRC("Theme Property"), "theme_item", p_match.doc->keywords, tooltip, false, false, p_match.name ? String() : p_match.keyword); } -TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_keywords, bool p_is_deprecated, bool p_is_experimental, const String &p_matching_keyword) { +TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const StringName &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_keywords, bool p_is_deprecated, bool p_is_experimental, const String &p_matching_keyword) { const String item_meta = "class_" + p_metatype + ":" + p_class_name + ":" + p_name; TreeItem *item = nullptr; @@ -978,7 +1282,10 @@ TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, cons } item->set_text(0, text); - _match_item(item, p_name); + // Don't match member items for short searches. + if (term.length() > 1 || term == "@") { + _match_item(item, p_name); + } for (const String &keyword : p_keywords.split(",")) { _match_item(item, keyword.strip_edges(), true); } @@ -989,9 +1296,17 @@ TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, cons bool EditorHelpSearch::Runner::work(uint64_t slot) { // Return true when the search has been completed, otherwise false. const uint64_t until = OS::get_singleton()->get_ticks_usec() + slot; - while (!_slice()) { - if (OS::get_singleton()->get_ticks_usec() > until) { - return false; + if (term.length() > 1 || term == "@") { + while (!_slice()) { + if (OS::get_singleton()->get_ticks_usec() > until) { + return false; + } + } + } else { + while (!_fill()) { + if (OS::get_singleton()->get_ticks_usec() > until) { + return false; + } } } return true; @@ -1001,7 +1316,7 @@ EditorHelpSearch::Runner::Runner(Control *p_icon_service, Tree *p_results_tree, ui_service(p_icon_service), results_tree(p_results_tree), tree_cache(p_tree_cache), - term((p_search_flags & SEARCH_CASE_SENSITIVE) == 0 ? p_term.strip_edges().to_lower() : p_term.strip_edges()), + term((p_search_flags & SEARCH_CASE_SENSITIVE) == 0 ? p_term.to_lower() : p_term), search_flags(p_search_flags), disabled_color(ui_service->get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor))) { } diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h index 58061dae4c..b8b3c26b41 100644 --- a/editor/editor_help_search.h +++ b/editor/editor_help_search.h @@ -63,6 +63,7 @@ class EditorHelpSearch : public ConfirmationDialog { Tree *results_tree = nullptr; bool old_search = false; String old_term; + int old_search_flags = 0; class Runner; Ref<Runner> search; @@ -119,26 +120,30 @@ class EditorHelpSearch::Runner : public RefCounted { template <typename T> struct MemberMatch { - T *doc = nullptr; + const T *doc = nullptr; bool name = false; String keyword; + + MemberMatch() {} + MemberMatch(const T *p_doc) : + doc(p_doc) {} }; struct ClassMatch { - DocData::ClassDoc *doc = nullptr; + const DocData::ClassDoc *doc = nullptr; bool name = false; String keyword; - Vector<MemberMatch<DocData::MethodDoc>> constructors; - Vector<MemberMatch<DocData::MethodDoc>> methods; - Vector<MemberMatch<DocData::MethodDoc>> operators; - Vector<MemberMatch<DocData::MethodDoc>> signals; - Vector<MemberMatch<DocData::ConstantDoc>> constants; - Vector<MemberMatch<DocData::PropertyDoc>> properties; - Vector<MemberMatch<DocData::ThemeItemDoc>> theme_properties; - Vector<MemberMatch<DocData::MethodDoc>> annotations; + LocalVector<MemberMatch<DocData::MethodDoc>> constructors; + LocalVector<MemberMatch<DocData::MethodDoc>> methods; + LocalVector<MemberMatch<DocData::MethodDoc>> operators; + LocalVector<MemberMatch<DocData::MethodDoc>> signals; + LocalVector<MemberMatch<DocData::ConstantDoc>> constants; + LocalVector<MemberMatch<DocData::PropertyDoc>> properties; + LocalVector<MemberMatch<DocData::ThemeItemDoc>> theme_properties; + LocalVector<MemberMatch<DocData::MethodDoc>> annotations; bool required() { - return name || !keyword.is_empty() || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size() || annotations.size(); + return name || !keyword.is_empty() || !constructors.is_empty() || !methods.is_empty() || !operators.is_empty() || !signals.is_empty() || !constants.is_empty() || !properties.is_empty() || !theme_properties.is_empty() || !annotations.is_empty(); } }; @@ -155,6 +160,7 @@ class EditorHelpSearch::Runner : public RefCounted { LocalVector<RBSet<String, NaturalNoCaseComparator>::Element *> iterator_stack; HashMap<String, ClassMatch> matches; HashMap<String, ClassMatch>::Iterator iterator_match; + LocalVector<Pair<DocData::ClassDoc *, String>> matched_classes; TreeItem *root_item = nullptr; HashMap<String, TreeItem *> class_items; TreeItem *matched_item = nullptr; @@ -165,6 +171,12 @@ class EditorHelpSearch::Runner : public RefCounted { void _populate_cache(); bool _find_or_create_item(TreeItem *p_parent, const String &p_item_meta, TreeItem *&r_item); + bool _fill(); + bool _phase_fill_classes_init(); + bool _phase_fill_classes(); + bool _phase_fill_member_items_init(); + bool _phase_fill_member_items(); + bool _slice(); bool _phase_match_classes_init(); bool _phase_match_classes(); @@ -177,21 +189,25 @@ class EditorHelpSearch::Runner : public RefCounted { String _build_method_tooltip(const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) const; String _build_keywords_tooltip(const String &p_keywords) const; - void _match_method_name_and_push_back(Vector<DocData::MethodDoc> &p_methods, Vector<MemberMatch<DocData::MethodDoc>> *r_match_methods); + void _match_method_name_and_push_back(Vector<DocData::MethodDoc> &p_methods, LocalVector<MemberMatch<DocData::MethodDoc>> *r_match_methods); bool _all_terms_in_name(const String &p_name) const; String _match_keywords_in_all_terms(const String &p_keywords) const; bool _match_string(const String &p_term, const String &p_string) const; String _match_keywords(const String &p_term, const String &p_keywords) const; void _match_item(TreeItem *p_item, const String &p_text, bool p_is_keywords = false); TreeItem *_create_class_hierarchy(const ClassMatch &p_match); + TreeItem *_create_class_hierarchy(const DocData::ClassDoc *p_class_doc, const String &p_matching_keyword, bool p_gray); TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray, const String &p_matching_keyword); - TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const MemberMatch<DocData::MethodDoc> &p_match); + TreeItem *_create_category_item(TreeItem *p_parent, const String &p_class, const StringName &p_icon, const String &p_metatype, const String &p_type); + TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match); + TreeItem *_create_constructor_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match); + TreeItem *_create_operator_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match); TreeItem *_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match); TreeItem *_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match); TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::ConstantDoc> &p_match); TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::PropertyDoc> &p_match); TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::ThemeItemDoc> &p_match); - TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_keywords, bool p_is_deprecated, bool p_is_experimental, const String &p_matching_keyword); + TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const StringName &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_keywords, bool p_is_deprecated, bool p_is_experimental, const String &p_matching_keyword); public: bool work(uint64_t slot = 100000); diff --git a/editor/editor_properties_vector.cpp b/editor/editor_properties_vector.cpp index a40055cf85..9ff8bf674d 100644 --- a/editor/editor_properties_vector.cpp +++ b/editor/editor_properties_vector.cpp @@ -130,9 +130,11 @@ void EditorPropertyVectorN::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { if (linked->is_visible()) { - const String key = vformat("%s:%s", get_edited_object()->get_class(), get_edited_property()); - linked->set_pressed_no_signal(EditorSettings::get_singleton()->get_project_metadata("linked_properties", key, true)); - _update_ratio(); + if (get_edited_object()) { + const String key = vformat("%s:%s", get_edited_object()->get_class(), get_edited_property()); + linked->set_pressed_no_signal(EditorSettings::get_singleton()->get_project_metadata("linked_properties", key, true)); + _update_ratio(); + } } } break; diff --git a/editor/icons/MemberConstructor.svg b/editor/icons/MemberConstructor.svg new file mode 100644 index 0000000000..0e61768739 --- /dev/null +++ b/editor/icons/MemberConstructor.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M9 6c-1.33 2.67-1.33 4.33 0 7h2c-1.33-2.67-1.33-4.33 0-7zm4 0c1.33 2.67 1.33 4.33 0 7h2c1.33-2.67 1.33-4.33 0-7zM1 11a1 1 0 0 0 0 2 1 1 0 0 0 0-2zm6 2v-2H6a1 1 0 0 1 0-2h1V7H6a3 3 0 0 0 0 6z"/></svg>
\ No newline at end of file diff --git a/editor/icons/MemberOperator.svg b/editor/icons/MemberOperator.svg new file mode 100644 index 0000000000..a00d990e26 --- /dev/null +++ b/editor/icons/MemberOperator.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M9 6c-1.33 2.67-1.33 4.33 0 7h2c-1.33-2.67-1.33-4.33 0-7zm4 0c1.33 2.67 1.33 4.33 0 7h2c1.33-2.67 1.33-4.33 0-7zM1 11a1 1 0 0 0 0 2 1 1 0 0 0 0-2zm4-4a3 3 0 0 0 0 6 3 3 0 0 0 0-6zm0 2a1 1 0 0 1 0 2 1 1 0 0 1 0-2z"/></svg>
\ No newline at end of file diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 230d5809aa..dc4d4db3f8 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -47,6 +47,7 @@ #include "scene/3d/physics/physics_body_3d.h" #include "scene/gui/separator.h" #include "scene/gui/texture_rect.h" +#include "scene/property_utils.h" #include "scene/resources/3d/capsule_shape_3d.h" #include "scene/resources/skeleton_profile.h" #include "scene/resources/surface_tool.h" @@ -65,7 +66,7 @@ void BoneTransformEditor::create_editors() { // Position property. position_property = memnew(EditorPropertyVector3()); - position_property->setup(-10000, 10000, 0.001f, true); + position_property->setup(-10000, 10000, 0.001, true); position_property->set_label("Position"); position_property->set_selectable(false); position_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed)); @@ -74,7 +75,7 @@ void BoneTransformEditor::create_editors() { // Rotation property. rotation_property = memnew(EditorPropertyQuaternion()); - rotation_property->setup(-10000, 10000, 0.001f, true); + rotation_property->setup(-10000, 10000, 0.001, true); rotation_property->set_label("Rotation"); rotation_property->set_selectable(false); rotation_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed)); @@ -83,7 +84,7 @@ void BoneTransformEditor::create_editors() { // Scale property. scale_property = memnew(EditorPropertyVector3()); - scale_property->setup(-10000, 10000, 0.001f, true); + scale_property->setup(-10000, 10000, 0.001, true, true); scale_property->set_label("Scale"); scale_property->set_selectable(false); scale_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed)); @@ -97,7 +98,7 @@ void BoneTransformEditor::create_editors() { // Transform/Matrix property. rest_matrix = memnew(EditorPropertyTransform3D()); - rest_matrix->setup(-10000, 10000, 0.001f, true); + rest_matrix->setup(-10000, 10000, 0.001, true); rest_matrix->set_label("Transform"); rest_matrix->set_selectable(false); rest_section->get_vbox()->add_child(rest_matrix); @@ -122,6 +123,13 @@ void BoneTransformEditor::_value_changed(const String &p_property, const Variant undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS); undo_redo->add_undo_property(skeleton, p_property, skeleton->get(p_property)); undo_redo->add_do_property(skeleton, p_property, p_value); + + Skeleton3DEditor *se = Skeleton3DEditor::get_singleton(); + if (se) { + undo_redo->add_do_method(se, "update_joint_tree"); + undo_redo->add_undo_method(se, "update_joint_tree"); + } + undo_redo->commit_action(); } } @@ -189,26 +197,31 @@ void BoneTransformEditor::_update_properties() { if (split[2] == "enabled") { enabled_checkbox->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); enabled_checkbox->update_property(); + enabled_checkbox->update_editor_property_status(); enabled_checkbox->queue_redraw(); } if (split[2] == "position") { position_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); position_property->update_property(); + position_property->update_editor_property_status(); position_property->queue_redraw(); } if (split[2] == "rotation") { rotation_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); rotation_property->update_property(); + rotation_property->update_editor_property_status(); rotation_property->queue_redraw(); } if (split[2] == "scale") { scale_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); scale_property->update_property(); + scale_property->update_editor_property_status(); scale_property->queue_redraw(); } if (split[2] == "rest") { rest_matrix->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); rest_matrix->update_property(); + rest_matrix->update_editor_property_status(); rest_matrix->queue_redraw(); } } @@ -232,6 +245,11 @@ void Skeleton3DEditor::set_bone_options_enabled(const bool p_bone_options_enable skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_SELECTED_POSES_TO_RESTS, !p_bone_options_enabled); }; +void Skeleton3DEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("update_all"), &Skeleton3DEditor::update_all); + ClassDB::bind_method(D_METHOD("update_joint_tree"), &Skeleton3DEditor::update_joint_tree); +} + void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) { if (!skeleton) { return; @@ -294,6 +312,10 @@ void Skeleton3DEditor::reset_pose(const bool p_all_bones) { ur->add_undo_method(skeleton, "set_bone_pose_scale", selected_bone, skeleton->get_bone_pose_scale(selected_bone)); ur->add_do_method(skeleton, "reset_bone_pose", selected_bone); } + + ur->add_undo_method(this, "update_joint_tree"); + ur->add_do_method(this, "update_joint_tree"); + ur->commit_action(); } @@ -357,6 +379,10 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) { ur->add_do_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_pose(selected_bone)); ur->add_undo_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_rest(selected_bone)); } + + ur->add_undo_method(this, "update_joint_tree"); + ur->add_do_method(this, "update_joint_tree"); + ur->commit_action(); } @@ -620,9 +646,12 @@ void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_se } ur->add_undo_method(skeleton_node, "set_bone_parent", p_selected_boneidx, skeleton_node->get_bone_parent(p_selected_boneidx)); ur->add_do_method(skeleton_node, "set_bone_parent", p_selected_boneidx, p_target_boneidx); + + ur->add_undo_method(this, "update_joint_tree"); + ur->add_do_method(this, "update_joint_tree"); + skeleton_node->set_bone_parent(p_selected_boneidx, p_target_boneidx); - update_joint_tree(); ur->commit_action(); } @@ -655,6 +684,107 @@ void Skeleton3DEditor::_joint_tree_selection_changed() { void Skeleton3DEditor::_joint_tree_rmb_select(const Vector2 &p_pos, MouseButton p_button) { } +void Skeleton3DEditor::_joint_tree_button_clicked(Object *p_item, int p_column, int p_id, MouseButton p_button) { + if (!skeleton) { + return; + } + + TreeItem *tree_item = Object::cast_to<TreeItem>(p_item); + if (tree_item) { + String tree_item_metadata = tree_item->get_metadata(0); + + String bone_enabled_property = tree_item_metadata + "/enabled"; + String bone_parent_property = tree_item_metadata + "/parent"; + String bone_name_property = tree_item_metadata + "/name"; + String bone_position_property = tree_item_metadata + "/position"; + String bone_rotation_property = tree_item_metadata + "/rotation"; + String bone_scale_property = tree_item_metadata + "/scale"; + String bone_rest_property = tree_item_metadata + "/rest"; + + Variant current_enabled = skeleton->get(bone_enabled_property); + Variant current_parent = skeleton->get(bone_parent_property); + Variant current_name = skeleton->get(bone_name_property); + Variant current_position = skeleton->get(bone_position_property); + Variant current_rotation = skeleton->get(bone_rotation_property); + Variant current_scale = skeleton->get(bone_scale_property); + Variant current_rest = skeleton->get(bone_rest_property); + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Revert Bone")); + + bool can_revert_enabled = EditorPropertyRevert::can_property_revert(skeleton, bone_enabled_property, ¤t_enabled); + if (can_revert_enabled) { + bool is_valid = false; + Variant new_enabled = EditorPropertyRevert::get_property_revert_value(skeleton, bone_enabled_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_enabled_property, current_enabled); + ur->add_do_method(skeleton, "set", bone_enabled_property, new_enabled); + } + } + + bool can_revert_parent = EditorPropertyRevert::can_property_revert(skeleton, bone_parent_property, ¤t_parent); + if (can_revert_parent) { + bool is_valid = false; + Variant new_parent = EditorPropertyRevert::get_property_revert_value(skeleton, bone_parent_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_parent_property, current_parent); + ur->add_do_method(skeleton, "set", bone_parent_property, new_parent); + } + } + bool can_revert_name = EditorPropertyRevert::can_property_revert(skeleton, bone_name_property, ¤t_name); + if (can_revert_name) { + bool is_valid = false; + Variant new_name = EditorPropertyRevert::get_property_revert_value(skeleton, bone_name_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_name_property, current_name); + ur->add_do_method(skeleton, "set", bone_name_property, new_name); + } + } + bool can_revert_position = EditorPropertyRevert::can_property_revert(skeleton, bone_position_property, ¤t_position); + if (can_revert_position) { + bool is_valid = false; + Variant new_position = EditorPropertyRevert::get_property_revert_value(skeleton, bone_position_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_position_property, current_position); + ur->add_do_method(skeleton, "set", bone_position_property, new_position); + } + } + bool can_revert_rotation = EditorPropertyRevert::can_property_revert(skeleton, bone_rotation_property, ¤t_rotation); + if (can_revert_rotation) { + bool is_valid = false; + Variant new_rotation = EditorPropertyRevert::get_property_revert_value(skeleton, bone_rotation_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_rotation_property, current_rotation); + ur->add_do_method(skeleton, "set", bone_rotation_property, new_rotation); + } + } + bool can_revert_scale = EditorPropertyRevert::can_property_revert(skeleton, bone_scale_property, ¤t_scale); + if (can_revert_scale) { + bool is_valid = false; + Variant new_scale = EditorPropertyRevert::get_property_revert_value(skeleton, bone_scale_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_scale_property, current_scale); + ur->add_do_method(skeleton, "set", bone_scale_property, new_scale); + } + } + bool can_revert_rest = EditorPropertyRevert::can_property_revert(skeleton, bone_rest_property, ¤t_rest); + if (can_revert_rest) { + bool is_valid = false; + Variant new_rest = EditorPropertyRevert::get_property_revert_value(skeleton, bone_rest_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_rest_property, current_rest); + ur->add_do_method(skeleton, "set", bone_rest_property, new_rest); + } + } + + ur->add_undo_method(this, "update_all"); + ur->add_do_method(this, "update_all"); + + ur->commit_action(); + } + return; +} + void Skeleton3DEditor::_update_properties() { if (pose_editor) { pose_editor->_update_properties(); @@ -693,15 +823,52 @@ void Skeleton3DEditor::update_joint_tree() { joint_item->set_selectable(0, true); joint_item->set_metadata(0, "bones/" + itos(current_bone_idx)); + String bone_enabled_property = "bones/" + itos(current_bone_idx) + "/enabled"; + String bone_parent_property = "bones/" + itos(current_bone_idx) + "/parent"; + String bone_name_property = "bones/" + itos(current_bone_idx) + "/name"; + String bone_position_property = "bones/" + itos(current_bone_idx) + "/position"; + String bone_rotation_property = "bones/" + itos(current_bone_idx) + "/rotation"; + String bone_scale_property = "bones/" + itos(current_bone_idx) + "/scale"; + String bone_rest_property = "bones/" + itos(current_bone_idx) + "/rest"; + + Variant current_enabled = skeleton->get(bone_enabled_property); + Variant current_parent = skeleton->get(bone_parent_property); + Variant current_name = skeleton->get(bone_name_property); + Variant current_position = skeleton->get(bone_position_property); + Variant current_rotation = skeleton->get(bone_rotation_property); + Variant current_scale = skeleton->get(bone_scale_property); + Variant current_rest = skeleton->get(bone_rest_property); + + bool can_revert_enabled = EditorPropertyRevert::can_property_revert(skeleton, bone_enabled_property, ¤t_enabled); + bool can_revert_parent = EditorPropertyRevert::can_property_revert(skeleton, bone_parent_property, ¤t_parent); + bool can_revert_name = EditorPropertyRevert::can_property_revert(skeleton, bone_name_property, ¤t_name); + bool can_revert_position = EditorPropertyRevert::can_property_revert(skeleton, bone_position_property, ¤t_position); + bool can_revert_rotation = EditorPropertyRevert::can_property_revert(skeleton, bone_rotation_property, ¤t_rotation); + bool can_revert_scale = EditorPropertyRevert::can_property_revert(skeleton, bone_scale_property, ¤t_scale); + bool can_revert_rest = EditorPropertyRevert::can_property_revert(skeleton, bone_rest_property, ¤t_rest); + + if (can_revert_enabled || can_revert_parent || can_revert_name || can_revert_position || can_revert_rotation || can_revert_scale || can_revert_rest) { + joint_item->add_button(0, get_editor_theme_icon(SNAME("ReloadSmall")), JOINT_BUTTON_REVERT, false, TTR("Revert")); + } + // Add the bone's children to the list of bones to be processed. Vector<int> current_bone_child_bones = skeleton->get_bone_children(current_bone_idx); int child_bone_size = current_bone_child_bones.size(); for (int i = 0; i < child_bone_size; i++) { bones_to_process.push_back(current_bone_child_bones[i]); } + + if (current_bone_idx == selected_bone) { + joint_item->select(0); + } } } +void Skeleton3DEditor::update_all() { + _update_properties(); + update_joint_tree(); +} + void Skeleton3DEditor::create_editors() { set_h_size_flags(SIZE_EXPAND_FILL); set_focus_mode(FOCUS_ALL); @@ -840,6 +1007,7 @@ void Skeleton3DEditor::_notification(int p_what) { joint_tree->connect(SceneStringName(item_selected), callable_mp(this, &Skeleton3DEditor::_joint_tree_selection_changed)); joint_tree->connect("item_mouse_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_rmb_select)); + joint_tree->connect("button_clicked", callable_mp(this, &Skeleton3DEditor::_joint_tree_button_clicked)); #ifdef TOOLS_ENABLED skeleton->connect(SceneStringName(pose_updated), callable_mp(this, &Skeleton3DEditor::_draw_gizmo)); skeleton->connect(SceneStringName(pose_updated), callable_mp(this, &Skeleton3DEditor::_update_properties)); @@ -1337,6 +1505,10 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c ur->add_undo_method(skeleton, "set_bone_pose_scale", p_ids[i], se->get_bone_original_scale()); } } + + ur->add_do_method(se, "update_joint_tree"); + ur->add_undo_method(se, "update_joint_tree"); + ur->commit_action(); } diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index 79dc16ae2f..0bb58aac23 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -96,6 +96,8 @@ public: class Skeleton3DEditor : public VBoxContainer { GDCLASS(Skeleton3DEditor, VBoxContainer); + static void _bind_methods(); + friend class Skeleton3DEditorPlugin; enum SkeletonOption { @@ -116,6 +118,10 @@ class Skeleton3DEditor : public VBoxContainer { Skeleton3D *skeleton = nullptr; + enum { + JOINT_BUTTON_REVERT = 0, + }; + Tree *joint_tree = nullptr; BoneTransformEditor *rest_editor = nullptr; BoneTransformEditor *pose_editor = nullptr; @@ -149,6 +155,7 @@ class Skeleton3DEditor : public VBoxContainer { EditorFileDialog *file_export_lib = nullptr; void update_joint_tree(); + void update_all(); void create_editors(); @@ -189,6 +196,7 @@ class Skeleton3DEditor : public VBoxContainer { void _joint_tree_selection_changed(); void _joint_tree_rmb_select(const Vector2 &p_pos, MouseButton p_button); + void _joint_tree_button_clicked(Object *p_item, int p_column, int p_id, MouseButton p_button); void _update_properties(); void _subgizmo_selection_change(); diff --git a/main/main.cpp b/main/main.cpp index 791562a9bb..101fc642b6 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -3394,7 +3394,8 @@ void Main::setup_boot_logo() { boot_logo.instantiate(); Error load_err = ImageLoader::load_image(boot_logo_path, boot_logo); if (load_err) { - ERR_PRINT("Non-existing or invalid boot splash at '" + boot_logo_path + "'. Loading default splash."); + String msg = (boot_logo_path.ends_with(".png") ? "" : "The only supported format is PNG."); + ERR_PRINT("Non-existing or invalid boot splash at '" + boot_logo_path + +"'. " + msg + " Loading default splash."); } } } else { diff --git a/methods.py b/methods.py index 6d81b35aff..bfd08cfc7b 100644 --- a/methods.py +++ b/methods.py @@ -163,7 +163,7 @@ def add_source_files(self, sources, files, allow_gen=False): def disable_warnings(self): # 'self' is the environment - if self.msvc: + if self.msvc and not using_clang(self): # We have to remove existing warning level defines before appending /w, # otherwise we get: "warning D9025 : overriding '/W3' with '/w'" self["CCFLAGS"] = [x for x in self["CCFLAGS"] if not (x.startswith("/W") or x.startswith("/w"))] @@ -817,21 +817,20 @@ def get_compiler_version(env): "apple_patch3": -1, } - if not env.msvc: - # Not using -dumpversion as some GCC distros only return major, and - # Clang used to return hardcoded 4.2.1: # https://reviews.llvm.org/D56803 - try: - version = ( - subprocess.check_output([env.subst(env["CXX"]), "--version"], shell=(os.name == "nt")) - .strip() - .decode("utf-8") - ) - except (subprocess.CalledProcessError, OSError): - print_warning("Couldn't parse CXX environment variable to infer compiler version.") - return ret - else: + if env.msvc and not using_clang(env): # TODO: Implement for MSVC return ret + + # Not using -dumpversion as some GCC distros only return major, and + # Clang used to return hardcoded 4.2.1: # https://reviews.llvm.org/D56803 + try: + version = subprocess.check_output( + [env.subst(env["CXX"]), "--version"], shell=(os.name == "nt"), encoding="utf-8" + ).strip() + except (subprocess.CalledProcessError, OSError): + print_warning("Couldn't parse CXX environment variable to infer compiler version.") + return ret + match = re.search( r"(?:(?<=version )|(?<=\) )|(?<=^))" r"(?P<major>\d+)" diff --git a/modules/mono/editor/hostfxr_resolver.cpp b/modules/mono/editor/hostfxr_resolver.cpp index e93c9a5faf..9c37ac810a 100644 --- a/modules/mono/editor/hostfxr_resolver.cpp +++ b/modules/mono/editor/hostfxr_resolver.cpp @@ -216,6 +216,7 @@ bool get_default_installation_dir(String &r_dotnet_root) { #endif } +#ifndef WINDOWS_ENABLED bool get_install_location_from_file(const String &p_file_path, String &r_dotnet_root) { Error err = OK; Ref<FileAccess> f = FileAccess::open(p_file_path, FileAccess::READ, &err); @@ -233,6 +234,7 @@ bool get_install_location_from_file(const String &p_file_path, String &r_dotnet_ r_dotnet_root = line; return true; } +#endif bool get_dotnet_self_registered_dir(String &r_dotnet_root) { #if defined(WINDOWS_ENABLED) diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index 82e8854b7a..c18ee7155b 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -36,6 +36,7 @@ #include "core/math/math_defs.h" #include "core/object/worker_thread_pool.h" +#include "servers/navigation/navigation_globals.h" #include <KdTree2d.h> #include <KdTree3d.h> @@ -55,21 +56,21 @@ class NavMap : public NavRid { /// To find the polygons edges the vertices are displaced in a grid where /// each cell has the following cell_size and cell_height. - real_t cell_size = 0.25; // Must match ProjectSettings default 3D cell_size and NavigationMesh cell_size. - real_t cell_height = 0.25; // Must match ProjectSettings default 3D cell_height and NavigationMesh cell_height. + real_t cell_size = NavigationDefaults3D::navmesh_cell_size; + real_t cell_height = NavigationDefaults3D::navmesh_cell_height; // For the inter-region merging to work, internal rasterization is performed. - float merge_rasterizer_cell_size = 0.25; - float merge_rasterizer_cell_height = 0.25; + float merge_rasterizer_cell_size = NavigationDefaults3D::navmesh_cell_size; + float merge_rasterizer_cell_height = NavigationDefaults3D::navmesh_cell_height; // This value is used to control sensitivity of internal rasterizer. float merge_rasterizer_cell_scale = 1.0; bool use_edge_connections = true; /// This value is used to detect the near edges to connect. - real_t edge_connection_margin = 0.25; + real_t edge_connection_margin = NavigationDefaults3D::edge_connection_margin; /// This value is used to limit how far links search to find polygons to connect to. - real_t link_connection_radius = 1.0; + real_t link_connection_radius = NavigationDefaults3D::link_connection_radius; bool regenerate_polygons = true; bool regenerate_links = true; diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index d0c22e9e4d..4bf09d3c84 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -136,11 +136,12 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, vo return 0; } - if (!bm_font->face->glyph_map.has(p_glyph)) { + HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph); + if (!E) { return 0; } - return bm_font->face->glyph_map[p_glyph].advance.x * 64; + return E->value.advance.x * 64; } hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { @@ -150,11 +151,12 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, vo return 0; } - if (!bm_font->face->glyph_map.has(p_glyph)) { + HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph); + if (!E) { return 0; } - return -bm_font->face->glyph_map[p_glyph].advance.y * 64; + return -E->value.advance.y * 64; } hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) { @@ -178,11 +180,12 @@ hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p return false; } - if (!bm_font->face->glyph_map.has(p_glyph)) { + HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph); + if (!E) { return false; } - *r_x = bm_font->face->glyph_map[p_glyph].advance.x * 32; + *r_x = E->value.advance.x * 32; *r_y = -bm_font->face->ascent * 64; return true; @@ -195,14 +198,15 @@ hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_ return false; } - if (!bm_font->face->glyph_map.has(p_glyph)) { + HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph); + if (!E) { return false; } r_extents->x_bearing = 0; r_extents->y_bearing = 0; - r_extents->width = bm_font->face->glyph_map[p_glyph].rect.size.x * 64; - r_extents->height = bm_font->face->glyph_map[p_glyph].rect.size.y * 64; + r_extents->width = E->value.rect.size.x * 64; + r_extents->height = E->value.rect.size.y * 64; return true; } @@ -1188,18 +1192,21 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma /* Font Cache */ /*************************************************************************/ -_FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const { - ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size), false); +_FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph, FontGlyph &r_glyph) const { + FontForSizeAdvanced *fd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size, fd), false); int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts. - FontForSizeAdvanced *fd = p_font_data->cache[p_size]; - if (fd->glyph_map.has(p_glyph)) { - return fd->glyph_map[p_glyph].found; + HashMap<int32_t, FontGlyph>::Iterator E = fd->glyph_map.find(p_glyph); + if (E) { + r_glyph = E->value; + return E->value.found; } if (glyph_index == 0) { // Non graphical or invalid glyph, do not render. - fd->glyph_map[p_glyph] = FontGlyph(); + E = fd->glyph_map.insert(p_glyph, FontGlyph()); + r_glyph = E->value; return true; } @@ -1235,7 +1242,8 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, int error = FT_Load_Glyph(fd->face, glyph_index, flags); if (error) { - fd->glyph_map[p_glyph] = FontGlyph(); + E = fd->glyph_map.insert(p_glyph, FontGlyph()); + r_glyph = E->value; return false; } @@ -1339,17 +1347,22 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, cleanup_stroker: FT_Stroker_Done(stroker); } - fd->glyph_map[p_glyph] = gl; + E = fd->glyph_map.insert(p_glyph, gl); + r_glyph = E->value; return gl.found; } #endif - fd->glyph_map[p_glyph] = FontGlyph(); + E = fd->glyph_map.insert(p_glyph, FontGlyph()); + r_glyph = E->value; return false; } -_FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size) const { +_FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size, FontForSizeAdvanced *&r_cache_for_size) const { ERR_FAIL_COND_V(p_size.x <= 0, false); - if (p_font_data->cache.has(p_size)) { + + HashMap<Vector2i, FontForSizeAdvanced *>::Iterator E = p_font_data->cache.find(p_size); + if (E) { + r_cache_for_size = E->value; return true; } @@ -1840,7 +1853,8 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f // Init bitmap font. fd->hb_handle = _bmp_font_create(fd, nullptr); } - p_font_data->cache[p_size] = fd; + p_font_data->cache.insert(p_size, fd); + r_cache_for_size = fd; return true; } @@ -1864,9 +1878,10 @@ hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_ MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), nullptr); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), nullptr); - return fd->cache[size]->hb_handle; + return ffsd->hb_handle; } RID TextServerAdvanced::_create_font() { @@ -1989,7 +2004,8 @@ void TextServerAdvanced::_font_set_style(const RID &p_font_rid, BitField<FontSty MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->style_flags = p_style; } @@ -1999,7 +2015,8 @@ BitField<TextServer::FontStyle> TextServerAdvanced::_font_get_style(const RID &p MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0); return fd->style_flags; } @@ -2009,7 +2026,8 @@ void TextServerAdvanced::_font_set_style_name(const RID &p_font_rid, const Strin MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->style_name = p_name; } @@ -2019,7 +2037,8 @@ String TextServerAdvanced::_font_get_style_name(const RID &p_font_rid) const { MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String()); return fd->style_name; } @@ -2029,7 +2048,8 @@ void TextServerAdvanced::_font_set_weight(const RID &p_font_rid, int64_t p_weigh MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->weight = CLAMP(p_weight, 100, 999); } @@ -2039,7 +2059,8 @@ int64_t TextServerAdvanced::_font_get_weight(const RID &p_font_rid) const { MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 400); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 400); return fd->weight; } @@ -2049,7 +2070,8 @@ void TextServerAdvanced::_font_set_stretch(const RID &p_font_rid, int64_t p_stre MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->stretch = CLAMP(p_stretch, 50, 200); } @@ -2059,7 +2081,8 @@ int64_t TextServerAdvanced::_font_get_stretch(const RID &p_font_rid) const { MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 100); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 100); return fd->stretch; } @@ -2069,7 +2092,8 @@ void TextServerAdvanced::_font_set_name(const RID &p_font_rid, const String &p_n MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->font_name = p_name; } @@ -2079,7 +2103,8 @@ String TextServerAdvanced::_font_get_name(const RID &p_font_rid) const { MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String()); return fd->font_name; } @@ -2089,9 +2114,10 @@ Dictionary TextServerAdvanced::_font_get_ot_name_strings(const RID &p_font_rid) MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary()); - hb_face_t *hb_face = hb_font_get_face(fd->cache[size]->hb_handle); + hb_face_t *hb_face = hb_font_get_face(ffsd->hb_handle); unsigned int num_entries = 0; const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries); @@ -2599,8 +2625,9 @@ void TextServerAdvanced::_font_set_ascent(const RID &p_font_rid, int64_t p_size, MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->ascent = p_ascent; + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->ascent = p_ascent; } double TextServerAdvanced::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const { @@ -2610,18 +2637,19 @@ double TextServerAdvanced::_font_get_ascent(const RID &p_font_rid, int64_t p_siz MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0); if (fd->msdf) { - return fd->cache[size]->ascent * (double)p_size / (double)fd->msdf_source_size; + return ffsd->ascent * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return fd->cache[size]->ascent * (double)p_size / (double)fd->fixed_size; + return ffsd->ascent * (double)p_size / (double)fd->fixed_size; } else { - return fd->cache[size]->ascent * Math::round((double)p_size / (double)fd->fixed_size); + return ffsd->ascent * Math::round((double)p_size / (double)fd->fixed_size); } } else { - return fd->cache[size]->ascent; + return ffsd->ascent; } } @@ -2631,8 +2659,9 @@ void TextServerAdvanced::_font_set_descent(const RID &p_font_rid, int64_t p_size Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->descent = p_descent; + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->descent = p_descent; } double TextServerAdvanced::_font_get_descent(const RID &p_font_rid, int64_t p_size) const { @@ -2642,18 +2671,19 @@ double TextServerAdvanced::_font_get_descent(const RID &p_font_rid, int64_t p_si MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0); if (fd->msdf) { - return fd->cache[size]->descent * (double)p_size / (double)fd->msdf_source_size; + return ffsd->descent * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return fd->cache[size]->descent * (double)p_size / (double)fd->fixed_size; + return ffsd->descent * (double)p_size / (double)fd->fixed_size; } else { - return fd->cache[size]->descent * Math::round((double)p_size / (double)fd->fixed_size); + return ffsd->descent * Math::round((double)p_size / (double)fd->fixed_size); } } else { - return fd->cache[size]->descent; + return ffsd->descent; } } @@ -2664,8 +2694,9 @@ void TextServerAdvanced::_font_set_underline_position(const RID &p_font_rid, int MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->underline_position = p_underline_position; + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->underline_position = p_underline_position; } double TextServerAdvanced::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const { @@ -2675,18 +2706,19 @@ double TextServerAdvanced::_font_get_underline_position(const RID &p_font_rid, i MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0); if (fd->msdf) { - return fd->cache[size]->underline_position * (double)p_size / (double)fd->msdf_source_size; + return ffsd->underline_position * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return fd->cache[size]->underline_position * (double)p_size / (double)fd->fixed_size; + return ffsd->underline_position * (double)p_size / (double)fd->fixed_size; } else { - return fd->cache[size]->underline_position * Math::round((double)p_size / (double)fd->fixed_size); + return ffsd->underline_position * Math::round((double)p_size / (double)fd->fixed_size); } } else { - return fd->cache[size]->underline_position; + return ffsd->underline_position; } } @@ -2697,8 +2729,9 @@ void TextServerAdvanced::_font_set_underline_thickness(const RID &p_font_rid, in MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->underline_thickness = p_underline_thickness; + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->underline_thickness = p_underline_thickness; } double TextServerAdvanced::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const { @@ -2708,18 +2741,19 @@ double TextServerAdvanced::_font_get_underline_thickness(const RID &p_font_rid, MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0); if (fd->msdf) { - return fd->cache[size]->underline_thickness * (double)p_size / (double)fd->msdf_source_size; + return ffsd->underline_thickness * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return fd->cache[size]->underline_thickness * (double)p_size / (double)fd->fixed_size; + return ffsd->underline_thickness * (double)p_size / (double)fd->fixed_size; } else { - return fd->cache[size]->underline_thickness * Math::round((double)p_size / (double)fd->fixed_size); + return ffsd->underline_thickness * Math::round((double)p_size / (double)fd->fixed_size); } } else { - return fd->cache[size]->underline_thickness; + return ffsd->underline_thickness; } } @@ -2730,13 +2764,15 @@ void TextServerAdvanced::_font_set_scale(const RID &p_font_rid, int64_t p_size, MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face) { + if (ffsd->face) { return; // Do not override scale for dynamic fonts, it's calculated automatically. } #endif - fd->cache[size]->scale = p_scale; + ffsd->scale = p_scale; } double TextServerAdvanced::_font_get_scale(const RID &p_font_rid, int64_t p_size) const { @@ -2746,18 +2782,19 @@ double TextServerAdvanced::_font_get_scale(const RID &p_font_rid, int64_t p_size MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0); if (fd->msdf) { - return fd->cache[size]->scale * (double)p_size / (double)fd->msdf_source_size; + return ffsd->scale * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return fd->cache[size]->scale * (double)p_size / (double)fd->fixed_size; + return ffsd->scale * (double)p_size / (double)fd->fixed_size; } else { - return fd->cache[size]->scale * Math::round((double)p_size / (double)fd->fixed_size); + return ffsd->scale * Math::round((double)p_size / (double)fd->fixed_size); } } else { - return fd->cache[size]->scale / fd->cache[size]->oversampling; + return ffsd->scale / ffsd->oversampling; } } @@ -2768,9 +2805,10 @@ int64_t TextServerAdvanced::_font_get_texture_count(const RID &p_font_rid, const MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0); - return fd->cache[size]->textures.size(); + return ffsd->textures.size(); } void TextServerAdvanced::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) { @@ -2779,8 +2817,9 @@ void TextServerAdvanced::_font_clear_textures(const RID &p_font_rid, const Vecto MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->textures.clear(); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->textures.clear(); } void TextServerAdvanced::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) { @@ -2789,10 +2828,11 @@ void TextServerAdvanced::_font_remove_texture(const RID &p_font_rid, const Vecto MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - ERR_FAIL_INDEX(p_texture_index, fd->cache[size]->textures.size()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ERR_FAIL_INDEX(p_texture_index, ffsd->textures.size()); - fd->cache[size]->textures.remove_at(p_texture_index); + ffsd->textures.remove_at(p_texture_index); } void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) { @@ -2802,13 +2842,14 @@ void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Ve MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); ERR_FAIL_COND(p_texture_index < 0); - if (p_texture_index >= fd->cache[size]->textures.size()) { - fd->cache[size]->textures.resize(p_texture_index + 1); + if (p_texture_index >= ffsd->textures.size()) { + ffsd->textures.resize(p_texture_index + 1); } - ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index]; + ShelfPackTexture &tex = ffsd->textures.write[p_texture_index]; tex.image = p_image; tex.texture_w = p_image->get_width(); @@ -2829,10 +2870,11 @@ Ref<Image> TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, co MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>()); - ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Ref<Image>()); + ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), Ref<Image>()); - const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index]; + const ShelfPackTexture &tex = ffsd->textures[p_texture_index]; return tex.image; } @@ -2843,13 +2885,14 @@ void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); ERR_FAIL_COND(p_texture_index < 0); - if (p_texture_index >= fd->cache[size]->textures.size()) { - fd->cache[size]->textures.resize(p_texture_index + 1); + if (p_texture_index >= ffsd->textures.size()) { + ffsd->textures.resize(p_texture_index + 1); } - ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index]; + ShelfPackTexture &tex = ffsd->textures.write[p_texture_index]; tex.shelves.clear(); for (int32_t i = 0; i < p_offsets.size(); i += 4) { tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3])); @@ -2862,10 +2905,11 @@ PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array()); - ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array()); + ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), PackedInt32Array()); - const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index]; + const ShelfPackTexture &tex = ffsd->textures[p_texture_index]; PackedInt32Array ret; ret.resize(tex.shelves.size() * 4); @@ -2887,10 +2931,11 @@ PackedInt32Array TextServerAdvanced::_font_get_glyph_list(const RID &p_font_rid, MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array()); PackedInt32Array ret; - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map; for (const KeyValue<int32_t, FontGlyph> &E : gl) { ret.push_back(E.key); } @@ -2903,9 +2948,10 @@ void TextServerAdvanced::_font_clear_glyphs(const RID &p_font_rid, const Vector2 MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - fd->cache[size]->glyph_map.clear(); + ffsd->glyph_map.clear(); } void TextServerAdvanced::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) { @@ -2914,9 +2960,10 @@ void TextServerAdvanced::_font_remove_glyph(const RID &p_font_rid, const Vector2 MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - fd->cache[size]->glyph_map.erase(p_glyph); + ffsd->glyph_map.erase(p_glyph); } double TextServerAdvanced::_get_extra_advance(RID p_font_rid, int p_font_size) const { @@ -2940,22 +2987,22 @@ Vector2 TextServerAdvanced::_font_get_glyph_advance(const RID &p_font_rid, int64 MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - Vector2 ea; if (fd->embolden != 0.0) { ea.x = fd->embolden * double(size.x) / 64.0; @@ -2963,17 +3010,17 @@ Vector2 TextServerAdvanced::_font_get_glyph_advance(const RID &p_font_rid, int64 double scale = _font_get_scale(p_font_rid, p_size); if (fd->msdf) { - return (gl[p_glyph | mod].advance + ea) * (double)p_size / (double)fd->msdf_source_size; + return (fgl.advance + ea) * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return (gl[p_glyph | mod].advance + ea) * (double)p_size / (double)fd->fixed_size; + return (fgl.advance + ea) * (double)p_size / (double)fd->fixed_size; } else { - return (gl[p_glyph | mod].advance + ea) * Math::round((double)p_size / (double)fd->fixed_size); + return (fgl.advance + ea) * Math::round((double)p_size / (double)fd->fixed_size); } } else if ((scale == 1.0) && ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE))) { - return (gl[p_glyph | mod].advance + ea).round(); + return (fgl.advance + ea).round(); } else { - return gl[p_glyph | mod].advance + ea; + return fgl.advance + ea; } } @@ -2984,12 +3031,13 @@ void TextServerAdvanced::_font_set_glyph_advance(const RID &p_font_rid, int64_t MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + FontGlyph &fgl = ffsd->glyph_map[p_glyph]; - gl[p_glyph].advance = p_advance; - gl[p_glyph].found = true; + fgl.advance = p_advance; + fgl.found = true; } Vector2 TextServerAdvanced::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { @@ -2999,32 +3047,32 @@ Vector2 TextServerAdvanced::_font_get_glyph_offset(const RID &p_font_rid, const MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - if (fd->msdf) { - return gl[p_glyph | mod].rect.position * (double)p_size.x / (double)fd->msdf_source_size; + return fgl.rect.position * (double)p_size.x / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return gl[p_glyph | mod].rect.position * (double)p_size.x / (double)fd->fixed_size; + return fgl.rect.position * (double)p_size.x / (double)fd->fixed_size; } else { - return gl[p_glyph | mod].rect.position * Math::round((double)p_size.x / (double)fd->fixed_size); + return fgl.rect.position * Math::round((double)p_size.x / (double)fd->fixed_size); } } else { - return gl[p_glyph | mod].rect.position; + return fgl.rect.position; } } @@ -3035,12 +3083,13 @@ void TextServerAdvanced::_font_set_glyph_offset(const RID &p_font_rid, const Vec MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + FontGlyph &fgl = ffsd->glyph_map[p_glyph]; - gl[p_glyph].rect.position = p_offset; - gl[p_glyph].found = true; + fgl.rect.position = p_offset; + fgl.found = true; } Vector2 TextServerAdvanced::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { @@ -3050,32 +3099,32 @@ Vector2 TextServerAdvanced::_font_get_glyph_size(const RID &p_font_rid, const Ve MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - if (fd->msdf) { - return gl[p_glyph | mod].rect.size * (double)p_size.x / (double)fd->msdf_source_size; + return fgl.rect.size * (double)p_size.x / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return gl[p_glyph | mod].rect.size * (double)p_size.x / (double)fd->fixed_size; + return fgl.rect.size * (double)p_size.x / (double)fd->fixed_size; } else { - return gl[p_glyph | mod].rect.size * Math::round((double)p_size.x / (double)fd->fixed_size); + return fgl.rect.size * Math::round((double)p_size.x / (double)fd->fixed_size); } } else { - return gl[p_glyph | mod].rect.size; + return fgl.rect.size; } } @@ -3086,12 +3135,13 @@ void TextServerAdvanced::_font_set_glyph_size(const RID &p_font_rid, const Vecto MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + FontGlyph &fgl = ffsd->glyph_map[p_glyph]; - gl[p_glyph].rect.size = p_gl_size; - gl[p_glyph].found = true; + fgl.rect.size = p_gl_size; + fgl.found = true; } Rect2 TextServerAdvanced::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { @@ -3101,22 +3151,23 @@ Rect2 TextServerAdvanced::_font_get_glyph_uv_rect(const RID &p_font_rid, const V MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Rect2()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Rect2()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return Rect2(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - return gl[p_glyph | mod].uv_rect; + return fgl.uv_rect; } void TextServerAdvanced::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) { @@ -3126,12 +3177,13 @@ void TextServerAdvanced::_font_set_glyph_uv_rect(const RID &p_font_rid, const Ve MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + FontGlyph &fgl = ffsd->glyph_map[p_glyph]; - gl[p_glyph].uv_rect = p_uv_rect; - gl[p_glyph].found = true; + fgl.uv_rect = p_uv_rect; + fgl.found = true; } int64_t TextServerAdvanced::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { @@ -3141,22 +3193,23 @@ int64_t TextServerAdvanced::_font_get_glyph_texture_idx(const RID &p_font_rid, c MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), -1); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), -1); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return -1; // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - return gl[p_glyph | mod].texture_idx; + return fgl.texture_idx; } void TextServerAdvanced::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) { @@ -3166,12 +3219,13 @@ void TextServerAdvanced::_font_set_glyph_texture_idx(const RID &p_font_rid, cons MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + FontGlyph &fgl = ffsd->glyph_map[p_glyph]; - gl[p_glyph].texture_idx = p_texture_idx; - gl[p_glyph].found = true; + fgl.texture_idx = p_texture_idx; + fgl.found = true; } RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { @@ -3181,27 +3235,28 @@ RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), RID()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return RID(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), RID()); + ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), RID()); if (RenderingServer::get_singleton() != nullptr) { - if (gl[p_glyph | mod].texture_idx != -1) { - if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) { - ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; + if (fgl.texture_idx != -1) { + if (ffsd->textures[fgl.texture_idx].dirty) { + ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx]; Ref<Image> img = tex.image; if (fd->mipmaps && !img->has_mipmaps()) { img = tex.image->duplicate(); @@ -3214,7 +3269,7 @@ RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const } tex.dirty = false; } - return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_rid(); + return ffsd->textures[fgl.texture_idx].texture->get_rid(); } } @@ -3228,27 +3283,28 @@ Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, co MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Size2()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return Size2(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), Size2()); + ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), Size2()); if (RenderingServer::get_singleton() != nullptr) { - if (gl[p_glyph | mod].texture_idx != -1) { - if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) { - ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; + if (fgl.texture_idx != -1) { + if (ffsd->textures[fgl.texture_idx].dirty) { + ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx]; Ref<Image> img = tex.image; if (fd->mipmaps && !img->has_mipmaps()) { img = tex.image->duplicate(); @@ -3261,7 +3317,7 @@ Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, co } tex.dirty = false; } - return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_size(); + return ffsd->textures[fgl.texture_idx].texture->get_size(); } } @@ -3275,7 +3331,8 @@ Dictionary TextServerAdvanced::_font_get_glyph_contours(const RID &p_font_rid, i MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary()); #ifdef MODULE_FREETYPE_ENABLED PackedVector3Array points; @@ -3283,20 +3340,20 @@ Dictionary TextServerAdvanced::_font_get_glyph_contours(const RID &p_font_rid, i int32_t index = p_index & 0xffffff; // Remove subpixel shifts. - int error = FT_Load_Glyph(fd->cache[size]->face, index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); + int error = FT_Load_Glyph(ffsd->face, index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); ERR_FAIL_COND_V(error, Dictionary()); if (fd->embolden != 0.f) { FT_Pos strength = fd->embolden * p_size * 4; // 26.6 fractional units (1 / 64). - FT_Outline_Embolden(&fd->cache[size]->face->glyph->outline, strength); + FT_Outline_Embolden(&ffsd->face->glyph->outline, strength); } if (fd->transform != Transform2D()) { FT_Matrix mat = { FT_Fixed(fd->transform[0][0] * 65536), FT_Fixed(fd->transform[0][1] * 65536), FT_Fixed(fd->transform[1][0] * 65536), FT_Fixed(fd->transform[1][1] * 65536) }; // 16.16 fractional units (1 / 65536). - FT_Outline_Transform(&fd->cache[size]->face->glyph->outline, &mat); + FT_Outline_Transform(&ffsd->face->glyph->outline, &mat); } - double scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale; + double scale = (1.0 / 64.0) / ffsd->oversampling * ffsd->scale; if (fd->msdf) { scale = scale * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { @@ -3306,13 +3363,13 @@ Dictionary TextServerAdvanced::_font_get_glyph_contours(const RID &p_font_rid, i scale = scale * Math::round((double)p_size / (double)fd->fixed_size); } } - for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) { - points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, -fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i]))); + for (short i = 0; i < ffsd->face->glyph->outline.n_points; i++) { + points.push_back(Vector3(ffsd->face->glyph->outline.points[i].x * scale, -ffsd->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(ffsd->face->glyph->outline.tags[i]))); } - for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) { - contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]); + for (short i = 0; i < ffsd->face->glyph->outline.n_contours; i++) { + contours.push_back(ffsd->face->glyph->outline.contours[i]); } - bool orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); + bool orientation = (FT_Outline_Get_Orientation(&ffsd->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); Dictionary out; out["points"] = points; @@ -3331,7 +3388,8 @@ TypedArray<Vector2i> TextServerAdvanced::_font_get_kerning_list(const RID &p_fon MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), TypedArray<Vector2i>()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), TypedArray<Vector2i>()); TypedArray<Vector2i> ret; for (const KeyValue<Vector2i, Vector2> &E : fd->cache[size]->kerning_map) { @@ -3347,8 +3405,9 @@ void TextServerAdvanced::_font_clear_kerning_map(const RID &p_font_rid, int64_t MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->kerning_map.clear(); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->kerning_map.clear(); } void TextServerAdvanced::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) { @@ -3358,8 +3417,9 @@ void TextServerAdvanced::_font_remove_kerning(const RID &p_font_rid, int64_t p_s MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->kerning_map.erase(p_glyph_pair); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->kerning_map.erase(p_glyph_pair); } void TextServerAdvanced::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { @@ -3369,8 +3429,9 @@ void TextServerAdvanced::_font_set_kerning(const RID &p_font_rid, int64_t p_size MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning; + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->kerning_map[p_glyph_pair] = p_kerning; } Vector2 TextServerAdvanced::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const { @@ -3380,9 +3441,10 @@ Vector2 TextServerAdvanced::_font_get_kerning(const RID &p_font_rid, int64_t p_s MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2()); - const HashMap<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map; + const HashMap<Vector2i, Vector2> &kern = ffsd->kerning_map; if (kern.has(p_glyph_pair)) { if (fd->msdf) { @@ -3398,9 +3460,9 @@ Vector2 TextServerAdvanced::_font_get_kerning(const RID &p_font_rid, int64_t p_s } } else { #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face) { + if (ffsd->face) { FT_Vector delta; - FT_Get_Kerning(fd->cache[size]->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta); + FT_Get_Kerning(ffsd->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta); if (fd->msdf) { return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { @@ -3426,14 +3488,15 @@ int64_t TextServerAdvanced::_font_get_glyph_index(const RID &p_font_rid, int64_t MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0); #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face) { + if (ffsd->face) { if (p_variation_selector) { - return FT_Face_GetCharVariantIndex(fd->cache[size]->face, p_char, p_variation_selector); + return FT_Face_GetCharVariantIndex(ffsd->face, p_char, p_variation_selector); } else { - return FT_Get_Char_Index(fd->cache[size]->face, p_char); + return FT_Get_Char_Index(ffsd->face, p_char); } } else { return (int64_t)p_char; @@ -3449,23 +3512,24 @@ int64_t TextServerAdvanced::_font_get_char_from_glyph_index(const RID &p_font_ri MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0); #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->inv_glyph_map.is_empty()) { - FT_Face face = fd->cache[size]->face; + if (ffsd->inv_glyph_map.is_empty()) { + FT_Face face = ffsd->face; FT_UInt gindex; FT_ULong charcode = FT_Get_First_Char(face, &gindex); while (gindex != 0) { if (charcode != 0) { - fd->cache[size]->inv_glyph_map[gindex] = charcode; + ffsd->inv_glyph_map[gindex] = charcode; } charcode = FT_Get_Next_Char(face, charcode, &gindex); } } - if (fd->cache[size]->inv_glyph_map.has(p_glyph_index)) { - return fd->cache[size]->inv_glyph_map[p_glyph_index]; + if (ffsd->inv_glyph_map.has(p_glyph_index)) { + return ffsd->inv_glyph_map[p_glyph_index]; } else { return 0; } @@ -3482,17 +3546,19 @@ bool TextServerAdvanced::_font_has_char(const RID &p_font_rid, int64_t p_char) c } MutexLock lock(fd->mutex); + FontForSizeAdvanced *ffsd = nullptr; if (fd->cache.is_empty()) { - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), false); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0), ffsd), false); + } else { + ffsd = fd->cache.begin()->value; } - FontForSizeAdvanced *at_size = fd->cache.begin()->value; #ifdef MODULE_FREETYPE_ENABLED - if (at_size && at_size->face) { - return FT_Get_Char_Index(at_size->face, p_char) != 0; + if (ffsd->face) { + return FT_Get_Char_Index(ffsd->face, p_char) != 0; } #endif - return (at_size) ? at_size->glyph_map.has((int32_t)p_char) : false; + return ffsd->glyph_map.has((int32_t)p_char); } String TextServerAdvanced::_font_get_supported_chars(const RID &p_font_rid) const { @@ -3500,30 +3566,30 @@ String TextServerAdvanced::_font_get_supported_chars(const RID &p_font_rid) cons ERR_FAIL_NULL_V(fd, String()); MutexLock lock(fd->mutex); + FontForSizeAdvanced *ffsd = nullptr; if (fd->cache.is_empty()) { - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), String()); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0), ffsd), String()); + } else { + ffsd = fd->cache.begin()->value; } - FontForSizeAdvanced *at_size = fd->cache.begin()->value; String chars; #ifdef MODULE_FREETYPE_ENABLED - if (at_size && at_size->face) { + if (ffsd->face) { FT_UInt gindex; - FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex); + FT_ULong charcode = FT_Get_First_Char(ffsd->face, &gindex); while (gindex != 0) { if (charcode != 0) { chars = chars + String::chr(charcode); } - charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex); + charcode = FT_Get_Next_Char(ffsd->face, charcode, &gindex); } return chars; } #endif - if (at_size) { - const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map; - for (const KeyValue<int32_t, FontGlyph> &E : gl) { - chars = chars + String::chr(E.key); - } + const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map; + for (const KeyValue<int32_t, FontGlyph> &E : gl) { + chars = chars + String::chr(E.key); } return chars; } @@ -3533,10 +3599,12 @@ PackedInt32Array TextServerAdvanced::_font_get_supported_glyphs(const RID &p_fon ERR_FAIL_NULL_V(fd, PackedInt32Array()); MutexLock lock(fd->mutex); + FontForSizeAdvanced *at_size = nullptr; if (fd->cache.is_empty()) { - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), PackedInt32Array()); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0), at_size), PackedInt32Array()); + } else { + at_size = fd->cache.begin()->value; } - FontForSizeAdvanced *at_size = fd->cache.begin()->value; PackedInt32Array glyphs; #ifdef MODULE_FREETYPE_ENABLED @@ -3567,25 +3635,27 @@ void TextServerAdvanced::_font_render_range(const RID &p_font_rid, const Vector2 MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); for (int64_t i = p_start; i <= p_end; i++) { #ifdef MODULE_FREETYPE_ENABLED - int32_t idx = FT_Get_Char_Index(fd->cache[size]->face, i); - if (fd->cache[size]->face) { + int32_t idx = FT_Get_Char_Index(ffsd->face, i); + if (ffsd->face) { + FontGlyph fgl; if (fd->msdf) { - _ensure_glyph(fd, size, (int32_t)idx); + _ensure_glyph(fd, size, (int32_t)idx, fgl); } else { for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) { if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl); } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl); } else { - _ensure_glyph(fd, size, (int32_t)idx | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl); } } } @@ -3600,24 +3670,26 @@ void TextServerAdvanced::_font_render_glyph(const RID &p_font_rid, const Vector2 MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); #ifdef MODULE_FREETYPE_ENABLED int32_t idx = p_index & 0xffffff; // Remove subpixel shifts. - if (fd->cache[size]->face) { + if (ffsd->face) { + FontGlyph fgl; if (fd->msdf) { - _ensure_glyph(fd, size, (int32_t)idx); + _ensure_glyph(fd, size, (int32_t)idx, fgl); } else { for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) { if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl); } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl); } else { - _ensure_glyph(fd, size, (int32_t)idx | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl); } } } @@ -3634,16 +3706,17 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); int32_t index = p_index & 0xffffff; // Remove subpixel shifts. bool lcd_aa = false; #ifdef MODULE_FREETYPE_ENABLED - if (!fd->msdf && fd->cache[size]->face) { + if (!fd->msdf && ffsd->face) { // LCD layout, bits 24, 25, 26 if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { lcd_aa = true; index = index | (layout << 24); @@ -3660,24 +3733,24 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca } #endif - if (!_ensure_glyph(fd, size, index)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, index, fgl)) { return; // Invalid or non-graphical glyph, do not display errors, nothing to draw. } - const FontGlyph &gl = fd->cache[size]->glyph_map[index]; - if (gl.found) { - ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); + if (fgl.found) { + ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size()); - if (gl.texture_idx != -1) { + if (fgl.texture_idx != -1) { Color modulate = p_color; #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { + if (ffsd->face && ffsd->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { modulate.r = modulate.g = modulate.b = 1.0; } #endif if (RenderingServer::get_singleton() != nullptr) { - if (fd->cache[size]->textures[gl.texture_idx].dirty) { - ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + if (ffsd->textures[fgl.texture_idx].dirty) { + ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx]; Ref<Image> img = tex.image; if (fd->mipmaps && !img->has_mipmaps()) { img = tex.image->duplicate(); @@ -3690,12 +3763,12 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca } tex.dirty = false; } - RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); + RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; - cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; - Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; - RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); + cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size; + Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size; + RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); } else { double scale = _font_get_scale(p_font_rid, p_size); Point2 cpos = p_pos; @@ -3708,8 +3781,8 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca cpos.y = Math::floor(cpos.y); cpos.x = Math::floor(cpos.x); } - Vector2 gpos = gl.rect.position; - Size2 csize = gl.rect.size; + Vector2 gpos = fgl.rect.position; + Size2 csize = fgl.rect.size; if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { double gl_scale = (double)p_size / (double)fd->fixed_size; @@ -3723,9 +3796,9 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca } cpos += gpos; if (lcd_aa) { - RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate); + RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate); } else { - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false); } } } @@ -3742,16 +3815,17 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, Vector2i(p_size, p_outline_size)); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); int32_t index = p_index & 0xffffff; // Remove subpixel shifts. bool lcd_aa = false; #ifdef MODULE_FREETYPE_ENABLED - if (!fd->msdf && fd->cache[size]->face) { + if (!fd->msdf && ffsd->face) { // LCD layout, bits 24, 25, 26 if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { lcd_aa = true; index = index | (layout << 24); @@ -3768,24 +3842,24 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R } #endif - if (!_ensure_glyph(fd, size, index)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, index, fgl)) { return; // Invalid or non-graphical glyph, do not display errors, nothing to draw. } - const FontGlyph &gl = fd->cache[size]->glyph_map[index]; - if (gl.found) { - ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); + if (fgl.found) { + ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size()); - if (gl.texture_idx != -1) { + if (fgl.texture_idx != -1) { Color modulate = p_color; #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { + if (ffsd->face && fd->cache[size]->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { modulate.r = modulate.g = modulate.b = 1.0; } #endif if (RenderingServer::get_singleton() != nullptr) { - if (fd->cache[size]->textures[gl.texture_idx].dirty) { - ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + if (ffsd->textures[fgl.texture_idx].dirty) { + ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx]; Ref<Image> img = tex.image; if (fd->mipmaps && !img->has_mipmaps()) { img = tex.image->duplicate(); @@ -3798,12 +3872,12 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R } tex.dirty = false; } - RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); + RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; - cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; - Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; - RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); + cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size; + Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size; + RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); } else { Point2 cpos = p_pos; double scale = _font_get_scale(p_font_rid, p_size); @@ -3816,8 +3890,8 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R cpos.y = Math::floor(cpos.y); cpos.x = Math::floor(cpos.x); } - Vector2 gpos = gl.rect.position; - Size2 csize = gl.rect.size; + Vector2 gpos = fgl.rect.position; + Size2 csize = fgl.rect.size; if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { double gl_scale = (double)p_size / (double)fd->fixed_size; @@ -3831,9 +3905,9 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R } cpos += gpos; if (lcd_aa) { - RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate); + RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate); } else { - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false); } } } @@ -3898,7 +3972,8 @@ bool TextServerAdvanced::_font_is_script_supported(const RID &p_font_rid, const return fd->script_support_overrides[p_script]; } else { Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), false); return fd->supported_scripts.has(hb_tag_from_string(p_script.ascii().get_data(), -1)); } } @@ -3945,7 +4020,8 @@ void TextServerAdvanced::_font_set_opentype_feature_overrides(const RID &p_font_ MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->feature_overrides = p_overrides; } @@ -3963,7 +4039,8 @@ Dictionary TextServerAdvanced::_font_supported_feature_list(const RID &p_font_ri MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary()); return fd->supported_features; } @@ -3973,7 +4050,8 @@ Dictionary TextServerAdvanced::_font_supported_variation_list(const RID &p_font_ MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary()); + FontForSizeAdvanced *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary()); return fd->supported_varaitions; } @@ -4048,7 +4126,7 @@ int64_t TextServerAdvanced::_convert_pos_inv(const ShapedTextDataAdvanced *p_sd, } void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *p_shaped, bool p_text) { - p_shaped->valid = false; + p_shaped->valid.clear(); p_shaped->sort_valid = false; p_shaped->line_breaks_valid = false; p_shaped->justification_ops_valid = false; @@ -4404,7 +4482,7 @@ bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const V sd->objects[p_key].rect.size = p_size; sd->objects[p_key].inline_align = p_inline_align; sd->objects[p_key].baseline = p_baseline; - if (sd->valid) { + if (sd->valid.is_set()) { // Recalc string metrics. sd->ascent = 0; sd->descent = 0; @@ -4548,7 +4626,7 @@ RID TextServerAdvanced::_shaped_text_substr(const RID &p_shaped, int64_t p_start if (sd->parent != RID()) { return _shaped_text_substr(sd->parent, p_start, p_length); } - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID()); @@ -4576,7 +4654,7 @@ RID TextServerAdvanced::_shaped_text_substr(const RID &p_shaped, int64_t p_start } bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const { - if (p_new_sd->valid) { + if (p_new_sd->valid.is_set()) { return true; } @@ -4725,7 +4803,7 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S _realign(p_new_sd); } - p_new_sd->valid = true; + p_new_sd->valid.set(); return true; } @@ -4743,7 +4821,7 @@ double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } if (!sd->justification_ops_valid) { @@ -4900,7 +4978,7 @@ double TextServerAdvanced::_shaped_text_tab_align(const RID &p_shaped, const Pac ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } if (!sd->line_breaks_valid) { @@ -5117,7 +5195,7 @@ void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ ERR_FAIL_NULL_MSG(sd, "ShapedTextDataAdvanced invalid."); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { _shaped_text_shape(p_shaped_line); } @@ -5144,7 +5222,7 @@ void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ Vector<ShapedTextDataAdvanced::Span> &spans = sd->spans; if (sd->parent != RID()) { ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent); - ERR_FAIL_COND(!parent_sd->valid); + ERR_FAIL_COND(!parent_sd->valid.is_set()); spans = parent_sd->spans; } @@ -5355,7 +5433,7 @@ void TextServerAdvanced::_update_chars(ShapedTextDataAdvanced *p_sd) const { Vector<ShapedTextDataAdvanced::Span> &spans = p_sd->spans; if (p_sd->parent != RID()) { ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(p_sd->parent); - ERR_FAIL_COND(!parent_sd->valid); + ERR_FAIL_COND(!parent_sd->valid.is_set()); spans = parent_sd->spans; } @@ -5403,7 +5481,7 @@ PackedInt32Array TextServerAdvanced::_shaped_text_get_character_breaks(const RID ERR_FAIL_NULL_V(sd, PackedInt32Array()); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } @@ -5417,7 +5495,7 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) { ERR_FAIL_NULL_V(sd, false); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { _shaped_text_shape(p_shaped); } @@ -5688,7 +5766,7 @@ bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shap ERR_FAIL_NULL_V(sd, false); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { _shaped_text_shape(p_shaped); } if (!sd->line_breaks_valid) { @@ -6068,7 +6146,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -6128,7 +6206,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star gl.index = glyph_info[i].codepoint; if (gl.index != 0) { - _ensure_glyph(fd, fss, gl.index | mod); + FontGlyph fgl; + _ensure_glyph(fd, fss, gl.index | mod, fgl); if (subpos) { gl.x_off = (double)glyph_pos[i].x_offset / (64.0 / scale); } else if (p_sd->orientation == ORIENTATION_HORIZONTAL) { @@ -6240,7 +6319,7 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { ERR_FAIL_NULL_V(sd, false); MutexLock lock(sd->mutex); - if (sd->valid) { + if (sd->valid.is_set()) { return true; } @@ -6248,13 +6327,13 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { if (sd->parent != RID()) { _shaped_text_shape(sd->parent); ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent); - ERR_FAIL_COND_V(!parent_sd->valid, false); + ERR_FAIL_COND_V(!parent_sd->valid.is_set(), false); ERR_FAIL_COND_V(!_shape_substr(sd, parent_sd, sd->start, sd->end - sd->start), false); return true; } if (sd->text.length() == 0) { - sd->valid = true; + sd->valid.set(); return true; } @@ -6447,16 +6526,16 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { } _realign(sd); - sd->valid = true; - return sd->valid; + sd->valid.set(); + return sd->valid.is_set(); } bool TextServerAdvanced::_shaped_text_is_ready(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_NULL_V(sd, false); - MutexLock lock(sd->mutex); - return sd->valid; + // Atomic read is safe and faster. + return sd->valid.is_set(); } const Glyph *TextServerAdvanced::_shaped_text_get_glyphs(const RID &p_shaped) const { @@ -6464,7 +6543,7 @@ const Glyph *TextServerAdvanced::_shaped_text_get_glyphs(const RID &p_shaped) co ERR_FAIL_NULL_V(sd, nullptr); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->glyphs.ptr(); @@ -6475,7 +6554,7 @@ int64_t TextServerAdvanced::_shaped_text_get_glyph_count(const RID &p_shaped) co ERR_FAIL_NULL_V(sd, 0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->glyphs.size(); @@ -6486,7 +6565,7 @@ const Glyph *TextServerAdvanced::_shaped_text_sort_logical(const RID &p_shaped) ERR_FAIL_NULL_V(sd, nullptr); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } @@ -6526,7 +6605,7 @@ Rect2 TextServerAdvanced::_shaped_text_get_object_rect(const RID &p_shaped, cons MutexLock lock(sd->mutex); ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2()); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->objects[p_key].rect; @@ -6547,7 +6626,7 @@ int64_t TextServerAdvanced::_shaped_text_get_object_glyph(const RID &p_shaped, c MutexLock lock(sd->mutex); ERR_FAIL_COND_V(!sd->objects.has(p_key), -1); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } const ShapedTextDataAdvanced::EmbeddedObject &obj = sd->objects[p_key]; @@ -6566,7 +6645,7 @@ Size2 TextServerAdvanced::_shaped_text_get_size(const RID &p_shaped) const { ERR_FAIL_NULL_V(sd, Size2()); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) { @@ -6581,7 +6660,7 @@ double TextServerAdvanced::_shaped_text_get_ascent(const RID &p_shaped) const { ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->ascent + sd->extra_spacing[SPACING_TOP]; @@ -6592,7 +6671,7 @@ double TextServerAdvanced::_shaped_text_get_descent(const RID &p_shaped) const { ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->descent + sd->extra_spacing[SPACING_BOTTOM]; @@ -6603,7 +6682,7 @@ double TextServerAdvanced::_shaped_text_get_width(const RID &p_shaped) const { ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return Math::ceil(sd->text_trimmed ? sd->width_trimmed : sd->width); @@ -6614,7 +6693,7 @@ double TextServerAdvanced::_shaped_text_get_underline_position(const RID &p_shap ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } @@ -6626,7 +6705,7 @@ double TextServerAdvanced::_shaped_text_get_underline_thickness(const RID &p_sha ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } @@ -7424,10 +7503,15 @@ bool TextServerAdvanced::_is_valid_letter(uint64_t p_unicode) const { return u_isalpha(p_unicode); } +void TextServerAdvanced::_update_settings() { + lcd_subpixel_layout.set((TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout")); +} + TextServerAdvanced::TextServerAdvanced() { _insert_num_systems_lang(); _insert_feature_sets(); _bmp_create_font_funcs(); + ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &TextServerAdvanced::_update_settings)); } void TextServerAdvanced::_cleanup() { diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index fdebb8e4cd..448be9ebe4 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -74,6 +74,7 @@ #include <godot_cpp/templates/hash_map.hpp> #include <godot_cpp/templates/hash_set.hpp> #include <godot_cpp/templates/rid_owner.hpp> +#include <godot_cpp/templates/safe_refcount.hpp> #include <godot_cpp/templates/vector.hpp> using namespace godot; @@ -85,6 +86,7 @@ using namespace godot; #include "core/object/worker_thread_pool.h" #include "core/templates/hash_map.h" #include "core/templates/rid_owner.h" +#include "core/templates/safe_refcount.h" #include "scene/resources/image_texture.h" #include "servers/text/text_server_extension.h" @@ -151,6 +153,9 @@ class TextServerAdvanced : public TextServerExtension { HashMap<StringName, int32_t> feature_sets; HashMap<int32_t, FeatureInfo> feature_sets_inv; + SafeNumeric<TextServer::FontLCDSubpixelLayout> lcd_subpixel_layout{ TextServer::FontLCDSubpixelLayout::FONT_LCD_SUBPIXEL_LAYOUT_NONE }; + void _update_settings(); + void _insert_num_systems_lang(); void _insert_feature_sets(); _FORCE_INLINE_ void _insert_feature(const StringName &p_name, int32_t p_tag, Variant::Type p_vtype = Variant::INT, bool p_hidden = false); @@ -327,7 +332,7 @@ class TextServerAdvanced : public TextServerExtension { int extra_spacing[4] = { 0, 0, 0, 0 }; double baseline_offset = 0.0; - HashMap<Vector2i, FontForSizeAdvanced *, VariantHasher, VariantComparator> cache; + HashMap<Vector2i, FontForSizeAdvanced *> cache; bool face_init = false; HashSet<uint32_t> supported_scripts; @@ -359,8 +364,8 @@ class TextServerAdvanced : public TextServerExtension { #ifdef MODULE_FREETYPE_ENABLED _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap p_bitmap, int p_yofs, int p_xofs, const Vector2 &p_advance, bool p_bgra) const; #endif - _FORCE_INLINE_ bool _ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const; - _FORCE_INLINE_ bool _ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size) const; + _FORCE_INLINE_ bool _ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph, FontGlyph &r_glyph) const; + _FORCE_INLINE_ bool _ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size, FontForSizeAdvanced *&r_cache_for_size) const; _FORCE_INLINE_ void _font_clear_cache(FontAdvanced *p_font_data); static void _generateMTSDF_threaded(void *p_td, uint32_t p_y); @@ -487,7 +492,7 @@ class TextServerAdvanced : public TextServerExtension { /* Shaped data */ TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction. int base_para_direction = UBIDI_DEFAULT_LTR; - bool valid = false; // String is shaped. + SafeFlag valid{ false }; // String is shaped. bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted). bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string. bool sort_valid = false; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index a7ddfc719e..540ba19cac 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -624,18 +624,21 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma /* Font Cache */ /*************************************************************************/ -_FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph) const { - ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size), false); +_FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph, FontGlyph &r_glyph) const { + FontForSizeFallback *fd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size, fd), false); int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts. - FontForSizeFallback *fd = p_font_data->cache[p_size]; - if (fd->glyph_map.has(p_glyph)) { - return fd->glyph_map[p_glyph].found; + HashMap<int32_t, FontGlyph>::Iterator E = fd->glyph_map.find(p_glyph); + if (E) { + r_glyph = E->value; + return E->value.found; } if (glyph_index == 0) { // Non graphical or invalid glyph, do not render. - fd->glyph_map[p_glyph] = FontGlyph(); + E = fd->glyph_map.insert(p_glyph, FontGlyph()); + r_glyph = E->value; return true; } @@ -673,7 +676,8 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data, int error = FT_Load_Glyph(fd->face, glyph_index, flags); if (error) { - fd->glyph_map[p_glyph] = FontGlyph(); + E = fd->glyph_map.insert(p_glyph, FontGlyph()); + r_glyph = E->value; return false; } @@ -777,20 +781,26 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data, cleanup_stroker: FT_Stroker_Done(stroker); } - fd->glyph_map[p_glyph] = gl; + E = fd->glyph_map.insert(p_glyph, gl); + r_glyph = E->value; return gl.found; } #endif - fd->glyph_map[p_glyph] = FontGlyph(); + E = fd->glyph_map.insert(p_glyph, FontGlyph()); + r_glyph = E->value; return false; } -_FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size) const { +_FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size, FontForSizeFallback *&r_cache_for_size) const { ERR_FAIL_COND_V(p_size.x <= 0, false); - if (p_font_data->cache.has(p_size)) { + + HashMap<Vector2i, FontForSizeFallback *>::Iterator E = p_font_data->cache.find(p_size); + if (E) { + r_cache_for_size = E->value; return true; } + r_cache_for_size = nullptr; FontForSizeFallback *fd = memnew(FontForSizeFallback); fd->size = p_size; if (p_font_data->data_ptr && (p_font_data->data_size > 0)) { @@ -973,7 +983,9 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!"); #endif } - p_font_data->cache[p_size] = fd; + + p_font_data->cache.insert(p_size, fd); + r_cache_for_size = fd; return true; } @@ -1041,7 +1053,8 @@ void TextServerFallback::_font_set_style(const RID &p_font_rid, BitField<FontSty MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->style_flags = p_style; } @@ -1119,7 +1132,8 @@ BitField<TextServer::FontStyle> TextServerFallback::_font_get_style(const RID &p MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0); return fd->style_flags; } @@ -1129,7 +1143,8 @@ void TextServerFallback::_font_set_style_name(const RID &p_font_rid, const Strin MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->style_name = p_name; } @@ -1139,7 +1154,8 @@ String TextServerFallback::_font_get_style_name(const RID &p_font_rid) const { MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String()); return fd->style_name; } @@ -1149,7 +1165,8 @@ void TextServerFallback::_font_set_weight(const RID &p_font_rid, int64_t p_weigh MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->weight = CLAMP(p_weight, 100, 999); } @@ -1159,7 +1176,8 @@ int64_t TextServerFallback::_font_get_weight(const RID &p_font_rid) const { MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 400); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 400); return fd->weight; } @@ -1169,7 +1187,8 @@ void TextServerFallback::_font_set_stretch(const RID &p_font_rid, int64_t p_stre MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->stretch = CLAMP(p_stretch, 50, 200); } @@ -1179,7 +1198,8 @@ int64_t TextServerFallback::_font_get_stretch(const RID &p_font_rid) const { MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 100); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 100); return fd->stretch; } @@ -1189,7 +1209,8 @@ void TextServerFallback::_font_set_name(const RID &p_font_rid, const String &p_n MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->font_name = p_name; } @@ -1199,7 +1220,8 @@ String TextServerFallback::_font_get_name(const RID &p_font_rid) const { MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String()); return fd->font_name; } @@ -1607,8 +1629,9 @@ void TextServerFallback::_font_set_ascent(const RID &p_font_rid, int64_t p_size, MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->ascent = p_ascent; + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->ascent = p_ascent; } double TextServerFallback::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const { @@ -1618,18 +1641,19 @@ double TextServerFallback::_font_get_ascent(const RID &p_font_rid, int64_t p_siz MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0); if (fd->msdf) { - return fd->cache[size]->ascent * (double)p_size / (double)fd->msdf_source_size; + return ffsd->ascent * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return fd->cache[size]->ascent * (double)p_size / (double)fd->fixed_size; + return ffsd->ascent * (double)p_size / (double)fd->fixed_size; } else { - return fd->cache[size]->ascent * Math::round((double)p_size / (double)fd->fixed_size); + return ffsd->ascent * Math::round((double)p_size / (double)fd->fixed_size); } } else { - return fd->cache[size]->ascent; + return ffsd->ascent; } } @@ -1639,8 +1663,9 @@ void TextServerFallback::_font_set_descent(const RID &p_font_rid, int64_t p_size Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->descent = p_descent; + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->descent = p_descent; } double TextServerFallback::_font_get_descent(const RID &p_font_rid, int64_t p_size) const { @@ -1650,18 +1675,19 @@ double TextServerFallback::_font_get_descent(const RID &p_font_rid, int64_t p_si MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0); if (fd->msdf) { - return fd->cache[size]->descent * (double)p_size / (double)fd->msdf_source_size; + return ffsd->descent * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return fd->cache[size]->descent * (double)p_size / (double)fd->fixed_size; + return ffsd->descent * (double)p_size / (double)fd->fixed_size; } else { - return fd->cache[size]->descent * Math::round((double)p_size / (double)fd->fixed_size); + return ffsd->descent * Math::round((double)p_size / (double)fd->fixed_size); } } else { - return fd->cache[size]->descent; + return ffsd->descent; } } @@ -1672,8 +1698,9 @@ void TextServerFallback::_font_set_underline_position(const RID &p_font_rid, int MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->underline_position = p_underline_position; + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->underline_position = p_underline_position; } double TextServerFallback::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const { @@ -1683,18 +1710,19 @@ double TextServerFallback::_font_get_underline_position(const RID &p_font_rid, i MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0); if (fd->msdf) { - return fd->cache[size]->underline_position * (double)p_size / (double)fd->msdf_source_size; + return ffsd->underline_position * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return fd->cache[size]->underline_position * (double)p_size / (double)fd->fixed_size; + return ffsd->underline_position * (double)p_size / (double)fd->fixed_size; } else { - return fd->cache[size]->underline_position * Math::round((double)p_size / (double)fd->fixed_size); + return ffsd->underline_position * Math::round((double)p_size / (double)fd->fixed_size); } } else { - return fd->cache[size]->underline_position; + return ffsd->underline_position; } } @@ -1705,8 +1733,9 @@ void TextServerFallback::_font_set_underline_thickness(const RID &p_font_rid, in MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->underline_thickness = p_underline_thickness; + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->underline_thickness = p_underline_thickness; } double TextServerFallback::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const { @@ -1716,18 +1745,19 @@ double TextServerFallback::_font_get_underline_thickness(const RID &p_font_rid, MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0); if (fd->msdf) { - return fd->cache[size]->underline_thickness * (double)p_size / (double)fd->msdf_source_size; + return ffsd->underline_thickness * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return fd->cache[size]->underline_thickness * (double)p_size / (double)fd->fixed_size; + return ffsd->underline_thickness * (double)p_size / (double)fd->fixed_size; } else { - return fd->cache[size]->underline_thickness * Math::round((double)p_size / (double)fd->fixed_size); + return ffsd->underline_thickness * Math::round((double)p_size / (double)fd->fixed_size); } } else { - return fd->cache[size]->underline_thickness; + return ffsd->underline_thickness; } } @@ -1738,13 +1768,14 @@ void TextServerFallback::_font_set_scale(const RID &p_font_rid, int64_t p_size, MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face) { + if (ffsd->face) { return; // Do not override scale for dynamic fonts, it's calculated automatically. } #endif - fd->cache[size]->scale = p_scale; + ffsd->scale = p_scale; } double TextServerFallback::_font_get_scale(const RID &p_font_rid, int64_t p_size) const { @@ -1754,18 +1785,19 @@ double TextServerFallback::_font_get_scale(const RID &p_font_rid, int64_t p_size MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0); if (fd->msdf) { - return fd->cache[size]->scale * (double)p_size / (double)fd->msdf_source_size; + return ffsd->scale * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return fd->cache[size]->scale * (double)p_size / (double)fd->fixed_size; + return ffsd->scale * (double)p_size / (double)fd->fixed_size; } else { - return fd->cache[size]->scale * Math::round((double)p_size / (double)fd->fixed_size); + return ffsd->scale * Math::round((double)p_size / (double)fd->fixed_size); } } else { - return fd->cache[size]->scale / fd->cache[size]->oversampling; + return ffsd->scale / ffsd->oversampling; } } @@ -1776,9 +1808,10 @@ int64_t TextServerFallback::_font_get_texture_count(const RID &p_font_rid, const MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0); - return fd->cache[size]->textures.size(); + return ffsd->textures.size(); } void TextServerFallback::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) { @@ -1787,8 +1820,9 @@ void TextServerFallback::_font_clear_textures(const RID &p_font_rid, const Vecto MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->textures.clear(); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->textures.clear(); } void TextServerFallback::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) { @@ -1797,10 +1831,11 @@ void TextServerFallback::_font_remove_texture(const RID &p_font_rid, const Vecto MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - ERR_FAIL_INDEX(p_texture_index, fd->cache[size]->textures.size()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ERR_FAIL_INDEX(p_texture_index, ffsd->textures.size()); - fd->cache[size]->textures.remove_at(p_texture_index); + ffsd->textures.remove_at(p_texture_index); } void TextServerFallback::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) { @@ -1810,13 +1845,14 @@ void TextServerFallback::_font_set_texture_image(const RID &p_font_rid, const Ve MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); ERR_FAIL_COND(p_texture_index < 0); - if (p_texture_index >= fd->cache[size]->textures.size()) { - fd->cache[size]->textures.resize(p_texture_index + 1); + if (p_texture_index >= ffsd->textures.size()) { + ffsd->textures.resize(p_texture_index + 1); } - ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index]; + ShelfPackTexture &tex = ffsd->textures.write[p_texture_index]; tex.image = p_image; tex.texture_w = p_image->get_width(); @@ -1837,10 +1873,11 @@ Ref<Image> TextServerFallback::_font_get_texture_image(const RID &p_font_rid, co MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>()); - ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Ref<Image>()); + ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), Ref<Image>()); - const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index]; + const ShelfPackTexture &tex = ffsd->textures[p_texture_index]; return tex.image; } @@ -1851,13 +1888,14 @@ void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); ERR_FAIL_COND(p_texture_index < 0); - if (p_texture_index >= fd->cache[size]->textures.size()) { - fd->cache[size]->textures.resize(p_texture_index + 1); + if (p_texture_index >= ffsd->textures.size()) { + ffsd->textures.resize(p_texture_index + 1); } - ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index]; + ShelfPackTexture &tex = ffsd->textures.write[p_texture_index]; tex.shelves.clear(); for (int32_t i = 0; i < p_offsets.size(); i += 4) { tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3])); @@ -1870,10 +1908,11 @@ PackedInt32Array TextServerFallback::_font_get_texture_offsets(const RID &p_font MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array()); - ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array()); + ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), PackedInt32Array()); - const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index]; + const ShelfPackTexture &tex = ffsd->textures[p_texture_index]; PackedInt32Array ret; ret.resize(tex.shelves.size() * 4); @@ -1895,10 +1934,11 @@ PackedInt32Array TextServerFallback::_font_get_glyph_list(const RID &p_font_rid, MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array()); PackedInt32Array ret; - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map; for (const KeyValue<int32_t, FontGlyph> &E : gl) { ret.push_back(E.key); } @@ -1911,9 +1951,10 @@ void TextServerFallback::_font_clear_glyphs(const RID &p_font_rid, const Vector2 MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - fd->cache[size]->glyph_map.clear(); + ffsd->glyph_map.clear(); } void TextServerFallback::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) { @@ -1922,9 +1963,10 @@ void TextServerFallback::_font_remove_glyph(const RID &p_font_rid, const Vector2 MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - fd->cache[size]->glyph_map.erase(p_glyph); + ffsd->glyph_map.erase(p_glyph); } Vector2 TextServerFallback::_font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const { @@ -1934,22 +1976,22 @@ Vector2 TextServerFallback::_font_get_glyph_advance(const RID &p_font_rid, int64 MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - Vector2 ea; if (fd->embolden != 0.0) { ea.x = fd->embolden * double(size.x) / 64.0; @@ -1957,17 +1999,17 @@ Vector2 TextServerFallback::_font_get_glyph_advance(const RID &p_font_rid, int64 double scale = _font_get_scale(p_font_rid, p_size); if (fd->msdf) { - return (gl[p_glyph | mod].advance + ea) * (double)p_size / (double)fd->msdf_source_size; + return (fgl.advance + ea) * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return (gl[p_glyph | mod].advance + ea) * (double)p_size / (double)fd->fixed_size; + return (fgl.advance + ea) * (double)p_size / (double)fd->fixed_size; } else { - return (gl[p_glyph | mod].advance + ea) * Math::round((double)p_size / (double)fd->fixed_size); + return (fgl.advance + ea) * Math::round((double)p_size / (double)fd->fixed_size); } } else if ((scale == 1.0) && ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE))) { - return (gl[p_glyph | mod].advance + ea).round(); + return (fgl.advance + ea).round(); } else { - return gl[p_glyph | mod].advance + ea; + return fgl.advance + ea; } } @@ -1978,12 +2020,13 @@ void TextServerFallback::_font_set_glyph_advance(const RID &p_font_rid, int64_t MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + FontGlyph &fgl = ffsd->glyph_map[p_glyph]; - gl[p_glyph].advance = p_advance; - gl[p_glyph].found = true; + fgl.advance = p_advance; + fgl.found = true; } Vector2 TextServerFallback::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { @@ -1993,32 +2036,32 @@ Vector2 TextServerFallback::_font_get_glyph_offset(const RID &p_font_rid, const MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - if (fd->msdf) { - return gl[p_glyph | mod].rect.position * (double)p_size.x / (double)fd->msdf_source_size; + return fgl.rect.position * (double)p_size.x / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return gl[p_glyph | mod].rect.position * (double)p_size.x / (double)fd->fixed_size; + return fgl.rect.position * (double)p_size.x / (double)fd->fixed_size; } else { - return gl[p_glyph | mod].rect.position * Math::round((double)p_size.x / (double)fd->fixed_size); + return fgl.rect.position * Math::round((double)p_size.x / (double)fd->fixed_size); } } else { - return gl[p_glyph | mod].rect.position; + return fgl.rect.position; } } @@ -2029,12 +2072,13 @@ void TextServerFallback::_font_set_glyph_offset(const RID &p_font_rid, const Vec MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + FontGlyph &fgl = ffsd->glyph_map[p_glyph]; - gl[p_glyph].rect.position = p_offset; - gl[p_glyph].found = true; + fgl.rect.position = p_offset; + fgl.found = true; } Vector2 TextServerFallback::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { @@ -2044,32 +2088,32 @@ Vector2 TextServerFallback::_font_get_glyph_size(const RID &p_font_rid, const Ve MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - if (fd->msdf) { - return gl[p_glyph | mod].rect.size * (double)p_size.x / (double)fd->msdf_source_size; + return fgl.rect.size * (double)p_size.x / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { - return gl[p_glyph | mod].rect.size * (double)p_size.x / (double)fd->fixed_size; + return fgl.rect.size * (double)p_size.x / (double)fd->fixed_size; } else { - return gl[p_glyph | mod].rect.size * Math::round((double)p_size.x / (double)fd->fixed_size); + return fgl.rect.size * Math::round((double)p_size.x / (double)fd->fixed_size); } } else { - return gl[p_glyph | mod].rect.size; + return fgl.rect.size; } } @@ -2080,12 +2124,13 @@ void TextServerFallback::_font_set_glyph_size(const RID &p_font_rid, const Vecto MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + FontGlyph &fgl = ffsd->glyph_map[p_glyph]; - gl[p_glyph].rect.size = p_gl_size; - gl[p_glyph].found = true; + fgl.rect.size = p_gl_size; + fgl.found = true; } Rect2 TextServerFallback::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { @@ -2095,22 +2140,23 @@ Rect2 TextServerFallback::_font_get_glyph_uv_rect(const RID &p_font_rid, const V MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Rect2()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Rect2()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return Rect2(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - return gl[p_glyph | mod].uv_rect; + return fgl.uv_rect; } void TextServerFallback::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) { @@ -2120,12 +2166,13 @@ void TextServerFallback::_font_set_glyph_uv_rect(const RID &p_font_rid, const Ve MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + FontGlyph &fgl = ffsd->glyph_map[p_glyph]; - gl[p_glyph].uv_rect = p_uv_rect; - gl[p_glyph].found = true; + fgl.uv_rect = p_uv_rect; + fgl.found = true; } int64_t TextServerFallback::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { @@ -2135,22 +2182,23 @@ int64_t TextServerFallback::_font_get_glyph_texture_idx(const RID &p_font_rid, c MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), -1); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), -1); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return -1; // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - return gl[p_glyph | mod].texture_idx; + return fgl.texture_idx; } void TextServerFallback::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) { @@ -2160,12 +2208,13 @@ void TextServerFallback::_font_set_glyph_texture_idx(const RID &p_font_rid, cons MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); - HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + FontGlyph &fgl = ffsd->glyph_map[p_glyph]; - gl[p_glyph].texture_idx = p_texture_idx; - gl[p_glyph].found = true; + fgl.texture_idx = p_texture_idx; + fgl.found = true; } RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { @@ -2175,27 +2224,28 @@ RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), RID()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return RID(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), RID()); + ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), RID()); if (RenderingServer::get_singleton() != nullptr) { - if (gl[p_glyph | mod].texture_idx != -1) { - if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) { - ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; + if (fgl.texture_idx != -1) { + if (ffsd->textures[fgl.texture_idx].dirty) { + ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx]; Ref<Image> img = tex.image; if (fd->mipmaps && !img->has_mipmaps()) { img = tex.image->duplicate(); @@ -2208,7 +2258,7 @@ RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const } tex.dirty = false; } - return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_rid(); + return ffsd->textures[fgl.texture_idx].texture->get_rid(); } } @@ -2222,27 +2272,28 @@ Size2 TextServerFallback::_font_get_glyph_texture_size(const RID &p_font_rid, co MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Size2()); int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } } - if (!_ensure_glyph(fd, size, p_glyph | mod)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) { return Size2(); // Invalid or non graphicl glyph, do not display errors. } - const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), Size2()); + ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), Size2()); if (RenderingServer::get_singleton() != nullptr) { - if (gl[p_glyph | mod].texture_idx != -1) { - if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) { - ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; + if (fgl.texture_idx != -1) { + if (ffsd->textures[fgl.texture_idx].dirty) { + ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx]; Ref<Image> img = tex.image; if (fd->mipmaps && !img->has_mipmaps()) { img = tex.image->duplicate(); @@ -2255,7 +2306,7 @@ Size2 TextServerFallback::_font_get_glyph_texture_size(const RID &p_font_rid, co } tex.dirty = false; } - return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_size(); + return ffsd->textures[fgl.texture_idx].texture->get_size(); } } @@ -2269,7 +2320,8 @@ Dictionary TextServerFallback::_font_get_glyph_contours(const RID &p_font_rid, i MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary()); #ifdef MODULE_FREETYPE_ENABLED PackedVector3Array points; @@ -2277,20 +2329,20 @@ Dictionary TextServerFallback::_font_get_glyph_contours(const RID &p_font_rid, i int32_t index = p_index & 0xffffff; // Remove subpixel shifts. - int error = FT_Load_Glyph(fd->cache[size]->face, FT_Get_Char_Index(fd->cache[size]->face, index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); + int error = FT_Load_Glyph(ffsd->face, FT_Get_Char_Index(ffsd->face, index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); ERR_FAIL_COND_V(error, Dictionary()); if (fd->embolden != 0.f) { FT_Pos strength = fd->embolden * p_size * 4; // 26.6 fractional units (1 / 64). - FT_Outline_Embolden(&fd->cache[size]->face->glyph->outline, strength); + FT_Outline_Embolden(&ffsd->face->glyph->outline, strength); } if (fd->transform != Transform2D()) { FT_Matrix mat = { FT_Fixed(fd->transform[0][0] * 65536), FT_Fixed(fd->transform[0][1] * 65536), FT_Fixed(fd->transform[1][0] * 65536), FT_Fixed(fd->transform[1][1] * 65536) }; // 16.16 fractional units (1 / 65536). - FT_Outline_Transform(&fd->cache[size]->face->glyph->outline, &mat); + FT_Outline_Transform(&ffsd->face->glyph->outline, &mat); } - double scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale; + double scale = (1.0 / 64.0) / ffsd->oversampling * ffsd->scale; if (fd->msdf) { scale = scale * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { @@ -2300,13 +2352,13 @@ Dictionary TextServerFallback::_font_get_glyph_contours(const RID &p_font_rid, i scale = scale * Math::round((double)p_size / (double)fd->fixed_size); } } - for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) { - points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, -fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i]))); + for (short i = 0; i < ffsd->face->glyph->outline.n_points; i++) { + points.push_back(Vector3(ffsd->face->glyph->outline.points[i].x * scale, -ffsd->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(ffsd->face->glyph->outline.tags[i]))); } - for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) { - contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]); + for (short i = 0; i < ffsd->face->glyph->outline.n_contours; i++) { + contours.push_back(ffsd->face->glyph->outline.contours[i]); } - bool orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); + bool orientation = (FT_Outline_Get_Orientation(&ffsd->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); Dictionary out; out["points"] = points; @@ -2325,10 +2377,11 @@ TypedArray<Vector2i> TextServerFallback::_font_get_kerning_list(const RID &p_fon MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), TypedArray<Vector2i>()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), TypedArray<Vector2i>()); TypedArray<Vector2i> ret; - for (const KeyValue<Vector2i, Vector2> &E : fd->cache[size]->kerning_map) { + for (const KeyValue<Vector2i, Vector2> &E : ffsd->kerning_map) { ret.push_back(E.key); } return ret; @@ -2341,8 +2394,9 @@ void TextServerFallback::_font_clear_kerning_map(const RID &p_font_rid, int64_t MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->kerning_map.clear(); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->kerning_map.clear(); } void TextServerFallback::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) { @@ -2352,8 +2406,9 @@ void TextServerFallback::_font_remove_kerning(const RID &p_font_rid, int64_t p_s MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->kerning_map.erase(p_glyph_pair); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->kerning_map.erase(p_glyph_pair); } void TextServerFallback::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { @@ -2363,8 +2418,9 @@ void TextServerFallback::_font_set_kerning(const RID &p_font_rid, int64_t p_size MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning; + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); + ffsd->kerning_map[p_glyph_pair] = p_kerning; } Vector2 TextServerFallback::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const { @@ -2374,9 +2430,10 @@ Vector2 TextServerFallback::_font_get_kerning(const RID &p_font_rid, int64_t p_s MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2()); - const HashMap<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map; + const HashMap<Vector2i, Vector2> &kern = ffsd->kerning_map; if (kern.has(p_glyph_pair)) { if (fd->msdf) { @@ -2392,11 +2449,11 @@ Vector2 TextServerFallback::_font_get_kerning(const RID &p_font_rid, int64_t p_s } } else { #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face) { + if (ffsd->face) { FT_Vector delta; - int32_t glyph_a = FT_Get_Char_Index(fd->cache[size]->face, p_glyph_pair.x); - int32_t glyph_b = FT_Get_Char_Index(fd->cache[size]->face, p_glyph_pair.y); - FT_Get_Kerning(fd->cache[size]->face, glyph_a, glyph_b, FT_KERNING_DEFAULT, &delta); + int32_t glyph_a = FT_Get_Char_Index(ffsd->face, p_glyph_pair.x); + int32_t glyph_b = FT_Get_Char_Index(ffsd->face, p_glyph_pair.y); + FT_Get_Kerning(ffsd->face, glyph_a, glyph_b, FT_KERNING_DEFAULT, &delta); if (fd->msdf) { return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size; } else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { @@ -2431,17 +2488,19 @@ bool TextServerFallback::_font_has_char(const RID &p_font_rid, int64_t p_char) c } MutexLock lock(fd->mutex); + FontForSizeFallback *ffsd = nullptr; if (fd->cache.is_empty()) { - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), false); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0), ffsd), false); + } else { + ffsd = fd->cache.begin()->value; } - FontForSizeFallback *at_size = fd->cache.begin()->value; #ifdef MODULE_FREETYPE_ENABLED - if (at_size && at_size->face) { - return FT_Get_Char_Index(at_size->face, p_char) != 0; + if (ffsd->face) { + return FT_Get_Char_Index(ffsd->face, p_char) != 0; } #endif - return (at_size) ? at_size->glyph_map.has((int32_t)p_char) : false; + return ffsd->glyph_map.has((int32_t)p_char); } String TextServerFallback::_font_get_supported_chars(const RID &p_font_rid) const { @@ -2449,30 +2508,30 @@ String TextServerFallback::_font_get_supported_chars(const RID &p_font_rid) cons ERR_FAIL_NULL_V(fd, String()); MutexLock lock(fd->mutex); + FontForSizeFallback *ffsd = nullptr; if (fd->cache.is_empty()) { - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), String()); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0), ffsd), String()); + } else { + ffsd = fd->cache.begin()->value; } - FontForSizeFallback *at_size = fd->cache.begin()->value; String chars; #ifdef MODULE_FREETYPE_ENABLED - if (at_size && at_size->face) { + if (ffsd->face) { FT_UInt gindex; - FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex); + FT_ULong charcode = FT_Get_First_Char(ffsd->face, &gindex); while (gindex != 0) { if (charcode != 0) { chars = chars + String::chr(charcode); } - charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex); + charcode = FT_Get_Next_Char(ffsd->face, charcode, &gindex); } return chars; } #endif - if (at_size) { - const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map; - for (const KeyValue<int32_t, FontGlyph> &E : gl) { - chars = chars + String::chr(E.key); - } + const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map; + for (const KeyValue<int32_t, FontGlyph> &E : gl) { + chars = chars + String::chr(E.key); } return chars; } @@ -2482,10 +2541,12 @@ PackedInt32Array TextServerFallback::_font_get_supported_glyphs(const RID &p_fon ERR_FAIL_NULL_V(fd, PackedInt32Array()); MutexLock lock(fd->mutex); + FontForSizeFallback *at_size = nullptr; if (fd->cache.is_empty()) { - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), PackedInt32Array()); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0), at_size), PackedInt32Array()); + } else { + at_size = fd->cache.begin()->value; } - FontForSizeFallback *at_size = fd->cache.begin()->value; PackedInt32Array glyphs; #ifdef MODULE_FREETYPE_ENABLED @@ -2516,25 +2577,27 @@ void TextServerFallback::_font_render_range(const RID &p_font_rid, const Vector2 MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); for (int64_t i = p_start; i <= p_end; i++) { #ifdef MODULE_FREETYPE_ENABLED int32_t idx = i; - if (fd->cache[size]->face) { + if (ffsd->face) { + FontGlyph fgl; if (fd->msdf) { - _ensure_glyph(fd, size, (int32_t)idx); + _ensure_glyph(fd, size, (int32_t)idx, fgl); } else { for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) { if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl); } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl); } else { - _ensure_glyph(fd, size, (int32_t)idx | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl); } } } @@ -2549,24 +2612,26 @@ void TextServerFallback::_font_render_glyph(const RID &p_font_rid, const Vector2 MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); #ifdef MODULE_FREETYPE_ENABLED int32_t idx = p_index & 0xffffff; // Remove subpixel shifts. - if (fd->cache[size]->face) { + if (ffsd->face) { + FontGlyph fgl; if (fd->msdf) { - _ensure_glyph(fd, size, (int32_t)idx); + _ensure_glyph(fd, size, (int32_t)idx, fgl); } else { for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) { if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl); } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl); } else { - _ensure_glyph(fd, size, (int32_t)idx | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl); } } } @@ -2583,16 +2648,17 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); int32_t index = p_index & 0xffffff; // Remove subpixel shifts. bool lcd_aa = false; #ifdef MODULE_FREETYPE_ENABLED - if (!fd->msdf && fd->cache[size]->face) { + if (!fd->msdf && ffsd->face) { // LCD layout, bits 24, 25, 26 if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { lcd_aa = true; index = index | (layout << 24); @@ -2609,24 +2675,24 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca } #endif - if (!_ensure_glyph(fd, size, index)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, index, fgl)) { return; // Invalid or non-graphical glyph, do not display errors, nothing to draw. } - const FontGlyph &gl = fd->cache[size]->glyph_map[index]; - if (gl.found) { - ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); + if (fgl.found) { + ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size()); - if (gl.texture_idx != -1) { + if (fgl.texture_idx != -1) { Color modulate = p_color; #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { + if (ffsd->face && ffsd->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { modulate.r = modulate.g = modulate.b = 1.0; } #endif if (RenderingServer::get_singleton() != nullptr) { - if (fd->cache[size]->textures[gl.texture_idx].dirty) { - ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + if (ffsd->textures[fgl.texture_idx].dirty) { + ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx]; Ref<Image> img = tex.image; if (fd->mipmaps && !img->has_mipmaps()) { img = tex.image->duplicate(); @@ -2639,12 +2705,12 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca } tex.dirty = false; } - RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); + RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; - cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; - Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; - RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); + cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size; + Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size; + RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); } else { Point2 cpos = p_pos; double scale = _font_get_scale(p_font_rid, p_size); @@ -2657,8 +2723,8 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca cpos.y = Math::floor(cpos.y); cpos.x = Math::floor(cpos.x); } - Vector2 gpos = gl.rect.position; - Size2 csize = gl.rect.size; + Vector2 gpos = fgl.rect.position; + Size2 csize = fgl.rect.size; if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { double gl_scale = (double)p_size / (double)fd->fixed_size; @@ -2672,9 +2738,9 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca } cpos += gpos; if (lcd_aa) { - RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate); + RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate); } else { - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false); } } } @@ -2691,16 +2757,17 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, Vector2i(p_size, p_outline_size)); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); int32_t index = p_index & 0xffffff; // Remove subpixel shifts. bool lcd_aa = false; #ifdef MODULE_FREETYPE_ENABLED - if (!fd->msdf && fd->cache[size]->face) { + if (!fd->msdf && ffsd->face) { // LCD layout, bits 24, 25, 26 if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get(); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { lcd_aa = true; index = index | (layout << 24); @@ -2717,24 +2784,24 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R } #endif - if (!_ensure_glyph(fd, size, index)) { + FontGlyph fgl; + if (!_ensure_glyph(fd, size, index, fgl)) { return; // Invalid or non-graphical glyph, do not display errors, nothing to draw. } - const FontGlyph &gl = fd->cache[size]->glyph_map[index]; - if (gl.found) { - ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); + if (fgl.found) { + ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size()); - if (gl.texture_idx != -1) { + if (fgl.texture_idx != -1) { Color modulate = p_color; #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { + if (ffsd->face && ffsd->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { modulate.r = modulate.g = modulate.b = 1.0; } #endif if (RenderingServer::get_singleton() != nullptr) { - if (fd->cache[size]->textures[gl.texture_idx].dirty) { - ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + if (ffsd->textures[fgl.texture_idx].dirty) { + ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx]; Ref<Image> img = tex.image; if (fd->mipmaps && !img->has_mipmaps()) { img = tex.image->duplicate(); @@ -2747,12 +2814,12 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R } tex.dirty = false; } - RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); + RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; - cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; - Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; - RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); + cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size; + Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size; + RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); } else { Point2 cpos = p_pos; double scale = _font_get_scale(p_font_rid, p_size); @@ -2765,8 +2832,8 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R cpos.y = Math::floor(cpos.y); cpos.x = Math::floor(cpos.x); } - Vector2 gpos = gl.rect.position; - Size2 csize = gl.rect.size; + Vector2 gpos = fgl.rect.position; + Size2 csize = fgl.rect.size; if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size) { if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) { double gl_scale = (double)p_size / (double)fd->fixed_size; @@ -2780,9 +2847,9 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R } cpos += gpos; if (lcd_aa) { - RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate); + RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate); } else { - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false); } } } @@ -2872,7 +2939,8 @@ void TextServerFallback::_font_remove_script_support_override(const RID &p_font_ MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->script_support_overrides.erase(p_script); } @@ -2894,7 +2962,8 @@ void TextServerFallback::_font_set_opentype_feature_overrides(const RID &p_font_ MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd)); fd->feature_overrides = p_overrides; } @@ -2916,7 +2985,8 @@ Dictionary TextServerFallback::_font_supported_variation_list(const RID &p_font_ MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, 16); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary()); + FontForSizeFallback *ffsd = nullptr; + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary()); return fd->supported_varaitions; } @@ -2953,7 +3023,7 @@ void TextServerFallback::_font_set_global_oversampling(double p_oversampling) { /*************************************************************************/ void TextServerFallback::invalidate(ShapedTextDataFallback *p_shaped) { - p_shaped->valid = false; + p_shaped->valid.clear(); p_shaped->sort_valid = false; p_shaped->line_breaks_valid = false; p_shaped->justification_ops_valid = false; @@ -3192,7 +3262,7 @@ void TextServerFallback::_shaped_set_span_update_font(const RID &p_shaped, int64 span.font_size = p_size; span.features = p_opentype_features; - sd->valid = false; + sd->valid.clear(); } bool TextServerFallback::_shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { @@ -3288,7 +3358,7 @@ bool TextServerFallback::_shaped_text_resize_object(const RID &p_shaped, const V sd->objects[p_key].rect.size = p_size; sd->objects[p_key].inline_align = p_inline_align; sd->objects[p_key].baseline = p_baseline; - if (sd->valid) { + if (sd->valid.is_set()) { // Recalc string metrics. sd->ascent = 0; sd->descent = 0; @@ -3431,7 +3501,7 @@ RID TextServerFallback::_shaped_text_substr(const RID &p_shaped, int64_t p_start if (sd->parent != RID()) { return _shaped_text_substr(sd->parent, p_start, p_length); } - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID()); @@ -3514,7 +3584,7 @@ RID TextServerFallback::_shaped_text_substr(const RID &p_shaped, int64_t p_start _realign(new_sd); } - new_sd->valid = true; + new_sd->valid.set(); return shaped_owner.make_rid(new_sd); } @@ -3532,7 +3602,7 @@ double TextServerFallback::_shaped_text_fit_to_width(const RID &p_shaped, double ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } if (!sd->justification_ops_valid) { @@ -3641,7 +3711,7 @@ double TextServerFallback::_shaped_text_tab_align(const RID &p_shaped, const Pac ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } if (!sd->line_breaks_valid) { @@ -3697,7 +3767,7 @@ bool TextServerFallback::_shaped_text_update_breaks(const RID &p_shaped) { ERR_FAIL_NULL_V(sd, false); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { _shaped_text_shape(p_shaped); } @@ -3761,7 +3831,7 @@ bool TextServerFallback::_shaped_text_update_justification_ops(const RID &p_shap ERR_FAIL_NULL_V(sd, false); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { _shaped_text_shape(p_shaped); } if (!sd->line_breaks_valid) { @@ -3940,7 +4010,7 @@ void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ ERR_FAIL_NULL_MSG(sd, "ShapedTextDataFallback invalid."); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { _shaped_text_shape(p_shaped_line); } @@ -3967,7 +4037,7 @@ void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ Vector<ShapedTextDataFallback::Span> &spans = sd->spans; if (sd->parent != RID()) { ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent); - ERR_FAIL_COND(!parent_sd->valid); + ERR_FAIL_COND(!parent_sd->valid.is_set()); spans = parent_sd->spans; } @@ -4161,7 +4231,7 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) { ERR_FAIL_NULL_V(sd, false); MutexLock lock(sd->mutex); - if (sd->valid) { + if (sd->valid.is_set()) { return true; } @@ -4178,7 +4248,7 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) { sd->glyphs.clear(); if (sd->text.length() == 0) { - sd->valid = true; + sd->valid.set(); return true; } @@ -4307,16 +4377,15 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) { // Align embedded objects to baseline. _realign(sd); - sd->valid = true; - return sd->valid; + sd->valid.set(); + return sd->valid.is_set(); } bool TextServerFallback::_shaped_text_is_ready(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_NULL_V(sd, false); - MutexLock lock(sd->mutex); - return sd->valid; + return sd->valid.is_set(); } const Glyph *TextServerFallback::_shaped_text_get_glyphs(const RID &p_shaped) const { @@ -4324,7 +4393,7 @@ const Glyph *TextServerFallback::_shaped_text_get_glyphs(const RID &p_shaped) co ERR_FAIL_NULL_V(sd, nullptr); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->glyphs.ptr(); @@ -4335,7 +4404,7 @@ int64_t TextServerFallback::_shaped_text_get_glyph_count(const RID &p_shaped) co ERR_FAIL_NULL_V(sd, 0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->glyphs.size(); @@ -4346,7 +4415,7 @@ const Glyph *TextServerFallback::_shaped_text_sort_logical(const RID &p_shaped) ERR_FAIL_NULL_V(sd, nullptr); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } @@ -4380,7 +4449,7 @@ Rect2 TextServerFallback::_shaped_text_get_object_rect(const RID &p_shaped, cons MutexLock lock(sd->mutex); ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2()); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->objects[p_key].rect; @@ -4417,7 +4486,7 @@ Size2 TextServerFallback::_shaped_text_get_size(const RID &p_shaped) const { ERR_FAIL_NULL_V(sd, Size2()); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) { @@ -4432,7 +4501,7 @@ double TextServerFallback::_shaped_text_get_ascent(const RID &p_shaped) const { ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->ascent + sd->extra_spacing[SPACING_TOP]; @@ -4443,7 +4512,7 @@ double TextServerFallback::_shaped_text_get_descent(const RID &p_shaped) const { ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->descent + sd->extra_spacing[SPACING_BOTTOM]; @@ -4454,7 +4523,7 @@ double TextServerFallback::_shaped_text_get_width(const RID &p_shaped) const { ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return Math::ceil(sd->width); @@ -4465,7 +4534,7 @@ double TextServerFallback::_shaped_text_get_underline_position(const RID &p_shap ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } @@ -4477,7 +4546,7 @@ double TextServerFallback::_shaped_text_get_underline_thickness(const RID &p_sha ERR_FAIL_NULL_V(sd, 0.0); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } @@ -4489,7 +4558,7 @@ PackedInt32Array TextServerFallback::_shaped_text_get_character_breaks(const RID ERR_FAIL_NULL_V(sd, PackedInt32Array()); MutexLock lock(sd->mutex); - if (!sd->valid) { + if (!sd->valid.is_set()) { const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } @@ -4626,8 +4695,13 @@ PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_str return ret; } +void TextServerFallback::_update_settings() { + lcd_subpixel_layout.set((TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout")); +} + TextServerFallback::TextServerFallback() { _insert_feature_sets(); + ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &TextServerFallback::_update_settings)); }; void TextServerFallback::_cleanup() { diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 1b76c6fa0f..ee1f72401f 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -72,6 +72,7 @@ #include <godot_cpp/templates/hash_map.hpp> #include <godot_cpp/templates/hash_set.hpp> #include <godot_cpp/templates/rid_owner.hpp> +#include <godot_cpp/templates/safe_refcount.hpp> #include <godot_cpp/templates/vector.hpp> using namespace godot; @@ -83,6 +84,7 @@ using namespace godot; #include "core/object/worker_thread_pool.h" #include "core/templates/hash_map.h" #include "core/templates/rid_owner.h" +#include "core/templates/safe_refcount.h" #include "scene/resources/image_texture.h" #include "servers/text/text_server_extension.h" @@ -116,6 +118,9 @@ class TextServerFallback : public TextServerExtension { HashMap<StringName, int32_t> feature_sets; HashMap<int32_t, StringName> feature_sets_inv; + SafeNumeric<TextServer::FontLCDSubpixelLayout> lcd_subpixel_layout{ TextServer::FontLCDSubpixelLayout::FONT_LCD_SUBPIXEL_LAYOUT_NONE }; + void _update_settings(); + void _insert_feature_sets(); _FORCE_INLINE_ void _insert_feature(const StringName &p_name, int32_t p_tag); @@ -278,7 +283,7 @@ class TextServerFallback : public TextServerExtension { int extra_spacing[4] = { 0, 0, 0, 0 }; double baseline_offset = 0.0; - HashMap<Vector2i, FontForSizeFallback *, VariantHasher, VariantComparator> cache; + HashMap<Vector2i, FontForSizeFallback *> cache; bool face_init = false; Dictionary supported_varaitions; @@ -308,8 +313,8 @@ class TextServerFallback : public TextServerExtension { #ifdef MODULE_FREETYPE_ENABLED _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap p_bitmap, int p_yofs, int p_xofs, const Vector2 &p_advance, bool p_bgra) const; #endif - _FORCE_INLINE_ bool _ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph) const; - _FORCE_INLINE_ bool _ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size) const; + _FORCE_INLINE_ bool _ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph, FontGlyph &r_glyph) const; + _FORCE_INLINE_ bool _ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size, FontForSizeFallback *&r_cache_for_size) const; _FORCE_INLINE_ void _font_clear_cache(FontFallback *p_font_data); static void _generateMTSDF_threaded(void *p_td, uint32_t p_y); @@ -432,7 +437,7 @@ class TextServerFallback : public TextServerExtension { /* Shaped data */ TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction. - bool valid = false; // String is shaped. + SafeFlag valid{ false }; // String is shaped. bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted). bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string. bool sort_valid = false; diff --git a/platform/windows/crash_handler_windows_seh.cpp b/platform/windows/crash_handler_windows_seh.cpp index 2abe285d31..a6015092e8 100644 --- a/platform/windows/crash_handler_windows_seh.cpp +++ b/platform/windows/crash_handler_windows_seh.cpp @@ -118,7 +118,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { HANDLE process = GetCurrentProcess(); HANDLE hThread = GetCurrentThread(); DWORD offset_from_symbol = 0; - IMAGEHLP_LINE64 line = { 0 }; + IMAGEHLP_LINE64 line = {}; std::vector<module_data> modules; DWORD cbNeeded; std::vector<HMODULE> module_handles(1); diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 82a98655c0..d2a9c2315f 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -381,6 +381,15 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): ## Compile/link flags + if env["use_llvm"]: + env["CC"] = "clang-cl" + env["CXX"] = "clang-cl" + env["LINK"] = "lld-link" + env["AR"] = "llvm-lib" + + env.AppendUnique(CPPDEFINES=["R128_STDC_ONLY"]) + env.extra_suffix = ".llvm" + env.extra_suffix + env["MAXLINELENGTH"] = 8192 # Windows Vista and beyond, so always applicable. if env["silence_msvc"] and not env.GetOption("clean"): @@ -465,7 +474,6 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"]) env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding. - env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++ # Once it was thought that only debug builds would be too large, # but this has recently stopped being true. See the mingw function # for notes on why this shouldn't be enabled for gcc @@ -590,6 +598,9 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): if env["target"] in ["editor", "template_debug"]: LIBS += ["psapi", "dbghelp"] + if env["use_llvm"]: + LIBS += [f"clang_rt.builtins-{env['arch']}"] + env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS]) if vcvars_msvc_config: @@ -605,14 +616,22 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): if env["lto"] != "none": if env["lto"] == "thin": - print_error("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.") - sys.exit(255) - env.AppendUnique(CCFLAGS=["/GL"]) - env.AppendUnique(ARFLAGS=["/LTCG"]) - if env["progress"]: - env.AppendUnique(LINKFLAGS=["/LTCG:STATUS"]) + if not env["use_llvm"]: + print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.") + sys.exit(255) + + env.Append(CCFLAGS=["-flto=thin"]) + env.Append(LINKFLAGS=["-flto=thin"]) + elif env["use_llvm"]: + env.Append(CCFLAGS=["-flto"]) + env.Append(LINKFLAGS=["-flto"]) else: - env.AppendUnique(LINKFLAGS=["/LTCG"]) + env.AppendUnique(CCFLAGS=["/GL"]) + env.AppendUnique(ARFLAGS=["/LTCG"]) + if env["progress"]: + env.AppendUnique(LINKFLAGS=["/LTCG:STATUS"]) + else: + env.AppendUnique(LINKFLAGS=["/LTCG"]) if vcvars_msvc_config: env.Prepend(CPPPATH=[p for p in str(os.getenv("INCLUDE")).split(";")]) diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp index b0ad7ec110..ba0958e74b 100644 --- a/scene/2d/tile_map_layer.cpp +++ b/scene/2d/tile_map_layer.cpp @@ -957,7 +957,7 @@ void TileMapLayer::_navigation_update(bool p_force_cleanup) { // Create a dedicated map for each layer. RID new_layer_map = ns->map_create(); // Set the default NavigationPolygon cell_size on the new map as a mismatch causes an error. - ns->map_set_cell_size(new_layer_map, 1.0); + ns->map_set_cell_size(new_layer_map, NavigationDefaults2D::navmesh_cell_size); ns->map_set_active(new_layer_map, true); navigation_map_override = new_layer_map; } diff --git a/scene/3d/physics/vehicle_body_3d.cpp b/scene/3d/physics/vehicle_body_3d.cpp index c23032d3b9..b4c321cf5f 100644 --- a/scene/3d/physics/vehicle_body_3d.cpp +++ b/scene/3d/physics/vehicle_body_3d.cpp @@ -219,6 +219,14 @@ bool VehicleWheel3D::is_in_contact() const { return m_raycastInfo.m_isInContact; } +Vector3 VehicleWheel3D::get_contact_point() const { + return m_raycastInfo.m_contactPointWS; +} + +Vector3 VehicleWheel3D::get_contact_normal() const { + return m_raycastInfo.m_contactNormalWS; +} + Node3D *VehicleWheel3D::get_contact_body() const { return m_raycastInfo.m_groundObject; } @@ -256,6 +264,8 @@ void VehicleWheel3D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_in_contact"), &VehicleWheel3D::is_in_contact); ClassDB::bind_method(D_METHOD("get_contact_body"), &VehicleWheel3D::get_contact_body); + ClassDB::bind_method(D_METHOD("get_contact_point"), &VehicleWheel3D::get_contact_point); + ClassDB::bind_method(D_METHOD("get_contact_normal"), &VehicleWheel3D::get_contact_normal); ClassDB::bind_method(D_METHOD("set_roll_influence", "roll_influence"), &VehicleWheel3D::set_roll_influence); ClassDB::bind_method(D_METHOD("get_roll_influence"), &VehicleWheel3D::get_roll_influence); diff --git a/scene/3d/physics/vehicle_body_3d.h b/scene/3d/physics/vehicle_body_3d.h index def9984440..24f120ed26 100644 --- a/scene/3d/physics/vehicle_body_3d.h +++ b/scene/3d/physics/vehicle_body_3d.h @@ -130,6 +130,10 @@ public: bool is_in_contact() const; + Vector3 get_contact_point() const; + + Vector3 get_contact_normal() const; + Node3D *get_contact_body() const; void set_roll_influence(real_t p_value); diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h index 6ea1cfdbb0..08d018eee9 100644 --- a/scene/3d/voxelizer.h +++ b/scene/3d/voxelizer.h @@ -35,9 +35,8 @@ class Voxelizer { private: - enum { + enum : uint32_t { CHILD_EMPTY = 0xFFFFFFFF - }; struct Cell { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 9bb6130742..0395dffad9 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -817,6 +817,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } int line_count = 0; + // Bottom margin for text clipping. + float v_limit = theme_cache.normal_style->get_margin(SIDE_BOTTOM); Size2 ctrl_size = get_size(); // Draw text. for (int line = 0; line < l.text_buf->get_line_count(); line++) { @@ -824,7 +826,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o off.y += theme_cache.line_separation; } - if (p_ofs.y + off.y >= ctrl_size.height) { + if (p_ofs.y + off.y >= ctrl_size.height - v_limit) { break; } @@ -1890,10 +1892,12 @@ void RichTextLabel::_notification(int p_what) { visible_paragraph_count = 0; visible_line_count = 0; + // Bottom margin for text clipping. + float v_limit = theme_cache.normal_style->get_margin(SIDE_BOTTOM); // New cache draw. Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs); int processed_glyphs = 0; - while (ofs.y < size.height && from_line < to_line) { + while (ofs.y < size.height - v_limit && from_line < to_line) { MutexLock lock(main->lines[from_line].text_buf->get_mutex()); visible_paragraph_count++; diff --git a/scene/resources/2d/navigation_polygon.h b/scene/resources/2d/navigation_polygon.h index 86bda47ace..ed2c606c55 100644 --- a/scene/resources/2d/navigation_polygon.h +++ b/scene/resources/2d/navigation_polygon.h @@ -33,6 +33,7 @@ #include "scene/2d/node_2d.h" #include "scene/resources/navigation_mesh.h" +#include "servers/navigation/navigation_globals.h" class NavigationPolygon : public Resource { GDCLASS(NavigationPolygon, Resource); @@ -50,7 +51,7 @@ class NavigationPolygon : public Resource { // Navigation mesh Ref<NavigationMesh> navigation_mesh; - real_t cell_size = 1.0f; // Must match ProjectSettings default 2D cell_size. + real_t cell_size = NavigationDefaults2D::navmesh_cell_size; real_t border_size = 0.0f; Rect2 baking_rect; diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h index 741cea0791..1b3db5bac2 100644 --- a/scene/resources/navigation_mesh.h +++ b/scene/resources/navigation_mesh.h @@ -33,6 +33,7 @@ #include "core/os/rw_lock.h" #include "scene/resources/mesh.h" +#include "servers/navigation/navigation_globals.h" class NavigationMesh : public Resource { GDCLASS(NavigationMesh, Resource); @@ -77,8 +78,8 @@ public: }; protected: - float cell_size = 0.25f; // Must match ProjectSettings default 3D cell_size and NavigationServer NavMap cell_size. - float cell_height = 0.25f; // Must match ProjectSettings default 3D cell_height and NavigationServer NavMap cell_height. + float cell_size = NavigationDefaults3D::navmesh_cell_size; + float cell_height = NavigationDefaults3D::navmesh_cell_height; float border_size = 0.0f; float agent_height = 1.5f; float agent_radius = 0.5f; diff --git a/servers/navigation/navigation_globals.h b/servers/navigation/navigation_globals.h new file mode 100644 index 0000000000..aa54f95519 --- /dev/null +++ b/servers/navigation/navigation_globals.h @@ -0,0 +1,66 @@ +/**************************************************************************/ +/* navigation_globals.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef NAVIGATION_GLOBALS_H +#define NAVIGATION_GLOBALS_H + +namespace NavigationDefaults3D { + +// Rasterization. + +// To find the polygons edges the vertices are displaced in a grid where +// each cell has the following cell_size and cell_height. +constexpr float navmesh_cell_size{ 0.25f }; // Must match ProjectSettings default 3D cell_size and NavigationMesh cell_size. +constexpr float navmesh_cell_height{ 0.25f }; // Must match ProjectSettings default 3D cell_height and NavigationMesh cell_height. +constexpr auto navmesh_cell_size_hint{ "0.001,100,0.001,or_greater" }; + +// Map. + +constexpr float edge_connection_margin{ 0.25f }; +constexpr float link_connection_radius{ 1.0f }; + +} //namespace NavigationDefaults3D + +namespace NavigationDefaults2D { + +// Rasterization. + +// Same as in 3D but larger since 1px is treated as 1m. +constexpr float navmesh_cell_size{ 1.0f }; // Must match ProjectSettings default 2D cell_size. +constexpr auto navmesh_cell_size_hint{ "0.001,100,0.001,or_greater" }; + +// Map. + +constexpr float edge_connection_margin{ 1.0f }; +constexpr float link_connection_radius{ 4.0f }; + +} //namespace NavigationDefaults2D + +#endif // NAVIGATION_GLOBALS_H diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 398ff1e1f3..f4ffcf5a3e 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "scene/main/node.h" +#include "servers/navigation/navigation_globals.h" NavigationServer3D *NavigationServer3D::singleton = nullptr; @@ -227,18 +228,18 @@ NavigationServer3D::NavigationServer3D() { ERR_FAIL_COND(singleton != nullptr); singleton = this; - GLOBAL_DEF_BASIC(PropertyInfo(Variant::FLOAT, "navigation/2d/default_cell_size", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), 1.0); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::FLOAT, "navigation/2d/default_cell_size", PROPERTY_HINT_RANGE, NavigationDefaults2D::navmesh_cell_size_hint), NavigationDefaults2D::navmesh_cell_size); GLOBAL_DEF("navigation/2d/use_edge_connections", true); - GLOBAL_DEF_BASIC("navigation/2d/default_edge_connection_margin", 1.0); - GLOBAL_DEF_BASIC("navigation/2d/default_link_connection_radius", 4.0); + GLOBAL_DEF_BASIC("navigation/2d/default_edge_connection_margin", NavigationDefaults2D::edge_connection_margin); + GLOBAL_DEF_BASIC("navigation/2d/default_link_connection_radius", NavigationDefaults2D::link_connection_radius); - GLOBAL_DEF_BASIC(PropertyInfo(Variant::FLOAT, "navigation/3d/default_cell_size", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), 0.25); - GLOBAL_DEF_BASIC("navigation/3d/default_cell_height", 0.25); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::FLOAT, "navigation/3d/default_cell_size", PROPERTY_HINT_RANGE, NavigationDefaults3D::navmesh_cell_size_hint), NavigationDefaults3D::navmesh_cell_size); + GLOBAL_DEF_BASIC("navigation/3d/default_cell_height", NavigationDefaults3D::navmesh_cell_height); GLOBAL_DEF("navigation/3d/default_up", Vector3(0, 1, 0)); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "navigation/3d/merge_rasterizer_cell_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001,or_greater"), 1.0); GLOBAL_DEF("navigation/3d/use_edge_connections", true); - GLOBAL_DEF_BASIC("navigation/3d/default_edge_connection_margin", 0.25); - GLOBAL_DEF_BASIC("navigation/3d/default_link_connection_radius", 1.0); + GLOBAL_DEF_BASIC("navigation/3d/default_edge_connection_margin", NavigationDefaults3D::edge_connection_margin); + GLOBAL_DEF_BASIC("navigation/3d/default_link_connection_radius", NavigationDefaults3D::link_connection_radius); GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_multiple_threads", true); GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_high_priority_threads", true); diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h index 94ab219dc2..1db58d72f9 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -49,7 +49,7 @@ namespace RendererRD { class LightStorage : public RendererLightStorage { public: - enum ShadowAtlastQuadrant { + enum ShadowAtlastQuadrant : uint32_t { QUADRANT_SHIFT = 27, OMNI_LIGHT_FLAG = 1 << 26, SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1, diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index d8f9e2c31a..1405f585b2 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -377,7 +377,9 @@ public: // used for the render pipelines. struct AttachmentFormat { - enum { UNUSED_ATTACHMENT = 0xFFFFFFFF }; + enum : uint32_t { + UNUSED_ATTACHMENT = 0xFFFFFFFF + }; DataFormat format; TextureSamples samples; uint32_t usage_flags; diff --git a/thirdparty/libwebp/patches/godot-clang-cl-fix.patch b/thirdparty/libwebp/patches/godot-clang-cl-fix.patch new file mode 100644 index 0000000000..ee4f598951 --- /dev/null +++ b/thirdparty/libwebp/patches/godot-clang-cl-fix.patch @@ -0,0 +1,19 @@ +diff --git a/thirdparty/libwebp/src/dsp/cpu.h b/thirdparty/libwebp/src/dsp/cpu.h +index c86540f280..4dbe607aec 100644 +--- a/thirdparty/libwebp/src/dsp/cpu.h ++++ b/thirdparty/libwebp/src/dsp/cpu.h +@@ -47,12 +47,12 @@ + // x86 defines. + + #if !defined(HAVE_CONFIG_H) +-#if defined(_MSC_VER) && _MSC_VER > 1310 && \ ++#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER > 1310 && \ + (defined(_M_X64) || defined(_M_IX86)) + #define WEBP_MSC_SSE2 // Visual C++ SSE2 targets + #endif + +-#if defined(_MSC_VER) && _MSC_VER >= 1500 && \ ++#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER >= 1500 && \ + (defined(_M_X64) || defined(_M_IX86)) + #define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets + #endif diff --git a/thirdparty/libwebp/src/dsp/cpu.h b/thirdparty/libwebp/src/dsp/cpu.h index c86540f280..4dbe607aec 100644 --- a/thirdparty/libwebp/src/dsp/cpu.h +++ b/thirdparty/libwebp/src/dsp/cpu.h @@ -47,12 +47,12 @@ // x86 defines. #if !defined(HAVE_CONFIG_H) -#if defined(_MSC_VER) && _MSC_VER > 1310 && \ +#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER > 1310 && \ (defined(_M_X64) || defined(_M_IX86)) #define WEBP_MSC_SSE2 // Visual C++ SSE2 targets #endif -#if defined(_MSC_VER) && _MSC_VER >= 1500 && \ +#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER >= 1500 && \ (defined(_M_X64) || defined(_M_IX86)) #define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets #endif |