diff options
70 files changed, 726 insertions, 167 deletions
diff --git a/SConstruct b/SConstruct index f7d589e799..83bd1560ff 100644 --- a/SConstruct +++ b/SConstruct @@ -300,6 +300,13 @@ opts.Update(env_base) env_base["platform"] = selected_platform # Must always be re-set after calling opts.Update(). Help(opts.GenerateHelpText(env_base)) +# Detect and print a warning listing unknown SCons variables to ease troubleshooting. +unknown = opts.UnknownVariables() +if unknown: + print("WARNING: Unknown SCons variables were passed and will be ignored:") + for item in unknown.items(): + print(" " + item[0] + "=" + item[1]) + # add default include paths env_base.Prepend(CPPPATH=["#"]) diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp index 4a76f0191d..d34b5b6fe3 100644 --- a/core/io/packed_data_container.cpp +++ b/core/io/packed_data_container.cpp @@ -100,6 +100,7 @@ Variant PackedDataContainer::_iter_get_ofs(const Variant &p_iter, uint32_t p_off } Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, bool &err) const { + ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), Variant()); uint32_t type = decode_uint32(p_buf + p_ofs); if (type == TYPE_ARRAY || type == TYPE_DICT) { @@ -122,6 +123,7 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, b } uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const { + ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), 0); const uint8_t *rd = data.ptr(); ERR_FAIL_COND_V(!rd, 0); const uint8_t *r = &rd[p_ofs]; @@ -131,6 +133,7 @@ uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const { } int PackedDataContainer::_size(uint32_t p_ofs) const { + ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), 0); const uint8_t *rd = data.ptr(); ERR_FAIL_COND_V(!rd, 0); const uint8_t *r = &rd[p_ofs]; @@ -149,6 +152,7 @@ int PackedDataContainer::_size(uint32_t p_ofs) const { } Variant PackedDataContainer::_key_at_ofs(uint32_t p_ofs, const Variant &p_key, bool &err) const { + ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), Variant()); const uint8_t *rd = data.ptr(); if (!rd) { err = true; diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index f6bb812070..8739e0157d 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -654,6 +654,12 @@ See [method add_theme_stylebox_override]. </description> </method> + <method name="is_drag_successful" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if drag operation is successful. + </description> + </method> <method name="is_layout_rtl" qualifiers="const"> <return type="bool" /> <description> @@ -714,6 +720,12 @@ Removes a local override for a theme [StyleBox] with the specified [code]name[/code] previously added by [method add_theme_stylebox_override] or via the Inspector dock. </description> </method> + <method name="reset_size"> + <return type="void" /> + <description> + Resets the size to [method get_combined_minimum_size]. This is equivalent to calling [code]set_size(Vector2())[/code] (or any size below the minimum). + </description> + </method> <method name="set_anchor"> <return type="void" /> <argument index="0" name="side" type="int" enum="Side" /> diff --git a/doc/classes/FontData.xml b/doc/classes/FontData.xml index ccfe861c92..c403d238c5 100644 --- a/doc/classes/FontData.xml +++ b/doc/classes/FontData.xml @@ -93,6 +93,12 @@ Returns font descent (number of pixels below the baseline). </description> </method> + <method name="get_fixed_size" qualifiers="const"> + <return type="int" /> + <description> + Returns font fixed size. + </description> + </method> <method name="get_font_name" qualifiers="const"> <return type="String" /> <description> @@ -481,6 +487,13 @@ Sets the font descent (number of pixels below the baseline). </description> </method> + <method name="set_fixed_size"> + <return type="void" /> + <argument index="0" name="fixed_size" type="int" /> + <description> + Sets the fixed size for the font. + </description> + </method> <method name="set_font_name"> <return type="void" /> <argument index="0" name="name" type="String" /> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index df9da7561e..860e252805 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -350,6 +350,7 @@ <argument index="0" name="property" type="NodePath" /> <description> Gets the object's property indexed by the given [NodePath]. The node path should be relative to the current object and can use the colon character ([code]:[/code]) to access nested properties. Examples: [code]"position:x"[/code] or [code]"material:next_pass:blend_mode"[/code]. + [b]Note:[/b] Even though the method takes [NodePath] argument, it doesn't support actual paths to [Node]s in the scene tree, only colon-separated sub-property paths. For the purpose of nodes, use [method Node.get_node_and_resource] instead. </description> </method> <method name="get_instance_id" qualifiers="const"> diff --git a/doc/classes/PhysicalSkyMaterial.xml b/doc/classes/PhysicalSkyMaterial.xml index b90f52a70d..e1e50a2b51 100644 --- a/doc/classes/PhysicalSkyMaterial.xml +++ b/doc/classes/PhysicalSkyMaterial.xml @@ -23,7 +23,7 @@ <member name="mie_coefficient" type="float" setter="set_mie_coefficient" getter="get_mie_coefficient" default="0.005"> Controls the strength of mie scattering for the sky. Mie scattering results from light colliding with larger particles (like water). On earth, mie scattering results in a whitish color around the sun and horizon. </member> - <member name="mie_color" type="Color" setter="set_mie_color" getter="get_mie_color" default="Color(0.36, 0.56, 0.82, 1)"> + <member name="mie_color" type="Color" setter="set_mie_color" getter="get_mie_color" default="Color(0.63, 0.77, 0.92, 1)"> Controls the [Color] of the mie scattering effect. While not physically accurate, this allows for the creation of alien looking planets. </member> <member name="mie_eccentricity" type="float" setter="set_mie_eccentricity" getter="get_mie_eccentricity" default="0.8"> @@ -35,7 +35,7 @@ <member name="rayleigh_coefficient" type="float" setter="set_rayleigh_coefficient" getter="get_rayleigh_coefficient" default="2.0"> Controls the strength of the Rayleigh scattering. Rayleigh scattering results from light colliding with small particles. It is responsible for the blue color of the sky. </member> - <member name="rayleigh_color" type="Color" setter="set_rayleigh_color" getter="get_rayleigh_color" default="Color(0.056, 0.14, 0.3, 1)"> + <member name="rayleigh_color" type="Color" setter="set_rayleigh_color" getter="get_rayleigh_color" default="Color(0.26, 0.41, 0.58, 1)"> Controls the [Color] of the Rayleigh scattering. While not physically accurate, this allows for the creation of alien looking planets. For example, setting this to a red [Color] results in a Mars looking atmosphere with a corresponding blue sunset. </member> <member name="sun_disk_scale" type="float" setter="set_sun_disk_scale" getter="get_sun_disk_scale" default="1.0"> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 400fae4aad..16d8595b4e 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -362,6 +362,24 @@ Returns OpenType feature [code]tag[/code]. </description> </method> + <method name="get_pos_at_line_column" qualifiers="const"> + <return type="Vector2i" /> + <argument index="0" name="line" type="int" /> + <argument index="1" name="column" type="int" /> + <description> + Returns the local position for the given [code]line[/code] and [code]column[/code]. If [code]x[/code] or [code]y[/code] of the returned vector equal [code]-1[/code], the position is outside of the viewable area of the control. + [b]Note:[/b] The Y position corresponds to the bottom side of the line. Use [method get_rect_at_line_column] to get the top side position. + </description> + </method> + <method name="get_rect_at_line_column" qualifiers="const"> + <return type="Rect2i" /> + <argument index="0" name="line" type="int" /> + <argument index="1" name="column" type="int" /> + <description> + Returns the local position and size for the grapheme at the given [code]line[/code] and [code]column[/code]. If [code]x[/code] or [code]y[/code] position of the returned rect equal [code]-1[/code], the position is outside of the viewable area of the control. + [b]Note:[/b] The Y position of the returned rect corresponds to the top side of the line, unlike [method get_pos_at_line_column] which returns the bottom side. + </description> + </method> <method name="get_saved_version" qualifiers="const"> <return type="int" /> <description> diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index e1c05165de..512078c56c 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -1028,6 +1028,14 @@ Returns text glyphs in the visual order. </description> </method> + <method name="shaped_text_get_grapheme_bounds" qualifiers="const"> + <return type="Vector2" /> + <argument index="0" name="shaped" type="RID" /> + <argument index="1" name="pos" type="int" /> + <description> + Returns composite character's bounds as offsets from the start of the line. + </description> + </method> <method name="shaped_text_get_line_breaks" qualifiers="const"> <return type="PackedInt32Array" /> <argument index="0" name="shaped" type="RID" /> diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml index 684a1aa755..32f8107e0a 100644 --- a/doc/classes/TextServerExtension.xml +++ b/doc/classes/TextServerExtension.xml @@ -1037,6 +1037,14 @@ Copies text glyphs in the visual order, into preallocated array of the size returned by [method _shaped_text_get_glyph_count]. </description> </method> + <method name="_shaped_text_get_grapheme_bounds" qualifiers="virtual const"> + <return type="Vector2" /> + <argument index="0" name="shaped" type="RID" /> + <argument index="1" name="pos" type="int" /> + <description> + Returns composite character's bounds as offsets from the start of the line. + </description> + </method> <method name="_shaped_text_get_line_breaks" qualifiers="virtual const"> <return type="PackedInt32Array" /> <argument index="0" name="shaped" type="RID" /> diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 8e75b474ed..d83645a8af 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -107,6 +107,12 @@ Returns the drag data from the GUI, that was previously returned by [method Control._get_drag_data]. </description> </method> + <method name="gui_is_drag_successful" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if the drag operation is successful. + </description> + </method> <method name="gui_is_dragging" qualifiers="const"> <return type="bool" /> <description> diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index f36b926bef..3fee1feae8 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -230,6 +230,12 @@ <description> </description> </method> + <method name="reset_size"> + <return type="void" /> + <description> + Resets the size to the minimum size, which is the max of [member min_size] and (if [member wrap_controls] is enabled) [method get_contents_minimum_size]. This is equivalent to calling [code]set_size(Vector2i())[/code] (or any size below the minimum). + </description> + </method> <method name="set_flag"> <return type="void" /> <argument index="0" name="flag" type="int" enum="Window.Flags" /> diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index c773f51342..b954c87476 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -378,7 +378,7 @@ void ConnectDialog::_advanced_pressed() { error_label->hide(); } else { set_min_size(Size2(600, 500) * EDSCALE); - set_size(Size2()); + reset_size(); connect_to_label->set_text(TTR("Connect to Script:")); tree->set_connect_to_script_mode(true); diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index e0d32756ca..b18c225f23 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -1420,7 +1420,7 @@ void ScriptEditorDebugger::_clear_errors_list() { // Right click on specific file(s) or folder(s). void ScriptEditorDebugger::_error_tree_item_rmb_selected(const Vector2 &p_pos) { item_menu->clear(); - item_menu->set_size(Size2(1, 1)); + item_menu->reset_size(); if (error_tree->is_anything_selected()) { item_menu->add_icon_item(get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")), TTR("Copy Error"), ACTION_COPY_ERROR); diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index d07d77c112..f18284638f 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -270,7 +270,7 @@ DependencyEditor::DependencyEditor() { ///////////////////////////////////// void DependencyEditorOwners::_list_rmb_select(int p_item, const Vector2 &p_pos) { file_options->clear(); - file_options->set_size(Size2(1, 1)); + file_options->reset_size(); if (p_item >= 0) { file_options->add_item(TTR("Open"), FILE_OPEN); } @@ -464,7 +464,7 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector< if (removed_deps.is_empty()) { owners->hide(); text->set_text(TTR("Remove the selected files from the project? (Cannot be undone.)\nDepending on your filesystem configuration, the files will either be moved to the system trash or deleted permanently.")); - set_size(Size2()); + reset_size(); popup_centered(); } else { _build_removed_dependency_tree(removed_deps); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 021ab8b93b..2d7c31b64c 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -576,7 +576,7 @@ void EditorFileDialog::_item_dc_selected(int p_item) { void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p_pos) { // Right click on specific file(s) or folder(s). item_menu->clear(); - item_menu->set_size(Size2(1, 1)); + item_menu->reset_size(); // Allow specific actions only on one item. bool single_item_selected = item_list->get_selected_items().size() == 1; @@ -620,7 +620,7 @@ void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) { } item_menu->clear(); - item_menu->set_size(Size2(1, 1)); + item_menu->reset_size(); if (can_create_dir) { item_menu->add_icon_item(item_list->get_theme_icon(SNAME("folder"), SNAME("FileDialog")), TTR("New Folder..."), ITEM_MENU_NEW_FOLDER, KeyModifierMask::CMD | Key::N); @@ -1117,7 +1117,7 @@ void EditorFileDialog::_delete_items() { } } if (folders.size() + files.size() > 0) { - remove_dialog->set_size(Size2(1, 1)); + remove_dialog->reset_size(); remove_dialog->show(folders, files); } } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 07e505adb4..2729b1eb3b 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -650,7 +650,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { } else if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) { _update_popup(); menu->set_position(get_screen_position() + get_local_mouse_position()); - menu->set_size(Vector2(1, 1)); + menu->reset_size(); menu->popup(); select(); return; @@ -1556,7 +1556,7 @@ void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int p_index rmb_popup->set_item_disabled(OPTION_MOVE_UP, popup_array_index_pressed == 0); rmb_popup->set_item_disabled(OPTION_MOVE_DOWN, popup_array_index_pressed == count - 1); rmb_popup->set_position(mb->get_global_position()); - rmb_popup->set_size(Vector2()); + rmb_popup->reset_size(); rmb_popup->popup(); } } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 368b7e6ab3..1ad6dc18cd 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -4903,7 +4903,7 @@ void EditorNode::_update_layouts_menu() { editor_layouts->clear(); overridden_default_layout = -1; - editor_layouts->set_size(Vector2()); + editor_layouts->reset_size(); editor_layouts->add_shortcut(ED_SHORTCUT("layout/save", TTR("Save Layout")), SETTINGS_LAYOUT_SAVE); editor_layouts->add_shortcut(ED_SHORTCUT("layout/delete", TTR("Delete Layout")), SETTINGS_LAYOUT_DELETE); editor_layouts->add_separator(); @@ -5030,7 +5030,7 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) { if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) { // context menu scene_tabs_context_menu->clear(); - scene_tabs_context_menu->set_size(Size2(1, 1)); + scene_tabs_context_menu->reset_size(); scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/new_scene"), FILE_NEW_SCENE); if (scene_tabs->get_hovered_tab() >= 0) { @@ -6882,10 +6882,12 @@ EditorNode::EditorNode() { file_export_lib->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action)); file_export_lib_merge = memnew(CheckBox); file_export_lib_merge->set_text(TTR("Merge With Existing")); + file_export_lib_merge->set_h_size_flags(Control::SIZE_SHRINK_CENTER); file_export_lib_merge->set_pressed(true); file_export_lib->get_vbox()->add_child(file_export_lib_merge); file_export_lib_apply_xforms = memnew(CheckBox); file_export_lib_apply_xforms->set_text(TTR("Apply MeshInstance Transforms")); + file_export_lib_apply_xforms->set_h_size_flags(Control::SIZE_SHRINK_CENTER); file_export_lib_apply_xforms->set_pressed(false); file_export_lib->get_vbox()->add_child(file_export_lib_apply_xforms); gui_base->add_child(file_export_lib); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 2942ece409..f07a5ab523 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -409,7 +409,7 @@ void EditorSpinSlider::_draw_spin_slider() { Vector2 scale = get_global_transform_with_canvas().get_scale(); grabber->set_scale(scale); - grabber->set_size(Size2(0, 0)); + grabber->reset_size(); grabber->set_position(get_global_position() + (grabber_rect.get_center() - grabber->get_size() * 0.5) * scale); if (mousewheel_over_grabber) { diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 1dde157527..7ae3dcd44f 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -2507,7 +2507,7 @@ void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos) { // Popup. if (!paths.is_empty()) { - tree_popup->set_size(Size2(1, 1)); + tree_popup->reset_size(); _file_and_folders_fill_popup(tree_popup, paths); tree_popup->set_position(tree->get_screen_position() + p_pos); tree_popup->popup(); @@ -2518,7 +2518,7 @@ void FileSystemDock::_tree_rmb_empty(const Vector2 &p_pos) { // Right click is pressed in the empty space of the tree. path = "res://"; tree_popup->clear(); - tree_popup->set_size(Size2(1, 1)); + tree_popup->reset_size(); tree_popup->add_icon_item(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), TTR("New Folder..."), FILE_NEW_FOLDER); tree_popup->add_icon_item(get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")), TTR("New Scene..."), FILE_NEW_SCENE); tree_popup->add_icon_item(get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), TTR("New Script..."), FILE_NEW_SCRIPT); @@ -2549,7 +2549,7 @@ void FileSystemDock::_file_list_rmb_select(int p_item, const Vector2 &p_pos) { // Popup. if (!paths.is_empty()) { file_list_popup->clear(); - file_list_popup->set_size(Size2(1, 1)); + file_list_popup->reset_size(); _file_and_folders_fill_popup(file_list_popup, paths, searched_string.length() == 0); file_list_popup->set_position(files->get_global_position() + p_pos); file_list_popup->popup(); @@ -2563,7 +2563,7 @@ void FileSystemDock::_file_list_rmb_pressed(const Vector2 &p_pos) { } file_list_popup->clear(); - file_list_popup->set_size(Size2(1, 1)); + file_list_popup->reset_size(); file_list_popup->add_icon_item(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), TTR("New Folder..."), FILE_NEW_FOLDER); file_list_popup->add_icon_item(get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")), TTR("New Scene..."), FILE_NEW_SCENE); diff --git a/editor/import/dynamicfont_import_settings.cpp b/editor/import/dynamicfont_import_settings.cpp index 474c9d5296..45937e20bc 100644 --- a/editor/import/dynamicfont_import_settings.cpp +++ b/editor/import/dynamicfont_import_settings.cpp @@ -1160,7 +1160,7 @@ void DynamicFontImportSettings::_range_update(int32_t p_start, int32_t p_end) { void DynamicFontImportSettings::_lang_add() { menu_langs->set_position(lang_list->get_screen_transform().xform(lang_list->get_local_mouse_position())); - menu_langs->set_size(Vector2(1, 1)); + menu_langs->reset_size(); menu_langs->popup(); } @@ -1187,7 +1187,7 @@ void DynamicFontImportSettings::_lang_remove(Object *p_item, int p_column, int p void DynamicFontImportSettings::_script_add() { menu_scripts->set_position(script_list->get_screen_transform().xform(script_list->get_local_mouse_position())); - menu_scripts->set_size(Vector2(1, 1)); + menu_scripts->reset_size(); menu_scripts->popup(); } diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 55ffbf9477..2aded41810 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -68,7 +68,7 @@ void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_scrip void AnimationNodeBlendTreeEditor::_update_options_menu(bool p_has_input_ports) { add_node->get_popup()->clear(); - add_node->get_popup()->set_size(Size2i(-1, -1)); + add_node->get_popup()->reset_size(); for (int i = 0; i < add_options.size(); i++) { if (p_has_input_ports && add_options[i].input_port_count == 0) { continue; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 02756916a5..ecc404f903 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -877,7 +877,7 @@ void CanvasItemEditor::_selection_result_pressed(int p_result) { void CanvasItemEditor::_selection_menu_hide() { selection_results.clear(); selection_menu->clear(); - selection_menu->set_size(Vector2(0, 0)); + selection_menu->reset_size(); } void CanvasItemEditor::_add_node_pressed(int p_result) { @@ -2265,7 +2265,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { } if (b.is_valid() && b->is_pressed() && b->get_button_index() == MouseButton::RIGHT) { - add_node_menu->set_size(Vector2(1, 1)); + add_node_menu->reset_size(); add_node_menu->set_position(get_screen_position() + b->get_position()); add_node_menu->popup(); node_create_position = transform.affine_inverse().xform((get_local_mouse_position())); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 005cf27e8a..daf34903e6 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -383,7 +383,7 @@ void CurveEditor::open_context_menu(Vector2 pos) { _context_menu->add_submenu_item(TTR("Load Preset"), _presets_menu->get_name()); - _context_menu->set_size(Size2(0, 0)); + _context_menu->reset_size(); _context_menu->popup(); } diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index b74d229d3e..d6e6f0597a 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -860,7 +860,7 @@ void Node3DEditorViewport::_update_name() { } view_menu->set_text(name); - view_menu->set_size(Vector2(0, 0)); // resets the button size + view_menu->reset_size(); } void Node3DEditorViewport::_compute_edit(const Point2 &p_point) { @@ -3620,7 +3620,7 @@ void Node3DEditorViewport::_selection_result_pressed(int p_result) { void Node3DEditorViewport::_selection_menu_hide() { selection_results.clear(); selection_menu->clear(); - selection_menu->set_size(Vector2(0, 0)); + selection_menu->reset_size(); } void Node3DEditorViewport::set_can_preview(Camera3D *p_preview) { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index e87d31f018..583862893c 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -3052,7 +3052,7 @@ void ScriptEditor::_make_script_list_context_menu() { context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/toggle_scripts_panel"), TOGGLE_SCRIPTS_PANEL); context_menu->set_position(get_global_transform().xform(get_local_mouse_position())); - context_menu->set_size(Vector2(1, 1)); + context_menu->reset_size(); context_menu->popup(); } diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 93adced59d..30a4cef8ca 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -550,7 +550,7 @@ void ScriptTextEditor::_validate_script() { void ScriptTextEditor::_update_bookmark_list() { bookmarks_menu->clear(); - bookmarks_menu->set_size(Size2(1, 1)); + bookmarks_menu->reset_size(); bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_bookmarks"), BOOKMARK_REMOVE_ALL); @@ -702,7 +702,7 @@ void ScriptTextEditor::_code_complete_script(const String &p_code, List<ScriptCo void ScriptTextEditor::_update_breakpoint_list() { breakpoints_menu->clear(); - breakpoints_menu->set_size(Size2(1, 1)); + breakpoints_menu->reset_size(); breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_breakpoint"), DEBUG_TOGGLE_BREAKPOINT); breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_breakpoints"), DEBUG_REMOVE_ALL_BREAKPOINTS); @@ -1689,7 +1689,7 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p context_menu->set_item_disabled(context_menu->get_item_index(EDIT_REDO), !tx->has_redo()); context_menu->set_position(get_global_transform().xform(p_pos)); - context_menu->set_size(Vector2(1, 1)); + context_menu->reset_size(); context_menu->popup(); } diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 6032267717..7c1fda77bb 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -646,7 +646,7 @@ void ShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) { context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); context_menu->set_position(get_global_transform().xform(p_position)); - context_menu->set_size(Vector2(1, 1)); + context_menu->reset_size(); context_menu->popup(); } diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index ebfe6c9ee3..e252792c43 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -508,7 +508,7 @@ void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is context_menu->set_item_disabled(context_menu->get_item_index(EDIT_REDO), !tx->has_redo()); context_menu->set_position(get_global_transform().xform(p_position)); - context_menu->set_size(Vector2(1, 1)); + context_menu->reset_size(); context_menu->popup(); } diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp index df0b35908b..f13fcb005f 100644 --- a/editor/plugins/theme_editor_preview.cpp +++ b/editor/plugins/theme_editor_preview.cpp @@ -71,6 +71,9 @@ void ThemeEditorPreview::_preview_visibility_changed() { void ThemeEditorPreview::_picker_button_cbk() { picker_overlay->set_visible(picker_button->is_pressed()); + if (picker_button->is_pressed()) { + _reset_picker_overlay(); + } } Control *ThemeEditorPreview::_find_hovered_control(Control *p_parent, Vector2 p_mouse_position) { diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp index 9e47a44b34..60a66ab954 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp @@ -34,7 +34,7 @@ void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, Object *p_item_list) { ItemList *item_list = Object::cast_to<ItemList>(p_item_list); - popup_menu->set_size(Vector2(1, 1)); + popup_menu->reset_size(); popup_menu->set_position(get_position() + item_list->get_global_mouse_position()); popup_menu->popup(); } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index a4706bf0d9..b1a9da9e26 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -132,7 +132,7 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p if (links[p_node_id].preview_visible && !is_dirty() && links[p_node_id].preview_box != nullptr) { links[p_node_id].graph_node->remove_child(links[p_node_id].preview_box); memdelete(links[p_node_id].preview_box); - links[p_node_id].graph_node->set_size(Vector2(-1, -1)); + links[p_node_id].graph_node->reset_size(); links[p_node_id].preview_visible = false; } @@ -256,7 +256,7 @@ void VisualShaderGraphPlugin::update_node_size(int p_node_id) { if (!links.has(p_node_id)) { return; } - links[p_node_id].graph_node->set_size(Size2(-1, -1)); + links[p_node_id].graph_node->reset_size(); } void VisualShaderGraphPlugin::register_default_input_button(int p_node_id, int p_port_id, Button *p_button) { @@ -1976,7 +1976,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p } gn->set_custom_minimum_size(size); - gn->set_size(Size2(1, 1)); + gn->reset_size(); if (!expression_node.is_null() && text_box) { Size2 box_size = size; @@ -1990,7 +1990,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p box_size.y -= text_box->get_offset(SIDE_TOP); box_size.y -= 28 * EDSCALE; text_box->set_custom_minimum_size(box_size); - text_box->set_size(Size2(1, 1)); + text_box->reset_size(); } } } @@ -2038,8 +2038,8 @@ void VisualShaderEditor::_comment_title_popup_show(const Point2 &p_position, int } void VisualShaderEditor::_comment_title_text_changed(const String &p_new_text) { - comment_title_change_edit->set_size(Size2(-1, -1)); - comment_title_change_popup->set_size(Size2(-1, -1)); + comment_title_change_edit->reset_size(); + comment_title_change_popup->reset_size(); } void VisualShaderEditor::_comment_title_text_submitted(const String &p_new_text) { @@ -2083,8 +2083,8 @@ void VisualShaderEditor::_comment_desc_popup_show(const Point2 &p_position, int } void VisualShaderEditor::_comment_desc_text_changed() { - comment_desc_change_edit->set_size(Size2(-1, -1)); - comment_desc_change_popup->set_size(Size2(-1, -1)); + comment_desc_change_edit->reset_size(); + comment_desc_change_popup->reset_size(); } void VisualShaderEditor::_comment_desc_confirm() { @@ -3167,7 +3167,7 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) { menu_point = graph->get_local_mouse_position(); Point2 gpos = Input::get_singleton()->get_mouse_position(); popup_menu->set_position(gpos); - popup_menu->set_size(Size2(-1, -1)); + popup_menu->reset_size(); popup_menu->popup(); } } @@ -4258,8 +4258,8 @@ VisualShaderEditor::VisualShaderEditor() { comment_title_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_title_text_changed)); comment_title_change_edit->connect("text_submitted", callable_mp(this, &VisualShaderEditor::_comment_title_text_submitted)); comment_title_change_popup->add_child(comment_title_change_edit); - comment_title_change_edit->set_size(Size2(-1, -1)); - comment_title_change_popup->set_size(Size2(-1, -1)); + comment_title_change_edit->reset_size(); + comment_title_change_popup->reset_size(); comment_title_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_title_popup_focus_out)); comment_title_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_title_popup_hide)); add_child(comment_title_change_popup); @@ -4271,8 +4271,8 @@ VisualShaderEditor::VisualShaderEditor() { comment_desc_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_desc_text_changed)); comment_desc_vbox->add_child(comment_desc_change_edit); comment_desc_change_edit->set_custom_minimum_size(Size2(300 * EDSCALE, 150 * EDSCALE)); - comment_desc_change_edit->set_size(Size2(-1, -1)); - comment_desc_change_popup->set_size(Size2(-1, -1)); + comment_desc_change_edit->reset_size(); + comment_desc_change_popup->reset_size(); comment_desc_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_desc_confirm)); comment_desc_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_desc_popup_hide)); Button *comment_desc_confirm_button = memnew(Button); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index d48d45d848..a97d38323e 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -1277,11 +1277,13 @@ ProjectExportDialog::ProjectExportDialog() { export_debug = memnew(CheckBox); export_debug->set_text(TTR("Export With Debug")); export_debug->set_pressed(true); + export_debug->set_h_size_flags(Control::SIZE_SHRINK_CENTER); export_project->get_vbox()->add_child(export_debug); export_pck_zip_debug = memnew(CheckBox); export_pck_zip_debug->set_text(TTR("Export With Debug")); export_pck_zip_debug->set_pressed(true); + export_pck_zip_debug->set_h_size_flags(Control::SIZE_SHRINK_CENTER); export_pck_zip->get_vbox()->add_child(export_pck_zip_debug); set_hide_on_ok(false); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index f10ecab34e..061f4d218a 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -312,7 +312,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: spinbox->hide(); slider->hide(); menu->clear(); - menu->set_size(Size2(1, 1) * EDSCALE); + menu->reset_size(); for (int i = 0; i < MAX_VALUE_EDITORS; i++) { if (i < MAX_VALUE_EDITORS / 4) { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 0b293c9caf..611038a947 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -899,7 +899,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { // Resize the dialog to its minimum size. // This prevents the dialog from being too wide after displaying // a deletion confirmation for a node with a long name. - delete_dialog->set_size(Size2()); + delete_dialog->reset_size(); delete_dialog->popup_centered(); } @@ -2575,7 +2575,7 @@ void SceneTreeDock::_files_dropped(Vector<String> p_files, NodePath p_to, int p_ menu_properties->set_item_metadata(menu_properties->get_item_count() - 1, p); } - menu_properties->set_size(Size2(1, 1)); + menu_properties->reset_size(); menu_properties->set_position(get_screen_position() + get_local_mouse_position()); menu_properties->popup(); } else if (!valid_properties.is_empty()) { @@ -2667,7 +2667,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_icon_shortcut(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANTIATE); } - menu->set_size(Size2(1, 1)); + menu->reset_size(); menu->set_position(get_screen_position() + p_menu_pos); menu->popup(); return; @@ -2690,7 +2690,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { if (profile_allow_editing) { subresources.clear(); menu_subresources->clear(); - menu_subresources->set_size(Size2(1, 1)); + menu_subresources->reset_size(); _add_children_to_popup(selection.front()->get(), 0); if (menu->get_item_count() > 0) { menu->add_separator(); @@ -2831,7 +2831,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_separator(); menu->add_icon_shortcut(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), Key::KEY_DELETE), TOOL_ERASE); } - menu->set_size(Size2(1, 1)); + menu->reset_size(); menu->set_position(p_menu_pos); menu->popup(); } @@ -2843,7 +2843,7 @@ void SceneTreeDock::_open_tree_menu() { menu->add_check_item(TTR("Auto Expand to Selected"), TOOL_AUTO_EXPAND); menu->set_item_checked(menu->get_item_idx_from_text(TTR("Auto Expand to Selected")), EditorSettings::get_singleton()->get("docks/scene_tree/auto_expand_to_selected")); - menu->set_size(Size2(1, 1)); + menu->reset_size(); menu->set_position(get_screen_position() + get_local_mouse_position()); menu->popup(); } diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp index 1c49029570..435069e25c 100644 --- a/modules/bullet/area_bullet.cpp +++ b/modules/bullet/area_bullet.cpp @@ -92,8 +92,8 @@ void AreaBullet::dispatch_callbacks() { overlapping_shapes.remove(i); // Remove after callback break; case OVERLAP_STATE_INSIDE: { - if (otherObj.object->getType() == TYPE_RIGID_BODY) { - RigidBodyBullet *body = static_cast<RigidBodyBullet *>(otherObj.object); + if (overlapping_shape.other_object->getType() == TYPE_RIGID_BODY) { + RigidBodyBullet *body = static_cast<RigidBodyBullet *>(overlapping_shape.other_object); body->scratch_space_override_modificator(); } break; @@ -276,7 +276,7 @@ void AreaBullet::set_param(PhysicsServer3D::AreaParameter p_param, const Variant default: WARN_PRINT("Area doesn't support this parameter in the Bullet backend: " + itos(p_param)); } - scratch(); + isScratched = true; } Variant AreaBullet::get_param(PhysicsServer3D::AreaParameter p_param) const { @@ -312,7 +312,7 @@ void AreaBullet::set_event_callback(Type p_callbackObjectType, const Callable &p set_godot_object_flags(get_godot_object_flags() | GOF_IS_MONITORING_AREA); } else { set_godot_object_flags(get_godot_object_flags() & (~GOF_IS_MONITORING_AREA)); - clear_overlaps(true); + clear_overlaps(); } } diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl index 158cd960c4..7bb8346c47 100644 --- a/modules/lightmapper_rd/lm_compute.glsl +++ b/modules/lightmapper_rd/lm_compute.glsl @@ -235,19 +235,39 @@ uint trace_ray(vec3 p_from, vec3 p_to return RAY_MISS; } +// https://www.reedbeta.com/blog/hash-functions-for-gpu-rendering/ +uint hash(uint value) { + uint state = value * 747796405u + 2891336453u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +uint random_seed(ivec3 seed) { + return hash(seed.x ^ hash(seed.y ^ hash(seed.z))); +} + +// generates a random value in range [0.0, 1.0) +float randomize(inout uint value) { + value = hash(value); + return float(value / 4294967296.0); +} + const float PI = 3.14159265f; -const float GOLDEN_ANGLE = PI * (3.0 - sqrt(5.0)); - -vec3 vogel_hemisphere(uint p_index, uint p_count, float p_offset) { - float r = sqrt(float(p_index) + 0.5f) / sqrt(float(p_count)); - float theta = float(p_index) * GOLDEN_ANGLE + p_offset; - float y = cos(r * PI * 0.5); - float l = sin(r * PI * 0.5); - return vec3(l * cos(theta), l * sin(theta), y); + +// http://www.realtimerendering.com/raytracinggems/unofficial_RayTracingGems_v1.4.pdf (chapter 15) +vec3 generate_hemisphere_uniform_direction(inout uint noise) { + float noise1 = randomize(noise); + float noise2 = randomize(noise) * 2.0 * PI; + + float factor = sqrt(1 - (noise1 * noise1)); + return vec3(factor * cos(noise2), factor * sin(noise2), noise1); } -float quick_hash(vec2 pos) { - return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237); +vec3 generate_hemisphere_cosine_weighted_direction(inout uint noise) { + float noise1 = randomize(noise); + float noise2 = randomize(noise) * 2.0 * PI; + + return vec3(sqrt(noise1) * cos(noise2), sqrt(noise1) * sin(noise2), sqrt(1.0 - noise1)); } float get_omni_attenuation(float distance, float inv_range, float decay) { @@ -404,8 +424,9 @@ void main() { #endif vec3 light_average = vec3(0.0); float active_rays = 0.0; + uint noise = random_seed(ivec3(params.ray_from, atlas_pos)); for (uint i = params.ray_from; i < params.ray_to; i++) { - vec3 ray_dir = normal_mat * vogel_hemisphere(i, params.ray_count, quick_hash(vec2(atlas_pos))); + vec3 ray_dir = normal_mat * generate_hemisphere_cosine_weighted_direction(noise); uint tidx; vec3 barycentric; @@ -550,8 +571,9 @@ void main() { vec4(0.0), vec4(0.0)); + uint noise = random_seed(ivec3(params.ray_from, probe_index, 49502741 /* some prime */)); for (uint i = params.ray_from; i < params.ray_to; i++) { - vec3 ray_dir = vogel_hemisphere(i, params.ray_count, quick_hash(vec2(float(probe_index), 0.0))); + vec3 ray_dir = generate_hemisphere_uniform_direction(noise); if (bool(i & 1)) { //throw to both sides, so alternate them ray_dir.z *= -1.0; diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp index 2096487235..e8b25b58b6 100644 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ b/modules/visual_script/editor/visual_script_editor.cpp @@ -998,7 +998,7 @@ void VisualScriptEditor::_change_port_type(int p_select, int p_id, int p_port, b void VisualScriptEditor::_update_node_size(int p_id) { Node *node = graph->get_node(itos(p_id)); if (Object::cast_to<Control>(node)) { - Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); // Shrink if text is smaller. + Object::cast_to<Control>(node)->reset_size(); // Shrink if text is smaller. } } @@ -1616,7 +1616,7 @@ void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id Node *node = graph->get_node(itos(p_id)); if (Object::cast_to<Control>(node)) { - Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); // Shrink if text is smaller. + Object::cast_to<Control>(node)->reset_size(); // Shrink if text is smaller. } updating_graph = false; @@ -3676,7 +3676,7 @@ void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_i } default_value_edit->set_position(Object::cast_to<Control>(p_button)->get_global_position() + Vector2(0, Object::cast_to<Control>(p_button)->get_size().y)); - default_value_edit->set_size(Size2(1, 1)); + default_value_edit->reset_size(); if (pinfo.type == Variant::NODE_PATH) { Node *edited_scene = get_tree()->get_edited_scene_root(); @@ -3832,7 +3832,7 @@ void VisualScriptEditor::_comment_node_resized(const Vector2 &p_new_size, int p_ undo_redo->commit_action(); gn->set_custom_minimum_size(new_size); - gn->set_size(Size2(1, 1)); + gn->reset_size(); graph->set_block_minimum_size_adjust(false); updating_graph = false; } @@ -4132,10 +4132,10 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) { member_popup->clear(); member_popup->set_position(members->get_global_position() + p_pos); - member_popup->set_size(Vector2()); + member_popup->reset_size(); function_name_edit->set_position(members->get_global_position() + p_pos); - function_name_edit->set_size(Vector2()); + function_name_edit->reset_size(); TreeItem *root = members->get_root(); diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 34f0064a5e..505e7ac0eb 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -119,7 +119,9 @@ DisplayServer::ScreenOrientation DisplayServerAndroid::screen_get_orientation(in GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java(); ERR_FAIL_COND_V(!godot_io_java, SCREEN_LANDSCAPE); - return (ScreenOrientation)godot_io_java->get_screen_orientation(); + const int orientation = godot_io_java->get_screen_orientation(); + ERR_FAIL_INDEX_V_MSG(orientation, 7, SCREEN_LANDSCAPE, "Unrecognized screen orientation"); + return (ScreenOrientation)orientation; } int DisplayServerAndroid::get_screen_count() const { diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 18e9e20948..05cd63d935 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -751,9 +751,9 @@ void EditorExportPlatformAndroid::_get_permissions(const Ref<EditorExportPreset> } int xr_mode_index = p_preset->get("xr_features/xr_mode"); - if (xr_mode_index == 1 /* XRMode.OVR */) { + if (xr_mode_index == XR_MODE_OPENXR) { int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required - if (hand_tracking_index > 0) { + if (hand_tracking_index > XR_HAND_TRACKING_NONE) { if (r_permissions.find("com.oculus.permission.HAND_TRACKING") == -1) { r_permissions.push_back("com.oculus.permission.HAND_TRACKING"); } @@ -964,6 +964,20 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p } } + if (tname == "meta-data" && attrname == "name" && value == "xr_mode_metadata_name") { + // Update the meta-data 'android:name' attribute based on the selected XR mode. + if (xr_mode_index == XR_MODE_OPENXR) { + string_table.write[attr_value] = "com.samsung.android.vr.application.mode"; + } + } + + if (tname == "meta-data" && attrname == "value" && value == "xr_mode_metadata_value") { + // Update the meta-data 'android:value' attribute based on the selected XR mode. + if (xr_mode_index == XR_MODE_OPENXR) { + string_table.write[attr_value] = "vr_only"; + } + } + iofs += 20; } @@ -978,7 +992,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p Vector<bool> feature_required_list; Vector<int> feature_versions; - if (xr_mode_index == 1 /* XRMode.OVR */) { + if (xr_mode_index == XR_MODE_OPENXR) { // Set degrees of freedom feature_names.push_back("android.hardware.vr.headtracking"); feature_required_list.push_back(true); @@ -986,11 +1000,19 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p // Check for hand tracking int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required - if (hand_tracking_index > 0) { + if (hand_tracking_index > XR_HAND_TRACKING_NONE) { feature_names.push_back("oculus.software.handtracking"); - feature_required_list.push_back(hand_tracking_index == 2); + feature_required_list.push_back(hand_tracking_index == XR_HAND_TRACKING_REQUIRED); feature_versions.push_back(-1); // no version attribute should be added. } + + // Check for passthrough + int passthrough_mode = p_preset->get("xr_features/passthrough"); + if (passthrough_mode > XR_PASSTHROUGH_NONE) { + feature_names.push_back("com.oculus.feature.PASSTHROUGH"); + feature_required_list.push_back(passthrough_mode == XR_PASSTHROUGH_REQUIRED); + feature_versions.push_back(-1); + } } if (feature_names.size() > 0) { @@ -1669,8 +1691,9 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/opengl_debug"), false)); - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,OpenXR"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/passthrough", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true)); @@ -2137,10 +2160,17 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr // Validate the Xr features are properly populated int xr_mode_index = p_preset->get("xr_features/xr_mode"); int hand_tracking = p_preset->get("xr_features/hand_tracking"); - if (xr_mode_index != /* XRMode.OVR*/ 1) { - if (hand_tracking > 0) { + int passthrough_mode = p_preset->get("xr_features/passthrough"); + if (xr_mode_index != XR_MODE_OPENXR) { + if (hand_tracking > XR_HAND_TRACKING_NONE) { + valid = false; + err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"OpenXR\"."); + err += "\n"; + } + + if (passthrough_mode > XR_PASSTHROUGH_NONE) { valid = false; - err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."); + err += TTR("\"Passthrough\" is only valid when \"Xr Mode\" is \"OpenXR\"."); err += "\n"; } } @@ -2202,8 +2232,8 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP } int xr_mode_index = p_preset->get("xr_features/xr_mode"); - if (xr_mode_index == 1) { - command_line_strings.push_back("--xr_mode_ovr"); + if (xr_mode_index == XR_MODE_OPENXR) { + command_line_strings.push_back("--xr_mode_openxr"); } else { // XRMode.REGULAR is the default. command_line_strings.push_back("--xr_mode_regular"); } diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index b0d623827e..658c0ecd0a 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -211,16 +211,24 @@ String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) { String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) { String manifest_xr_features; - bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1; + int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode")); + bool uses_xr = xr_mode_index == XR_MODE_OPENXR; if (uses_xr) { manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"true\" android:version=\"1\" />\n"; int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required - if (hand_tracking_index == 1) { + if (hand_tracking_index == XR_HAND_TRACKING_OPTIONAL) { manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n"; - } else if (hand_tracking_index == 2) { + } else if (hand_tracking_index == XR_HAND_TRACKING_REQUIRED) { manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"true\" />\n"; } + + int passthrough_mode = p_preset->get("xr_features/passthrough"); + if (passthrough_mode == XR_PASSTHROUGH_OPTIONAL) { + manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"com.oculus.feature.PASSTHROUGH\" android:required=\"false\" />\n"; + } else if (passthrough_mode == XR_PASSTHROUGH_REQUIRED) { + manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"com.oculus.feature.PASSTHROUGH\" android:required=\"true\" />\n"; + } } return manifest_xr_features; } @@ -239,7 +247,8 @@ String _get_instrumentation_tag(const Ref<EditorExportPreset> &p_preset) { } String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) { - bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1; + int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode")); + bool uses_xr = xr_mode_index == XR_MODE_OPENXR; String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation")))); String manifest_activity_text = vformat( " <activity android:name=\"com.godot.game.GodotApp\" " @@ -256,6 +265,8 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) { } String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_storage_permission) { + int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode")); + bool uses_xr = xr_mode_index == XR_MODE_OPENXR; String manifest_application_text = vformat( " <application android:label=\"@string/godot_project_name_string\"\n" " android:allowBackup=\"%s\"\n" @@ -270,6 +281,9 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_ bool_to_string(p_preset->get("package/retain_data_on_uninstall")), bool_to_string(p_has_storage_permission)); + if (uses_xr) { + manifest_application_text += " <meta-data tools:node=\"replace\" android:name=\"com.samsung.android.vr.application.mode\" android:value=\"vr_only\" />\n"; + } manifest_application_text += _get_activity_tag(p_preset); manifest_application_text += " </application>\n"; return manifest_application_text; diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 744022f1f9..db05c7534c 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -44,6 +44,21 @@ const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="ut </resources> )"; +// Supported XR modes. +// This should match the entries in 'platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java' +static const int XR_MODE_REGULAR = 0; +static const int XR_MODE_OPENXR = 1; + +// Supported XR hand tracking modes. +static const int XR_HAND_TRACKING_NONE = 0; +static const int XR_HAND_TRACKING_OPTIONAL = 1; +static const int XR_HAND_TRACKING_REQUIRED = 2; + +// Supported XR passthrough modes. +static const int XR_PASSTHROUGH_NONE = 0; +static const int XR_PASSTHROUGH_OPTIONAL = 1; +static const int XR_PASSTHROUGH_REQUIRED = 2; + struct CustomExportData { String assets_directory; bool debug; diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml index d7bf6cef30..9ae6367b42 100644 --- a/platform/android/java/app/AndroidManifest.xml +++ b/platform/android/java/app/AndroidManifest.xml @@ -33,6 +33,11 @@ <!-- The following metadata values are replaced when Godot exports, modifying them here has no effect. --> <!-- Do these changes in the export preset. Adding new ones is fine. --> + <!-- XR mode metadata. This is modified by the exporter based on the selected xr mode. DO NOT CHANGE the values here. --> + <meta-data + android:name="xr_mode_metadata_name" + android:value="xr_mode_metadata_value" /> + <activity android:name=".GodotApp" android:label="@string/godot_project_name_string" diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index b6476fa61a..17ff3c75c0 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -502,8 +502,8 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC boolean has_extra = i < command_line.length - 1; if (command_line[i].equals(XRMode.REGULAR.cmdLineArg)) { xrMode = XRMode.REGULAR; - } else if (command_line[i].equals(XRMode.OVR.cmdLineArg)) { - xrMode = XRMode.OVR; + } else if (command_line[i].equals(XRMode.OPENXR.cmdLineArg)) { + xrMode = XRMode.OPENXR; } else if (command_line[i].equals("--debug_opengl")) { use_debug_opengl = true; } else if (command_line[i].equals("--use_immersive")) { diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java index 088b048502..d5b0b67903 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java @@ -174,7 +174,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView setPreserveEGLContextOnPause(true); setFocusableInTouchMode(true); switch (xrMode) { - case OVR: + case OPENXR: // Replace the default egl config chooser. setEGLConfigChooser(new OvrConfigChooser()); diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java index d85d88ec6c..5f354b6b4c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -288,7 +288,34 @@ public class GodotIO { } public int getScreenOrientation() { - return activity.getRequestedOrientation(); + int orientation = activity.getRequestedOrientation(); + switch (orientation) { + case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: + return SCREEN_LANDSCAPE; + case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: + return SCREEN_PORTRAIT; + case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE: + return SCREEN_REVERSE_LANDSCAPE; + case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT: + return SCREEN_REVERSE_PORTRAIT; + case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: + case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE: + return SCREEN_SENSOR_LANDSCAPE; + case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: + case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT: + return SCREEN_SENSOR_PORTRAIT; + case ActivityInfo.SCREEN_ORIENTATION_SENSOR: + case ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR: + case ActivityInfo.SCREEN_ORIENTATION_FULL_USER: + return SCREEN_SENSOR; + case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED: + case ActivityInfo.SCREEN_ORIENTATION_USER: + case ActivityInfo.SCREEN_ORIENTATION_BEHIND: + case ActivityInfo.SCREEN_ORIENTATION_NOSENSOR: + case ActivityInfo.SCREEN_ORIENTATION_LOCKED: + default: + return -1; + } } public void setEdit(GodotEditText _edit) { diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java b/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java index 0995477baf..58f02b0396 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java @@ -35,7 +35,7 @@ package org.godotengine.godot.xr; */ public enum XRMode { REGULAR(0, "Regular", "--xr_mode_regular", "Default Android Gamepad"), // Regular/flatscreen - OVR(1, "Oculus Mobile VR", "--xr_mode_ovr", ""); + OPENXR(1, "OpenXR", "--xr_mode_openxr", ""); final int index; final String label; diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index d9a2ea756a..edaf76bc3e 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -1587,6 +1587,7 @@ void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResu Vector3 prev_wall_normal = wall_normal; int wall_collision_count = 0; Vector3 combined_wall_normal; + Vector3 tmp_wall_col; // Avoid duplicate on average calculation. for (int i = p_result.collision_count - 1; i >= 0; i--) { const PhysicsServer3D::MotionCollision &collision = p_result.collisions[i]; @@ -1633,8 +1634,11 @@ void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResu } // Collect normal for calculating average. - combined_wall_normal += collision.normal; - wall_collision_count++; + if (!collision.normal.is_equal_approx(tmp_wall_col)) { + tmp_wall_col = collision.normal; + combined_wall_normal += collision.normal; + wall_collision_count++; + } } if (r_state.wall) { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 582c8e5860..9f715be155 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -810,6 +810,10 @@ void Control::set_drag_preview(Control *p_control) { get_viewport()->_gui_set_drag_preview(this, p_control); } +bool Control::is_drag_successful() const { + return is_inside_tree() && get_viewport()->gui_is_drag_successful(); +} + void Control::_call_gui_input(const Ref<InputEvent> &p_event) { emit_signal(SceneStringNames::get_singleton()->gui_input, p_event); //signal should be first, so it's possible to override an event (and then accept it) if (!is_inside_tree() || get_viewport()->is_input_handled()) { @@ -1821,6 +1825,10 @@ Size2 Control::get_size() const { return data.size_cache; } +void Control::reset_size() { + set_size(Size2()); +} + Rect2 Control::get_global_rect() const { return Rect2(get_global_position(), get_size()); } @@ -2841,6 +2849,7 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("set_position", "position", "keep_offsets"), &Control::set_position, DEFVAL(false)); ClassDB::bind_method(D_METHOD("_set_position", "position"), &Control::_set_position); ClassDB::bind_method(D_METHOD("set_size", "size", "keep_offsets"), &Control::set_size, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("reset_size"), &Control::reset_size); ClassDB::bind_method(D_METHOD("_set_size", "size"), &Control::_set_size); ClassDB::bind_method(D_METHOD("set_custom_minimum_size", "size"), &Control::set_custom_minimum_size); ClassDB::bind_method(D_METHOD("set_global_position", "position", "keep_offsets"), &Control::set_global_position, DEFVAL(false)); @@ -2964,6 +2973,7 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("set_drag_forwarding", "target"), &Control::set_drag_forwarding); ClassDB::bind_method(D_METHOD("set_drag_preview", "control"), &Control::set_drag_preview); + ClassDB::bind_method(D_METHOD("is_drag_successful"), &Control::is_drag_successful); ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Control::warp_mouse); diff --git a/scene/gui/control.h b/scene/gui/control.h index 02ab336ef0..1a94cc68a6 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -357,6 +357,7 @@ public: virtual void drop_data(const Point2 &p_point, const Variant &p_data); void set_drag_preview(Control *p_control); void force_drag(const Variant &p_data, Control *p_control); + bool is_drag_successful() const; void set_custom_minimum_size(const Size2 &p_custom); Size2 get_custom_minimum_size() const; @@ -400,6 +401,7 @@ public: void set_size(const Size2 &p_size, bool p_keep_offsets = false); Size2 get_size() const; + void reset_size(); Rect2 get_rect() const; Rect2 get_global_rect() const; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 124d5c7821..69b08fda3c 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -228,7 +228,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { if (b->is_pressed() && b->get_button_index() == MouseButton::RIGHT && context_menu_enabled) { _ensure_menu(); menu->set_position(get_screen_transform().xform(get_local_mouse_position())); - menu->set_size(Vector2(1, 1)); + menu->reset_size(); menu->popup(); grab_focus(); accept_event(); @@ -268,7 +268,9 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { return; } - shift_selection_check_pre(b->is_shift_pressed()); + if (b->is_shift_pressed()) { + shift_selection_check_pre(true); + } set_caret_at_pixel_pos(b->get_position().x); @@ -345,6 +347,9 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { } selection.creating = false; selection.double_click = false; + if (!drag_action) { + selection.drag_attempt = false; + } show_virtual_keyboard(); } @@ -369,6 +374,11 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { selection_fill_at_caret(); } } + + if (drag_action && can_drop_data(m->get_position(), get_viewport()->gui_get_drag_data())) { + drag_caret_force_displayed = true; + set_caret_at_pixel_pos(m->get_position().x); + } } Ref<InputEventKey> k = p_event; @@ -383,7 +393,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { _ensure_menu(); Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")))) / 2); menu->set_position(get_global_transform().xform(pos)); - menu->set_size(Vector2(1, 1)); + menu->reset_size(); menu->popup(); menu->grab_focus(); } @@ -569,21 +579,44 @@ bool LineEdit::can_drop_data(const Point2 &p_point, const Variant &p_data) const return drop_override; } - return p_data.get_type() == Variant::STRING; + return is_editable() && p_data.get_type() == Variant::STRING; } void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) { Control::drop_data(p_point, p_data); - if (p_data.get_type() == Variant::STRING) { + if (p_data.get_type() == Variant::STRING && is_editable()) { set_caret_at_pixel_pos(p_point.x); + int caret_column_tmp = caret_column; + if (selection.drag_attempt) { + selection.drag_attempt = false; + if (caret_column < selection.begin || caret_column > selection.end) { + if (caret_column_tmp > selection.end) { + caret_column_tmp = caret_column_tmp - (selection.end - selection.begin); + } + selection_delete(); - text = text.left(selection.begin) + text.substr(selection.end); - _shape(); - - insert_text_at_caret(p_data); - selection.begin = caret_column - (selection.end - selection.begin); - selection.end = caret_column; + set_caret_column(caret_column_tmp); + insert_text_at_caret(p_data); + } + } else if (selection.enabled && caret_column >= selection.begin && caret_column <= selection.end) { + caret_column_tmp = selection.begin; + selection_delete(); + set_caret_column(caret_column_tmp); + insert_text_at_caret(p_data); + grab_focus(); + } else { + insert_text_at_caret(p_data); + grab_focus(); + } + select(caret_column_tmp, caret_column); + if (!text_changed_dirty) { + if (is_inside_tree()) { + MessageQueue::get_singleton()->push_call(this, "_text_changed"); + } + text_changed_dirty = true; + } + update(); } } @@ -803,7 +836,7 @@ void LineEdit::_notification(int p_what) { // Draw carets. ofs.x = x_ofs + scroll_offset; - if (draw_caret) { + if (draw_caret || drag_caret_force_displayed) { if (ime_text.length() == 0) { // Normal caret. CaretInfo caret = TS->shaped_text_get_carets(text_rid, caret_column); @@ -921,7 +954,7 @@ void LineEdit::_notification(int p_what) { DisplayServer::get_singleton()->virtual_keyboard_hide(); } - if (deselect_on_focus_loss_enabled) { + if (deselect_on_focus_loss_enabled && !selection.drag_attempt) { deselect(); } } break; @@ -935,6 +968,25 @@ void LineEdit::_notification(int p_what) { update(); } } break; + case Control::NOTIFICATION_DRAG_BEGIN: { + drag_action = true; + } break; + case Control::NOTIFICATION_DRAG_END: { + if (is_drag_successful()) { + if (selection.drag_attempt) { + selection.drag_attempt = false; + if (is_editable()) { + selection_delete(); + } else if (deselect_on_focus_loss_enabled) { + deselect(); + } + } + } else { + selection.drag_attempt = false; + } + drag_action = false; + drag_caret_force_displayed = false; + } break; } } @@ -999,6 +1051,9 @@ void LineEdit::undo() { } else if (undo_stack_pos == undo_stack.front()) { return; } + + deselect(); + undo_stack_pos = undo_stack_pos->prev(); TextOperation op = undo_stack_pos->get(); text = op.text; @@ -1020,6 +1075,9 @@ void LineEdit::redo() { if (undo_stack_pos == undo_stack.back()) { return; } + + deselect(); + undo_stack_pos = undo_stack_pos->next(); TextOperation op = undo_stack_pos->get(); text = op.text; diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 134d5f8f76..221dd9eb2e 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -129,6 +129,9 @@ private: bool middle_mouse_paste_enabled = true; + bool drag_action = false; + bool drag_caret_force_displayed = false; + Ref<Texture2D> right_icon; bool flat = false; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 74268707ff..c8f6ecdafd 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -608,7 +608,7 @@ void TextEdit::_notification(int p_what) { int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0); draw_amount += get_line_wrap_count(first_visible_line + 1); - // minimap + // Draw minimap. if (draw_minimap) { int minimap_visible_lines = get_minimap_visible_lines(); int minimap_line_height = (minimap_char_size.y + minimap_line_spacing); @@ -788,8 +788,9 @@ void TextEdit::_notification(int p_what) { bottom_limit_y -= style_normal->get_margin(SIDE_BOTTOM); } - // draw main text + // Draw main text. caret.visible = false; + line_drawing_cache.clear(); int row_height = get_line_height(); int line = first_visible_line; for (int i = 0; i < draw_amount; i++) { @@ -810,6 +811,8 @@ void TextEdit::_notification(int p_what) { continue; } + LineDrawingCache cache_entry; + Dictionary color_map = _get_line_syntax_highlighting(line); // Ensure we at least use the font color. @@ -899,6 +902,8 @@ void TextEdit::_notification(int p_what) { if (line_wrap_index == 0) { // Only do these if we are on the first wrapped part of a line. + cache_entry.y_offset = ofs_y; + int gutter_offset = style_normal->get_margin(SIDE_LEFT); for (int g = 0; g < gutters.size(); g++) { const GutterInfo gutter = gutters[g]; @@ -1076,6 +1081,10 @@ void TextEdit::_notification(int p_what) { int gl_size = TS->shaped_text_get_glyph_count(rid); ofs_y += ldata->get_line_ascent(line_wrap_index); + + int first_visible_char = TS->shaped_text_get_range(rid).y; + int last_visible_char = TS->shaped_text_get_range(rid).x; + int char_ofs = 0; if (outline_size > 0 && outline_color.a > 0) { for (int j = 0; j < gl_size; j++) { @@ -1143,21 +1152,36 @@ void TextEdit::_notification(int p_what) { } } + bool had_glyphs_drawn = false; for (int k = 0; k < glyphs[j].repeat; k++) { if (!clipped && (char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) { if (glyphs[j].font_rid != RID()) { TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color); + had_glyphs_drawn = true; } else if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { TS->draw_hex_code_box(ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color); + had_glyphs_drawn = true; } } char_ofs += glyphs[j].advance; } + + if (had_glyphs_drawn) { + if (first_visible_char > glyphs[j].start) { + first_visible_char = glyphs[j].start; + } else if (last_visible_char < glyphs[j].end) { + last_visible_char = glyphs[j].end; + } + } + if ((char_ofs + char_margin) >= xmargin_end) { break; } } + cache_entry.first_visible_chars.push_back(first_visible_char); + cache_entry.last_visible_chars.push_back(last_visible_char); + // is_line_folded if (line_wrap_index == line_wrap_amount && line < text.size() - 1 && _is_line_hidden(line + 1)) { int xofs = char_ofs + char_margin + ofs_x + (folded_eol_icon->get_width() / 2); @@ -1308,6 +1332,8 @@ void TextEdit::_notification(int p_what) { } } } + + line_drawing_cache[line] = cache_entry; } if (has_focus()) { @@ -1569,7 +1595,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { _generate_context_menu(); menu->set_position(get_screen_transform().xform(mpos)); - menu->set_size(Vector2(1, 1)); + menu->reset_size(); menu->popup(); grab_focus(); } @@ -1802,7 +1828,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { _generate_context_menu(); adjust_viewport_to_caret(); menu->set_position(get_screen_transform().xform(get_caret_draw_pos())); - menu->set_size(Vector2(1, 1)); + menu->reset_size(); menu->popup(); menu->grab_focus(); } @@ -3457,6 +3483,49 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_ return Point2i(col, row); } +Point2i TextEdit::get_pos_at_line_column(int p_line, int p_column) const { + Rect2i rect = get_rect_at_line_column(p_line, p_column); + return rect.position + Vector2i(0, get_line_height()); +} + +Rect2i TextEdit::get_rect_at_line_column(int p_line, int p_column) const { + ERR_FAIL_INDEX_V(p_line, text.size(), Rect2i(-1, -1, 0, 0)); + ERR_FAIL_COND_V(p_column < 0, Rect2i(-1, -1, 0, 0)); + ERR_FAIL_COND_V(p_column > text[p_line].length(), Rect2i(-1, -1, 0, 0)); + + if (line_drawing_cache.size() == 0 || !line_drawing_cache.has(p_line)) { + // Line is not in the cache, which means it's outside of the viewing area. + return Rect2i(-1, -1, 0, 0); + } + LineDrawingCache cache_entry = line_drawing_cache[p_line]; + + int wrap_index = get_line_wrap_index_at_column(p_line, p_column); + if (wrap_index >= cache_entry.first_visible_chars.size()) { + // Line seems to be wrapped beyond the viewable area. + return Rect2i(-1, -1, 0, 0); + } + + int first_visible_char = cache_entry.first_visible_chars[wrap_index]; + int last_visible_char = cache_entry.last_visible_chars[wrap_index]; + if (p_column < first_visible_char || p_column > last_visible_char) { + // Character is outside of the viewing area, no point calculating its position. + return Rect2i(-1, -1, 0, 0); + } + + Point2i pos, size; + pos.y = cache_entry.y_offset + get_line_height() * wrap_index; + pos.x = get_total_gutter_width() + style_normal->get_margin(SIDE_LEFT) - get_h_scroll(); + + RID text_rid = text.get_line_data(p_line)->get_line_rid(wrap_index); + Vector2 col_bounds = TS->shaped_text_get_grapheme_bounds(text_rid, p_column); + pos.x += col_bounds.x; + size.x = col_bounds.y - col_bounds.x; + + size.y = get_line_height(); + + return Rect2i(pos, size); +} + int TextEdit::get_minimap_line_at_pos(const Point2i &p_pos) const { float rows = p_pos.y; rows -= style_normal->get_margin(SIDE_TOP); @@ -3897,7 +3966,7 @@ void TextEdit::delete_selection() { update(); } -/* line wrapping. */ +/* Line wrapping. */ void TextEdit::set_line_wrapping_mode(LineWrappingMode p_wrapping_mode) { if (line_wrapping_mode != p_wrapping_mode) { line_wrapping_mode = p_wrapping_mode; @@ -4701,6 +4770,9 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_word_at_pos", "position"), &TextEdit::get_word_at_pos); ClassDB::bind_method(D_METHOD("get_line_column_at_pos", "position", "allow_out_of_bounds"), &TextEdit::get_line_column_at_pos, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("get_pos_at_line_column", "line", "column"), &TextEdit::get_pos_at_line_column); + ClassDB::bind_method(D_METHOD("get_rect_at_line_column", "line", "column"), &TextEdit::get_rect_at_line_column); + ClassDB::bind_method(D_METHOD("get_minimap_line_at_pos", "position"), &TextEdit::get_minimap_line_at_pos); ClassDB::bind_method(D_METHOD("is_dragging_cursor"), &TextEdit::is_dragging_cursor); @@ -4778,7 +4850,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("deselect"), &TextEdit::deselect); ClassDB::bind_method(D_METHOD("delete_selection"), &TextEdit::delete_selection); - /* line wrapping. */ + /* Line wrapping. */ BIND_ENUM_CONSTANT(LINE_WRAPPING_NONE); BIND_ENUM_CONSTANT(LINE_WRAPPING_BOUNDARY); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 09315ae395..b13adb8519 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -271,7 +271,7 @@ private: bool virtual_keyboard_enabled = true; bool middle_mouse_paste_enabled = true; - // Overridable actions + // Overridable actions. String cut_copy_line = ""; // Context menu. @@ -336,6 +336,14 @@ private: Variant tooltip_ud; /* Mouse */ + struct LineDrawingCache { + int y_offset = 0; + Vector<int> first_visible_chars; + Vector<int> last_visible_chars; + }; + + Map<int, LineDrawingCache> line_drawing_cache; + int _get_char_pos_for_line(int p_px, int p_line, int p_wrap_index = 0) const; /* Caret. */ @@ -415,7 +423,7 @@ private: void _pre_shift_selection(); void _post_shift_selection(); - /* line wrapping. */ + /* Line wrapping. */ LineWrappingMode line_wrapping_mode = LineWrappingMode::LINE_WRAPPING_NONE; int wrap_at_column = 0; @@ -455,14 +463,14 @@ private: void _scroll_lines_up(); void _scroll_lines_down(); - // Minimap + // Minimap. bool draw_minimap = false; int minimap_width = 80; Point2 minimap_char_size = Point2(1, 2); int minimap_line_spacing = 1; - // minimap scroll + // Minimap scroll. bool minimap_clicked = false; bool hovering_minimap = false; bool dragging_minimap = false; @@ -717,6 +725,9 @@ public: String get_word_at_pos(const Vector2 &p_pos) const; Point2i get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_of_bounds = true) const; + Point2i get_pos_at_line_column(int p_line, int p_column) const; + Rect2i get_rect_at_line_column(int p_line, int p_column) const; + int get_minimap_line_at_pos(const Point2i &p_pos) const; bool is_dragging_cursor() const; @@ -782,7 +793,7 @@ public: void deselect(); void delete_selection(); - /* line wrapping. */ + /* Line wrapping. */ void set_line_wrapping_mode(LineWrappingMode p_wrapping_mode); LineWrappingMode get_line_wrapping_mode() const; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 1ecc3c762a..48a672b310 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1515,8 +1515,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MouseButton::LEFT) { // Alternate drop use (when using force_drag(), as proposed by #5342). + gui.drag_successful = false; if (gui.mouse_focus) { - _gui_drop(gui.mouse_focus, pos, false); + gui.drag_successful = _gui_drop(gui.mouse_focus, pos, false); } gui.drag_data = Variant(); @@ -1534,8 +1535,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { _gui_cancel_tooltip(); } else { if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MouseButton::LEFT) { + gui.drag_successful = false; if (gui.drag_mouse_over) { - _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false); + gui.drag_successful = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false); } Control *drag_preview = _gui_get_drag_preview(); @@ -2895,6 +2897,10 @@ bool Viewport::gui_is_dragging() const { return gui.dragging; } +bool Viewport::gui_is_drag_successful() const { + return gui.drag_successful; +} + void Viewport::set_input_as_handled() { _drop_physics_mouseover(); @@ -3534,6 +3540,7 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data); ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging); + ClassDB::bind_method(D_METHOD("gui_is_drag_successful"), &Viewport::gui_is_drag_successful); ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input); ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 5320aea02a..11b76b32eb 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -348,6 +348,7 @@ private: List<Control *> roots; int canvas_sort_index = 0; //for sorting items with canvas as root bool dragging = false; + bool drag_successful = false; bool embed_subwindows_hint = false; bool embedding_subwindows = false; @@ -556,6 +557,7 @@ public: bool is_handling_input_locally() const; bool gui_is_dragging() const; + bool gui_is_drag_successful() const; Control *gui_find_control(const Point2 &p_global); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 5da5a183f7..20f8b30dc6 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -88,6 +88,10 @@ Size2i Window::get_size() const { return size; } +void Window::reset_size() { + set_size(Size2i()); +} + Size2i Window::get_real_size() const { if (window_id != DisplayServer::INVALID_WINDOW_ID) { return DisplayServer::get_singleton()->window_get_real_size(window_id); @@ -1410,6 +1414,7 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("set_size", "size"), &Window::set_size); ClassDB::bind_method(D_METHOD("get_size"), &Window::get_size); + ClassDB::bind_method(D_METHOD("reset_size"), &Window::reset_size); ClassDB::bind_method(D_METHOD("get_real_size"), &Window::get_real_size); diff --git a/scene/main/window.h b/scene/main/window.h index def6eab7b8..0b1075ff76 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -178,6 +178,7 @@ public: void set_size(const Size2i &p_size); Size2i get_size() const; + void reset_size(); Size2i get_real_size() const; diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 29aca6b321..d31771e71a 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -335,7 +335,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { bt->values.write[i].value.in_handle.y = rv[i * 6 + 2]; bt->values.write[i].value.out_handle.x = rv[i * 6 + 3]; bt->values.write[i].value.out_handle.y = rv[i * 6 + 4]; - bt->values.write[i].value.handle_mode = (HandleMode)rv[i * 6 + 5]; + bt->values.write[i].value.handle_mode = static_cast<HandleMode>((int)rv[i * 6 + 5]); } } @@ -1634,7 +1634,7 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke k.value.in_handle.y = arr[2]; k.value.out_handle.x = arr[3]; k.value.out_handle.y = arr[4]; - k.value.handle_mode = (HandleMode) int(arr[5]); + k.value.handle_mode = static_cast<HandleMode>((int)arr[5]); _insert(p_time, bt->values, k); } break; @@ -2155,7 +2155,7 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p bt->values.write[p_key_idx].value.in_handle.y = arr[2]; bt->values.write[p_key_idx].value.out_handle.x = arr[3]; bt->values.write[p_key_idx].value.out_handle.y = arr[4]; - bt->values.write[p_key_idx].value.handle_mode = (HandleMode) int(arr[5]); + bt->values.write[p_key_idx].value.handle_mode = static_cast<HandleMode>((int)arr[5]); } break; case TYPE_AUDIO: { diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index d9de47afc7..6cd42e1456 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -88,6 +88,9 @@ void FontData::_bind_methods() { ClassDB::bind_method(D_METHOD("set_msdf_size", "msdf_size"), &FontData::set_msdf_size); ClassDB::bind_method(D_METHOD("get_msdf_size"), &FontData::get_msdf_size); + ClassDB::bind_method(D_METHOD("set_fixed_size", "fixed_size"), &FontData::set_fixed_size); + ClassDB::bind_method(D_METHOD("get_fixed_size"), &FontData::get_fixed_size); + ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &FontData::set_force_autohinter); ClassDB::bind_method(D_METHOD("is_force_autohinter"), &FontData::is_force_autohinter); diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index ed9ccd168d..ff388e288c 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -564,10 +564,10 @@ void PhysicalSkyMaterial::_update_shader() { shader_type sky; uniform float rayleigh : hint_range(0, 64) = 2.0; -uniform vec4 rayleigh_color : hint_color = vec4(0.056, 0.14, 0.3, 1.0); +uniform vec4 rayleigh_color : hint_color = vec4(0.26, 0.41, 0.58, 1.0); uniform float mie : hint_range(0, 1) = 0.005; uniform float mie_eccentricity : hint_range(-1, 1) = 0.8; -uniform vec4 mie_color : hint_color = vec4(0.36, 0.56, 0.82, 1.0); +uniform vec4 mie_color : hint_color = vec4(0.63, 0.77, 0.92, 1.0); uniform float turbidity : hint_range(0, 1000) = 10.0; uniform float sun_disk_scale : hint_range(0, 360) = 1.0; @@ -661,10 +661,10 @@ void sky() { PhysicalSkyMaterial::PhysicalSkyMaterial() { set_rayleigh_coefficient(2.0); - set_rayleigh_color(Color(0.056, 0.14, 0.3)); + set_rayleigh_color(Color(0.26, 0.41, 0.58)); set_mie_coefficient(0.005); set_mie_eccentricity(0.8); - set_mie_color(Color(0.36, 0.56, 0.82)); + set_mie_color(Color(0.63, 0.77, 0.92)); set_turbidity(10.0); set_sun_disk_scale(1.0); set_ground_color(Color(1.0, 1.0, 1.0)); diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index 0a7523e33a..d6d98b4f8f 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -260,6 +260,7 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_shaped_text_draw, "shaped", "canvas", "pos", "clip_l", "clip_r", "color"); GDVIRTUAL_BIND(_shaped_text_draw_outline, "shaped", "canvas", "pos", "clip_l", "clip_r", "outline_size", "color"); + GDVIRTUAL_BIND(_shaped_text_get_grapheme_bounds, "shaped", "pos"); GDVIRTUAL_BIND(_shaped_text_next_grapheme_pos, "shaped", "pos"); GDVIRTUAL_BIND(_shaped_text_prev_grapheme_pos, "shaped", "pos"); @@ -1292,6 +1293,14 @@ void TextServerExtension::shaped_text_draw_outline(RID p_shaped, RID p_canvas, c shaped_text_draw_outline(p_shaped, p_canvas, p_pos, p_clip_l, p_clip_r, p_outline_size, p_color); } +Vector2 TextServerExtension::shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const { + Vector2 ret; + if (GDVIRTUAL_CALL(_shaped_text_get_grapheme_bounds, p_shaped, p_pos, ret)) { + return ret; + } + return TextServer::shaped_text_get_grapheme_bounds(p_shaped, p_pos); +} + int TextServerExtension::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const { int ret; if (GDVIRTUAL_CALL(_shaped_text_next_grapheme_pos, p_shaped, p_pos, ret)) { diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index e419b4055d..a2dbd25e05 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -428,8 +428,10 @@ public: GDVIRTUAL6C(_shaped_text_draw, RID, RID, const Vector2 &, float, float, const Color &); GDVIRTUAL7C(_shaped_text_draw_outline, RID, RID, const Vector2 &, float, float, int, const Color &); + virtual Vector2 shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const override; virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const override; virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const override; + GDVIRTUAL2RC(Vector2, _shaped_text_get_grapheme_bounds, RID, int); GDVIRTUAL2RC(int, _shaped_text_next_grapheme_pos, RID, int); GDVIRTUAL2RC(int, _shaped_text_prev_grapheme_pos, RID, int); diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 9034239fe0..8fc1b56ae4 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -403,6 +403,7 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shaped_text_hit_test_grapheme", "shaped", "coords"), &TextServer::shaped_text_hit_test_grapheme); ClassDB::bind_method(D_METHOD("shaped_text_hit_test_position", "shaped", "coords"), &TextServer::shaped_text_hit_test_position); + ClassDB::bind_method(D_METHOD("shaped_text_get_grapheme_bounds", "shaped", "pos"), &TextServer::shaped_text_get_grapheme_bounds); ClassDB::bind_method(D_METHOD("shaped_text_next_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_next_grapheme_pos); ClassDB::bind_method(D_METHOD("shaped_text_prev_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_prev_grapheme_pos); @@ -1120,6 +1121,27 @@ int TextServer::shaped_text_hit_test_position(RID p_shaped, real_t p_coords) con return 0; } +Vector2 TextServer::shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const { + int v_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); + + real_t off = 0.0f; + for (int i = 0; i < v_size; i++) { + if ((glyphs[i].count > 0) && ((glyphs[i].index != 0) || ((glyphs[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE))) { + if (glyphs[i].start <= p_pos && glyphs[i].end >= p_pos) { + real_t advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance; + } + return Vector2(off, off + advance); + } + } + off += glyphs[i].advance * glyphs[i].repeat; + } + + return Vector2(); +} + int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const { int v_size = shaped_text_get_glyph_count(p_shaped); const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); diff --git a/servers/text_server.h b/servers/text_server.h index 4f55f881e6..5c994feaae 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -438,6 +438,7 @@ public: virtual int shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const; // Return grapheme index. virtual int shaped_text_hit_test_position(RID p_shaped, float p_coords) const; // Return caret/selection position. + virtual Vector2 shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const; virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const; virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const; diff --git a/thirdparty/README.md b/thirdparty/README.md index 18da4d6a63..6ebcffb7ae 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -333,7 +333,7 @@ File extracted from upstream release tarball: ## meshoptimizer - Upstream: https://github.com/zeux/meshoptimizer -- Version: git (f5d83e879c48f8664783a69b4f50711d27549b66, 2021) +- Version: git (f4c356d79fadb99cbf432f7e199d823581b0e19e, 2021) - License: MIT Files extracted from upstream repository: diff --git a/thirdparty/meshoptimizer/clusterizer.cpp b/thirdparty/meshoptimizer/clusterizer.cpp index f8aad7b49c..b1f7b359c1 100644 --- a/thirdparty/meshoptimizer/clusterizer.cpp +++ b/thirdparty/meshoptimizer/clusterizer.cpp @@ -368,8 +368,7 @@ static size_t kdtreeBuild(size_t offset, KDNode* nodes, size_t node_count, const } // split axis is one where the variance is largest - unsigned int axis = vars[0] >= vars[1] && vars[0] >= vars[2] ? 0 : vars[1] >= vars[2] ? 1 - : 2; + unsigned int axis = vars[0] >= vars[1] && vars[0] >= vars[2] ? 0 : vars[1] >= vars[2] ? 1 : 2; float split = mean[axis]; size_t middle = kdtreePartition(indices, count, points, stride, axis, split); diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h index e44b99ce52..a420eb1098 100644 --- a/thirdparty/meshoptimizer/meshoptimizer.h +++ b/thirdparty/meshoptimizer/meshoptimizer.h @@ -278,9 +278,30 @@ MESHOPTIMIZER_API int meshopt_decodeVertexBuffer(void* destination, size_t verte * meshopt_decodeFilterExp decodes exponential encoding of floating-point data with 8-bit exponent and 24-bit integer mantissa as 2^E*M. * Each 32-bit component is decoded in isolation; stride must be divisible by 4. */ -MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterOct(void* buffer, size_t vertex_count, size_t vertex_size); -MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterQuat(void* buffer, size_t vertex_count, size_t vertex_size); -MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterExp(void* buffer, size_t vertex_count, size_t vertex_size); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterOct(void* buffer, size_t count, size_t stride); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterQuat(void* buffer, size_t count, size_t stride); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterExp(void* buffer, size_t count, size_t stride); + +/** + * Vertex buffer filter encoders + * These functions can be used to encode data in a format that meshopt_decodeFilter can decode + * + * meshopt_encodeFilterOct encodes unit vectors with K-bit (K <= 16) signed X/Y as an output. + * Each component is stored as an 8-bit or 16-bit normalized integer; stride must be equal to 4 or 8. W is preserved as is. + * Input data must contain 4 floats for every vector (count*4 total). + * + * meshopt_encodeFilterQuat encodes unit quaternions with K-bit (4 <= K <= 16) component encoding. + * Each component is stored as an 16-bit integer; stride must be equal to 8. + * Input data must contain 4 floats for every quaternion (count*4 total). + * + * meshopt_encodeFilterExp encodes arbitrary (finite) floating-point data with 8-bit exponent and K-bit integer mantissa (1 <= K <= 24). + * Mantissa is shared between all components of a given vector as defined by stride; stride must be divisible by 4. + * Input data must contain stride/4 floats for every vector (count*stride/4 total). + * When individual (scalar) encoding is desired, simply pass stride=4 and adjust count accordingly. + */ +MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeFilterOct(void* destination, size_t count, size_t stride, int bits, const float* data); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeFilterQuat(void* destination, size_t count, size_t stride, int bits, const float* data); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeFilterExp(void* destination, size_t count, size_t stride, int bits, const float* data); /** * Experimental: Mesh simplifier @@ -305,7 +326,7 @@ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* d /** * Experimental: Mesh simplifier (sloppy) - * Reduces the number of triangles in the mesh, sacrificing mesh apperance for simplification performance + * Reduces the number of triangles in the mesh, sacrificing mesh appearance for simplification performance * The algorithm doesn't preserve mesh topology but can stop short of the target goal based on target error. * Returns the number of indices after simplification, with destination containing new index data * The resulting index buffer references vertices from the original vertex buffer. diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp index cf5db4e119..ccc99edb1a 100644 --- a/thirdparty/meshoptimizer/simplifier.cpp +++ b/thirdparty/meshoptimizer/simplifier.cpp @@ -358,7 +358,7 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned #if TRACE printf("locked: many open edges %d, disconnected seam %d, many seam edges %d, many wedges %d\n", - int(stats[0]), int(stats[1]), int(stats[2]), int(stats[3])); + int(stats[0]), int(stats[1]), int(stats[2]), int(stats[3])); #endif } @@ -1114,8 +1114,8 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char* float error_goal_perfect = edge_collapse_goal < collapse_count ? collapses[collapse_order[edge_collapse_goal]].error : 0.f; printf("removed %d triangles, error %e (goal %e); evaluated %d/%d collapses (done %d, skipped %d, invalid %d)\n", - int(triangle_collapses), sqrtf(result_error), sqrtf(error_goal_perfect), - int(stats[0]), int(collapse_count), int(edge_collapses), int(stats[1]), int(stats[2])); + int(triangle_collapses), sqrtf(result_error), sqrtf(error_goal_perfect), + int(stats[0]), int(collapse_count), int(edge_collapses), int(stats[1]), int(stats[2])); #endif return edge_collapses; @@ -1473,7 +1473,7 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned kinds[vertex_kind[i]] += remap[i] == i; printf("kinds: manifold %d, border %d, seam %d, complex %d, locked %d\n", - int(kinds[Kind_Manifold]), int(kinds[Kind_Border]), int(kinds[Kind_Seam]), int(kinds[Kind_Complex]), int(kinds[Kind_Locked])); + int(kinds[Kind_Manifold]), int(kinds[Kind_Border]), int(kinds[Kind_Seam]), int(kinds[Kind_Complex]), int(kinds[Kind_Locked])); #endif Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count); @@ -1649,9 +1649,9 @@ size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* ind #if TRACE printf("pass %d (%s): grid size %d, triangles %d, %s\n", - pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary", - grid_size, int(triangles), - (triangles <= target_index_count / 3) ? "under" : "over"); + pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary", + grid_size, int(triangles), + (triangles <= target_index_count / 3) ? "under" : "over"); #endif float tip = interpolate(float(target_index_count / 3), float(min_grid), float(min_triangles), float(grid_size), float(triangles), float(max_grid), float(max_triangles)); @@ -1778,9 +1778,9 @@ size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_pos #if TRACE printf("pass %d (%s): grid size %d, vertices %d, %s\n", - pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary", - grid_size, int(vertices), - (vertices <= target_vertex_count) ? "under" : "over"); + pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary", + grid_size, int(vertices), + (vertices <= target_vertex_count) ? "under" : "over"); #endif float tip = interpolate(float(target_vertex_count), float(min_grid), float(min_vertices), float(grid_size), float(vertices), float(max_grid), float(max_vertices)); diff --git a/thirdparty/meshoptimizer/vertexcodec.cpp b/thirdparty/meshoptimizer/vertexcodec.cpp index 5f3ec204ab..7925ea862c 100644 --- a/thirdparty/meshoptimizer/vertexcodec.cpp +++ b/thirdparty/meshoptimizer/vertexcodec.cpp @@ -77,6 +77,8 @@ #endif #ifdef SIMD_WASM +#undef __DEPRECATED +#pragma clang diagnostic ignored "-Wdeprecated-declarations" #include <wasm_simd128.h> #endif @@ -1028,7 +1030,7 @@ static unsigned int getCpuFeatures() return cpuinfo[2]; } -unsigned int cpuid = getCpuFeatures(); +static unsigned int cpuid = getCpuFeatures(); #endif } // namespace meshopt diff --git a/thirdparty/meshoptimizer/vertexfilter.cpp b/thirdparty/meshoptimizer/vertexfilter.cpp index 39946f46ed..606a280aa9 100644 --- a/thirdparty/meshoptimizer/vertexfilter.cpp +++ b/thirdparty/meshoptimizer/vertexfilter.cpp @@ -52,6 +52,7 @@ #endif #ifdef SIMD_WASM +#undef __DEPRECATED #include <wasm_simd128.h> #endif @@ -160,7 +161,8 @@ static void decodeFilterExp(unsigned int* data, size_t count) #endif #if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) -template <typename T> static void dispatchSimd(void (*process)(T*, size_t), T* data, size_t count, size_t stride) +template <typename T> +static void dispatchSimd(void (*process)(T*, size_t), T* data, size_t count, size_t stride) { assert(stride <= 4); @@ -791,52 +793,170 @@ static void decodeFilterExpSimd(unsigned int* data, size_t count) } // namespace meshopt -void meshopt_decodeFilterOct(void* buffer, size_t vertex_count, size_t vertex_size) +void meshopt_decodeFilterOct(void* buffer, size_t count, size_t stride) { using namespace meshopt; - assert(vertex_size == 4 || vertex_size == 8); + assert(stride == 4 || stride == 8); #if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) - if (vertex_size == 4) - dispatchSimd(decodeFilterOctSimd, static_cast<signed char*>(buffer), vertex_count, 4); + if (stride == 4) + dispatchSimd(decodeFilterOctSimd, static_cast<signed char*>(buffer), count, 4); else - dispatchSimd(decodeFilterOctSimd, static_cast<short*>(buffer), vertex_count, 4); + dispatchSimd(decodeFilterOctSimd, static_cast<short*>(buffer), count, 4); #else - if (vertex_size == 4) - decodeFilterOct(static_cast<signed char*>(buffer), vertex_count); + if (stride == 4) + decodeFilterOct(static_cast<signed char*>(buffer), count); else - decodeFilterOct(static_cast<short*>(buffer), vertex_count); + decodeFilterOct(static_cast<short*>(buffer), count); #endif } -void meshopt_decodeFilterQuat(void* buffer, size_t vertex_count, size_t vertex_size) +void meshopt_decodeFilterQuat(void* buffer, size_t count, size_t stride) { using namespace meshopt; - assert(vertex_size == 8); - (void)vertex_size; + assert(stride == 8); + (void)stride; #if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) - dispatchSimd(decodeFilterQuatSimd, static_cast<short*>(buffer), vertex_count, 4); + dispatchSimd(decodeFilterQuatSimd, static_cast<short*>(buffer), count, 4); #else - decodeFilterQuat(static_cast<short*>(buffer), vertex_count); + decodeFilterQuat(static_cast<short*>(buffer), count); #endif } -void meshopt_decodeFilterExp(void* buffer, size_t vertex_count, size_t vertex_size) +void meshopt_decodeFilterExp(void* buffer, size_t count, size_t stride) { using namespace meshopt; - assert(vertex_size % 4 == 0); + assert(stride > 0 && stride % 4 == 0); #if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) - dispatchSimd(decodeFilterExpSimd, static_cast<unsigned int*>(buffer), vertex_count * (vertex_size / 4), 1); + dispatchSimd(decodeFilterExpSimd, static_cast<unsigned int*>(buffer), count * (stride / 4), 1); #else - decodeFilterExp(static_cast<unsigned int*>(buffer), vertex_count * (vertex_size / 4)); + decodeFilterExp(static_cast<unsigned int*>(buffer), count * (stride / 4)); #endif } +void meshopt_encodeFilterOct(void* destination, size_t count, size_t stride, int bits, const float* data) +{ + assert(stride == 4 || stride == 8); + assert(bits >= 1 && bits <= 16); + + signed char* d8 = static_cast<signed char*>(destination); + short* d16 = static_cast<short*>(destination); + + int bytebits = int(stride * 2); + + for (size_t i = 0; i < count; ++i) + { + const float* n = &data[i * 4]; + + // octahedral encoding of a unit vector + float nx = n[0], ny = n[1], nz = n[2], nw = n[3]; + float nl = fabsf(nx) + fabsf(ny) + fabsf(nz); + float ns = nl == 0.f ? 0.f : 1.f / nl; + + nx *= ns; + ny *= ns; + + float u = (nz >= 0.f) ? nx : (1 - fabsf(ny)) * (nx >= 0.f ? 1.f : -1.f); + float v = (nz >= 0.f) ? ny : (1 - fabsf(nx)) * (ny >= 0.f ? 1.f : -1.f); + + int fu = meshopt_quantizeSnorm(u, bits); + int fv = meshopt_quantizeSnorm(v, bits); + int fo = meshopt_quantizeSnorm(1.f, bits); + int fw = meshopt_quantizeSnorm(nw, bytebits); + + if (stride == 4) + { + d8[i * 4 + 0] = (signed char)(fu); + d8[i * 4 + 1] = (signed char)(fv); + d8[i * 4 + 2] = (signed char)(fo); + d8[i * 4 + 3] = (signed char)(fw); + } + else + { + d16[i * 4 + 0] = short(fu); + d16[i * 4 + 1] = short(fv); + d16[i * 4 + 2] = short(fo); + d16[i * 4 + 3] = short(fw); + } + } +} + +void meshopt_encodeFilterQuat(void* destination_, size_t count, size_t stride, int bits, const float* data) +{ + assert(stride == 8); + assert(bits >= 4 && bits <= 16); + (void)stride; + + short* destination = static_cast<short*>(destination_); + + const float scaler = sqrtf(2.f); + + for (size_t i = 0; i < count; ++i) + { + const float* q = &data[i * 4]; + short* d = &destination[i * 4]; + + // establish maximum quaternion component + int qc = 0; + qc = fabsf(q[1]) > fabsf(q[qc]) ? 1 : qc; + qc = fabsf(q[2]) > fabsf(q[qc]) ? 2 : qc; + qc = fabsf(q[3]) > fabsf(q[qc]) ? 3 : qc; + + // we use double-cover properties to discard the sign + float sign = q[qc] < 0.f ? -1.f : 1.f; + + // note: we always encode a cyclical swizzle to be able to recover the order via rotation + d[0] = short(meshopt_quantizeSnorm(q[(qc + 1) & 3] * scaler * sign, bits)); + d[1] = short(meshopt_quantizeSnorm(q[(qc + 2) & 3] * scaler * sign, bits)); + d[2] = short(meshopt_quantizeSnorm(q[(qc + 3) & 3] * scaler * sign, bits)); + d[3] = short((meshopt_quantizeSnorm(1.f, bits) & ~3) | qc); + } +} + +void meshopt_encodeFilterExp(void* destination_, size_t count, size_t stride, int bits, const float* data) +{ + assert(stride > 0 && stride % 4 == 0); + assert(bits >= 1 && bits <= 24); + + unsigned int* destination = static_cast<unsigned int*>(destination_); + size_t stride_float = stride / sizeof(float); + + for (size_t i = 0; i < count; ++i) + { + const float* v = &data[i * stride_float]; + unsigned int* d = &destination[i * stride_float]; + + // use maximum exponent to encode values; this guarantess that mantissa is [-1, 1] + int exp = -100; + + for (size_t j = 0; j < stride_float; ++j) + { + int e; + frexp(v[j], &e); + + exp = (exp < e) ? e : exp; + } + + // note that we additionally scale the mantissa to make it a K-bit signed integer (K-1 bits for magnitude) + exp -= (bits - 1); + + // compute renormalized rounded mantissa for each component + int mmask = (1 << 24) - 1; + + for (size_t j = 0; j < stride_float; ++j) + { + int m = int(ldexp(v[j], -exp) + (v[j] >= 0 ? 0.5f : -0.5f)); + + d[j] = (m & mmask) | (unsigned(exp) << 24); + } + } +} + #undef SIMD_SSE #undef SIMD_NEON #undef SIMD_WASM |