diff options
Diffstat (limited to 'scene')
31 files changed, 543 insertions, 339 deletions
diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp index b527a72de6..7b9f7e14ca 100644 --- a/scene/2d/joint_2d.cpp +++ b/scene/2d/joint_2d.cpp @@ -50,6 +50,7 @@ void Joint2D::_disconnect_signals() { void Joint2D::_body_exit_tree() { _disconnect_signals(); _update_joint(true); + update_configuration_warnings(); } void Joint2D::_update_joint(bool p_only_free) { @@ -64,7 +65,6 @@ void Joint2D::_update_joint(bool p_only_free) { if (p_only_free || !is_inside_tree()) { PhysicsServer2D::get_singleton()->joint_clear(joint); warning = String(); - update_configuration_warnings(); return; } diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp index c22e3f6d91..b6fc83e599 100644 --- a/scene/3d/joint_3d.cpp +++ b/scene/3d/joint_3d.cpp @@ -49,6 +49,7 @@ void Joint3D::_disconnect_signals() { void Joint3D::_body_exit_tree() { _disconnect_signals(); _update_joint(true); + update_configuration_warnings(); } void Joint3D::_update_joint(bool p_only_free) { @@ -65,7 +66,6 @@ void Joint3D::_update_joint(bool p_only_free) { if (p_only_free || !is_inside_tree()) { PhysicsServer3D::get_singleton()->joint_clear(joint); warning = String(); - update_configuration_warnings(); return; } diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp index 2d7da48ab1..78da22a0c3 100644 --- a/scene/3d/label_3d.cpp +++ b/scene/3d/label_3d.cpp @@ -788,6 +788,11 @@ Ref<Font> Label3D::get_font() const { } Ref<Font> Label3D::_get_font_or_default() const { + if (theme_font.is_valid()) { + theme_font->disconnect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed")); + theme_font.unref(); + } + if (font_override.is_valid() && font_override->get_data_count() > 0) { return font_override; } @@ -799,7 +804,12 @@ Ref<Font> Label3D::_get_font_or_default() const { for (const StringName &E : theme_types) { if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - return Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + Ref<Font> f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (f.is_valid()) { + theme_font = f; + theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed")); + } + return f; } } } @@ -811,13 +821,23 @@ Ref<Font> Label3D::_get_font_or_default() const { for (const StringName &E : theme_types) { if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (f.is_valid()) { + theme_font = f; + theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed")); + } + return f; } } } // If they don't exist, use any type to return the default/empty value. - return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); + Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); + if (f.is_valid()) { + theme_font = f; + theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed")); + } + return f; } void Label3D::set_font_size(int p_size) { diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h index f57797a247..62f4c3fe96 100644 --- a/scene/3d/label_3d.h +++ b/scene/3d/label_3d.h @@ -96,6 +96,7 @@ private: int font_size = 16; Ref<Font> font_override; + mutable Ref<Font> theme_font; Color modulate = Color(1, 1, 1, 1); Point2 lbl_offset; int outline_render_priority = -1; diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 39849a0b00..fcc4548929 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -551,7 +551,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s } } - // time left must always be 1 because the end node don't lenght to compute + // time left must always be 1 because the end node don't length to compute if (p_state_machine->end_node != current) { rem = 1; } else { diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 921a06b73c..921b59748c 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1240,8 +1240,6 @@ void AnimationPlayer::_animation_set_cache_update() { void AnimationPlayer::_animation_added(const StringName &p_name, const StringName &p_library) { _animation_set_cache_update(); - - update_configuration_warnings(); } void AnimationPlayer::_animation_removed(const StringName &p_name, const StringName &p_library) { @@ -1265,8 +1263,6 @@ void AnimationPlayer::_animation_removed(const StringName &p_name, const StringN blend_times.erase(to_erase.front()->get()); to_erase.pop_front(); } - - update_configuration_warnings(); } void AnimationPlayer::_rename_animation(const StringName &p_from_name, const StringName &p_to_name) { @@ -1317,7 +1313,6 @@ void AnimationPlayer::_animation_renamed(const StringName &p_name, const StringN _animation_set_cache_update(); _rename_animation(from_name, to_name); - update_configuration_warnings(); } Error AnimationPlayer::add_animation_library(const StringName &p_name, const Ref<AnimationLibrary> &p_animation_library) { @@ -1353,7 +1348,6 @@ Error AnimationPlayer::add_animation_library(const StringName &p_name, const Ref notify_property_list_changed(); - update_configuration_warnings(); return OK; } @@ -1383,7 +1377,6 @@ void AnimationPlayer::remove_animation_library(const StringName &p_name) { _animation_set_cache_update(); notify_property_list_changed(); - update_configuration_warnings(); } void AnimationPlayer::_ref_anim(const Ref<Animation> &p_anim) { @@ -1469,25 +1462,12 @@ void AnimationPlayer::get_animation_library_list(List<StringName> *p_libraries) } } -TypedArray<String> AnimationPlayer::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); - - for (uint32_t i = 0; i < animation_libraries.size(); i++) { - for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[i].library->animations) { - if (animation_set.has(K.key) && animation_set[K.key].animation_library != animation_libraries[i].name) { - warnings.push_back(vformat(RTR("Animation '%s' in library '%s' is unused because another animation with the same name exists in library '%s'."), K.key, animation_libraries[i].name, animation_set[K.key].animation_library)); - } - } - } - return warnings; -} - bool AnimationPlayer::has_animation(const StringName &p_name) const { return animation_set.has(p_name); } Ref<Animation> AnimationPlayer::get_animation(const StringName &p_name) const { - ERR_FAIL_COND_V(!animation_set.has(p_name), Ref<Animation>()); + ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref<Animation>(), vformat("Animation not found: %s.", p_name)); const AnimationData &data = animation_set[p_name]; @@ -1509,8 +1489,8 @@ void AnimationPlayer::get_animation_list(List<StringName> *p_animations) const { } void AnimationPlayer::set_blend_time(const StringName &p_animation1, const StringName &p_animation2, float p_time) { - ERR_FAIL_COND(!animation_set.has(p_animation1)); - ERR_FAIL_COND(!animation_set.has(p_animation2)); + ERR_FAIL_COND_MSG(!animation_set.has(p_animation1), vformat("Animation not found: %s.", p_animation1)); + ERR_FAIL_COND_MSG(!animation_set.has(p_animation2), vformat("Animation not found: %s.", p_animation2)); ERR_FAIL_COND_MSG(p_time < 0, "Blend time cannot be smaller than 0."); BlendKey bk; @@ -1567,7 +1547,7 @@ void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float name = playback.assigned; } - ERR_FAIL_COND_MSG(!animation_set.has(name), "Animation not found: " + name + "."); + ERR_FAIL_COND_MSG(!animation_set.has(name), vformat("Animation not found: %s.", name)); Playback &c = playback; @@ -1670,7 +1650,7 @@ void AnimationPlayer::set_assigned_animation(const String &p_anim) { if (is_playing()) { play(p_anim); } else { - ERR_FAIL_COND(!animation_set.has(p_anim)); + ERR_FAIL_COND_MSG(!animation_set.has(p_anim), vformat("Animation not found: %s.", p_anim)); playback.current.pos = 0; playback.current.from = &animation_set[p_anim]; playback.assigned = p_anim; @@ -1713,7 +1693,7 @@ float AnimationPlayer::get_playing_speed() const { void AnimationPlayer::seek(double p_time, bool p_update) { if (!playback.current.from) { if (playback.assigned) { - ERR_FAIL_COND(!animation_set.has(playback.assigned)); + ERR_FAIL_COND_MSG(!animation_set.has(playback.assigned), vformat("Animation not found: %s.", playback.assigned)); playback.current.from = &animation_set[playback.assigned]; } ERR_FAIL_COND(!playback.current.from); @@ -1729,7 +1709,7 @@ void AnimationPlayer::seek(double p_time, bool p_update) { void AnimationPlayer::seek_delta(double p_time, float p_delta) { if (!playback.current.from) { if (playback.assigned) { - ERR_FAIL_COND(!animation_set.has(playback.assigned)); + ERR_FAIL_COND_MSG(!animation_set.has(playback.assigned), vformat("Animation not found: %s.", playback.assigned)); playback.current.from = &animation_set[playback.assigned]; } ERR_FAIL_COND(!playback.current.from); @@ -1899,7 +1879,7 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) { } void AnimationPlayer::animation_set_next(const StringName &p_animation, const StringName &p_next) { - ERR_FAIL_COND(!animation_set.has(p_animation)); + ERR_FAIL_COND_MSG(!animation_set.has(p_animation), vformat("Animation not found: %s.", p_animation)); animation_set[p_animation].next = p_next; } @@ -2012,7 +1992,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) { al.instantiate(); al->add_animation(SceneStringNames::get_singleton()->RESET, reset_anim); aux_player->add_animation_library("default", al); - aux_player->set_assigned_animation(SceneStringNames::get_singleton()->RESET); + aux_player->set_assigned_animation("default/" + SceneStringNames::get_singleton()->RESET); // Forcing the use of the original root because the scene where original player belongs may be not the active one Node *root = get_node(get_root()); Ref<AnimatedValuesBackup> old_values = aux_player->backup_animated_values(root); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index c679405dfe..7e4bda14e5 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -388,8 +388,6 @@ public: bool can_apply_reset() const; #endif - TypedArray<String> get_configuration_warnings() const override; - AnimationPlayer(); ~AnimationPlayer(); }; diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 4b79d79846..a86f2bdbc1 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -320,7 +320,7 @@ int OptionButton::get_selectable_item(bool p_from_last) const { } } } else { - for (int i = get_item_count() - 1; i >= 0; i++) { + for (int i = get_item_count() - 1; i >= 0; i--) { if (!is_item_disabled(i) && !is_item_separator(i)) { return i; } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 050c510a96..0f74c9c357 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2452,17 +2452,17 @@ void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) { if (p_word) { int column = caret.column; // Check for the case "<word><space><caret>" and ignore the space. - // No need to check for column being 0 since it is cheked above. + // No need to check for column being 0 since it is checked above. if (is_whitespace(text[caret.line][caret.column - 1])) { column -= 1; } // Get a list with the indices of the word bounds of the given text line. const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid()); if (words.is_empty() || column <= words[0]) { - // If "words" is empty, meaning no words are left, we can remove everything until the begining of the line. + // If "words" is empty, meaning no words are left, we can remove everything until the beginning of the line. column = 0; } else { - // Otherwise search for the first word break that is smaller than the index from we're currentlu deleteing + // Otherwise search for the first word break that is smaller than the index from which we're currently deleting. for (int i = words.size() - 2; i >= 0; i = i - 2) { if (words[i] < column) { column = words[i]; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 0ca9a66e08..4d18bc91c4 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -544,6 +544,21 @@ bool TreeItem::is_collapsed() { return collapsed; } +void TreeItem::set_visible(bool p_visible) { + if (visible == p_visible) { + return; + } + visible = p_visible; + if (tree) { + tree->update(); + _changed_notify(); + } +} + +bool TreeItem::is_visible() { + return visible; +} + void TreeItem::uncollapse_tree() { TreeItem *t = this; while (t) { @@ -646,7 +661,7 @@ TreeItem *TreeItem::get_first_child() const { return first_child; } -TreeItem *TreeItem::get_prev_visible(bool p_wrap) { +TreeItem *TreeItem::_get_prev_visible(bool p_wrap) { TreeItem *current = this; TreeItem *prev = current->get_prev(); @@ -682,7 +697,21 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) { return current; } -TreeItem *TreeItem::get_next_visible(bool p_wrap) { +TreeItem *TreeItem::get_prev_visible(bool p_wrap) { + TreeItem *loop = this; + TreeItem *prev = this->_get_prev_visible(p_wrap); + while (prev && !prev->is_visible()) { + prev = prev->_get_prev_visible(p_wrap); + if (prev == loop) { + // Check that we haven't looped all the way around to the start. + prev = nullptr; + break; + } + } + return prev; +} + +TreeItem *TreeItem::_get_next_visible(bool p_wrap) { TreeItem *current = this; if (!current->collapsed && current->first_child) { @@ -709,12 +738,37 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) { return current; } +TreeItem *TreeItem::get_next_visible(bool p_wrap) { + TreeItem *loop = this; + TreeItem *next = this->_get_next_visible(p_wrap); + while (next && !next->is_visible()) { + next = next->_get_next_visible(p_wrap); + if (next == loop) { + // Check that we haven't looped all the way around to the start. + next = nullptr; + break; + } + } + return next; +} + TreeItem *TreeItem::get_child(int p_idx) { _create_children_cache(); ERR_FAIL_INDEX_V(p_idx, children_cache.size(), nullptr); return children_cache.get(p_idx); } +int TreeItem::get_visible_child_count() { + _create_children_cache(); + int visible_count = 0; + for (int i = 0; i < children_cache.size(); i++) { + if (children_cache[i]->is_visible()) { + visible_count += 1; + } + } + return visible_count; +} + int TreeItem::get_child_count() { _create_children_cache(); return children_cache.size(); @@ -1256,6 +1310,9 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed); ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed); + ClassDB::bind_method(D_METHOD("set_visible", "enable"), &TreeItem::set_visible); + ClassDB::bind_method(D_METHOD("is_visible"), &TreeItem::is_visible); + ClassDB::bind_method(D_METHOD("uncollapse_tree"), &TreeItem::uncollapse_tree); ClassDB::bind_method(D_METHOD("set_custom_minimum_height", "height"), &TreeItem::set_custom_minimum_height); @@ -1340,6 +1397,7 @@ void TreeItem::_bind_methods() { } ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_folding"), "set_disable_folding", "is_folding_disabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "custom_minimum_height", PROPERTY_HINT_RANGE, "0,1000,1"), "set_custom_minimum_height", "get_custom_minimum_height"); @@ -1445,7 +1503,7 @@ void Tree::update_cache() { } int Tree::compute_item_height(TreeItem *p_item) const { - if (p_item == root && hide_root) { + if ((p_item == root && hide_root) || !p_item->is_visible()) { return 0; } @@ -1506,6 +1564,9 @@ int Tree::compute_item_height(TreeItem *p_item) const { } int Tree::get_item_height(TreeItem *p_item) const { + if (!p_item->is_visible()) { + return 0; + } int height = compute_item_height(p_item); height += cache.vseparation; @@ -1686,6 +1747,10 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 return -1; //draw no more! } + if (!p_item->is_visible()) { + return 0; + } + RID ci = get_canvas_item(); int htotal = 0; @@ -2056,7 +2121,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } } - if (!p_item->disable_folding && !hide_folding && p_item->first_child) { //has children, draw the guide box + if (!p_item->disable_folding && !hide_folding && p_item->first_child && p_item->get_visible_child_count() != 0) { //has visible children, draw the guide box Ref<Texture2D> arrow; @@ -2382,6 +2447,11 @@ void Tree::_range_click_timeout() { } int Tree::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<InputEventWithModifiers> &p_mod) { + if (p_item && !p_item->is_visible()) { + // Skip any processing of invisible items. + return 0; + } + int item_h = compute_item_height(p_item) + cache.vseparation; bool skip = (p_item == root && hide_root); @@ -2491,7 +2561,6 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int cache.click_column = col; cache.click_pos = click_pos; update(); - //emit_signal(SNAME("button_pressed")); return -1; } @@ -2513,9 +2582,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int if (!c.selected || p_button == MouseButton::RIGHT) { p_item->select(col); emit_signal(SNAME("multi_selected"), p_item, col, true); - if (p_button == MouseButton::RIGHT) { - emit_signal(SNAME("item_rmb_selected"), get_local_mouse_position()); - } + emit_signal(SNAME("item_mouse_selected"), get_local_mouse_position(), p_button); //p_item->selected_signal.call(col); } else { @@ -2530,9 +2597,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int bool inrange = false; select_single_item(p_item, root, col, selected_item, &inrange); - if (p_button == MouseButton::RIGHT) { - emit_signal(SNAME("item_rmb_selected"), get_local_mouse_position()); - } + emit_signal(SNAME("item_mouse_selected"), get_local_mouse_position(), p_button); } else { int icount = _count_selected_items(root); @@ -2544,9 +2609,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int select_single_item(p_item, root, col); } - if (p_button == MouseButton::RIGHT) { - emit_signal(SNAME("item_rmb_selected"), get_local_mouse_position()); - } + emit_signal(SNAME("item_mouse_selected"), get_local_mouse_position(), p_button); } } @@ -2583,11 +2646,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int if (force_edit_checkbox_only_on_checkbox) { if (x < cache.checked->get_width()) { p_item->set_checked(col, !c.checked); - item_edited(col, p_item); + item_edited(col, p_item, p_button); } } else { p_item->set_checked(col, !c.checked); - item_edited(col, p_item); + item_edited(col, p_item, p_button); } click_handled = true; //p_item->edited_signal.call(col); @@ -2629,17 +2692,17 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int p_item->set_range(col, c.val + (up ? 1.0 : -1.0) * c.step); - item_edited(col, p_item); + item_edited(col, p_item, p_button); } else if (p_button == MouseButton::RIGHT) { p_item->set_range(col, (up ? c.max : c.min)); - item_edited(col, p_item); + item_edited(col, p_item, p_button); } else if (p_button == MouseButton::WHEEL_UP) { p_item->set_range(col, c.val + c.step); - item_edited(col, p_item); + item_edited(col, p_item, p_button); } else if (p_button == MouseButton::WHEEL_DOWN) { p_item->set_range(col, c.val - c.step); - item_edited(col, p_item); + item_edited(col, p_item, p_button); } //p_item->edited_signal.call(col); @@ -2670,7 +2733,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int } if (!p_item->cells[col].custom_button || !on_arrow) { - item_edited(col, p_item, p_button == MouseButton::LEFT); + item_edited(col, p_item, p_button); } click_handled = true; return -1; @@ -2717,8 +2780,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int item_h += child_h; } } - if (p_item == root && p_button == MouseButton::RIGHT) { - emit_signal(SNAME("empty_rmb"), get_local_mouse_position()); + if (p_item == root) { + emit_signal(SNAME("empty_clicked"), get_local_mouse_position(), p_button); } } @@ -3126,7 +3189,6 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } Ref<InputEventMouseMotion> mm = p_event; - if (mm.is_valid()) { if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff update_cache(); @@ -3256,18 +3318,17 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } } - Ref<InputEventMouseButton> b = p_event; - - if (b.is_valid()) { + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid()) { if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff update_cache(); } bool rtl = is_layout_rtl(); - if (!b->is_pressed()) { - if (b->get_button_index() == MouseButton::LEFT) { - Point2 pos = b->get_position(); + if (!mb->is_pressed()) { + if (mb->get_button_index() == MouseButton::LEFT) { + Point2 pos = mb->get_position(); if (rtl) { pos.x = get_size().width - pos.x; } @@ -3302,7 +3363,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { warp_mouse(range_drag_capture_pos); } else { Rect2 rect = get_selected()->get_meta("__focus_rect"); - Point2 mpos = b->get_position(); + Point2 mpos = mb->get_position(); int icon_size_x = 0; Ref<Texture2D> icon = get_selected()->get_icon(selected_col); if (icon.is_valid()) { @@ -3330,17 +3391,6 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { pressing_for_editor = false; } - if (cache.click_type == Cache::CLICK_BUTTON && cache.click_item != nullptr) { - // make sure in case of wrong reference after reconstructing whole TreeItems - cache.click_item = get_item_at_position(cache.click_pos); - emit_signal(SNAME("button_pressed"), cache.click_item, cache.click_column, cache.click_id); - } - cache.click_type = Cache::CLICK_NONE; - cache.click_index = -1; - cache.click_id = -1; - cache.click_item = nullptr; - cache.click_column = 0; - if (drag_touching) { if (drag_speed == 0) { drag_touching_deaccel = false; @@ -3350,8 +3400,20 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { drag_touching_deaccel = true; } } - update(); } + + if (cache.click_type == Cache::CLICK_BUTTON && cache.click_item != nullptr) { + // make sure in case of wrong reference after reconstructing whole TreeItems + cache.click_item = get_item_at_position(cache.click_pos); + emit_signal("button_clicked", cache.click_item, cache.click_column, cache.click_id, mb->get_button_index()); + } + + cache.click_type = Cache::CLICK_NONE; + cache.click_index = -1; + cache.click_id = -1; + cache.click_item = nullptr; + cache.click_column = 0; + update(); return; } @@ -3359,12 +3421,12 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { return; } - switch (b->get_button_index()) { + switch (mb->get_button_index()) { case MouseButton::RIGHT: case MouseButton::LEFT: { Ref<StyleBox> bg = cache.bg; - Point2 pos = b->get_position(); + Point2 pos = mb->get_position(); if (rtl) { pos.x = get_size().width - pos.x; } @@ -3374,7 +3436,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { pos.y -= _get_title_button_height(); if (pos.y < 0) { - if (b->get_button_index() == MouseButton::LEFT) { + if (mb->get_button_index() == MouseButton::LEFT) { pos.x += cache.offset.x; int len = 0; for (int i = 0; i < columns.size(); i++) { @@ -3391,10 +3453,8 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { break; } } + if (!root || (!root->get_first_child() && hide_root)) { - if (b->get_button_index() == MouseButton::RIGHT && allow_rmb_select) { - emit_signal(SNAME("empty_tree_rmb_selected"), get_local_mouse_position()); - } break; } @@ -3409,17 +3469,17 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { cache.rtl = is_layout_rtl(); blocked++; - propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, b->is_double_click(), root, b->get_button_index(), b); + propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, mb->is_double_click(), root, mb->get_button_index(), mb); blocked--; if (pressing_for_editor) { - pressing_pos = b->get_position(); + pressing_pos = mb->get_position(); if (rtl) { pressing_pos.x = get_size().width - pressing_pos.x; } } - if (b->get_button_index() == MouseButton::RIGHT) { + if (mb->get_button_index() == MouseButton::RIGHT) { break; } @@ -3442,8 +3502,8 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { set_physics_process_internal(true); } - if (b->get_button_index() == MouseButton::LEFT) { - if (get_item_at_position(b->get_position()) == nullptr && !b->is_shift_pressed() && !b->is_ctrl_pressed() && !b->is_command_pressed()) { + if (mb->get_button_index() == MouseButton::LEFT) { + if (get_item_at_position(mb->get_position()) == nullptr && !mb->is_shift_pressed() && !mb->is_ctrl_pressed() && !mb->is_command_pressed()) { emit_signal(SNAME("nothing_selected")); } } @@ -3457,7 +3517,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } break; case MouseButton::WHEEL_UP: { double prev_value = v_scroll->get_value(); - v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8); + v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * mb->get_factor() / 8); if (v_scroll->get_value() != prev_value) { accept_event(); } @@ -3465,7 +3525,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } break; case MouseButton::WHEEL_DOWN: { double prev_value = v_scroll->get_value(); - v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8); + v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * mb->get_factor() / 8); if (v_scroll->get_value() != prev_value) { accept_event(); } @@ -3911,16 +3971,16 @@ TreeItem *Tree::get_last_item() const { return last; } -void Tree::item_edited(int p_column, TreeItem *p_item, bool p_lmb) { +void Tree::item_edited(int p_column, TreeItem *p_item, MouseButton p_mouse_index) { edited_item = p_item; edited_col = p_column; if (p_item != nullptr && p_column >= 0 && p_column < p_item->cells.size()) { edited_item->cells.write[p_column].dirty = true; } - if (p_lmb) { + if (p_mouse_index == MouseButton::NONE) { emit_signal(SNAME("item_edited")); } else { - emit_signal(SNAME("item_rmb_edited")); + emit_signal(SNAME("custom_item_clicked"), p_mouse_index); } } @@ -4147,7 +4207,7 @@ int Tree::get_column_minimum_width(int p_column) const { depth += 1; } else { TreeItem *common_parent = item->get_parent(); - while (common_parent != next->get_parent()) { + while (common_parent != next->get_parent() && common_parent) { common_parent = common_parent->get_parent(); depth -= 1; } @@ -4464,7 +4524,7 @@ Point2 Tree::get_scroll() const { } void Tree::scroll_to_item(TreeItem *p_item, bool p_center_on_item) { - if (!is_visible_in_tree()) { + if (!is_visible_in_tree() || !p_item->is_visible()) { return; // Hack to work around crash in get_item_rect() if Tree is not in tree. } @@ -4588,7 +4648,7 @@ void Tree::_do_incr_search(const String &p_add) { TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_column, int &h, int §ion) const { Point2 pos = p_pos; - if (root != p_item || !hide_root) { + if ((root != p_item || !hide_root) && p_item->is_visible()) { h = compute_item_height(p_item) + cache.vseparation; if (pos.y < h) { if (drop_mode_flags == DROP_MODE_ON_ITEM) { @@ -4621,7 +4681,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_ h = 0; } - if (p_item->is_collapsed()) { + if (p_item->is_collapsed() || !p_item->is_visible()) { return nullptr; // do not try children, it's collapsed } @@ -4965,17 +5025,15 @@ void Tree::_bind_methods() { ADD_SIGNAL(MethodInfo("item_selected")); ADD_SIGNAL(MethodInfo("cell_selected")); ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::BOOL, "selected"))); - ADD_SIGNAL(MethodInfo("item_rmb_selected", PropertyInfo(Variant::VECTOR2, "position"))); - ADD_SIGNAL(MethodInfo("empty_rmb", PropertyInfo(Variant::VECTOR2, "position"))); - ADD_SIGNAL(MethodInfo("empty_tree_rmb_selected", PropertyInfo(Variant::VECTOR2, "position"))); + ADD_SIGNAL(MethodInfo("item_mouse_selected", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::INT, "mouse_button_index"))); + ADD_SIGNAL(MethodInfo("empty_clicked", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::INT, "mouse_button_index"))); ADD_SIGNAL(MethodInfo("item_edited")); - ADD_SIGNAL(MethodInfo("item_rmb_edited")); + ADD_SIGNAL(MethodInfo("custom_item_clicked", PropertyInfo(Variant::INT, "mouse_button_index"))); ADD_SIGNAL(MethodInfo("item_custom_button_pressed")); ADD_SIGNAL(MethodInfo("item_double_clicked")); ADD_SIGNAL(MethodInfo("item_collapsed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"))); ADD_SIGNAL(MethodInfo("check_propagated_to_item", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"))); - //ADD_SIGNAL( MethodInfo("item_double_clicked" ) ); - ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("button_clicked", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "mouse_button_index"))); ADD_SIGNAL(MethodInfo("custom_popup_edited", PropertyInfo(Variant::BOOL, "arrow_clicked"))); ADD_SIGNAL(MethodInfo("item_activated")); ADD_SIGNAL(MethodInfo("column_title_pressed", PropertyInfo(Variant::INT, "column"))); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 8ee2a3c382..a70f24cb62 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -124,6 +124,7 @@ private: Vector<Cell> cells; bool collapsed = false; // won't show children + bool visible = true; bool disable_folding = false; int custom_min_height = 0; @@ -209,6 +210,9 @@ private: void _propagate_check_through_children(int p_column, bool p_checked, bool p_emit_signal); void _propagate_check_through_parents(int p_column, bool p_emit_signal); + TreeItem *_get_prev_visible(bool p_wrap = false); + TreeItem *_get_next_visible(bool p_wrap = false); + public: void set_text(int p_column, String p_text); String get_text(int p_column) const; @@ -273,6 +277,9 @@ public: void set_collapsed(bool p_collapsed); bool is_collapsed(); + void set_visible(bool p_visible); + bool is_visible(); + void uncollapse_tree(); void set_custom_minimum_height(int p_height); @@ -335,6 +342,7 @@ public: TreeItem *get_next_visible(bool p_wrap = false); TreeItem *get_child(int p_idx); + int get_visible_child_count(); int get_child_count(); Array get_children(); int get_index(); @@ -466,7 +474,7 @@ private: void _notification(int p_what); - void item_edited(int p_column, TreeItem *p_item, bool p_lmb = true); + void item_edited(int p_column, TreeItem *p_item, MouseButton p_mouse_index = MouseButton::NONE); void item_changed(int p_column, TreeItem *p_item); void item_selected(int p_column, TreeItem *p_item); void item_deselected(int p_column, TreeItem *p_item); diff --git a/scene/multiplayer/multiplayer_spawner.cpp b/scene/multiplayer/multiplayer_spawner.cpp index a9b9ffa989..ddd01d0a43 100644 --- a/scene/multiplayer/multiplayer_spawner.cpp +++ b/scene/multiplayer/multiplayer_spawner.cpp @@ -35,12 +35,106 @@ #include "scene/main/window.h" #include "scene/scene_string_names.h" +#ifdef TOOLS_ENABLED +/* This is editor only */ +bool MultiplayerSpawner::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "_spawnable_scene_count") { + spawnable_scenes.resize(p_value); + notify_property_list_changed(); + return true; + } else { + String ns = p_name; + if (ns.begins_with("scenes/")) { + uint32_t index = ns.get_slicec('/', 1).to_int(); + ERR_FAIL_UNSIGNED_INDEX_V(index, spawnable_scenes.size(), false); + spawnable_scenes[index].path = p_value; + return true; + } + } + return false; +} + +bool MultiplayerSpawner::_get(const StringName &p_name, Variant &r_ret) const { + if (p_name == "_spawnable_scene_count") { + r_ret = spawnable_scenes.size(); + return true; + } else { + String ns = p_name; + if (ns.begins_with("scenes/")) { + uint32_t index = ns.get_slicec('/', 1).to_int(); + ERR_FAIL_UNSIGNED_INDEX_V(index, spawnable_scenes.size(), false); + r_ret = spawnable_scenes[index].path; + return true; + } + } + return false; +} + +void MultiplayerSpawner::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back(PropertyInfo(Variant::INT, "_spawnable_scene_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Scenes,scenes/")); + List<String> exts; + ResourceLoader::get_recognized_extensions_for_type("PackedScene", &exts); + String ext_hint; + for (const String &E : exts) { + if (!ext_hint.is_empty()) { + ext_hint += ","; + } + ext_hint += "*." + E; + } + for (uint32_t i = 0; i < spawnable_scenes.size(); i++) { + p_list->push_back(PropertyInfo(Variant::STRING, "scenes/" + itos(i), PROPERTY_HINT_FILE, ext_hint, PROPERTY_USAGE_EDITOR)); + } +} +#endif +void MultiplayerSpawner::add_spawnable_scene(const String &p_path) { + SpawnableScene sc; + sc.path = p_path; + if (Engine::get_singleton()->is_editor_hint()) { + ERR_FAIL_COND(!FileAccess::exists(p_path)); + } else { + sc.cache = ResourceLoader::load(p_path); + ERR_FAIL_COND_MSG(sc.cache.is_null(), "Invalid spawnable scene: " + p_path); + } + spawnable_scenes.push_back(sc); +} +int MultiplayerSpawner::get_spawnable_scene_count() const { + return spawnable_scenes.size(); +} +String MultiplayerSpawner::get_spawnable_scene(int p_idx) const { + return spawnable_scenes[p_idx].path; +} +void MultiplayerSpawner::clear_spawnable_scenes() { + spawnable_scenes.clear(); +} + +Vector<String> MultiplayerSpawner::_get_spawnable_scenes() const { + Vector<String> ss; + ss.resize(spawnable_scenes.size()); + for (int i = 0; i < ss.size(); i++) { + ss.write[i] = spawnable_scenes[i].path; + } + return ss; +} + +void MultiplayerSpawner::_set_spawnable_scenes(const Vector<String> &p_scenes) { + clear_spawnable_scenes(); + for (int i = 0; i < p_scenes.size(); i++) { + add_spawnable_scene(p_scenes[i]); + } +} + void MultiplayerSpawner::_bind_methods() { - ClassDB::bind_method(D_METHOD("spawn", "data"), &MultiplayerSpawner::spawn, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("add_spawnable_scene", "path"), &MultiplayerSpawner::add_spawnable_scene); + ClassDB::bind_method(D_METHOD("get_spawnable_scene_count"), &MultiplayerSpawner::get_spawnable_scene_count); + ClassDB::bind_method(D_METHOD("get_spawnable_scene", "path"), &MultiplayerSpawner::get_spawnable_scene); + ClassDB::bind_method(D_METHOD("clear_spawnable_scenes"), &MultiplayerSpawner::clear_spawnable_scenes); + + ClassDB::bind_method(D_METHOD("_get_spawnable_scenes"), &MultiplayerSpawner::_get_spawnable_scenes); + ClassDB::bind_method(D_METHOD("_set_spawnable_scenes", "scenes"), &MultiplayerSpawner::_set_spawnable_scenes); - ClassDB::bind_method(D_METHOD("get_spawnable_scenes"), &MultiplayerSpawner::get_spawnable_scenes); - ClassDB::bind_method(D_METHOD("set_spawnable_scenes", "scenes"), &MultiplayerSpawner::set_spawnable_scenes); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "replication", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "PackedScene"), (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_spawnable_scenes", "get_spawnable_scenes"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "_spawnable_scenes", PROPERTY_HINT_NONE, "", (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL)), "_set_spawnable_scenes", "_get_spawnable_scenes"); + + ClassDB::bind_method(D_METHOD("spawn", "data"), &MultiplayerSpawner::spawn, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("get_spawn_path"), &MultiplayerSpawner::get_spawn_path); ClassDB::bind_method(D_METHOD("set_spawn_path", "path"), &MultiplayerSpawner::set_spawn_path); @@ -118,7 +212,7 @@ void MultiplayerSpawner::_node_added(Node *p_node) { if (!parent || p_node->get_parent() != parent) { return; } - int id = get_scene_id(p_node->get_scene_file_path()); + int id = find_spawnable_scene_index_from_path(p_node->get_scene_file_path()); if (id == INVALID_ID) { return; } @@ -136,14 +230,6 @@ bool MultiplayerSpawner::is_auto_spawning() const { return auto_spawn; } -TypedArray<PackedScene> MultiplayerSpawner::get_spawnable_scenes() { - return spawnable_scenes; -} - -void MultiplayerSpawner::set_spawnable_scenes(TypedArray<PackedScene> p_scenes) { - spawnable_scenes = p_scenes; -} - NodePath MultiplayerSpawner::get_spawn_path() const { return spawn_path; } @@ -175,18 +261,16 @@ void MultiplayerSpawner::_node_exit(ObjectID p_id) { } } -int MultiplayerSpawner::get_scene_id(const String &p_scene) const { - for (int i = 0; i < spawnable_scenes.size(); i++) { - Ref<PackedScene> ps = spawnable_scenes[i]; - ERR_CONTINUE(ps.is_null()); - if (ps->get_path() == p_scene) { +int MultiplayerSpawner::find_spawnable_scene_index_from_path(const String &p_scene) const { + for (uint32_t i = 0; i < spawnable_scenes.size(); i++) { + if (spawnable_scenes[i].path == p_scene) { return i; } } return INVALID_ID; } -int MultiplayerSpawner::get_spawn_id(const ObjectID &p_id) const { +int MultiplayerSpawner::find_spawnable_scene_index_from_object(const ObjectID &p_id) const { const SpawnInfo *info = tracked_nodes.getptr(p_id); return info ? info->id : INVALID_ID; } @@ -198,8 +282,8 @@ const Variant MultiplayerSpawner::get_spawn_argument(const ObjectID &p_id) const Node *MultiplayerSpawner::instantiate_scene(int p_id) { ERR_FAIL_COND_V_MSG(spawn_limit && spawn_limit <= tracked_nodes.size(), nullptr, "Spawn limit reached!"); - ERR_FAIL_INDEX_V(p_id, spawnable_scenes.size(), nullptr); - Ref<PackedScene> scene = spawnable_scenes[p_id]; + ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_id, spawnable_scenes.size(), nullptr); + Ref<PackedScene> scene = spawnable_scenes[p_id].cache; ERR_FAIL_COND_V(scene.is_null(), nullptr); return scene->instantiate(); } diff --git a/scene/multiplayer/multiplayer_spawner.h b/scene/multiplayer/multiplayer_spawner.h index 8fbc9c4803..e8abe702a0 100644 --- a/scene/multiplayer/multiplayer_spawner.h +++ b/scene/multiplayer/multiplayer_spawner.h @@ -33,6 +33,7 @@ #include "scene/main/node.h" +#include "core/templates/local_vector.h" #include "core/variant/typed_array.h" #include "scene/resources/packed_scene.h" #include "scene/resources/scene_replication_config.h" @@ -46,7 +47,13 @@ public: }; private: - TypedArray<PackedScene> spawnable_scenes; + struct SpawnableScene { + String path; + Ref<PackedScene> cache; + }; + + LocalVector<SpawnableScene> spawnable_scenes; + HashSet<ResourceUID::ID> spawnable_ids; NodePath spawn_path; @@ -71,14 +78,26 @@ private: void _node_exit(ObjectID p_id); void _node_ready(ObjectID p_id); + Vector<String> _get_spawnable_scenes() const; + void _set_spawnable_scenes(const Vector<String> &p_scenes); + protected: static void _bind_methods(); void _notification(int p_what); +#ifdef TOOLS_ENABLED + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; +#endif public: Node *get_spawn_node() const { return spawn_node.is_valid() ? Object::cast_to<Node>(ObjectDB::get_instance(spawn_node)) : nullptr; } - TypedArray<PackedScene> get_spawnable_scenes(); - void set_spawnable_scenes(TypedArray<PackedScene> p_scenes); + + void add_spawnable_scene(const String &p_path); + int get_spawnable_scene_count() const; + String get_spawnable_scene(int p_idx) const; + void clear_spawnable_scenes(); + NodePath get_spawn_path() const; void set_spawn_path(const NodePath &p_path); uint32_t get_spawn_limit() const { return spawn_limit; } @@ -87,8 +106,8 @@ public: void set_auto_spawning(bool p_enabled); const Variant get_spawn_argument(const ObjectID &p_id) const; - int get_spawn_id(const ObjectID &p_id) const; - int get_scene_id(const String &p_path) const; + int find_spawnable_scene_index_from_object(const ObjectID &p_id) const; + int find_spawnable_scene_index_from_path(const String &p_path) const; Node *spawn(const Variant &p_data = Variant()); Node *instantiate_custom(const Variant &p_data); Node *instantiate_scene(int p_idx); diff --git a/scene/multiplayer/multiplayer_synchronizer.cpp b/scene/multiplayer/multiplayer_synchronizer.cpp index 33e845a7a3..34d5abf9f6 100644 --- a/scene/multiplayer/multiplayer_synchronizer.cpp +++ b/scene/multiplayer/multiplayer_synchronizer.cpp @@ -96,7 +96,7 @@ void MultiplayerSynchronizer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_replication_config", "config"), &MultiplayerSynchronizer::set_replication_config); ClassDB::bind_method(D_METHOD("get_replication_config"), &MultiplayerSynchronizer::get_replication_config); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "congiruation", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config"); } void MultiplayerSynchronizer::_notification(int p_what) { diff --git a/scene/multiplayer/multiplayer_synchronizer.h b/scene/multiplayer/multiplayer_synchronizer.h index e856745379..f61ef459da 100644 --- a/scene/multiplayer/multiplayer_synchronizer.h +++ b/scene/multiplayer/multiplayer_synchronizer.h @@ -40,7 +40,7 @@ class MultiplayerSynchronizer : public Node { private: Ref<SceneReplicationConfig> replication_config; - NodePath root_path; + NodePath root_path = NodePath(".."); // Start with parent, like with AnimationPlayer. uint64_t interval_msec = 0; static Object *_get_prop_target(Object *p_obj, const NodePath &p_prop); diff --git a/scene/multiplayer/scene_replication_interface.cpp b/scene/multiplayer/scene_replication_interface.cpp index 19c69adb4a..e4715ceb88 100644 --- a/scene/multiplayer/scene_replication_interface.cpp +++ b/scene/multiplayer/scene_replication_interface.cpp @@ -167,7 +167,7 @@ Error SceneReplicationInterface::_send_spawn(Node *p_node, MultiplayerSpawner *p uint32_t nid = rep_state->ensure_net_id(oid); // Prepare custom arg and scene_id - uint8_t scene_id = p_spawner->get_spawn_id(oid); + uint8_t scene_id = p_spawner->find_spawnable_scene_index_from_object(oid); bool is_custom = scene_id == MultiplayerSpawner::INVALID_ID; Variant spawn_arg = p_spawner->get_spawn_argument(oid); int spawn_arg_size = 0; diff --git a/scene/resources/animation_library.cpp b/scene/resources/animation_library.cpp index 2a581fb126..361bfd0cb3 100644 --- a/scene/resources/animation_library.cpp +++ b/scene/resources/animation_library.cpp @@ -63,7 +63,7 @@ Error AnimationLibrary::add_animation(const StringName &p_name, const Ref<Animat } void AnimationLibrary::remove_animation(const StringName &p_name) { - ERR_FAIL_COND(!animations.has(p_name)); + ERR_FAIL_COND_MSG(!animations.has(p_name), vformat("Animation not found: %s.", p_name)); animations.erase(p_name); emit_signal(SNAME("animation_removed"), p_name); @@ -71,9 +71,9 @@ void AnimationLibrary::remove_animation(const StringName &p_name) { } void AnimationLibrary::rename_animation(const StringName &p_name, const StringName &p_new_name) { - ERR_FAIL_COND(!animations.has(p_name)); + ERR_FAIL_COND_MSG(!animations.has(p_name), vformat("Animation not found: %s.", p_name)); ERR_FAIL_COND_MSG(!is_valid_animation_name(p_new_name), "Invalid animation name: '" + String(p_new_name) + "'."); - ERR_FAIL_COND(animations.has(p_new_name)); + ERR_FAIL_COND_MSG(animations.has(p_new_name), vformat("Animation name \"%s\" already exists in library.", p_new_name)); animations.insert(p_new_name, animations[p_name]); animations.erase(p_name); diff --git a/scene/resources/fog_material.cpp b/scene/resources/fog_material.cpp index a05ef0c779..39ade85af6 100644 --- a/scene/resources/fog_material.cpp +++ b/scene/resources/fog_material.cpp @@ -148,11 +148,11 @@ void FogMaterial::_update_shader() { shader_type fog; uniform float density : hint_range(0, 1, 0.0001) = 1.0; -uniform vec4 albedo : hint_color = vec4(1.0); -uniform vec4 emission : hint_color = vec4(0, 0, 0, 1); +uniform vec4 albedo : source_color = vec4(1.0); +uniform vec4 emission : source_color = vec4(0, 0, 0, 1); uniform float height_falloff = 0.0; uniform float edge_fade = 0.1; -uniform sampler3D density_texture: hint_white; +uniform sampler3D density_texture: hint_default_white; void fog() { diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index b8171ca4bd..591d58d527 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -631,8 +631,8 @@ void BaseMaterial3D::_update_shader() { code += ";\n"; - code += "uniform vec4 albedo : hint_color;\n"; - code += "uniform sampler2D texture_albedo : hint_albedo," + texfilter_str + ";\n"; + code += "uniform vec4 albedo : source_color;\n"; + code += "uniform sampler2D texture_albedo : source_color," + texfilter_str + ";\n"; if (grow_enabled) { code += "uniform float grow;\n"; } @@ -669,7 +669,7 @@ void BaseMaterial3D::_update_shader() { //TODO ALL HINTS if (!orm) { code += "uniform float roughness : hint_range(0,1);\n"; - code += "uniform sampler2D texture_metallic : hint_white," + texfilter_str + ";\n"; + code += "uniform sampler2D texture_metallic : hint_default_white," + texfilter_str + ";\n"; code += "uniform vec4 metallic_texture_channel;\n"; switch (roughness_texture_channel) { case TEXTURE_CHANNEL_RED: { @@ -704,8 +704,8 @@ void BaseMaterial3D::_update_shader() { } if (features[FEATURE_EMISSION]) { - code += "uniform sampler2D texture_emission : hint_black_albedo," + texfilter_str + ";\n"; - code += "uniform vec4 emission : hint_color;\n"; + code += "uniform sampler2D texture_emission : source_color, hint_default_black," + texfilter_str + ";\n"; + code += "uniform vec4 emission : source_color;\n"; code += "uniform float emission_energy;\n"; } @@ -722,48 +722,48 @@ void BaseMaterial3D::_update_shader() { if (features[FEATURE_RIM]) { code += "uniform float rim : hint_range(0,1);\n"; code += "uniform float rim_tint : hint_range(0,1);\n"; - code += "uniform sampler2D texture_rim : hint_white," + texfilter_str + ";\n"; + code += "uniform sampler2D texture_rim : hint_default_white," + texfilter_str + ";\n"; } if (features[FEATURE_CLEARCOAT]) { code += "uniform float clearcoat : hint_range(0,1);\n"; code += "uniform float clearcoat_roughness : hint_range(0,1);\n"; - code += "uniform sampler2D texture_clearcoat : hint_white," + texfilter_str + ";\n"; + code += "uniform sampler2D texture_clearcoat : hint_default_white," + texfilter_str + ";\n"; } if (features[FEATURE_ANISOTROPY]) { code += "uniform float anisotropy_ratio : hint_range(0,256);\n"; code += "uniform sampler2D texture_flowmap : hint_anisotropy," + texfilter_str + ";\n"; } if (features[FEATURE_AMBIENT_OCCLUSION]) { - code += "uniform sampler2D texture_ambient_occlusion : hint_white, " + texfilter_str + ";\n"; + code += "uniform sampler2D texture_ambient_occlusion : hint_default_white, " + texfilter_str + ";\n"; code += "uniform vec4 ao_texture_channel;\n"; code += "uniform float ao_light_affect;\n"; } if (features[FEATURE_DETAIL]) { - code += "uniform sampler2D texture_detail_albedo : hint_albedo," + texfilter_str + ";\n"; + code += "uniform sampler2D texture_detail_albedo : source_color," + texfilter_str + ";\n"; code += "uniform sampler2D texture_detail_normal : hint_normal," + texfilter_str + ";\n"; - code += "uniform sampler2D texture_detail_mask : hint_white," + texfilter_str + ";\n"; + code += "uniform sampler2D texture_detail_mask : hint_default_white," + texfilter_str + ";\n"; } if (features[FEATURE_SUBSURFACE_SCATTERING]) { code += "uniform float subsurface_scattering_strength : hint_range(0,1);\n"; - code += "uniform sampler2D texture_subsurface_scattering : hint_white," + texfilter_str + ";\n"; + code += "uniform sampler2D texture_subsurface_scattering : hint_default_white," + texfilter_str + ";\n"; } if (features[FEATURE_SUBSURFACE_TRANSMITTANCE]) { - code += "uniform vec4 transmittance_color : hint_color;\n"; + code += "uniform vec4 transmittance_color : source_color;\n"; code += "uniform float transmittance_depth;\n"; - code += "uniform sampler2D texture_subsurface_transmittance : hint_white," + texfilter_str + ";\n"; + code += "uniform sampler2D texture_subsurface_transmittance : hint_default_white," + texfilter_str + ";\n"; code += "uniform float transmittance_boost;\n"; } if (features[FEATURE_BACKLIGHT]) { - code += "uniform vec4 backlight : hint_color;\n"; - code += "uniform sampler2D texture_backlight : hint_black," + texfilter_str + ";\n"; + code += "uniform vec4 backlight : source_color;\n"; + code += "uniform sampler2D texture_backlight : hint_default_black," + texfilter_str + ";\n"; } if (features[FEATURE_HEIGHT_MAPPING]) { - code += "uniform sampler2D texture_heightmap : hint_black," + texfilter_str + ";\n"; + code += "uniform sampler2D texture_heightmap : hint_default_black," + texfilter_str + ";\n"; code += "uniform float heightmap_scale;\n"; code += "uniform int heightmap_min_layers;\n"; code += "uniform int heightmap_max_layers;\n"; diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index f795e0ffd0..b90f396110 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -544,7 +544,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has Variant value = p_node->get(name); if (E.type == Variant::OBJECT && missing_resource_properties.has(E.name)) { - // Was this missing resource overriden? If so do not save the old value. + // Was this missing resource overridden? If so do not save the old value. Ref<Resource> ures = value; if (ures.is_null()) { value = missing_resource_properties[E.name]; @@ -613,7 +613,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has if (states_stack.is_empty() && !is_editable_instance) { //this node is not part of an instancing process, so save the type if (missing_node != nullptr) { - // Its a missing node (type non existant on load). + // It's a missing node (type non existent on load). nd.type = _nm_get_string(missing_node->get_original_class(), name_map); } else { nd.type = _nm_get_string(p_node->get_class(), name_map); diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index fced9e91c9..c4b15df6bb 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -197,14 +197,14 @@ void ParticlesMaterial::_update_shader() { code += "uniform vec3 emission_box_extents;\n"; } break; case EMISSION_SHAPE_DIRECTED_POINTS: { - code += "uniform sampler2D emission_texture_normal : hint_black;\n"; + code += "uniform sampler2D emission_texture_normal : hint_default_black;\n"; [[fallthrough]]; } case EMISSION_SHAPE_POINTS: { - code += "uniform sampler2D emission_texture_points : hint_black;\n"; + code += "uniform sampler2D emission_texture_points : hint_default_black;\n"; code += "uniform int emission_texture_point_count;\n"; if (emission_color_texture.is_valid()) { - code += "uniform sampler2D emission_texture_color : hint_white;\n"; + code += "uniform sampler2D emission_texture_color : hint_default_white;\n"; } } break; case EMISSION_SHAPE_RING: { @@ -228,7 +228,7 @@ void ParticlesMaterial::_update_shader() { code += "uniform bool sub_emitter_keep_velocity;\n"; } - code += "uniform vec4 color_value : hint_color;\n"; + code += "uniform vec4 color_value : source_color;\n"; code += "uniform vec3 gravity;\n"; diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 4d83f8772e..36c8a9b435 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -745,10 +745,10 @@ BoxMesh::BoxMesh() {} */ void CylinderMesh::_create_mesh_array(Array &p_arr) const { - create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings); + create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings, cap_top, cap_bottom); } -void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments, int rings) { +void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments, int rings, bool cap_top, bool cap_bottom) { int i, j, prevrow, thisrow, point; float x, y, z, u, v, radius; @@ -806,7 +806,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto }; // add top - if (top_radius > 0.0) { + if (cap_top && top_radius > 0.0) { y = height * 0.5; thisrow = point; @@ -842,7 +842,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto }; // add bottom - if (bottom_radius > 0.0) { + if (cap_bottom && bottom_radius > 0.0) { y = height * -0.5; thisrow = point; @@ -897,11 +897,19 @@ void CylinderMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CylinderMesh::set_rings); ClassDB::bind_method(D_METHOD("get_rings"), &CylinderMesh::get_rings); + ClassDB::bind_method(D_METHOD("set_cap_top", "cap_top"), &CylinderMesh::set_cap_top); + ClassDB::bind_method(D_METHOD("is_cap_top"), &CylinderMesh::is_cap_top); + + ClassDB::bind_method(D_METHOD("set_cap_bottom", "cap_bottom"), &CylinderMesh::set_cap_bottom); + ClassDB::bind_method(D_METHOD("is_cap_bottom"), &CylinderMesh::is_cap_bottom); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "top_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater,suffix:m"), "set_top_radius", "get_top_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bottom_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater,suffix:m"), "set_bottom_radius", "get_bottom_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_top"), "set_cap_top", "is_cap_top"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_bottom"), "set_cap_bottom", "is_cap_bottom"); } void CylinderMesh::set_top_radius(const float p_radius) { @@ -949,6 +957,24 @@ int CylinderMesh::get_rings() const { return rings; } +void CylinderMesh::set_cap_top(bool p_cap_top) { + cap_top = p_cap_top; + _request_update(); +} + +bool CylinderMesh::is_cap_top() const { + return cap_top; +} + +void CylinderMesh::set_cap_bottom(bool p_cap_bottom) { + cap_bottom = p_cap_bottom; + _request_update(); +} + +bool CylinderMesh::is_cap_bottom() const { + return cap_bottom; +} + CylinderMesh::CylinderMesh() {} /** @@ -2229,17 +2255,27 @@ void TextMesh::_generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_gl) con } } else if (points[j].z == TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC) { // Cubic Bezier arc. + int32_t cur = j; int32_t next1 = (j == end) ? start : (j + 1); int32_t next2 = (next1 == end) ? start : (next1 + 1); int32_t prev = (j == start) ? end : (j - 1); // There must be exactly two OFF points and two ON points for each cubic arc. + if (points[prev].z != TextServer::CONTOUR_CURVE_TAG_ON) { + cur = (cur == 0) ? end : cur - 1; + next1 = (next1 == 0) ? end : next1 - 1; + next2 = (next2 == 0) ? end : next2 - 1; + prev = (prev == 0) ? end : prev - 1; + } else { + j++; + } ERR_FAIL_COND_MSG(points[prev].z != TextServer::CONTOUR_CURVE_TAG_ON, vformat("Invalid cubic arc point sequence at %d:%d", i, prev)); + ERR_FAIL_COND_MSG(points[cur].z != TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC, vformat("Invalid cubic arc point sequence at %d:%d", i, cur)); ERR_FAIL_COND_MSG(points[next1].z != TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC, vformat("Invalid cubic arc point sequence at %d:%d", i, next1)); ERR_FAIL_COND_MSG(points[next2].z != TextServer::CONTOUR_CURVE_TAG_ON, vformat("Invalid cubic arc point sequence at %d:%d", i, next2)); Vector2 p0 = Vector2(points[prev].x, points[prev].y); - Vector2 p1 = Vector2(points[j].x, points[j].y); + Vector2 p1 = Vector2(points[cur].x, points[cur].y); Vector2 p2 = Vector2(points[next1].x, points[next1].y); Vector2 p3 = Vector2(points[next2].x, points[next2].y); @@ -2257,7 +2293,6 @@ void TextMesh::_generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_gl) con polygon.push_back(ContourPoint(p, false)); t += step; } - i++; } else { ERR_FAIL_MSG(vformat("Unknown point tag at %d:%d", i, j)); } @@ -2304,18 +2339,18 @@ void TextMesh::_generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_gl) con //Decompose and triangulate. List<TPPLPoly> out_poly; if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { - ERR_FAIL_MSG("Convex decomposing failed!"); + ERR_FAIL_MSG("Convex decomposing failed. Make sure the font doesn't contain self-intersecting lines, as these are not supported in TextMesh."); } List<TPPLPoly> out_tris; for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) { if (tpart.Triangulate_OPT(&(I->get()), &out_tris) == 0) { - ERR_FAIL_MSG("Triangulation failed!"); + ERR_FAIL_MSG("Triangulation failed. Make sure the font doesn't contain self-intersecting lines, as these are not supported in TextMesh."); } } for (List<TPPLPoly>::Element *I = out_tris.front(); I; I = I->next()) { TPPLPoly &tp = I->get(); - ERR_FAIL_COND(tp.GetNumPoints() != 3); // Trianges only. + ERR_FAIL_COND(tp.GetNumPoints() != 3); // Triangles only. for (int i = 0; i < 3; i++) { gl_data.triangles.push_back(Vector2(tp.GetPoint(i).x, tp.GetPoint(i).y)); @@ -2393,6 +2428,10 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { Vector2 offset_pre = offset; for (int i = 0; i < gl_size; i++) { + if (glyphs[i].index == 0) { + offset.x += glyphs[i].advance * pixel_size * glyphs[i].repeat; + continue; + } if (glyphs[i].font_rid != RID()) { uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id()); hash = hash_djb2_one_32(glyphs[i].index, hash); @@ -2448,6 +2487,10 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { int32_t p_idx = 0; int32_t i_idx = 0; for (int i = 0; i < gl_size; i++) { + if (glyphs[i].index == 0) { + offset.x += glyphs[i].advance * pixel_size * glyphs[i].repeat; + continue; + } if (glyphs[i].font_rid != RID()) { uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id()); hash = hash_djb2_one_32(glyphs[i].index, hash); @@ -2587,7 +2630,7 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { } if (p_size == 0) { - // If empty, add single trinagle to suppress errors. + // If empty, add single triangle to suppress errors. vertices.push_back(Vector3()); normals.push_back(Vector3()); uvs.push_back(Vector2()); diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 3849c92a7b..38cc7db5fe 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -183,13 +183,15 @@ private: float height = 2.0; int radial_segments = 64; int rings = 4; + bool cap_top = true; + bool cap_bottom = true; protected: static void _bind_methods(); virtual void _create_mesh_array(Array &p_arr) const override; public: - static void create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments = 64, int rings = 4); + static void create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments = 64, int rings = 4, bool cap_top = true, bool cap_bottom = true); void set_top_radius(const float p_radius); float get_top_radius() const; @@ -206,6 +208,12 @@ public: void set_rings(const int p_rings); int get_rings() const; + void set_cap_top(bool p_cap_top); + bool is_cap_top() const; + + void set_cap_bottom(bool p_cap_bottom); + bool is_cap_bottom() const; + CylinderMesh(); }; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 72d66ee4f5..9d586c6f03 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1891,7 +1891,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso } if (PE->get().type == Variant::OBJECT && missing_resource_properties.has(PE->get().name)) { - // Was this missing resource overriden? If so do not save the old value. + // Was this missing resource overridden? If so do not save the old value. Ref<Resource> ures = value; if (ures.is_null()) { value = missing_resource_properties[PE->get().name]; diff --git a/scene/resources/scene_replication_config.cpp b/scene/resources/scene_replication_config.cpp index 2acc0f1922..4aea04bf87 100644 --- a/scene/resources/scene_replication_config.cpp +++ b/scene/resources/scene_replication_config.cpp @@ -124,6 +124,15 @@ void SceneReplicationConfig::remove_property(const NodePath &p_path) { properties.erase(p_path); } +bool SceneReplicationConfig::has_property(const NodePath &p_path) const { + for (int i = 0; i < properties.size(); i++) { + if (properties[i].name == p_path) { + return true; + } + } + return false; +} + int SceneReplicationConfig::property_get_index(const NodePath &p_path) const { for (int i = 0; i < properties.size(); i++) { if (properties[i].name == p_path) { @@ -178,6 +187,7 @@ void SceneReplicationConfig::property_set_sync(const NodePath &p_path, bool p_en void SceneReplicationConfig::_bind_methods() { ClassDB::bind_method(D_METHOD("get_properties"), &SceneReplicationConfig::get_properties); ClassDB::bind_method(D_METHOD("add_property", "path", "index"), &SceneReplicationConfig::add_property, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("has_property", "path"), &SceneReplicationConfig::has_property); ClassDB::bind_method(D_METHOD("remove_property", "path"), &SceneReplicationConfig::remove_property); ClassDB::bind_method(D_METHOD("property_get_index", "path"), &SceneReplicationConfig::property_get_index); ClassDB::bind_method(D_METHOD("property_get_spawn", "path"), &SceneReplicationConfig::property_get_spawn); diff --git a/scene/resources/scene_replication_config.h b/scene/resources/scene_replication_config.h index b791be9414..ab3658d2a7 100644 --- a/scene/resources/scene_replication_config.h +++ b/scene/resources/scene_replication_config.h @@ -73,6 +73,7 @@ public: void add_property(const NodePath &p_path, int p_index = -1); void remove_property(const NodePath &p_path); + bool has_property(const NodePath &p_path) const; int property_get_index(const NodePath &p_path) const; bool property_get_spawn(const NodePath &p_path); diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 593689fbcb..3abffaa6a6 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -250,14 +250,14 @@ void ProceduralSkyMaterial::_update_shader() { shader_type sky; -uniform vec4 sky_top_color : hint_color = vec4(0.385, 0.454, 0.55, 1.0); -uniform vec4 sky_horizon_color : hint_color = vec4(0.646, 0.656, 0.67, 1.0); +uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0); +uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0); uniform float sky_curve : hint_range(0, 1) = 0.15; uniform float sky_energy = 1.0; -uniform sampler2D sky_cover : hint_black_albedo; -uniform vec4 sky_cover_modulate : hint_color = vec4(1.0, 1.0, 1.0, 1.0); -uniform vec4 ground_bottom_color : hint_color = vec4(0.2, 0.169, 0.133, 1.0); -uniform vec4 ground_horizon_color : hint_color = vec4(0.646, 0.656, 0.67, 1.0); +uniform sampler2D sky_cover : source_color, hint_default_black; +uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0); +uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0); +uniform vec4 ground_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0); uniform float ground_curve : hint_range(0, 1) = 0.02; uniform float ground_energy = 1.0; uniform float sun_angle_max = 30.0; @@ -434,7 +434,7 @@ void PanoramaSkyMaterial::_update_shader() { shader_type sky; -uniform sampler2D source_panorama : %s, hint_black_albedo; +uniform sampler2D source_panorama : %s, source_color, hint_default_black; void sky() { COLOR = texture(source_panorama, SKY_COORDS).rgb; @@ -646,18 +646,18 @@ void PhysicalSkyMaterial::_update_shader() { shader_type sky; uniform float rayleigh : hint_range(0, 64) = 2.0; -uniform vec4 rayleigh_color : hint_color = vec4(0.3, 0.405, 0.6, 1.0); +uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0); uniform float mie : hint_range(0, 1) = 0.005; uniform float mie_eccentricity : hint_range(-1, 1) = 0.8; -uniform vec4 mie_color : hint_color = vec4(0.69, 0.729, 0.812, 1.0); +uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0); uniform float turbidity : hint_range(0, 1000) = 10.0; uniform float sun_disk_scale : hint_range(0, 360) = 1.0; -uniform vec4 ground_color : hint_color = vec4(0.1, 0.07, 0.034, 1.0); +uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0); uniform float exposure : hint_range(0, 128) = 0.1; uniform float dither_strength : hint_range(0, 10) = 1.0; -uniform sampler2D night_sky : hint_black_albedo; +uniform sampler2D night_sky : source_color, hint_default_black; const vec3 UP = vec3( 0.0, 1.0, 0.0 ); diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp index fc1e610e98..92efe3ce6f 100644 --- a/scene/resources/sphere_shape_3d.cpp +++ b/scene/resources/sphere_shape_3d.cpp @@ -83,5 +83,5 @@ void SphereShape3D::_bind_methods() { SphereShape3D::SphereShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_SPHERE)) { - set_radius(1.0); + set_radius(0.5); } diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h index 20887dd092..8f77378ef4 100644 --- a/scene/resources/sphere_shape_3d.h +++ b/scene/resources/sphere_shape_3d.h @@ -35,7 +35,7 @@ class SphereShape3D : public Shape3D { GDCLASS(SphereShape3D, Shape3D); - float radius = 1.0f; + float radius = 0.5f; protected: static void _bind_methods(); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 18bb0ff01d..47bb1b264c 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -910,6 +910,48 @@ void VisualShader::replace_node(Type p_type, int p_id, const StringName &p_new_c return; } VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(p_new_class)); + VisualShaderNode *prev_vsn = g->nodes[p_id].node.ptr(); + + // Update connection data. + for (int i = 0; i < vsn->get_output_port_count(); i++) { + if (i < prev_vsn->get_output_port_count()) { + if (prev_vsn->is_output_port_connected(i)) { + vsn->set_output_port_connected(i, true); + } + + if (prev_vsn->is_output_port_expandable(i) && prev_vsn->_is_output_port_expanded(i) && vsn->is_output_port_expandable(i)) { + vsn->_set_output_port_expanded(i, true); + + int component_count = 0; + switch (prev_vsn->get_output_port_type(i)) { + case VisualShaderNode::PORT_TYPE_VECTOR_2D: + component_count = 2; + break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: + component_count = 3; + break; + case VisualShaderNode::PORT_TYPE_VECTOR_4D: + component_count = 4; + break; + default: + break; + } + + for (int j = 0; j < component_count; j++) { + int sub_port = i + 1 + j; + + if (prev_vsn->is_output_port_connected(sub_port)) { + vsn->set_output_port_connected(sub_port, true); + } + } + + i += component_count; + } + } else { + break; + } + } + vsn->connect("changed", callable_mp(this, &VisualShader::_queue_update)); g->nodes[p_id].node = Ref<VisualShaderNode>(vsn); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index dbd45793f9..5c0f36ca92 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -700,7 +700,7 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade case TYPE_DATA: break; case TYPE_COLOR: - u += " : hint_albedo"; + u += " : source_color"; break; case TYPE_NORMAL_MAP: u += " : hint_normal"; @@ -1463,7 +1463,7 @@ String VisualShaderNodeCubemap::generate_global(Shader::Mode p_mode, VisualShade case TYPE_DATA: break; case TYPE_COLOR: - u += " : hint_albedo"; + u += " : source_color"; break; case TYPE_NORMAL_MAP: u += " : hint_normal"; @@ -5113,7 +5113,7 @@ Color VisualShaderNodeColorUniform::get_default_value() const { } String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - String code = _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : hint_color"; + String code = _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : source_color"; if (default_value_enabled) { code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.r, default_value.g, default_value.b, default_value.a); } @@ -5567,71 +5567,32 @@ Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() c VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() { } -////////////// Texture Uniform - -String VisualShaderNodeTextureUniform::get_caption() const { - return "TextureUniform"; -} - -int VisualShaderNodeTextureUniform::get_input_port_count() const { - return 0; -} - -VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_input_port_type(int p_port) const { - return PORT_TYPE_SCALAR; -} - -String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const { - return ""; -} +////////////// -int VisualShaderNodeTextureUniform::get_output_port_count() const { - return 1; -} - -VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const { - switch (p_port) { - case 0: - return PORT_TYPE_SAMPLER; - default: - return PORT_TYPE_SCALAR; - } -} - -String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const { - switch (p_port) { - case 0: - return "sampler2D"; - default: - return ""; - } -} - -String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { +String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_type, VisualShaderNodeTextureUniform::ColorDefault p_color_default, VisualShaderNodeTextureUniform::TextureFilter p_texture_filter, VisualShaderNodeTextureUniform::TextureRepeat p_texture_repeat) { + String code; bool has_colon = false; - String code = _get_qual_str() + "uniform sampler2D " + get_uniform_name(); // type { String type_code; - switch (texture_type) { - case TYPE_DATA: - if (color_default == COLOR_DEFAULT_BLACK) { - type_code = "hint_black"; + switch (p_texture_type) { + case VisualShaderNodeTextureUniform::TYPE_DATA: + if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) { + type_code = "hint_default_black"; } break; - case TYPE_COLOR: - if (color_default == COLOR_DEFAULT_BLACK) { - type_code = "hint_black_albedo"; - } else { - type_code = "hint_albedo"; + case VisualShaderNodeTextureUniform::TYPE_COLOR: + type_code = "source_color"; + if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) { + type_code += ", hint_default_black"; } break; - case TYPE_NORMAL_MAP: + case VisualShaderNodeTextureUniform::TYPE_NORMAL_MAP: type_code = "hint_normal"; break; - case TYPE_ANISOTROPY: + case VisualShaderNodeTextureUniform::TYPE_ANISOTROPY: type_code = "hint_anisotropy"; break; default: @@ -5648,23 +5609,23 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu { String filter_code; - switch (texture_filter) { - case FILTER_NEAREST: + switch (p_texture_filter) { + case VisualShaderNodeTextureUniform::FILTER_NEAREST: filter_code = "filter_nearest"; break; - case FILTER_LINEAR: + case VisualShaderNodeTextureUniform::FILTER_LINEAR: filter_code = "filter_linear"; break; - case FILTER_NEAREST_MIPMAP: + case VisualShaderNodeTextureUniform::FILTER_NEAREST_MIPMAP: filter_code = "filter_nearest_mipmap"; break; - case FILTER_LINEAR_MIPMAP: + case VisualShaderNodeTextureUniform::FILTER_LINEAR_MIPMAP: filter_code = "filter_linear_mipmap"; break; - case FILTER_NEAREST_MIPMAP_ANISOTROPIC: + case VisualShaderNodeTextureUniform::FILTER_NEAREST_MIPMAP_ANISOTROPIC: filter_code = "filter_nearest_mipmap_anisotropic"; break; - case FILTER_LINEAR_MIPMAP_ANISOTROPIC: + case VisualShaderNodeTextureUniform::FILTER_LINEAR_MIPMAP_ANISOTROPIC: filter_code = "filter_linear_mipmap_anisotropic"; break; default: @@ -5686,11 +5647,11 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu { String repeat_code; - switch (texture_repeat) { - case REPEAT_ENABLED: + switch (p_texture_repeat) { + case VisualShaderNodeTextureUniform::REPEAT_ENABLED: repeat_code = "repeat_enable"; break; - case REPEAT_DISABLED: + case VisualShaderNodeTextureUniform::REPEAT_DISABLED: repeat_code = "repeat_disable"; break; default: @@ -5707,6 +5668,52 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu } } + return code; +} + +////////////// Texture Uniform + +String VisualShaderNodeTextureUniform::get_caption() const { + return "TextureUniform"; +} + +int VisualShaderNodeTextureUniform::get_input_port_count() const { + return 0; +} + +VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeTextureUniform::get_output_port_count() const { + return 1; +} + +VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const { + switch (p_port) { + case 0: + return PORT_TYPE_SAMPLER; + default: + return PORT_TYPE_SCALAR; + } +} + +String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const { + switch (p_port) { + case 0: + return "sampler2D"; + default: + return ""; + } +} + +String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform sampler2D " + get_uniform_name(); + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); code += ";\n"; return code; } @@ -5986,33 +5993,8 @@ String VisualShaderNodeTexture2DArrayUniform::get_output_port_name(int p_port) c String VisualShaderNodeTexture2DArrayUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = _get_qual_str() + "uniform sampler2DArray " + get_uniform_name(); - - switch (texture_type) { - case TYPE_DATA: - if (color_default == COLOR_DEFAULT_BLACK) { - code += " : hint_black;\n"; - } else { - code += ";\n"; - } - break; - case TYPE_COLOR: - if (color_default == COLOR_DEFAULT_BLACK) { - code += " : hint_black_albedo;\n"; - } else { - code += " : hint_albedo;\n"; - } - break; - case TYPE_NORMAL_MAP: - code += " : hint_normal;\n"; - break; - case TYPE_ANISOTROPY: - code += " : hint_anisotropy;\n"; - break; - default: - code += ";\n"; - break; - } - + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); + code += ";\n"; return code; } @@ -6035,33 +6017,8 @@ String VisualShaderNodeTexture3DUniform::get_output_port_name(int p_port) const String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = _get_qual_str() + "uniform sampler3D " + get_uniform_name(); - - switch (texture_type) { - case TYPE_DATA: - if (color_default == COLOR_DEFAULT_BLACK) { - code += " : hint_black;\n"; - } else { - code += ";\n"; - } - break; - case TYPE_COLOR: - if (color_default == COLOR_DEFAULT_BLACK) { - code += " : hint_black_albedo;\n"; - } else { - code += " : hint_albedo;\n"; - } - break; - case TYPE_NORMAL_MAP: - code += " : hint_normal;\n"; - break; - case TYPE_ANISOTROPY: - code += " : hint_anisotropy;\n"; - break; - default: - code += ";\n"; - break; - } - + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); + code += ";\n"; return code; } @@ -6084,33 +6041,8 @@ String VisualShaderNodeCubemapUniform::get_output_port_name(int p_port) const { String VisualShaderNodeCubemapUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = _get_qual_str() + "uniform samplerCube " + get_uniform_name(); - - switch (texture_type) { - case TYPE_DATA: - if (color_default == COLOR_DEFAULT_BLACK) { - code += " : hint_black;\n"; - } else { - code += ";\n"; - } - break; - case TYPE_COLOR: - if (color_default == COLOR_DEFAULT_BLACK) { - code += " : hint_black_albedo;\n"; - } else { - code += " : hint_albedo;\n"; - } - break; - case TYPE_NORMAL_MAP: - code += " : hint_normal;\n"; - break; - case TYPE_ANISOTROPY: - code += " : hint_anisotropy;\n"; - break; - default: - code += ";\n"; - break; - } - + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); + code += ";\n"; return code; } |