From 5eabd5e04a56c100b8a885ca9289bedcc94ec530 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Mon, 24 Jul 2023 08:32:44 +0200 Subject: [PATCH 01/96] [Web] Always return -1 as body length in HTTPClientWeb. Body length cannot be reliably retrieved from the web. Reading the "content-length" value will return a meaningless value when the response is compressed, as reading will return uncompressed chunks in any case, resulting in a mismatch between the detected body size and the actual size returned by repeatedly calling read_response_body_chunk. Additionally, while "content-length" is considered a safe CORS header, "content-encoding" is not, so using the "content-encoding" to decide if "content-length" is meaningful is not an option either. We simply must accept the fact that browsers are awful when it comes to networking APIs. (cherry picked from commit f4713d235a498ee7805e8bd39273622e363059d0) --- doc/classes/HTTPClient.xml | 1 + platform/web/http_client_web.cpp | 10 +++++++++- platform/web/http_client_web.h | 1 - platform/web/js/libs/library_godot_fetch.js | 15 --------------- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml index 39cebf773b2..6c7cc299e53 100644 --- a/doc/classes/HTTPClient.xml +++ b/doc/classes/HTTPClient.xml @@ -41,6 +41,7 @@ Returns the response's body length. [b]Note:[/b] Some Web servers may not send a body length. In this case, the value returned will be [code]-1[/code]. If using chunked transfer encoding, the body length will also be [code]-1[/code]. + [b]Note:[/b] This function always returns [code]-1[/code] on the Web platform due to browsers limitations. diff --git a/platform/web/http_client_web.cpp b/platform/web/http_client_web.cpp index 3e4ba5a2ae1..ea9226a5a48 100644 --- a/platform/web/http_client_web.cpp +++ b/platform/web/http_client_web.cpp @@ -149,7 +149,15 @@ Error HTTPClientWeb::get_response_headers(List *r_response) { } int64_t HTTPClientWeb::get_response_body_length() const { - return godot_js_fetch_body_length_get(js_id); + // Body length cannot be consistently retrieved from the web. + // Reading the "content-length" value will return a meaningless value when the response is compressed, + // as reading will return uncompressed chunks in any case, resulting in a mismatch between the detected + // body size and the actual size returned by repeatedly calling read_response_body_chunk. + // Additionally, while "content-length" is considered a safe CORS header, "content-encoding" is not, + // so using the "content-encoding" to decide if "content-length" is meaningful is not an option either. + // We simply must accept the fact that browsers are awful when it comes to networking APIs. + // See GH-47597, and GH-79327. + return -1; } PackedByteArray HTTPClientWeb::read_response_body_chunk() { diff --git a/platform/web/http_client_web.h b/platform/web/http_client_web.h index bb9672ab82e..4d3c457a7d0 100644 --- a/platform/web/http_client_web.h +++ b/platform/web/http_client_web.h @@ -51,7 +51,6 @@ extern int godot_js_fetch_read_headers(int p_id, void (*parse_callback)(int p_si extern int godot_js_fetch_read_chunk(int p_id, uint8_t *p_buf, int p_buf_size); extern void godot_js_fetch_free(int p_id); extern godot_js_fetch_state_t godot_js_fetch_state_get(int p_id); -extern int godot_js_fetch_body_length_get(int p_id); extern int godot_js_fetch_http_status_get(int p_id); extern int godot_js_fetch_is_chunked(int p_id); diff --git a/platform/web/js/libs/library_godot_fetch.js b/platform/web/js/libs/library_godot_fetch.js index 1bb48bfd6a3..4ef24903e38 100644 --- a/platform/web/js/libs/library_godot_fetch.js +++ b/platform/web/js/libs/library_godot_fetch.js @@ -50,22 +50,17 @@ const GodotFetch = { return; } let chunked = false; - let bodySize = -1; response.headers.forEach(function (value, header) { const v = value.toLowerCase().trim(); const h = header.toLowerCase().trim(); if (h === 'transfer-encoding' && v === 'chunked') { chunked = true; } - if (h === 'content-length') { - bodySize = parseInt(v, 10); - } }); obj.status = response.status; obj.response = response; obj.reader = response.body.getReader(); obj.chunked = chunked; - obj.bodySize = bodySize; }, onerror: function (id, err) { @@ -87,7 +82,6 @@ const GodotFetch = { reading: false, status: 0, chunks: [], - bodySize: -1, }; const id = IDHandler.add(obj); const init = { @@ -224,15 +218,6 @@ const GodotFetch = { return p_buf_size - to_read; }, - godot_js_fetch_body_length_get__sig: 'ii', - godot_js_fetch_body_length_get: function (p_id) { - const obj = IDHandler.get(p_id); - if (!obj || !obj.response) { - return -1; - } - return obj.bodySize; - }, - godot_js_fetch_is_chunked__sig: 'ii', godot_js_fetch_is_chunked: function (p_id) { const obj = IDHandler.get(p_id); From 75db138533985cdb5b53e66afebabb43e008ee7b Mon Sep 17 00:00:00 2001 From: Danil Alexeev Date: Tue, 11 Jul 2023 11:58:19 +0300 Subject: [PATCH 02/96] GUI: Fix `Tree` performance regression by using cache (cherry picked from commit 5fb975e4a578579bd02d287e4aa3b98daa2c0e3a) --- scene/gui/tree.cpp | 90 ++++++++++++++++++++++++++-------------------- scene/gui/tree.h | 6 +++- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index f9f7438576a..9fa54742b19 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1912,6 +1912,7 @@ void Tree::update_column(int p_col) { } columns.write[p_col].text_buf->add_string(columns[p_col].title, theme_cache.font, theme_cache.font_size, columns[p_col].language); + columns.write[p_col].cached_minimum_width_dirty = true; } void Tree::update_item_cell(TreeItem *p_item, int p_col) { @@ -2004,7 +2005,7 @@ void Tree::update_item_cache(TreeItem *p_item) { } } -int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item, int *r_self_height) { +int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item, int &r_self_height) { if (p_pos.y - theme_cache.offset.y > (p_draw_size.height)) { return -1; //draw no more! } @@ -2086,11 +2087,12 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 p_item->cells.write[i].text_buf->set_width(item_width); - label_h = compute_item_height(p_item); - if (r_self_height != nullptr) { - *r_self_height = label_h; + r_self_height = compute_item_height(p_item); + label_h = r_self_height + theme_cache.v_separation; + + if (p_pos.y + label_h - theme_cache.offset.y < 0) { + continue; // No need to draw. } - label_h += theme_cache.v_separation; Rect2i item_rect = Rect2i(Point2i(ofs, p_pos.y) - theme_cache.offset + p_draw_ofs, Size2i(item_width, label_h)); Rect2i cell_rect = item_rect; @@ -2439,7 +2441,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 int child_h = -1; int child_self_height = 0; if (htotal >= 0) { - child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c, &child_self_height); + child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c, child_self_height); child_self_height += theme_cache.v_separation; } @@ -4221,7 +4223,8 @@ void Tree::_notification(int p_what) { cache.rtl = is_layout_rtl(); if (root && get_size().x > 0 && get_size().y > 0) { - draw_item(Point2(), draw_ofs, draw_size, root); + int self_height = 0; // Just to pass a reference, we don't need the root's `self_height`. + draw_item(Point2(), draw_ofs, draw_size, root, self_height); } if (show_column_titles) { @@ -4239,6 +4242,7 @@ void Tree::_notification(int p_what) { //text int clip_w = tbrect.size.width - sb->get_minimum_size().width; columns.write[i].text_buf->set_width(clip_w); + columns.write[i].cached_minimum_width_dirty = true; Vector2 text_pos = Point2i(tbrect.position.x, tbrect.position.y + (tbrect.size.height - columns[i].text_buf->get_size().y) / 2); switch (columns[i].title_alignment) { @@ -4376,6 +4380,7 @@ void Tree::item_edited(int p_column, TreeItem *p_item, MouseButton p_custom_mous void Tree::item_changed(int p_column, TreeItem *p_item) { if (p_item != nullptr && p_column >= 0 && p_column < p_item->cells.size()) { p_item->cells.write[p_column].dirty = true; + columns.write[p_column].cached_minimum_width_dirty = true; } queue_redraw(); } @@ -4507,6 +4512,7 @@ void Tree::set_column_custom_minimum_width(int p_column, int p_min_width) { return; } columns.write[p_column].custom_min_width = p_min_width; + columns.write[p_column].cached_minimum_width_dirty = true; queue_redraw(); } @@ -4518,6 +4524,7 @@ void Tree::set_column_expand(int p_column, bool p_expand) { } columns.write[p_column].expand = p_expand; + columns.write[p_column].cached_minimum_width_dirty = true; queue_redraw(); } @@ -4529,6 +4536,7 @@ void Tree::set_column_expand_ratio(int p_column, int p_ratio) { } columns.write[p_column].expand_ratio = p_ratio; + columns.write[p_column].cached_minimum_width_dirty = true; queue_redraw(); } @@ -4540,6 +4548,7 @@ void Tree::set_column_clip_content(int p_column, bool p_fit) { } columns.write[p_column].clip_content = p_fit; + columns.write[p_column].cached_minimum_width_dirty = true; queue_redraw(); } @@ -4622,46 +4631,51 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) { int Tree::get_column_minimum_width(int p_column) const { ERR_FAIL_INDEX_V(p_column, columns.size(), -1); - // Use the custom minimum width. - int min_width = columns[p_column].custom_min_width; + if (columns[p_column].cached_minimum_width_dirty) { + // Use the custom minimum width. + int min_width = columns[p_column].custom_min_width; - // Check if the visible title of the column is wider. - if (show_column_titles) { - min_width = MAX(theme_cache.font->get_string_size(columns[p_column].title, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_RIGHT), min_width); - } + // Check if the visible title of the column is wider. + if (show_column_titles) { + min_width = MAX(theme_cache.font->get_string_size(columns[p_column].title, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_RIGHT), min_width); + } - if (!columns[p_column].clip_content) { - int depth = 0; - TreeItem *next; - for (TreeItem *item = get_root(); item; item = next) { - next = item->get_next_visible(); - // Compute the depth in tree. - if (next && p_column == 0) { - if (next->get_parent() == item) { - depth += 1; - } else { - TreeItem *common_parent = item->get_parent(); - while (common_parent != next->get_parent() && common_parent) { - common_parent = common_parent->get_parent(); - depth -= 1; + if (!columns[p_column].clip_content) { + int depth = 0; + TreeItem *next; + for (TreeItem *item = get_root(); item; item = next) { + next = item->get_next_visible(); + // Compute the depth in tree. + if (next && p_column == 0) { + if (next->get_parent() == item) { + depth += 1; + } else { + TreeItem *common_parent = item->get_parent(); + while (common_parent != next->get_parent() && common_parent) { + common_parent = common_parent->get_parent(); + depth -= 1; + } } } - } - // Get the item minimum size. - Size2 item_size = item->get_minimum_size(p_column); - if (p_column == 0) { - item_size.width += theme_cache.item_margin * depth; - } else { - item_size.width += theme_cache.h_separation; - } + // Get the item minimum size. + Size2 item_size = item->get_minimum_size(p_column); + if (p_column == 0) { + item_size.width += theme_cache.item_margin * depth; + } else { + item_size.width += theme_cache.h_separation; + } - // Check if the item is wider. - min_width = MAX(min_width, item_size.width); + // Check if the item is wider. + min_width = MAX(min_width, item_size.width); + } } + + columns.get(p_column).cached_minimum_width = min_width; + columns.get(p_column).cached_minimum_width_dirty = false; } - return min_width; + return columns[p_column].cached_minimum_width; } int Tree::get_column_width(int p_column) const { diff --git a/scene/gui/tree.h b/scene/gui/tree.h index c0814c651d6..1789470f830 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -451,6 +451,10 @@ private: Ref text_buf; String language; Control::TextDirection text_direction = Control::TEXT_DIRECTION_INHERITED; + + mutable int cached_minimum_width = 0; + mutable bool cached_minimum_width_dirty = true; + ColumnInfo() { text_buf.instantiate(); } @@ -483,7 +487,7 @@ private: void update_item_cache(TreeItem *p_item); //void draw_item_text(String p_text,const Ref& p_icon,int p_icon_max_w,bool p_tool,Rect2i p_rect,const Color& p_color); void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color); - int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item, int *r_self_height = nullptr); + int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item, int &r_self_height); void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = nullptr, bool *r_in_range = nullptr, bool p_force_deselect = false); int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int x_limit, bool p_double_click, TreeItem *p_item, MouseButton p_button, const Ref &p_mod); void _line_editor_submit(String p_text); From 18f69e9ee15c6ec90e06478e003ecf57a5e43cad Mon Sep 17 00:00:00 2001 From: Danil Alexeev Date: Tue, 27 Jun 2023 18:22:10 +0300 Subject: [PATCH 03/96] GUI: Fix text overlapping icon in `Tree` (cherry picked from commit 07d23489f48dbc3c64ebf7c90b991a70b3418554) --- doc/classes/TreeItem.xml | 15 +++++++++++++++ scene/gui/tree.cpp | 29 +++++++++++++++++++++++++++-- scene/gui/tree.h | 4 ++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index 559d38e5cca..ddef2d8d478 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -339,6 +339,13 @@ Returns item's text base writing direction. + + + + + Returns the clipping behavior when the text exceeds the item's bounding rectangle in the given [param column]. By default it is [constant TextServer.OVERRUN_TRIM_ELLIPSIS]. + + @@ -719,6 +726,14 @@ Sets item's text base writing direction. + + + + + + Sets the clipping behavior when the text exceeds the item's bounding rectangle in the given [param column]. + + diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 9fa54742b19..51462a7c02f 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -351,6 +351,24 @@ TextServer::AutowrapMode TreeItem::get_autowrap_mode(int p_column) const { return cells[p_column].autowrap_mode; } +void TreeItem::set_text_overrun_behavior(int p_column, TextServer::OverrunBehavior p_behavior) { + ERR_FAIL_INDEX(p_column, cells.size()); + + if (cells[p_column].text_buf->get_text_overrun_behavior() == p_behavior) { + return; + } + + cells.write[p_column].text_buf->set_text_overrun_behavior(p_behavior); + cells.write[p_column].dirty = true; + _changed_notify(p_column); + cells.write[p_column].cached_minimum_size_dirty = true; +} + +TextServer::OverrunBehavior TreeItem::get_text_overrun_behavior(int p_column) const { + ERR_FAIL_INDEX_V(p_column, cells.size(), TextServer::OVERRUN_TRIM_ELLIPSIS); + return cells[p_column].text_buf->get_text_overrun_behavior(); +} + void TreeItem::set_structured_text_bidi_override(int p_column, TextServer::StructuredTextParser p_parser) { ERR_FAIL_INDEX(p_column, cells.size()); @@ -1505,6 +1523,9 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_autowrap_mode", "column", "autowrap_mode"), &TreeItem::set_autowrap_mode); ClassDB::bind_method(D_METHOD("get_autowrap_mode", "column"), &TreeItem::get_autowrap_mode); + ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "column", "overrun_behavior"), &TreeItem::set_text_overrun_behavior); + ClassDB::bind_method(D_METHOD("get_text_overrun_behavior", "column"), &TreeItem::get_text_overrun_behavior); + ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override", "column", "parser"), &TreeItem::set_structured_text_bidi_override); ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override", "column"), &TreeItem::get_structured_text_bidi_override); @@ -2085,7 +2106,12 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 buttons_width += button_size.width + theme_cache.button_margin; } - p_item->cells.write[i].text_buf->set_width(item_width); + int text_width = item_width; + if (p_item->cells[i].icon.is_valid()) { + text_width -= p_item->cells[i].get_icon_size().x + theme_cache.h_separation; + } + + p_item->cells.write[i].text_buf->set_width(text_width); r_self_height = compute_item_height(p_item); label_h = r_self_height + theme_cache.v_separation; @@ -2213,7 +2239,6 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 Point2i text_pos = item_rect.position; text_pos.y += Math::floor(p_draw_ofs.y) - _get_title_button_height(); - int text_width = p_item->cells[i].text_buf->get_size().x; switch (p_item->cells[i].mode) { case TreeItem::CELL_MODE_STRING: { diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 1789470f830..f2b743cb052 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -117,6 +117,7 @@ private: Cell() { text_buf.instantiate(); + text_buf->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); } Size2 get_icon_size() const; @@ -231,6 +232,9 @@ public: void set_autowrap_mode(int p_column, TextServer::AutowrapMode p_mode); TextServer::AutowrapMode get_autowrap_mode(int p_column) const; + void set_text_overrun_behavior(int p_column, TextServer::OverrunBehavior p_behavior); + TextServer::OverrunBehavior get_text_overrun_behavior(int p_column) const; + void set_structured_text_bidi_override(int p_column, TextServer::StructuredTextParser p_parser); TextServer::StructuredTextParser get_structured_text_bidi_override(int p_column) const; From d5c246bbd321d4f2988473602fd1f2ea38439a27 Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Sat, 26 Aug 2023 17:39:43 +0200 Subject: [PATCH 04/96] Ensure OpenXR classes are declared properly Co-authored-by: Bastiaan Olij (cherry picked from commit c23bd8b1431a745991a19f7cb89e4111efedf555) --- .../openxr/action_map/openxr_action_map.cpp | 4 +- .../action_map/openxr_interaction_profile.h | 2 +- ...> openxr_interaction_profile_metadata.cpp} | 48 +++++++++---------- ... => openxr_interaction_profile_metadata.h} | 22 +++++---- modules/openxr/config.py | 3 ++ .../doc_classes/OpenXRInteractionProfile.xml | 2 +- .../OpenXRInteractionProfileMetadata.xml | 46 ++++++++++++++++++ .../openxr_interaction_profile_editor.cpp | 10 ++-- .../openxr_interaction_profile_editor.h | 6 +-- ...enxr_select_interaction_profile_dialog.cpp | 4 +- ...openxr_select_interaction_profile_dialog.h | 2 +- .../openxr_htc_controller_extension.cpp | 4 +- .../openxr_htc_vive_tracker_extension.cpp | 4 +- .../openxr_huawei_controller_extension.cpp | 4 +- .../openxr_ml2_controller_extension.cpp | 4 +- .../openxr_pico_controller_extension.cpp | 4 +- .../openxr_wmr_controller_extension.cpp | 4 +- modules/openxr/openxr_api.cpp | 8 ++-- modules/openxr/register_types.cpp | 24 +++++----- servers/xr/xr_interface.h | 2 +- tests/scene/test_arraymesh.h | 2 +- 21 files changed, 130 insertions(+), 79 deletions(-) rename modules/openxr/action_map/{openxr_interaction_profile_meta_data.cpp => openxr_interaction_profile_metadata.cpp} (95%) rename modules/openxr/action_map/{openxr_interaction_profile_meta_data.h => openxr_interaction_profile_metadata.h} (91%) create mode 100644 modules/openxr/doc_classes/OpenXRInteractionProfileMetadata.xml diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp index 63abbf0d71e..80beed807e6 100644 --- a/modules/openxr/action_map/openxr_action_map.cpp +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -547,7 +547,7 @@ PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref p for (int i = 0; i < interaction_profiles.size(); i++) { Ref ip = interaction_profiles[i]; - const OpenXRInteractionProfileMetaData::InteractionProfile *profile = OpenXRInteractionProfileMetaData::get_singleton()->get_profile(ip->get_interaction_profile_path()); + const OpenXRInteractionProfileMetadata::InteractionProfile *profile = OpenXRInteractionProfileMetadata::get_singleton()->get_profile(ip->get_interaction_profile_path()); if (profile != nullptr) { for (int j = 0; j < ip->get_binding_count(); j++) { @@ -556,7 +556,7 @@ PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref p PackedStringArray paths = binding->get_paths(); for (int k = 0; k < paths.size(); k++) { - const OpenXRInteractionProfileMetaData::IOPath *io_path = profile->get_io_path(paths[k]); + const OpenXRInteractionProfileMetadata::IOPath *io_path = profile->get_io_path(paths[k]); if (io_path != nullptr) { String top_path = io_path->top_level_path; diff --git a/modules/openxr/action_map/openxr_interaction_profile.h b/modules/openxr/action_map/openxr_interaction_profile.h index 4a82785f14a..479cc3c5270 100644 --- a/modules/openxr/action_map/openxr_interaction_profile.h +++ b/modules/openxr/action_map/openxr_interaction_profile.h @@ -32,7 +32,7 @@ #define OPENXR_INTERACTION_PROFILE_H #include "openxr_action.h" -#include "openxr_interaction_profile_meta_data.h" +#include "openxr_interaction_profile_metadata.h" #include "core/io/resource.h" diff --git a/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp b/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp similarity index 95% rename from modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp rename to modules/openxr/action_map/openxr_interaction_profile_metadata.cpp index 11449bdfb4d..9f0198dfc4f 100644 --- a/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp +++ b/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp @@ -1,5 +1,5 @@ /**************************************************************************/ -/* openxr_interaction_profile_meta_data.cpp */ +/* openxr_interaction_profile_metadata.cpp */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,30 +28,30 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#include "openxr_interaction_profile_meta_data.h" +#include "openxr_interaction_profile_metadata.h" #include "../openxr_api.h" -OpenXRInteractionProfileMetaData *OpenXRInteractionProfileMetaData::singleton = nullptr; +OpenXRInteractionProfileMetadata *OpenXRInteractionProfileMetadata::singleton = nullptr; -OpenXRInteractionProfileMetaData::OpenXRInteractionProfileMetaData() { +OpenXRInteractionProfileMetadata::OpenXRInteractionProfileMetadata() { singleton = this; _register_core_metadata(); OpenXRAPI::register_extension_metadata(); } -OpenXRInteractionProfileMetaData::~OpenXRInteractionProfileMetaData() { +OpenXRInteractionProfileMetadata::~OpenXRInteractionProfileMetadata() { singleton = nullptr; } -void OpenXRInteractionProfileMetaData::_bind_methods() { - ClassDB::bind_method(D_METHOD("register_top_level_path", "display_name", "openxr_path", "openxr_extension_name"), &OpenXRInteractionProfileMetaData::register_top_level_path); - ClassDB::bind_method(D_METHOD("register_interaction_profile", "display_name", "openxr_path", "openxr_extension_name"), &OpenXRInteractionProfileMetaData::register_interaction_profile); - ClassDB::bind_method(D_METHOD("register_io_path", "interaction_profile", "display_name", "toplevel_path", "openxr_path", "openxr_extension_name", "action_type"), &OpenXRInteractionProfileMetaData::register_io_path); +void OpenXRInteractionProfileMetadata::_bind_methods() { + ClassDB::bind_method(D_METHOD("register_top_level_path", "display_name", "openxr_path", "openxr_extension_name"), &OpenXRInteractionProfileMetadata::register_top_level_path); + ClassDB::bind_method(D_METHOD("register_interaction_profile", "display_name", "openxr_path", "openxr_extension_name"), &OpenXRInteractionProfileMetadata::register_interaction_profile); + ClassDB::bind_method(D_METHOD("register_io_path", "interaction_profile", "display_name", "toplevel_path", "openxr_path", "openxr_extension_name", "action_type"), &OpenXRInteractionProfileMetadata::register_io_path); } -void OpenXRInteractionProfileMetaData::register_top_level_path(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name) { +void OpenXRInteractionProfileMetadata::register_top_level_path(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name) { ERR_FAIL_COND_MSG(has_top_level_path(p_openxr_path), p_openxr_path + " had already been registered"); TopLevelPath new_toplevel_path = { @@ -63,7 +63,7 @@ void OpenXRInteractionProfileMetaData::register_top_level_path(const String &p_d top_level_paths.push_back(new_toplevel_path); } -void OpenXRInteractionProfileMetaData::register_interaction_profile(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name) { +void OpenXRInteractionProfileMetadata::register_interaction_profile(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name) { ERR_FAIL_COND_MSG(has_interaction_profile(p_openxr_path), p_openxr_path + " has already been registered"); InteractionProfile new_profile; @@ -74,7 +74,7 @@ void OpenXRInteractionProfileMetaData::register_interaction_profile(const String interaction_profiles.push_back(new_profile); } -void OpenXRInteractionProfileMetaData::register_io_path(const String &p_interaction_profile, const String &p_display_name, const String &p_toplevel_path, const String &p_openxr_path, const String &p_openxr_extension_name, OpenXRAction::ActionType p_action_type) { +void OpenXRInteractionProfileMetadata::register_io_path(const String &p_interaction_profile, const String &p_display_name, const String &p_toplevel_path, const String &p_openxr_path, const String &p_openxr_extension_name, OpenXRAction::ActionType p_action_type) { ERR_FAIL_COND_MSG(!has_interaction_profile(p_interaction_profile), "Unknown interaction profile " + p_interaction_profile); ERR_FAIL_COND_MSG(!has_top_level_path(p_toplevel_path), "Unknown top level path " + p_toplevel_path); @@ -95,7 +95,7 @@ void OpenXRInteractionProfileMetaData::register_io_path(const String &p_interact } } -bool OpenXRInteractionProfileMetaData::has_top_level_path(const String p_openxr_path) const { +bool OpenXRInteractionProfileMetadata::has_top_level_path(const String p_openxr_path) const { for (int i = 0; i < top_level_paths.size(); i++) { if (top_level_paths[i].openxr_path == p_openxr_path) { return true; @@ -105,7 +105,7 @@ bool OpenXRInteractionProfileMetaData::has_top_level_path(const String p_openxr_ return false; } -String OpenXRInteractionProfileMetaData::get_top_level_name(const String p_openxr_path) const { +String OpenXRInteractionProfileMetadata::get_top_level_name(const String p_openxr_path) const { for (int i = 0; i < top_level_paths.size(); i++) { if (top_level_paths[i].openxr_path == p_openxr_path) { return top_level_paths[i].display_name; @@ -115,7 +115,7 @@ String OpenXRInteractionProfileMetaData::get_top_level_name(const String p_openx return String(); } -String OpenXRInteractionProfileMetaData::get_top_level_extension(const String p_openxr_path) const { +String OpenXRInteractionProfileMetadata::get_top_level_extension(const String p_openxr_path) const { for (int i = 0; i < top_level_paths.size(); i++) { if (top_level_paths[i].openxr_path == p_openxr_path) { return top_level_paths[i].openxr_extension_name; @@ -125,7 +125,7 @@ String OpenXRInteractionProfileMetaData::get_top_level_extension(const String p_ return XR_PATH_UNSUPPORTED_NAME; } -bool OpenXRInteractionProfileMetaData::has_interaction_profile(const String p_openxr_path) const { +bool OpenXRInteractionProfileMetadata::has_interaction_profile(const String p_openxr_path) const { for (int i = 0; i < interaction_profiles.size(); i++) { if (interaction_profiles[i].openxr_path == p_openxr_path) { return true; @@ -135,7 +135,7 @@ bool OpenXRInteractionProfileMetaData::has_interaction_profile(const String p_op return false; } -String OpenXRInteractionProfileMetaData::get_interaction_profile_extension(const String p_openxr_path) const { +String OpenXRInteractionProfileMetadata::get_interaction_profile_extension(const String p_openxr_path) const { for (int i = 0; i < interaction_profiles.size(); i++) { if (interaction_profiles[i].openxr_path == p_openxr_path) { return interaction_profiles[i].openxr_extension_name; @@ -145,7 +145,7 @@ String OpenXRInteractionProfileMetaData::get_interaction_profile_extension(const return XR_PATH_UNSUPPORTED_NAME; } -const OpenXRInteractionProfileMetaData::InteractionProfile *OpenXRInteractionProfileMetaData::get_profile(const String p_openxr_path) const { +const OpenXRInteractionProfileMetadata::InteractionProfile *OpenXRInteractionProfileMetadata::get_profile(const String p_openxr_path) const { for (int i = 0; i < interaction_profiles.size(); i++) { if (interaction_profiles[i].openxr_path == p_openxr_path) { return &interaction_profiles[i]; @@ -155,7 +155,7 @@ const OpenXRInteractionProfileMetaData::InteractionProfile *OpenXRInteractionPro return nullptr; } -bool OpenXRInteractionProfileMetaData::InteractionProfile::has_io_path(const String p_io_path) const { +bool OpenXRInteractionProfileMetadata::InteractionProfile::has_io_path(const String p_io_path) const { for (int i = 0; i < io_paths.size(); i++) { if (io_paths[i].openxr_path == p_io_path) { return true; @@ -165,7 +165,7 @@ bool OpenXRInteractionProfileMetaData::InteractionProfile::has_io_path(const Str return false; } -const OpenXRInteractionProfileMetaData::IOPath *OpenXRInteractionProfileMetaData::InteractionProfile::get_io_path(const String p_io_path) const { +const OpenXRInteractionProfileMetadata::IOPath *OpenXRInteractionProfileMetadata::InteractionProfile::get_io_path(const String p_io_path) const { for (int i = 0; i < io_paths.size(); i++) { if (io_paths[i].openxr_path == p_io_path) { return &io_paths[i]; @@ -175,8 +175,8 @@ const OpenXRInteractionProfileMetaData::IOPath *OpenXRInteractionProfileMetaData return nullptr; } -const OpenXRInteractionProfileMetaData::IOPath *OpenXRInteractionProfileMetaData::get_io_path(const String p_interaction_profile, const String p_io_path) const { - const OpenXRInteractionProfileMetaData::InteractionProfile *profile = get_profile(p_interaction_profile); +const OpenXRInteractionProfileMetadata::IOPath *OpenXRInteractionProfileMetadata::get_io_path(const String p_interaction_profile, const String p_io_path) const { + const OpenXRInteractionProfileMetadata::InteractionProfile *profile = get_profile(p_interaction_profile); if (profile != nullptr) { return profile->get_io_path(p_io_path); } @@ -184,7 +184,7 @@ const OpenXRInteractionProfileMetaData::IOPath *OpenXRInteractionProfileMetaData return nullptr; } -PackedStringArray OpenXRInteractionProfileMetaData::get_interaction_profile_paths() const { +PackedStringArray OpenXRInteractionProfileMetadata::get_interaction_profile_paths() const { PackedStringArray arr; for (int i = 0; i < interaction_profiles.size(); i++) { @@ -194,7 +194,7 @@ PackedStringArray OpenXRInteractionProfileMetaData::get_interaction_profile_path return arr; } -void OpenXRInteractionProfileMetaData::_register_core_metadata() { +void OpenXRInteractionProfileMetadata::_register_core_metadata() { // Note, currently we add definitions that belong in extensions. // Extensions are registered when our OpenXRAPI is instantiated // however this does not happen in the editor. diff --git a/modules/openxr/action_map/openxr_interaction_profile_meta_data.h b/modules/openxr/action_map/openxr_interaction_profile_metadata.h similarity index 91% rename from modules/openxr/action_map/openxr_interaction_profile_meta_data.h rename to modules/openxr/action_map/openxr_interaction_profile_metadata.h index 3eab2139ffd..91f97c73a65 100644 --- a/modules/openxr/action_map/openxr_interaction_profile_meta_data.h +++ b/modules/openxr/action_map/openxr_interaction_profile_metadata.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* openxr_interaction_profile_meta_data.h */ +/* openxr_interaction_profile_metadata.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef OPENXR_INTERACTION_PROFILE_META_DATA_H -#define OPENXR_INTERACTION_PROFILE_META_DATA_H +#ifndef OPENXR_INTERACTION_PROFILE_METADATA_H +#define OPENXR_INTERACTION_PROFILE_METADATA_H /////////////////////////////////////////////////////////////////////////// -// Stores available interaction profile meta data +// Stores available interaction profile metadata // // OpenXR defines and hardcodes all the supported input devices and their // paths as part of the OpenXR spec. When support for new devices is @@ -57,7 +57,9 @@ #define XR_PATH_UNSUPPORTED_NAME "unsupported" -class OpenXRInteractionProfileMetaData : public Object { +class OpenXRInteractionProfileMetadata : public Object { + GDCLASS(OpenXRInteractionProfileMetadata, Object); + public: struct TopLevelPath { String display_name; // User friendly display name (i.e. Left controller) @@ -84,7 +86,7 @@ public: }; private: - static OpenXRInteractionProfileMetaData *singleton; + static OpenXRInteractionProfileMetadata *singleton; Vector top_level_paths; Vector interaction_profiles; @@ -95,10 +97,10 @@ protected: static void _bind_methods(); public: - static OpenXRInteractionProfileMetaData *get_singleton() { return singleton; } + static OpenXRInteractionProfileMetadata *get_singleton() { return singleton; } - OpenXRInteractionProfileMetaData(); - ~OpenXRInteractionProfileMetaData(); + OpenXRInteractionProfileMetadata(); + ~OpenXRInteractionProfileMetadata(); void register_top_level_path(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name); bool has_top_level_path(const String p_openxr_path) const; @@ -115,4 +117,4 @@ public: const IOPath *get_io_path(const String p_interaction_profile, const String p_io_path) const; }; -#endif // OPENXR_INTERACTION_PROFILE_META_DATA_H +#endif // OPENXR_INTERACTION_PROFILE_METADATA_H diff --git a/modules/openxr/config.py b/modules/openxr/config.py index e503f127391..7d0653ba7e7 100644 --- a/modules/openxr/config.py +++ b/modules/openxr/config.py @@ -16,7 +16,10 @@ def get_doc_classes(): "OpenXRAction", "OpenXRActionSet", "OpenXRActionMap", + "OpenXRAPIExtension", + "OpenXRExtensionWrapperExtension", "OpenXRInteractionProfile", + "OpenXRInteractionProfileMetadata", "OpenXRIPBinding", "OpenXRHand", ] diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml index 8c55a3360be..bd3970f4e1d 100644 --- a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml +++ b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml @@ -4,7 +4,7 @@ Suggested bindings object for OpenXR. - This object stores suggested bindings for an interaction profile. Interaction profiles define the meta data for a tracked XR device such as an XR controller. + This object stores suggested bindings for an interaction profile. Interaction profiles define the metadata for a tracked XR device such as an XR controller. For more information see the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-interaction-profiles]interaction profiles info in the OpenXR specification[/url]. diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfileMetadata.xml b/modules/openxr/doc_classes/OpenXRInteractionProfileMetadata.xml new file mode 100644 index 00000000000..582cf202990 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRInteractionProfileMetadata.xml @@ -0,0 +1,46 @@ + + + + Meta class registering supported devices in OpenXR. + + + This class allows OpenXR core and extensions to register metadata relating to supported interaction devices such as controllers, trackers, haptic devices, etc. It is primarily used by the action map editor and to sanitize any action map by removing extension-dependent entries when applicable. + + + + + + + + + + + Registers an interaction profile using its OpenXR designation (e.g. [code]/interaction_profiles/khr/simple_controller[/code] is the profile for OpenXR's simple controller profile). + [param display_name] is the description shown to the user. [param openxr_path] is the interaction profile path being registered. [param openxr_extension_name] optionally restricts this profile to the given extension being enabled/available. If the extension is not available, the profile and all related entries used in an action map are filtered out. + + + + + + + + + + + + Registers an input/output path for the given [param interaction_profile]. The profile should previously have been registered using [method register_interaction_profile]. [param display_name] is the description shown to the user. [param toplevel_path] specifies the bind path this input/output can be bound to (e.g. [code]/user/hand/left[/code] or [code]/user/hand/right[/code]). [param openxr_path] is the action input/output being registered (e.g. [code]/user/hand/left/input/aim/pose[/code]). [param openxr_extension_name] restricts this input/output to an enabled/available extension, this doesn't need to repeat the extension on the profile but relates to overlapping extension (e.g. [code]XR_EXT_palm_pose[/code] that introduces [code]…/input/palm_ext/pose[/code] input paths). [param action_type] defines the type of input or output provided by OpenXR. + + + + + + + + + Registers a top level path to which profiles can be bound. For instance [code]/user/hand/left[/code] refers to the bind point for the player's left hand. Extensions can register additional top level paths, for instance a haptic vest extension might register [code]/user/body/vest[/code]. + [param display_name] is the name shown to the user. [param openxr_path] is the top level path being registered. [param openxr_extension_name] is optional and ensures the top level path is only used if the specified extension is available/enabled. + When a top level path ends up being bound by OpenXR, a [XRPositionalTracker] is instantiated to manage the state of the device. + + + + diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp index 1f63399ee7e..9998bb80e3e 100644 --- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp +++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp @@ -148,7 +148,7 @@ OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Refget_interaction_profile_path(); String profile_name = profile_path; - profile_def = OpenXRInteractionProfileMetaData::get_singleton()->get_profile(profile_path); + profile_def = OpenXRInteractionProfileMetadata::get_singleton()->get_profile(profile_path); if (profile_def != nullptr) { profile_name = profile_def->display_name; } @@ -185,7 +185,7 @@ void OpenXRInteractionProfileEditor::_on_remove_pressed(const String p_action, c undo_redo->commit_action(true); } -void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, const OpenXRInteractionProfileMetaData::IOPath *p_io_path) { +void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, const OpenXRInteractionProfileMetadata::IOPath *p_io_path) { HBoxContainer *path_hb = memnew(HBoxContainer); path_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); p_container->add_child(path_hb); @@ -274,7 +274,7 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() { // Determine toplevel paths Vector top_level_paths; for (int i = 0; i < profile_def->io_paths.size(); i++) { - const OpenXRInteractionProfileMetaData::IOPath *io_path = &profile_def->io_paths[i]; + const OpenXRInteractionProfileMetadata::IOPath *io_path = &profile_def->io_paths[i]; if (!top_level_paths.has(io_path->top_level_path)) { top_level_paths.push_back(io_path->top_level_path); @@ -291,11 +291,11 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() { panel->add_child(container); Label *label = memnew(Label); - label->set_text(OpenXRInteractionProfileMetaData::get_singleton()->get_top_level_name(top_level_paths[i])); + label->set_text(OpenXRInteractionProfileMetadata::get_singleton()->get_top_level_name(top_level_paths[i])); container->add_child(label); for (int j = 0; j < profile_def->io_paths.size(); j++) { - const OpenXRInteractionProfileMetaData::IOPath *io_path = &profile_def->io_paths[j]; + const OpenXRInteractionProfileMetadata::IOPath *io_path = &profile_def->io_paths[j]; if (io_path->top_level_path == top_level_paths[i]) { _add_io_path(container, io_path); } diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.h b/modules/openxr/editor/openxr_interaction_profile_editor.h index b9b3fbd81d2..2ec72127cfc 100644 --- a/modules/openxr/editor/openxr_interaction_profile_editor.h +++ b/modules/openxr/editor/openxr_interaction_profile_editor.h @@ -33,7 +33,7 @@ #include "../action_map/openxr_action_map.h" #include "../action_map/openxr_interaction_profile.h" -#include "../action_map/openxr_interaction_profile_meta_data.h" +#include "../action_map/openxr_interaction_profile_metadata.h" #include "openxr_select_action_dialog.h" #include "editor/editor_undo_redo_manager.h" @@ -52,7 +52,7 @@ protected: static void _bind_methods(); void _notification(int p_what); - const OpenXRInteractionProfileMetaData::InteractionProfile *profile_def = nullptr; + const OpenXRInteractionProfileMetadata::InteractionProfile *profile_def = nullptr; public: Ref get_interaction_profile() { return interaction_profile; } @@ -77,7 +77,7 @@ private: HBoxContainer *main_hb = nullptr; OpenXRSelectActionDialog *select_action_dialog = nullptr; - void _add_io_path(VBoxContainer *p_container, const OpenXRInteractionProfileMetaData::IOPath *p_io_path); + void _add_io_path(VBoxContainer *p_container, const OpenXRInteractionProfileMetadata::IOPath *p_io_path); public: void select_action_for(const String p_io_path); diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp index 9362c081746..08fcdaf771f 100644 --- a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp +++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp @@ -75,13 +75,13 @@ void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_inclu ip_buttons.clear(); // in with the new - PackedStringArray interaction_profiles = OpenXRInteractionProfileMetaData::get_singleton()->get_interaction_profile_paths(); + PackedStringArray interaction_profiles = OpenXRInteractionProfileMetadata::get_singleton()->get_interaction_profile_paths(); for (int i = 0; i < interaction_profiles.size(); i++) { String path = interaction_profiles[i]; if (!p_do_not_include.has(path)) { Button *ip_button = memnew(Button); ip_button->set_flat(true); - ip_button->set_text(OpenXRInteractionProfileMetaData::get_singleton()->get_profile(path)->display_name); + ip_button->set_text(OpenXRInteractionProfileMetadata::get_singleton()->get_profile(path)->display_name); ip_button->connect("pressed", callable_mp(this, &OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile).bind(path)); main_vb->add_child(ip_button); diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.h b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h index aae0368f674..1d1615321c9 100644 --- a/modules/openxr/editor/openxr_select_interaction_profile_dialog.h +++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h @@ -31,7 +31,7 @@ #ifndef OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H #define OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H -#include "../action_map/openxr_interaction_profile_meta_data.h" +#include "../action_map/openxr_interaction_profile_metadata.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" diff --git a/modules/openxr/extensions/openxr_htc_controller_extension.cpp b/modules/openxr/extensions/openxr_htc_controller_extension.cpp index 51364d83d81..c4ecb4e57c6 100644 --- a/modules/openxr/extensions/openxr_htc_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_htc_controller_extension.cpp @@ -30,7 +30,7 @@ #include "openxr_htc_controller_extension.h" -#include "../action_map/openxr_interaction_profile_meta_data.h" +#include "../action_map/openxr_interaction_profile_metadata.h" HashMap OpenXRHTCControllerExtension::get_requested_extensions() { HashMap request_extensions; @@ -46,7 +46,7 @@ bool OpenXRHTCControllerExtension::is_available(HTCControllers p_type) { } void OpenXRHTCControllerExtension::on_register_metadata() { - OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton(); ERR_FAIL_NULL(metadata); // HTC Vive Cosmos controller diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp index 087631a8b90..8b8c6c53538 100644 --- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp +++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp @@ -30,7 +30,7 @@ #include "openxr_htc_vive_tracker_extension.h" -#include "../action_map/openxr_interaction_profile_meta_data.h" +#include "../action_map/openxr_interaction_profile_metadata.h" #include "core/string/print_string.h" @@ -47,7 +47,7 @@ bool OpenXRHTCViveTrackerExtension::is_available() { } void OpenXRHTCViveTrackerExtension::on_register_metadata() { - OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton(); ERR_FAIL_NULL(metadata); // HTC Vive tracker diff --git a/modules/openxr/extensions/openxr_huawei_controller_extension.cpp b/modules/openxr/extensions/openxr_huawei_controller_extension.cpp index 8b8662cfcb9..baa6d6ded85 100644 --- a/modules/openxr/extensions/openxr_huawei_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_huawei_controller_extension.cpp @@ -30,7 +30,7 @@ #include "openxr_huawei_controller_extension.h" -#include "../action_map/openxr_interaction_profile_meta_data.h" +#include "../action_map/openxr_interaction_profile_metadata.h" HashMap OpenXRHuaweiControllerExtension::get_requested_extensions() { HashMap request_extensions; @@ -45,7 +45,7 @@ bool OpenXRHuaweiControllerExtension::is_available() { } void OpenXRHuaweiControllerExtension::on_register_metadata() { - OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton(); ERR_FAIL_NULL(metadata); // Huawei controller diff --git a/modules/openxr/extensions/openxr_ml2_controller_extension.cpp b/modules/openxr/extensions/openxr_ml2_controller_extension.cpp index 7dad8deb8ca..979ac22d087 100644 --- a/modules/openxr/extensions/openxr_ml2_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_ml2_controller_extension.cpp @@ -30,7 +30,7 @@ #include "openxr_ml2_controller_extension.h" -#include "../action_map/openxr_interaction_profile_meta_data.h" +#include "../action_map/openxr_interaction_profile_metadata.h" HashMap OpenXRML2ControllerExtension::get_requested_extensions() { HashMap request_extensions; @@ -45,7 +45,7 @@ bool OpenXRML2ControllerExtension::is_available() { } void OpenXRML2ControllerExtension::on_register_metadata() { - OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton(); ERR_FAIL_NULL(metadata); // Magic Leap 2 Controller diff --git a/modules/openxr/extensions/openxr_pico_controller_extension.cpp b/modules/openxr/extensions/openxr_pico_controller_extension.cpp index 8be961a68e4..6c492d2e5ab 100644 --- a/modules/openxr/extensions/openxr_pico_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_pico_controller_extension.cpp @@ -30,7 +30,7 @@ #include "openxr_pico_controller_extension.h" -#include "../action_map/openxr_interaction_profile_meta_data.h" +#include "../action_map/openxr_interaction_profile_metadata.h" // Pico controllers are not part of the OpenXR spec at the time of writing this // code. We'll hardcode the extension name that is used internally, verified by @@ -53,7 +53,7 @@ bool OpenXRPicoControllerExtension::is_available() { } void OpenXRPicoControllerExtension::on_register_metadata() { - OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton(); ERR_FAIL_NULL(metadata); // Pico controller (Pico 4 and Pico Neo 3 controllers) diff --git a/modules/openxr/extensions/openxr_wmr_controller_extension.cpp b/modules/openxr/extensions/openxr_wmr_controller_extension.cpp index a9b27013f13..7d43d2e3049 100644 --- a/modules/openxr/extensions/openxr_wmr_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_wmr_controller_extension.cpp @@ -30,7 +30,7 @@ #include "openxr_wmr_controller_extension.h" -#include "../action_map/openxr_interaction_profile_meta_data.h" +#include "../action_map/openxr_interaction_profile_metadata.h" HashMap OpenXRWMRControllerExtension::get_requested_extensions() { HashMap request_extensions; @@ -47,7 +47,7 @@ bool OpenXRWMRControllerExtension::is_available(WMRControllers p_type) { } void OpenXRWMRControllerExtension::on_register_metadata() { - OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton(); ERR_FAIL_NULL(metadata); // HP MR controller (newer G2 controllers) diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 4ab280f3c37..ae45a27a560 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -215,7 +215,7 @@ bool OpenXRAPI::is_extension_enabled(const String &p_extension) const { } bool OpenXRAPI::is_top_level_path_supported(const String &p_toplevel_path) { - String required_extension = OpenXRInteractionProfileMetaData::get_singleton()->get_top_level_extension(p_toplevel_path); + String required_extension = OpenXRInteractionProfileMetadata::get_singleton()->get_top_level_extension(p_toplevel_path); // If unsupported is returned we likely have a misspelled interaction profile path in our action map. Always output that as an error. ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported toplevel path " + p_toplevel_path); @@ -235,7 +235,7 @@ bool OpenXRAPI::is_top_level_path_supported(const String &p_toplevel_path) { } bool OpenXRAPI::is_interaction_profile_supported(const String &p_ip_path) { - String required_extension = OpenXRInteractionProfileMetaData::get_singleton()->get_interaction_profile_extension(p_ip_path); + String required_extension = OpenXRInteractionProfileMetadata::get_singleton()->get_interaction_profile_extension(p_ip_path); // If unsupported is returned we likely have a misspelled interaction profile path in our action map. Always output that as an error. ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported interaction profile " + p_ip_path); @@ -259,9 +259,9 @@ bool OpenXRAPI::interaction_profile_supports_io_path(const String &p_ip_path, co return false; } - const OpenXRInteractionProfileMetaData::IOPath *io_path = OpenXRInteractionProfileMetaData::get_singleton()->get_io_path(p_ip_path, p_io_path); + const OpenXRInteractionProfileMetadata::IOPath *io_path = OpenXRInteractionProfileMetadata::get_singleton()->get_io_path(p_ip_path, p_io_path); - // If the io_path is not part of our meta data we've likely got a misspelled name or a bad action map, report + // If the io_path is not part of our metadata we've likely got a misspelled name or a bad action map, report ERR_FAIL_NULL_V_MSG(io_path, false, "OpenXR: Unsupported io path " + String(p_ip_path) + String(p_io_path)); if (io_path->openxr_extension_name == "") { diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index 27b179a7883..77f02ddb28a 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -34,7 +34,7 @@ #include "action_map/openxr_action_map.h" #include "action_map/openxr_action_set.h" #include "action_map/openxr_interaction_profile.h" -#include "action_map/openxr_interaction_profile_meta_data.h" +#include "action_map/openxr_interaction_profile_metadata.h" #include "openxr_interface.h" #include "scene/openxr_hand.h" @@ -66,7 +66,7 @@ #endif static OpenXRAPI *openxr_api = nullptr; -static OpenXRInteractionProfileMetaData *openxr_interaction_profile_meta_data = nullptr; +static OpenXRInteractionProfileMetadata *openxr_interaction_profile_metadata = nullptr; static Ref openxr_interface; #ifdef TOOLS_ENABLED @@ -74,10 +74,10 @@ static void _editor_init() { if (OpenXRAPI::openxr_is_enabled(false)) { // Only add our OpenXR action map editor if OpenXR is enabled for our project - if (openxr_interaction_profile_meta_data == nullptr) { - // If we didn't initialize our actionmap meta data at startup, we initialize it now. - openxr_interaction_profile_meta_data = memnew(OpenXRInteractionProfileMetaData); - ERR_FAIL_NULL(openxr_interaction_profile_meta_data); + if (openxr_interaction_profile_metadata == nullptr) { + // If we didn't initialize our actionmap metadata at startup, we initialize it now. + openxr_interaction_profile_metadata = memnew(OpenXRInteractionProfileMetadata); + ERR_FAIL_NULL(openxr_interaction_profile_metadata); } OpenXREditorPlugin *openxr_plugin = memnew(OpenXREditorPlugin()); @@ -110,8 +110,8 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { } if (OpenXRAPI::openxr_is_enabled()) { - openxr_interaction_profile_meta_data = memnew(OpenXRInteractionProfileMetaData); - ERR_FAIL_NULL(openxr_interaction_profile_meta_data); + openxr_interaction_profile_metadata = memnew(OpenXRInteractionProfileMetadata); + ERR_FAIL_NULL(openxr_interaction_profile_metadata); openxr_api = memnew(OpenXRAPI); ERR_FAIL_NULL(openxr_api); @@ -142,7 +142,7 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(OpenXRAction); GDREGISTER_CLASS(OpenXRActionSet); GDREGISTER_CLASS(OpenXRActionMap); - GDREGISTER_CLASS(OpenXRInteractionProfileMetaData); + GDREGISTER_CLASS(OpenXRInteractionProfileMetadata); GDREGISTER_CLASS(OpenXRIPBinding); GDREGISTER_CLASS(OpenXRInteractionProfile); @@ -195,9 +195,9 @@ void uninitialize_openxr_module(ModuleInitializationLevel p_level) { openxr_api = nullptr; } - if (openxr_interaction_profile_meta_data) { - memdelete(openxr_interaction_profile_meta_data); - openxr_interaction_profile_meta_data = nullptr; + if (openxr_interaction_profile_metadata) { + memdelete(openxr_interaction_profile_metadata); + openxr_interaction_profile_metadata = nullptr; } // cleanup our extension wrappers diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index 44275285c83..b42cb372344 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -52,7 +52,7 @@ class XRInterface : public RefCounted { GDCLASS(XRInterface, RefCounted); public: - enum Capabilities { /* purely meta data, provides some info about what this interface supports */ + enum Capabilities { /* purely metadata, provides some info about what this interface supports */ XR_NONE = 0, /* no capabilities */ XR_MONO = 1, /* can be used with mono output */ XR_STEREO = 2, /* can be used with stereo output */ diff --git a/tests/scene/test_arraymesh.h b/tests/scene/test_arraymesh.h index b2a2ecc3bf7..0e97e7d75f4 100644 --- a/tests/scene/test_arraymesh.h +++ b/tests/scene/test_arraymesh.h @@ -154,7 +154,7 @@ TEST_CASE("[SceneTree][ArrayMesh] Adding and modifying blendshapes.") { } } -TEST_CASE("[SceneTree][ArrayMesh] Surface meta data tests.") { +TEST_CASE("[SceneTree][ArrayMesh] Surface metadata tests.") { Ref mesh = memnew(ArrayMesh); Ref cylinder = memnew(CylinderMesh); Array cylinder_array{}; From dbae37cc506f251a2209695a64f6d7dd3e84cce2 Mon Sep 17 00:00:00 2001 From: Markus Sauermann <6299227+Sauermann@users.noreply.github.com> Date: Tue, 1 Aug 2023 01:55:31 +0200 Subject: [PATCH 05/96] Fix global transform validity for `Node2D` and `Control` Set global transform to invalid when changing transform (cherry picked from commit 152572ac3862718e770b81c862970089810bcc34) --- scene/2d/node_2d.cpp | 8 ----- scene/gui/control.cpp | 4 +++ scene/main/canvas_item.cpp | 7 ++-- scene/main/canvas_item.h | 5 +-- tests/scene/test_control.h | 66 ++++++++++++++++++++++++++++++++++++++ tests/scene/test_node_2d.h | 63 ++++++++++++++++++++++++++++++++++++ tests/test_main.cpp | 2 ++ 7 files changed, 141 insertions(+), 14 deletions(-) create mode 100644 tests/scene/test_control.h create mode 100644 tests/scene/test_node_2d.h diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 4b7fad5edf0..fb3b1996389 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -138,10 +138,6 @@ void Node2D::_update_transform() { RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), transform); - if (!is_inside_tree()) { - return; - } - _notify_transform(); } @@ -378,10 +374,6 @@ void Node2D::set_transform(const Transform2D &p_transform) { RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), transform); - if (!is_inside_tree()) { - return; - } - _notify_transform(); } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 78862364d57..7d83eeea69a 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1734,6 +1734,10 @@ void Control::_size_changed() { if (pos_changed && !size_changed) { _update_canvas_item_transform(); //move because it won't be updated } + } else { + if (pos_changed) { + _notify_transform(); + } } } diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 2947d73552f..855cad51e9c 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -320,7 +320,6 @@ void CanvasItem::_notification(int p_what) { } } - _set_global_invalid(true); _enter_canvas(); RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, is_visible_in_tree()); // The visibility of the parent may change. @@ -367,7 +366,11 @@ void CanvasItem::_notification(int p_what) { case NOTIFICATION_WORLD_2D_CHANGED: { _exit_canvas(); _enter_canvas(); - } + } break; + case NOTIFICATION_PARENTED: { + // The node is not inside the tree during this notification. + _notify_transform(); + } break; } } diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index fcb951a89dd..c4a9ff5ad13 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -152,11 +152,8 @@ private: protected: _FORCE_INLINE_ void _notify_transform() { - if (!is_inside_tree()) { - return; - } _notify_transform(this); - if (!block_transform_notify && notify_local_transform) { + if (is_inside_tree() && !block_transform_notify && notify_local_transform) { notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); } } diff --git a/tests/scene/test_control.h b/tests/scene/test_control.h new file mode 100644 index 00000000000..3d7e389e0a7 --- /dev/null +++ b/tests/scene/test_control.h @@ -0,0 +1,66 @@ +/**************************************************************************/ +/* test_control.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef TEST_CONTROL_H +#define TEST_CONTROL_H + +#include "scene/gui/control.h" + +#include "tests/test_macros.h" + +namespace TestControl { + +TEST_CASE("[SceneTree][Control]") { + SUBCASE("[Control][Global Transform] Global Transform should be accessible while not in SceneTree.") { // GH-79453 + Control *test_node = memnew(Control); + Control *test_child = memnew(Control); + test_node->add_child(test_child); + + test_node->set_global_position(Point2(1, 1)); + CHECK_EQ(test_node->get_global_position(), Point2(1, 1)); + CHECK_EQ(test_child->get_global_position(), Point2(1, 1)); + test_node->set_global_position(Point2(2, 2)); + CHECK_EQ(test_node->get_global_position(), Point2(2, 2)); + test_node->set_scale(Vector2(4, 4)); + CHECK_EQ(test_node->get_global_transform(), Transform2D(0, Size2(4, 4), 0, Vector2(2, 2))); + test_node->set_scale(Vector2(1, 1)); + test_node->set_rotation_degrees(90); + CHECK_EQ(test_node->get_global_transform(), Transform2D(Math_PI / 2, Vector2(2, 2))); + test_node->set_pivot_offset(Vector2(1, 0)); + CHECK_EQ(test_node->get_global_transform(), Transform2D(Math_PI / 2, Vector2(3, 1))); + + memdelete(test_child); + memdelete(test_node); + } +} + +} // namespace TestControl + +#endif // TEST_CONTROL_H diff --git a/tests/scene/test_node_2d.h b/tests/scene/test_node_2d.h new file mode 100644 index 00000000000..7e93c77e22f --- /dev/null +++ b/tests/scene/test_node_2d.h @@ -0,0 +1,63 @@ +/**************************************************************************/ +/* test_node_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef TEST_NODE_2D_H +#define TEST_NODE_2D_H + +#include "scene/2d/node_2d.h" + +#include "tests/test_macros.h" + +namespace TestNode2D { + +TEST_CASE("[SceneTree][Node2D]") { + SUBCASE("[Node2D][Global Transform] Global Transform should be accessible while not in SceneTree.") { // GH-79453 + Node2D *test_node = memnew(Node2D); + test_node->set_name("node"); + Node2D *test_child = memnew(Node2D); + test_child->set_name("child"); + test_node->add_child(test_child); + + test_node->set_global_position(Point2(1, 1)); + CHECK_EQ(test_node->get_global_position(), Point2(1, 1)); + CHECK_EQ(test_child->get_global_position(), Point2(1, 1)); + test_node->set_global_position(Point2(2, 2)); + CHECK_EQ(test_node->get_global_position(), Point2(2, 2)); + test_node->set_global_transform(Transform2D(0, Point2(3, 3))); + CHECK_EQ(test_node->get_global_position(), Point2(3, 3)); + + memdelete(test_child); + memdelete(test_node); + } +} + +} // namespace TestNode2D + +#endif // TEST_NODE_2D_H diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 2e99e6fdb6a..0c5fa82f46a 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -93,6 +93,7 @@ #include "tests/scene/test_bit_map.h" #include "tests/scene/test_code_edit.h" #include "tests/scene/test_color_picker.h" +#include "tests/scene/test_control.h" #include "tests/scene/test_curve.h" #include "tests/scene/test_curve_2d.h" #include "tests/scene/test_curve_3d.h" @@ -104,6 +105,7 @@ #include "tests/scene/test_navigation_region_2d.h" #include "tests/scene/test_navigation_region_3d.h" #include "tests/scene/test_node.h" +#include "tests/scene/test_node_2d.h" #include "tests/scene/test_path_2d.h" #include "tests/scene/test_path_3d.h" #include "tests/scene/test_primitives.h" From c57d6c9371fd3b864d6e979361155c6db84c4aa2 Mon Sep 17 00:00:00 2001 From: Danil Alexeev Date: Wed, 12 Jul 2023 14:59:44 +0300 Subject: [PATCH 06/96] Core: Fix recursion level check for array stringification (cherry picked from commit bb40bd9aaaa6ee1b0332572d4406d8d90d4766ed) --- core/variant/variant.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 10a267e5a99..8a0289898de 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -1754,11 +1754,10 @@ String Variant::stringify(int recursion_count) const { case COLOR: return operator Color(); case DICTIONARY: { + ERR_FAIL_COND_V_MSG(recursion_count > MAX_RECURSION, "{ ... }", "Maximum dictionary recursion reached!"); + recursion_count++; + const Dictionary &d = *reinterpret_cast(_data._mem); - if (recursion_count > MAX_RECURSION) { - ERR_PRINT("Maximum dictionary recursion reached!"); - return "{ ... }"; - } // Add leading and trailing space to Dictionary printing. This distinguishes it // from array printing on fonts that have similar-looking {} and [] characters. @@ -1768,7 +1767,6 @@ String Variant::stringify(int recursion_count) const { Vector<_VariantStrPair> pairs; - recursion_count++; for (List::Element *E = keys.front(); E; E = E->next()) { _VariantStrPair sp; sp.key = stringify_variant_clean(E->get(), recursion_count); @@ -1787,6 +1785,7 @@ String Variant::stringify(int recursion_count) const { return str; } + // Packed arrays cannot contain recursive structures, the recursion_count increment is not needed. case PACKED_VECTOR2_ARRAY: { return stringify_vector(operator Vector(), recursion_count); } @@ -1815,13 +1814,10 @@ String Variant::stringify(int recursion_count) const { return stringify_vector(operator Vector(), recursion_count); } case ARRAY: { - Array arr = operator Array(); - if (recursion_count > MAX_RECURSION) { - ERR_PRINT("Maximum array recursion reached!"); - return "[...]"; - } + ERR_FAIL_COND_V_MSG(recursion_count > MAX_RECURSION, "[...]", "Maximum array recursion reached!"); + recursion_count++; - return stringify_vector(arr, recursion_count); + return stringify_vector(operator Array(), recursion_count); } case OBJECT: { if (_get_obj().obj) { From a606b03fd749a204959e4de97441dbc4c6d65b6e Mon Sep 17 00:00:00 2001 From: bitsawer Date: Thu, 17 Aug 2023 11:17:54 +0300 Subject: [PATCH 07/96] Fix Shader and ShaderInclude resource loading (cherry picked from commit 26e3443eef49a7189eba5e1648ae7be13d95afd2) --- scene/resources/shader.cpp | 13 ++++++++----- scene/resources/shader_include.cpp | 13 ++++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 361a28194fc..ac6bffa077f 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -234,13 +234,16 @@ Ref ResourceFormatLoaderShader::load(const String &p_path, const Strin *r_error = ERR_FILE_CANT_OPEN; } - Ref shader; - shader.instantiate(); - - Vector buffer = FileAccess::get_file_as_bytes(p_path); + Error error = OK; + Vector buffer = FileAccess::get_file_as_bytes(p_path, &error); + ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot load shader: " + p_path); String str; - str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + error = str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot parse shader: " + p_path); + + Ref shader; + shader.instantiate(); shader->set_include_path(p_path); shader->set_code(str); diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp index 6e9c64d34b4..f4bbb44fd1d 100644 --- a/scene/resources/shader_include.cpp +++ b/scene/resources/shader_include.cpp @@ -88,13 +88,16 @@ Ref ResourceFormatLoaderShaderInclude::load(const String &p_path, cons *r_error = ERR_FILE_CANT_OPEN; } - Ref shader_inc; - shader_inc.instantiate(); - - Vector buffer = FileAccess::get_file_as_bytes(p_path); + Error error = OK; + Vector buffer = FileAccess::get_file_as_bytes(p_path, &error); + ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot load shader include: " + p_path); String str; - str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + error = str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot parse shader include: " + p_path); + + Ref shader_inc; + shader_inc.instantiate(); shader_inc->set_include_path(p_path); shader_inc->set_code(str); From 3920b2db053ebc7e43f7567ff5a62f8308573b6d Mon Sep 17 00:00:00 2001 From: bitsawer Date: Mon, 4 Sep 2023 14:59:59 +0300 Subject: [PATCH 08/96] Fix empty shader resource loading (cherry picked from commit 15eec2450a1911292106e3e815022234bad2363c) --- scene/resources/shader.cpp | 6 ++++-- scene/resources/shader_include.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index ac6bffa077f..1a86bcfbf48 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -239,8 +239,10 @@ Ref ResourceFormatLoaderShader::load(const String &p_path, const Strin ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot load shader: " + p_path); String str; - error = str.parse_utf8((const char *)buffer.ptr(), buffer.size()); - ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot parse shader: " + p_path); + if (buffer.size() > 0) { + error = str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot parse shader: " + p_path); + } Ref shader; shader.instantiate(); diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp index f4bbb44fd1d..8afa7f5b398 100644 --- a/scene/resources/shader_include.cpp +++ b/scene/resources/shader_include.cpp @@ -93,8 +93,10 @@ Ref ResourceFormatLoaderShaderInclude::load(const String &p_path, cons ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot load shader include: " + p_path); String str; - error = str.parse_utf8((const char *)buffer.ptr(), buffer.size()); - ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot parse shader include: " + p_path); + if (buffer.size() > 0) { + error = str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot parse shader include: " + p_path); + } Ref shader_inc; shader_inc.instantiate(); From bf15d20e56f07ae52c3af65911df509640ed2c30 Mon Sep 17 00:00:00 2001 From: kleonc <9283098+kleonc@users.noreply.github.com> Date: Thu, 14 Sep 2023 23:37:28 +0200 Subject: [PATCH 09/96] Enable transparent background for GUI tooltips (cherry picked from commit c66dfd2cfe8f2bb11b1ac5b237b9aba63fdd069f) --- scene/main/viewport.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 8609b779446..41439153975 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1448,6 +1448,9 @@ void Viewport::_gui_show_tooltip() { PopupPanel *panel = memnew(PopupPanel); panel->set_theme_type_variation(SNAME("TooltipPanel")); + // Ensure no opaque background behind the panel as its StyleBox can be partially transparent (e.g. corners). + panel->set_transparent_background(true); + // Controls can implement `make_custom_tooltip` to provide their own tooltip. // This should be a Control node which will be added as child to a TooltipPanel. Control *base_tooltip = tooltip_owner->make_custom_tooltip(tooltip_text); From e7978fe277ea03d40f5d594eda4b5954f7a5b3b3 Mon Sep 17 00:00:00 2001 From: Ryan Hitchman Date: Mon, 18 Sep 2023 16:30:04 -0600 Subject: [PATCH 10/96] Fix Curve3D baking up vectors for nontrivial curves. The code was modified in 42aa539 to have a different basis vector, but this line was missed and caused up vectors to invert sometimes. Fixes #81879 (cherry picked from commit 734b9d2379c5ad8511f3a4d020dce60bb18abd88) --- scene/resources/curve.cpp | 4 ++-- tests/scene/test_curve_3d.h | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 12ee36654d1..0b5ecc596be 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -1646,7 +1646,7 @@ void Curve3D::_bake() const { const Vector3 *forward_ptr = baked_forward_vector_cache.ptr(); const Vector3 *points_ptr = baked_point_cache.ptr(); - Basis frame; // X-right, Y-up, Z-forward. + Basis frame; // X-right, Y-up, -Z-forward. Basis frame_prev; // Set the initial frame based on Y-up rule. @@ -1667,7 +1667,7 @@ void Curve3D::_bake() const { Vector3 forward = forward_ptr[idx]; Basis rotate; - rotate.rotate_to_align(frame_prev.get_column(2), forward); + rotate.rotate_to_align(-frame_prev.get_column(2), forward); frame = rotate * frame_prev; frame.orthonormalize(); // guard against float error accumulation diff --git a/tests/scene/test_curve_3d.h b/tests/scene/test_curve_3d.h index 4d7b718d7e0..d73bb1ad35b 100644 --- a/tests/scene/test_curve_3d.h +++ b/tests/scene/test_curve_3d.h @@ -209,6 +209,14 @@ TEST_CASE("[Curve3D] Sampling") { CHECK(curve->get_closest_point(Vector3(50, 50, 0)) == Vector3(0, 50, 0)); CHECK(curve->get_closest_point(Vector3(0, 100, 0)) == Vector3(0, 50, 0)); } + + SUBCASE("sample_baked_up_vector, off-axis") { + // Regression test for issue #81879 + Ref c = memnew(Curve3D); + c->add_point(Vector3()); + c->add_point(Vector3(0, .1, 1)); + CHECK_LT((c->sample_baked_up_vector(c->get_closest_offset(Vector3(0, 0, .9))) - Vector3(0, 0.995037, -0.099504)).length(), 0.01); + } } TEST_CASE("[Curve3D] Tessellation") { From 76f61b39604ad619f8a5f2d3a8d4695f588ae987 Mon Sep 17 00:00:00 2001 From: Fabian Keller Date: Sun, 10 Sep 2023 09:22:21 +0200 Subject: [PATCH 11/96] bugfix for audio stream generators getting killed accidentally by audio server (cherry picked from commit 4eac548202ffb2ce4e0c0b9d6792620a23b8ab5c) --- servers/audio/effects/audio_stream_generator.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/servers/audio/effects/audio_stream_generator.cpp b/servers/audio/effects/audio_stream_generator.cpp index 5cfe51465d2..f4727e72ecd 100644 --- a/servers/audio/effects/audio_stream_generator.cpp +++ b/servers/audio/effects/audio_stream_generator.cpp @@ -143,6 +143,10 @@ void AudioStreamGeneratorPlayback::clear_buffer() { } int AudioStreamGeneratorPlayback::_mix_internal(AudioFrame *p_buffer, int p_frames) { + if (!active) { + return 0; + } + int read_amount = buffer.data_left(); if (p_frames < read_amount) { read_amount = p_frames; @@ -151,16 +155,15 @@ int AudioStreamGeneratorPlayback::_mix_internal(AudioFrame *p_buffer, int p_fram buffer.read(p_buffer, read_amount); if (read_amount < p_frames) { - //skipped, not ideal + // Fill with zeros as fallback in case of buffer underrun. for (int i = read_amount; i < p_frames; i++) { p_buffer[i] = AudioFrame(0, 0); } - skips++; } mixed += p_frames / generator->get_mix_rate(); - return read_amount < p_frames ? read_amount : p_frames; + return p_frames; } float AudioStreamGeneratorPlayback::get_stream_sampling_rate() { @@ -181,7 +184,7 @@ void AudioStreamGeneratorPlayback::stop() { } bool AudioStreamGeneratorPlayback::is_playing() const { - return active; //always playing, can't be stopped + return active; } int AudioStreamGeneratorPlayback::get_loop_count() const { From 5f46bca8240bb440a1581cd6380f624df010aad3 Mon Sep 17 00:00:00 2001 From: Rindbee Date: Thu, 29 Jun 2023 15:38:19 +0800 Subject: [PATCH 12/96] Fix history mismatch Set the properties of the resource's proxy instead of setting the resource's properties directly. (For action "Set ...") Update the path of the edited scene when saving the scene. (For action "Add atlas source") (cherry picked from commit 28db5e76495bab5f0cb3fa4a4b7d4769d25c9962) --- editor/editor_node.cpp | 3 +++ editor/plugins/tiles/tile_set_atlas_source_editor.cpp | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 5b3a29ac2cf..4e3b3fcc904 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1982,6 +1982,9 @@ void EditorNode::_dialog_action(String p_file) { if (scene_idx != -1) { _discard_changes(); + } else { + // Update the path of the edited scene to ensure later do/undo action history matches. + editor_data.set_scene_path(editor_data.get_edited_scene(), p_file); } } diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 6ec45b1f956..7a337a9f2b2 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -2156,7 +2156,7 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo Ref atlas_source = atlas_source_proxy->get_edited(); ERR_FAIL_COND(!atlas_source.is_valid()); - UndoRedo *internal_undo_redo = undo_redo_man->get_history_for_object(atlas_source.ptr()).undo_redo; + UndoRedo *internal_undo_redo = undo_redo_man->get_history_for_object(atlas_source_proxy).undo_redo; internal_undo_redo->start_force_keep_in_merge_ends(); PackedVector2Array arr; @@ -2180,7 +2180,7 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo String prefix = vformat("%d:%d/", coords.x, coords.y); for (PropertyInfo pi : properties) { if (pi.name.begins_with(prefix)) { - ADD_UNDO(atlas_source.ptr(), pi.name); + ADD_UNDO(atlas_source_proxy, pi.name); } } } From 8f32e968b82b652ce6f6e8c7e3c75b1da2f7ac7e Mon Sep 17 00:00:00 2001 From: Hrvoje Varga Date: Thu, 27 Jul 2023 07:38:40 +0200 Subject: [PATCH 13/96] Fix scene tab close (cherry picked from commit 51923fc528fe2342fb27d64c1389641ecdb0c777) --- editor/editor_node.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 4e3b3fcc904..3c1b1fd1d0b 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -3577,7 +3577,9 @@ void EditorNode::set_current_scene(int p_idx) { _update_title(); _update_scene_tabs(); - call_deferred(SNAME("_set_main_scene_state"), state, get_edited_scene()); // Do after everything else is done setting up. + if (tabs_to_close.is_empty()) { + call_deferred(SNAME("_set_main_scene_state"), state, get_edited_scene()); // Do after everything else is done setting up. + } } void EditorNode::setup_color_picker(ColorPicker *p_picker) { From f54cbe6b763b89afc3ad121813626c0bce229d6a Mon Sep 17 00:00:00 2001 From: Ninni Pipping Date: Tue, 11 Jul 2023 12:40:53 +0200 Subject: [PATCH 14/96] Prevent crash when accessing `Node` Multiplayer from thread (cherry picked from commit 7bd3a3a5e539d22302ce388f6bcae64f2e78f7c8) --- scene/main/node.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 6b18e47f2df..adc565285a2 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -645,7 +645,8 @@ int Node::get_multiplayer_authority() const { bool Node::is_multiplayer_authority() const { ERR_FAIL_COND_V(!is_inside_tree(), false); - return get_multiplayer()->get_unique_id() == data.multiplayer_authority; + Ref api = get_multiplayer(); + return api.is_valid() && (api->get_unique_id() == data.multiplayer_authority); } /***** RPC CONFIG ********/ @@ -724,7 +725,12 @@ Error Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallE Error Node::rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED); - return get_multiplayer()->rpcp(this, p_peer_id, p_method, p_arg, p_argcount); + + Ref api = get_multiplayer(); + if (api.is_null()) { + return ERR_UNCONFIGURED; + } + return api->rpcp(this, p_peer_id, p_method, p_arg, p_argcount); } Ref Node::get_multiplayer() const { From 6fa4270d71c0cdefef18eaa80b9c6db40430c2e6 Mon Sep 17 00:00:00 2001 From: Lyuma Date: Sat, 5 Aug 2023 16:52:51 -0700 Subject: [PATCH 15/96] Use image index instead of texture index for source_images (cherry picked from commit f67b6c158ce780641d9174e75441a5ca0ee92444) --- modules/gltf/gltf_document.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 00bf3e58b04..c3c7a4c4b0d 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -3385,10 +3385,11 @@ Ref GLTFDocument::_get_texture(Ref p_state, const GLTFText const GLTFImageIndex image = p_state->textures[p_texture]->get_src_image(); ERR_FAIL_INDEX_V(image, p_state->images.size(), Ref()); if (GLTFState::GLTFHandleBinary(p_state->handle_binary_image) == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EMBED_AS_BASISU) { + ERR_FAIL_INDEX_V(image, p_state->source_images.size(), Ref()); Ref portable_texture; portable_texture.instantiate(); portable_texture->set_keep_compressed_buffer(true); - Ref new_img = p_state->source_images[p_texture]->duplicate(); + Ref new_img = p_state->source_images[image]->duplicate(); ERR_FAIL_COND_V(new_img.is_null(), Ref()); new_img->generate_mipmaps(); if (p_texture_types) { From 2c9901af360a9002e85eb0ca787b16bf9c900fc2 Mon Sep 17 00:00:00 2001 From: clayjohn Date: Tue, 8 Aug 2023 10:56:54 +0200 Subject: [PATCH 16/96] Remove GPU readback from NoiseTexture3D.get_format (cherry picked from commit 60d5571d6cf31c6c6aec8afe71ef295a4b45c5f8) --- modules/noise/noise_texture_3d.cpp | 4 ++-- modules/noise/noise_texture_3d.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/noise/noise_texture_3d.cpp b/modules/noise/noise_texture_3d.cpp index f6c67b0f2de..bc17c951ffb 100644 --- a/modules/noise/noise_texture_3d.cpp +++ b/modules/noise/noise_texture_3d.cpp @@ -112,6 +112,7 @@ void NoiseTexture3D::_set_texture_data(const TypedArray &p_data) { } else { texture = RS::get_singleton()->texture_3d_create(data[0]->get_format(), data[0]->get_width(), data[0]->get_height(), data.size(), false, data); } + format = data[0]->get_format(); } emit_changed(); } @@ -348,6 +349,5 @@ Vector> NoiseTexture3D::get_data() const { } Image::Format NoiseTexture3D::get_format() const { - ERR_FAIL_COND_V(!texture.is_valid(), Image::FORMAT_L8); - return RS::get_singleton()->texture_3d_get(texture)[0]->get_format(); + return format; } diff --git a/modules/noise/noise_texture_3d.h b/modules/noise/noise_texture_3d.h index 397711ca981..13125efe7f2 100644 --- a/modules/noise/noise_texture_3d.h +++ b/modules/noise/noise_texture_3d.h @@ -60,6 +60,8 @@ private: Ref color_ramp; Ref noise; + Image::Format format = Image::FORMAT_L8; + void _thread_done(const TypedArray &p_data); static void _thread_function(void *p_ud); From 96b8861c9d39df16033183686784be369a05c15c Mon Sep 17 00:00:00 2001 From: HolonProduction Date: Sat, 19 Aug 2023 11:20:38 +0200 Subject: [PATCH 17/96] Fix crash when hiding subwindow during popup of new subwindow (cherry picked from commit e2cea458a34665c03d57aa52bddcfd8054d3bf03) --- scene/main/viewport.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 41439153975..b3fb6bf6834 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -364,6 +364,7 @@ void Viewport::_sub_window_grab_focus(Window *p_window) { return; } + // The index needs to be update before every usage in case an event callback changed the window list. int index = _sub_window_find(p_window); ERR_FAIL_COND(index == -1); @@ -375,6 +376,8 @@ void Viewport::_sub_window_grab_focus(Window *p_window) { gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; } // Can only move to foreground, but no focus granted. + index = _sub_window_find(p_window); + ERR_FAIL_COND(index == -1); SubWindow sw = gui.sub_windows[index]; gui.sub_windows.remove_at(index); gui.sub_windows.push_back(sw); @@ -402,6 +405,8 @@ void Viewport::_sub_window_grab_focus(Window *p_window) { gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); { // Move to foreground. + index = _sub_window_find(p_window); + ERR_FAIL_COND(index == -1); SubWindow sw = gui.sub_windows[index]; gui.sub_windows.remove_at(index); gui.sub_windows.push_back(sw); From 4e539028fb60cc84c0648a2eb3f9da8086ef26bb Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:01:21 +0200 Subject: [PATCH 18/96] Fix memory access error for `MultiMesh` with GLES3 Buffer was incorrectly assigned when invalid data was provided (cherry picked from commit 6cb28e481f72d6fa1b2d06ff1e0c8664dcbd22ca) --- drivers/gles3/storage/mesh_storage.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index f3be6f509e2..8bb47f76adb 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -1685,14 +1685,16 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector &p_b // Color and custom need to be packed so copy buffer to data_cache and pack. _multimesh_make_local(multimesh); - multimesh->data_cache = p_buffer; - float *w = multimesh->data_cache.ptrw(); uint32_t old_stride = multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12; old_stride += multimesh->uses_colors ? 4 : 0; old_stride += multimesh->uses_custom_data ? 4 : 0; ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)old_stride)); + multimesh->data_cache = p_buffer; + + float *w = multimesh->data_cache.ptrw(); + for (int i = 0; i < multimesh->instances; i++) { { float *dataptr = w + i * old_stride; From 3c5f715053cd782397434f70ca03de6798c48d3c Mon Sep 17 00:00:00 2001 From: bitsawer Date: Mon, 21 Aug 2023 12:46:15 +0300 Subject: [PATCH 19/96] Fix Vulkan crash with many Omni/SpotLights, Decals or ReflectionProbes (cherry picked from commit d6f45e4f1429f4867f02e1070c7609b34e90f4bd) --- servers/rendering/renderer_rd/cluster_builder_rd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp index d2a1a5ab9c3..64950c6991a 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp +++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp @@ -285,7 +285,7 @@ void ClusterBuilderRD::setup(Size2i p_screen_size, uint32_t p_max_elements, RID cluster_render_buffer = RD::get_singleton()->storage_buffer_create(cluster_render_buffer_size); cluster_buffer = RD::get_singleton()->storage_buffer_create(cluster_buffer_size); - render_elements = static_cast(memalloc(sizeof(RenderElementData *) * render_element_max)); + render_elements = static_cast(memalloc(sizeof(RenderElementData) * render_element_max)); render_element_count = 0; element_buffer = RD::get_singleton()->storage_buffer_create(sizeof(RenderElementData) * render_element_max); From 6d5127d34ba329c429ffc18b5cf84dde662c8bc6 Mon Sep 17 00:00:00 2001 From: Danil Alexeev Date: Tue, 29 Aug 2023 15:05:53 +0300 Subject: [PATCH 20/96] Core: Fix recursion level check for `VariantWriter::write()` with objects (cherry picked from commit 5d689ad560e5ab42081717872532cb2afc44aee1) --- core/variant/variant_parser.cpp | 57 ++++++++++++--------------------- core/variant/variant_parser.h | 2 +- 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index 33207509949..b7bdf1d97a6 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -1708,7 +1708,7 @@ static String rtos_fix(double p_value) { } } -Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int recursion_count) { +Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count) { switch (p_variant.get_type()) { case Variant::NIL: { p_store_string_func(p_store_string_ud, "null"); @@ -1730,10 +1730,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::STRING: { String str = p_variant; - str = "\"" + str.c_escape_multiline() + "\""; p_store_string_func(p_store_string_ud, str); } break; + + // Math types. case Variant::VECTOR2: { Vector2 v = p_variant; p_store_string_func(p_store_string_ud, "Vector2(" + rtos_fix(v.x) + ", " + rtos_fix(v.y) + ")"); @@ -1745,12 +1746,10 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str case Variant::RECT2: { Rect2 aabb = p_variant; p_store_string_func(p_store_string_ud, "Rect2(" + rtos_fix(aabb.position.x) + ", " + rtos_fix(aabb.position.y) + ", " + rtos_fix(aabb.size.x) + ", " + rtos_fix(aabb.size.y) + ")"); - } break; case Variant::RECT2I: { Rect2i aabb = p_variant; p_store_string_func(p_store_string_ud, "Rect2i(" + itos(aabb.position.x) + ", " + itos(aabb.position.y) + ", " + itos(aabb.size.x) + ", " + itos(aabb.size.y) + ")"); - } break; case Variant::VECTOR3: { Vector3 v = p_variant; @@ -1771,17 +1770,14 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str case Variant::PLANE: { Plane p = p_variant; p_store_string_func(p_store_string_ud, "Plane(" + rtos_fix(p.normal.x) + ", " + rtos_fix(p.normal.y) + ", " + rtos_fix(p.normal.z) + ", " + rtos_fix(p.d) + ")"); - } break; case Variant::AABB: { AABB aabb = p_variant; p_store_string_func(p_store_string_ud, "AABB(" + rtos_fix(aabb.position.x) + ", " + rtos_fix(aabb.position.y) + ", " + rtos_fix(aabb.position.z) + ", " + rtos_fix(aabb.size.x) + ", " + rtos_fix(aabb.size.y) + ", " + rtos_fix(aabb.size.z) + ")"); - } break; case Variant::QUATERNION: { Quaternion quaternion = p_variant; p_store_string_func(p_store_string_ud, "Quaternion(" + rtos_fix(quaternion.x) + ", " + rtos_fix(quaternion.y) + ", " + rtos_fix(quaternion.z) + ", " + rtos_fix(quaternion.w) + ")"); - } break; case Variant::TRANSFORM2D: { String s = "Transform2D("; @@ -1796,7 +1792,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, s + ")"); - } break; case Variant::BASIS: { String s = "Basis("; @@ -1811,7 +1806,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, s + ")"); - } break; case Variant::TRANSFORM3D: { String s = "Transform3D("; @@ -1845,30 +1839,23 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, s + ")"); } break; - // misc types + // Misc types. case Variant::COLOR: { Color c = p_variant; p_store_string_func(p_store_string_ud, "Color(" + rtos_fix(c.r) + ", " + rtos_fix(c.g) + ", " + rtos_fix(c.b) + ", " + rtos_fix(c.a) + ")"); - } break; case Variant::STRING_NAME: { String str = p_variant; - str = "&\"" + str.c_escape() + "\""; p_store_string_func(p_store_string_ud, str); - } break; case Variant::NODE_PATH: { String str = p_variant; - str = "NodePath(\"" + str.c_escape() + "\")"; p_store_string_func(p_store_string_ud, str); - } break; - case Variant::RID: { RID rid = p_variant; - if (rid == RID()) { p_store_string_func(p_store_string_ud, "RID()"); } else { @@ -1885,6 +1872,13 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::OBJECT: { + if (unlikely(p_recursion_count > MAX_RECURSION)) { + ERR_PRINT("Max recursion reached"); + p_store_string_func(p_store_string_ud, "null"); + return OK; + } + p_recursion_count++; + Object *obj = p_variant.get_validated_object(); if (!obj) { @@ -1934,21 +1928,20 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, "\"" + E.name + "\":"); - write(obj->get(E.name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); + write(obj->get(E.name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); } } p_store_string_func(p_store_string_ud, ")\n"); - } break; case Variant::DICTIONARY: { Dictionary dict = p_variant; - if (recursion_count > MAX_RECURSION) { + if (unlikely(p_recursion_count > MAX_RECURSION)) { ERR_PRINT("Max recursion reached"); p_store_string_func(p_store_string_ud, "{}"); } else { - recursion_count++; + p_recursion_count++; List keys; dict.get_key_list(&keys); @@ -1961,9 +1954,9 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, "{\n"); for (List::Element *E = keys.front(); E; E = E->next()) { - write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, recursion_count); + write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); p_store_string_func(p_store_string_ud, ": "); - write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, recursion_count); + write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); if (E->next()) { p_store_string_func(p_store_string_ud, ",\n"); } else { @@ -1973,7 +1966,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, "}"); } - } break; case Variant::ARRAY: { @@ -2009,11 +2001,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, "]("); } - if (recursion_count > MAX_RECURSION) { + if (unlikely(p_recursion_count > MAX_RECURSION)) { ERR_PRINT("Max recursion reached"); p_store_string_func(p_store_string_ud, "[]"); } else { - recursion_count++; + p_recursion_count++; p_store_string_func(p_store_string_ud, "["); int len = array.size(); @@ -2021,7 +2013,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i > 0) { p_store_string_func(p_store_string_ud, ", "); } - write(array[i], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, recursion_count); + write(array[i], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); } p_store_string_func(p_store_string_ud, "]"); @@ -2030,7 +2022,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (array.get_typed_builtin() != Variant::NIL) { p_store_string_func(p_store_string_ud, ")"); } - } break; case Variant::PACKED_BYTE_ARRAY: { @@ -2048,7 +2039,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, ")"); - } break; case Variant::PACKED_INT32_ARRAY: { p_store_string_func(p_store_string_ud, "PackedInt32Array("); @@ -2065,7 +2055,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, ")"); - } break; case Variant::PACKED_INT64_ARRAY: { p_store_string_func(p_store_string_ud, "PackedInt64Array("); @@ -2082,7 +2071,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, ")"); - } break; case Variant::PACKED_FLOAT32_ARRAY: { p_store_string_func(p_store_string_ud, "PackedFloat32Array("); @@ -2098,7 +2086,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, ")"); - } break; case Variant::PACKED_FLOAT64_ARRAY: { p_store_string_func(p_store_string_ud, "PackedFloat64Array("); @@ -2114,7 +2101,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, ")"); - } break; case Variant::PACKED_STRING_ARRAY: { p_store_string_func(p_store_string_ud, "PackedStringArray("); @@ -2130,7 +2116,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, ")"); - } break; case Variant::PACKED_VECTOR2_ARRAY: { p_store_string_func(p_store_string_ud, "PackedVector2Array("); @@ -2146,7 +2131,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, ")"); - } break; case Variant::PACKED_VECTOR3_ARRAY: { p_store_string_func(p_store_string_ud, "PackedVector3Array("); @@ -2162,7 +2146,6 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, ")"); - } break; case Variant::PACKED_COLOR_ARRAY: { p_store_string_func(p_store_string_ud, "PackedColorArray("); @@ -2178,8 +2161,8 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, ")"); - } break; + default: { ERR_PRINT("Unknown variant type"); return ERR_BUG; diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h index 88be99e5511..8505fff739a 100644 --- a/core/variant/variant_parser.h +++ b/core/variant/variant_parser.h @@ -160,7 +160,7 @@ public: typedef Error (*StoreStringFunc)(void *ud, const String &p_string); typedef String (*EncodeResourceFunc)(void *ud, const Ref &p_resource); - static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int recursion_count = 0); + static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count = 0); static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr); }; From f2b6eda2105a8518e09b4a44d60662753996cb94 Mon Sep 17 00:00:00 2001 From: jsjtxietian Date: Wed, 6 Sep 2023 11:11:07 +0800 Subject: [PATCH 21/96] Fix a crash when enable a plugin uses `make_mesh_previews` The bug happens when plugin tree is propagating mouse events (so it is blocked), but EditorProgress's dtor will make main editor focused and call update_plugins immediately which will update the blocked tree. (cherry picked from commit 7e3a76236983563201fdb358665fd748845ab023) --- editor/editor_plugin_settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index 7f57619ac8d..525c9168cb7 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -243,7 +243,7 @@ EditorPluginSettings::EditorPluginSettings() { plugin_list->set_column_custom_minimum_width(3, 80 * EDSCALE); plugin_list->set_column_custom_minimum_width(4, 40 * EDSCALE); plugin_list->set_hide_root(true); - plugin_list->connect("item_edited", callable_mp(this, &EditorPluginSettings::_plugin_activity_changed)); + plugin_list->connect("item_edited", callable_mp(this, &EditorPluginSettings::_plugin_activity_changed), CONNECT_DEFERRED); VBoxContainer *mc = memnew(VBoxContainer); mc->add_child(plugin_list); From f6f2b0897a5bccbbd7b501ea0f88ab3fd5312f81 Mon Sep 17 00:00:00 2001 From: Dario Date: Mon, 11 Sep 2023 09:14:39 -0300 Subject: [PATCH 22/96] Propagate error correctly when max texture size for lightmaps is too small. Add error handling for BAKE_ERROR_LIGHTMAP_TOO_SMALL, which was previously ignored. Fixes #81453. (cherry picked from commit 7dfb854556f0a69672f5e112e3bfbe7f507db3b0) --- doc/classes/LightmapGI.xml | 3 +++ editor/plugins/lightmap_gi_editor_plugin.cpp | 3 +++ scene/3d/lightmap_gi.cpp | 5 ++++- scene/3d/lightmap_gi.h | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml index 55c6ef5eb5d..2b7875a939d 100644 --- a/doc/classes/LightmapGI.xml +++ b/doc/classes/LightmapGI.xml @@ -117,6 +117,9 @@ The user aborted the lightmap baking operation (typically by clicking the [b]Cancel[/b] button in the progress dialog). + + Lightmap baking failed as the maximum texture size is too small to fit some of the meshes marked for baking. + Ignore environment lighting when baking lightmaps. diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp index b549a958e69..7fc462edbbb 100644 --- a/editor/plugins/lightmap_gi_editor_plugin.cpp +++ b/editor/plugins/lightmap_gi_editor_plugin.cpp @@ -103,6 +103,9 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) { case LightmapGI::BAKE_ERROR_FOREIGN_DATA: { EditorNode::get_singleton()->show_warning(TTR("Lightmap data is not local to the scene.")); } break; + case LightmapGI::BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL: { + EditorNode::get_singleton()->show_warning(TTR("Maximum texture size is too small for the lightmap images.")); + } break; default: { } break; } diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 3ee08fd5485..237c3ef953e 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -1081,7 +1081,9 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bias, max_texture_size, directional, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud, exposure_normalization); - if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES) { + if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_TOO_SMALL) { + return BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL; + } else if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES) { return BAKE_ERROR_MESHES_INVALID; } @@ -1565,6 +1567,7 @@ void LightmapGI::_bind_methods() { BIND_ENUM_CONSTANT(BAKE_ERROR_MESHES_INVALID); BIND_ENUM_CONSTANT(BAKE_ERROR_CANT_CREATE_IMAGE); BIND_ENUM_CONSTANT(BAKE_ERROR_USER_ABORTED); + BIND_ENUM_CONSTANT(BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL); BIND_ENUM_CONSTANT(ENVIRONMENT_MODE_DISABLED); BIND_ENUM_CONSTANT(ENVIRONMENT_MODE_SCENE); diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index b9e33cf3004..02123ef7ba6 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -132,6 +132,7 @@ public: BAKE_ERROR_MESHES_INVALID, BAKE_ERROR_CANT_CREATE_IMAGE, BAKE_ERROR_USER_ABORTED, + BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL, }; enum EnvironmentMode { From 9332a2b3870e1fc510973eeaaa54f0972f328acf Mon Sep 17 00:00:00 2001 From: William Edwards Date: Tue, 12 Sep 2023 18:43:31 -0700 Subject: [PATCH 23/96] Fix dumping of signal API parameters (cherry picked from commit 188132884d88fa33e4e848ca2b2b61c826c534c9) --- modules/gdscript/language_server/gdscript_extend_parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 3a5a54e275e..7c911aed617 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -812,7 +812,7 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode api["name"] = m.signal->identifier->name; Array pars; for (int j = 0; j < m.signal->parameters.size(); j++) { - pars.append(String(m.signal->parameters[i]->identifier->name)); + pars.append(String(m.signal->parameters[j]->identifier->name)); } api["arguments"] = pars; if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(m.signal->start_line))) { From ef1d0cda30340ba79e1755506e92fd944b9b80ff Mon Sep 17 00:00:00 2001 From: kobewi Date: Wed, 26 Jul 2023 14:52:45 +0200 Subject: [PATCH 24/96] Automatically add path to built-in scripts (cherry picked from commit ed6ad376c6b4e20ebd2224f1c30a80138fa322f9) --- editor/scene_tree_dock.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 818f5667087..b366d7c9962 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -2053,6 +2053,10 @@ void SceneTreeDock::_script_created(Ref