diff options
Diffstat (limited to 'scene')
33 files changed, 591 insertions, 90 deletions
diff --git a/scene/2d/parallax_2d.cpp b/scene/2d/parallax_2d.cpp index fdb2d2cdd0..c6176390dc 100644 --- a/scene/2d/parallax_2d.cpp +++ b/scene/2d/parallax_2d.cpp @@ -83,7 +83,11 @@ void Parallax2D::_validate_property(PropertyInfo &p_property) const { void Parallax2D::_camera_moved(const Transform2D &p_transform, const Point2 &p_screen_offset, const Point2 &p_adj_screen_pos) { if (!ignore_camera_scroll) { if (get_viewport() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) { - set_screen_offset((p_adj_screen_pos + Vector2(0.5, 0.5)).floor()); + Size2 vps = get_viewport_rect().size; + Vector2 offset; + offset.x = ((int)vps.width % 2) ? 0.0 : 0.5; + offset.y = ((int)vps.height % 2) ? 0.0 : 0.5; + set_screen_offset((p_adj_screen_pos + offset).floor()); } else { set_screen_offset(p_adj_screen_pos); } diff --git a/scene/2d/physics/shape_cast_2d.cpp b/scene/2d/physics/shape_cast_2d.cpp index b92978bcad..dd9d589165 100644 --- a/scene/2d/physics/shape_cast_2d.cpp +++ b/scene/2d/physics/shape_cast_2d.cpp @@ -34,7 +34,7 @@ #include "scene/2d/physics/collision_object_2d.h" #include "scene/2d/physics/physics_body_2d.h" #include "scene/resources/2d/circle_shape_2d.h" -#include "servers/physics_2d/godot_physics_server_2d.h" +#include "servers/physics_server_2d.h" void ShapeCast2D::set_target_position(const Vector2 &p_point) { target_position = p_point; diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h index cc0a5b49fb..6cb481849c 100644 --- a/scene/2d/tile_map_layer.h +++ b/scene/2d/tile_map_layer.h @@ -90,7 +90,7 @@ public: TerrainConstraint(Ref<TileSet> p_tile_set, const Vector2i &p_position, int p_terrain); // For the center terrain bit TerrainConstraint(Ref<TileSet> p_tile_set, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain); // For peering bits - TerrainConstraint(){}; + TerrainConstraint() {} }; #ifdef DEBUG_ENABLED diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 591528b915..98bee2115c 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -401,10 +401,19 @@ Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() { if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) { total_max = MAX(total_max, listener_area_pos.length()); } - if (total_max > max_distance) { + if (dist > total_max || total_max > max_distance) { + if (!was_further_than_max_distance_last_frame) { + HashMap<StringName, Vector<AudioFrame>> bus_volumes; + for (Ref<AudioStreamPlayback> &playback : internal->stream_playbacks) { + // So the player gets muted and mostly stops mixing when out of range. + AudioServer::get_singleton()->set_playback_bus_volumes_linear(playback, bus_volumes); + } + was_further_than_max_distance_last_frame = true; // Cache so we don't set the volume over and over. + } continue; //can't hear this sound in this listener } } + was_further_than_max_distance_last_frame = false; float multiplier = Math::db_to_linear(_get_attenuation_db(dist)); if (max_distance > 0) { diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 72356faad7..91104a06c7 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -105,6 +105,7 @@ private: float linear_attenuation = 0; float max_distance = 0.0; + bool was_further_than_max_distance_last_frame = false; Ref<VelocityTracker3D> velocity_tracker; diff --git a/scene/3d/physics/character_body_3d.cpp b/scene/3d/physics/character_body_3d.cpp index dda3ea9cca..e3815e8219 100644 --- a/scene/3d/physics/character_body_3d.cpp +++ b/scene/3d/physics/character_body_3d.cpp @@ -60,8 +60,13 @@ bool CharacterBody3D::move_and_slide() { // We need to check the platform_rid object still exists before accessing. // A valid RID is no guarantee that the object has not been deleted. - if (ObjectDB::get_instance(platform_object_id)) { - //this approach makes sure there is less delay between the actual body velocity and the one we saved + + // We can only perform the ObjectDB lifetime check on Object derived objects. + // Note that physics also creates RIDs for non-Object derived objects, these cannot + // be lifetime checked through ObjectDB, and therefore there is a still a vulnerability + // to dangling RIDs (access after free) in this scenario. + if (platform_object_id.is_null() || ObjectDB::get_instance(platform_object_id)) { + // This approach makes sure there is less delay between the actual body velocity and the one we saved. bs = PhysicsServer3D::get_singleton()->body_get_direct_state(platform_rid); } diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index cdc85d2b2d..a96417738f 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -1139,7 +1139,11 @@ void AnimationNodeTransition::remove_input(int p_index) { bool AnimationNodeTransition::set_input_name(int p_input, const String &p_name) { pending_update = true; - return AnimationNode::set_input_name(p_input, p_name); + if (!AnimationNode::set_input_name(p_input, p_name)) { + return false; + } + emit_signal(SNAME("tree_changed")); // For updating enum options. + return true; } void AnimationNodeTransition::set_input_as_auto_advance(int p_input, bool p_enable) { diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index c3287035ff..635228670d 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -831,6 +831,9 @@ void CodeEdit::_cut_internal(int p_caret) { delete_selection(p_caret); return; } + if (!is_empty_selection_clipboard_enabled()) { + return; + } if (p_caret == -1) { delete_lines(); } else { diff --git a/scene/gui/color_mode.h b/scene/gui/color_mode.h index 84e9d4542d..94193ccf74 100644 --- a/scene/gui/color_mode.h +++ b/scene/gui/color_mode.h @@ -50,14 +50,14 @@ public: virtual Color get_color() const = 0; - virtual void _value_changed(){}; + virtual void _value_changed() {} virtual void slider_draw(int p_which) = 0; virtual bool apply_theme() const { return false; } virtual ColorPicker::PickerShapeType get_shape_override() const { return ColorPicker::SHAPE_MAX; } ColorMode(ColorPicker *p_color_picker); - virtual ~ColorMode(){}; + virtual ~ColorMode() {} }; class ColorModeHSV : public ColorMode { @@ -81,7 +81,7 @@ public: virtual void slider_draw(int p_which) override; ColorModeHSV(ColorPicker *p_color_picker) : - ColorMode(p_color_picker){}; + ColorMode(p_color_picker) {} }; class ColorModeRGB : public ColorMode { @@ -100,7 +100,7 @@ public: virtual void slider_draw(int p_which) override; ColorModeRGB(ColorPicker *p_color_picker) : - ColorMode(p_color_picker){}; + ColorMode(p_color_picker) {} }; class ColorModeRAW : public ColorMode { @@ -122,7 +122,7 @@ public: virtual bool apply_theme() const override; ColorModeRAW(ColorPicker *p_color_picker) : - ColorMode(p_color_picker){}; + ColorMode(p_color_picker) {} }; class ColorModeOKHSL : public ColorMode { @@ -147,9 +147,9 @@ public: virtual ColorPicker::PickerShapeType get_shape_override() const override { return ColorPicker::SHAPE_OKHSL_CIRCLE; } ColorModeOKHSL(ColorPicker *p_color_picker) : - ColorMode(p_color_picker){}; + ColorMode(p_color_picker) {} - ~ColorModeOKHSL(){}; + ~ColorModeOKHSL() {} }; #endif // COLOR_MODE_H diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 1fc8586448..6f61295a91 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -1526,6 +1526,7 @@ FileDialog::FileDialog() { update_dir(); set_hide_on_ok(false); + set_size(Size2(640, 360)); if (register_func) { register_func(this); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 1a066b0728..43782409a8 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -103,7 +103,7 @@ void LineEdit::_close_ime_window() { void LineEdit::_update_ime_window_position() { DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID; - if (wid == DisplayServer::INVALID_WINDOW_ID || !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) { + if (wid == DisplayServer::INVALID_WINDOW_ID || !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME) || !DisplayServer::get_singleton()->window_is_focused(wid)) { return; } DisplayServer::get_singleton()->window_set_ime_active(true, wid); @@ -921,6 +921,7 @@ Variant LineEdit::get_drag_data(const Point2 &p_point) { String t = get_selected_text(); Label *l = memnew(Label); l->set_text(t); + l->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // Don't translate user input. set_drag_preview(l); return t; } @@ -2763,6 +2764,8 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("select", "from", "to"), &LineEdit::select, DEFVAL(0), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("select_all"), &LineEdit::select_all); ClassDB::bind_method(D_METHOD("deselect"), &LineEdit::deselect); + ClassDB::bind_method(D_METHOD("has_undo"), &LineEdit::has_undo); + ClassDB::bind_method(D_METHOD("has_redo"), &LineEdit::has_redo); ClassDB::bind_method(D_METHOD("has_selection"), &LineEdit::has_selection); ClassDB::bind_method(D_METHOD("get_selected_text"), &LineEdit::get_selected_text); ClassDB::bind_method(D_METHOD("get_selection_from_column"), &LineEdit::get_selection_from_column); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 0c3c90d070..e302927692 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -5431,6 +5431,7 @@ Variant RichTextLabel::get_drag_data(const Point2 &p_point) { String t = get_selected_text(); Label *l = memnew(Label); l->set_text(t); + l->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // Text is already translated. set_drag_preview(l); return t; } diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index f1902bade4..2211bd76fc 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -58,7 +58,7 @@ Size2 ScrollContainer::get_minimum_size() const { if (horizontal_scroll_mode == SCROLL_MODE_DISABLED) { min_size.x = largest_child_min_size.x; - bool v_scroll_show = vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (vertical_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.y > size.y); + bool v_scroll_show = vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || vertical_scroll_mode == SCROLL_MODE_RESERVE || (vertical_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.y > size.y); if (v_scroll_show && v_scroll->get_parent() == this) { min_size.x += v_scroll->get_minimum_size().x; } @@ -66,7 +66,7 @@ Size2 ScrollContainer::get_minimum_size() const { if (vertical_scroll_mode == SCROLL_MODE_DISABLED) { min_size.y = largest_child_min_size.y; - bool h_scroll_show = horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (horizontal_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.x > size.x); + bool h_scroll_show = horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || horizontal_scroll_mode == SCROLL_MODE_RESERVE || (horizontal_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.x > size.x); if (h_scroll_show && h_scroll->get_parent() == this) { min_size.y += h_scroll->get_minimum_size().y; } @@ -92,6 +92,15 @@ void ScrollContainer::_cancel_drag() { } } +bool ScrollContainer::_is_h_scroll_visible() const { + // Scrolls may have been moved out for reasons. + return h_scroll->is_visible() && h_scroll->get_parent() == this; +} + +bool ScrollContainer::_is_v_scroll_visible() const { + return v_scroll->is_visible() && v_scroll->get_parent() == this; +} + void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) { ERR_FAIL_COND(p_gui_input.is_null()); @@ -298,11 +307,11 @@ void ScrollContainer::_reposition_children() { ofs += theme_cache.panel_style->get_offset(); bool rtl = is_layout_rtl(); - if (h_scroll->is_visible_in_tree() && h_scroll->get_parent() == this) { //scrolls may have been moved out for reasons + if (_is_h_scroll_visible() || horizontal_scroll_mode == SCROLL_MODE_RESERVE) { size.y -= h_scroll->get_minimum_size().y; } - if (v_scroll->is_visible_in_tree() && v_scroll->get_parent() == this) { //scrolls may have been moved out for reasons + if (_is_v_scroll_visible() || vertical_scroll_mode == SCROLL_MODE_RESERVE) { size.x -= v_scroll->get_minimum_size().x; } @@ -324,7 +333,7 @@ void ScrollContainer::_reposition_children() { r.size.height = MAX(size.height, minsize.height); } r.position += ofs; - if (rtl && v_scroll->is_visible_in_tree() && v_scroll->get_parent() == this) { + if (rtl && _is_v_scroll_visible()) { r.position.x += v_scroll->get_minimum_size().x; } r.position = r.position.floor(); @@ -436,14 +445,14 @@ void ScrollContainer::update_scrollbars() { Size2 hmin = h_scroll->get_combined_minimum_size(); Size2 vmin = v_scroll->get_combined_minimum_size(); - h_scroll->set_visible(horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (horizontal_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.width > size.width)); - v_scroll->set_visible(vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (vertical_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.height > size.height)); + h_scroll->set_visible(horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || ((horizontal_scroll_mode == SCROLL_MODE_AUTO || horizontal_scroll_mode == SCROLL_MODE_RESERVE) && largest_child_min_size.width > size.width)); + v_scroll->set_visible(vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || ((vertical_scroll_mode == SCROLL_MODE_AUTO || vertical_scroll_mode == SCROLL_MODE_RESERVE) && largest_child_min_size.height > size.height)); h_scroll->set_max(largest_child_min_size.width); - h_scroll->set_page((v_scroll->is_visible() && v_scroll->get_parent() == this) ? size.width - vmin.width : size.width); + h_scroll->set_page(_is_v_scroll_visible() ? size.width - vmin.width : size.width); v_scroll->set_max(largest_child_min_size.height); - v_scroll->set_page((h_scroll->is_visible() && h_scroll->get_parent() == this) ? size.height - hmin.height : size.height); + v_scroll->set_page(_is_h_scroll_visible() ? size.height - hmin.height : size.height); // Avoid scrollbar overlapping. _updating_scrollbars = true; @@ -603,14 +612,15 @@ void ScrollContainer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_vertical", PROPERTY_HINT_NONE, "suffix:px"), "set_v_scroll", "get_v_scroll"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_horizontal_custom_step", PROPERTY_HINT_RANGE, "-1,4096,suffix:px"), "set_horizontal_custom_step", "get_horizontal_custom_step"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_vertical_custom_step", PROPERTY_HINT_RANGE, "-1,4096,suffix:px"), "set_vertical_custom_step", "get_vertical_custom_step"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "horizontal_scroll_mode", PROPERTY_HINT_ENUM, "Disabled,Auto,Always Show,Never Show"), "set_horizontal_scroll_mode", "get_horizontal_scroll_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_scroll_mode", PROPERTY_HINT_ENUM, "Disabled,Auto,Always Show,Never Show"), "set_vertical_scroll_mode", "get_vertical_scroll_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "horizontal_scroll_mode", PROPERTY_HINT_ENUM, "Disabled,Auto,Always Show,Never Show,Reserve"), "set_horizontal_scroll_mode", "get_horizontal_scroll_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_scroll_mode", PROPERTY_HINT_ENUM, "Disabled,Auto,Always Show,Never Show,Reserve"), "set_vertical_scroll_mode", "get_vertical_scroll_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_deadzone"), "set_deadzone", "get_deadzone"); BIND_ENUM_CONSTANT(SCROLL_MODE_DISABLED); BIND_ENUM_CONSTANT(SCROLL_MODE_AUTO); BIND_ENUM_CONSTANT(SCROLL_MODE_SHOW_ALWAYS); BIND_ENUM_CONSTANT(SCROLL_MODE_SHOW_NEVER); + BIND_ENUM_CONSTANT(SCROLL_MODE_RESERVE); BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollContainer, panel_style, "panel"); diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index 02146618cd..afd3c8bd57 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -44,6 +44,7 @@ public: SCROLL_MODE_AUTO, SCROLL_MODE_SHOW_ALWAYS, SCROLL_MODE_SHOW_NEVER, + SCROLL_MODE_RESERVE, }; private: @@ -75,6 +76,9 @@ private: void _cancel_drag(); + bool _is_h_scroll_visible() const; + bool _is_v_scroll_visible() const; + protected: Size2 get_minimum_size() const override; diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index 3e0d6adf42..90bb0799b1 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -1250,6 +1250,7 @@ Variant TabBar::_handle_get_drag_data(const String &p_type, const Point2 &p_poin } Label *label = memnew(Label(get_tab_title(tab_over))); + label->set_auto_translate_mode(get_auto_translate_mode()); // Reflect how the title is displayed. drag_preview->add_child(label); set_drag_preview(drag_preview); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 23b99d1e53..eb9616c939 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -267,10 +267,14 @@ void TabContainer::_repaint() { Vector<Control *> controls = _get_tab_controls(); int current = get_current_tab(); + // Move the TabBar to the top or bottom. + // Don't change the left and right offsets since the TabBar will resize and may change tab offset. if (tabs_position == POSITION_BOTTOM) { - tab_bar->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE); + tab_bar->set_anchor_and_offset(SIDE_BOTTOM, 1.0, 0.0); + tab_bar->set_anchor_and_offset(SIDE_TOP, 1.0, -_get_tab_height()); } else { - tab_bar->set_anchors_and_offsets_preset(PRESET_TOP_WIDE); + tab_bar->set_anchor_and_offset(SIDE_BOTTOM, 0.0, _get_tab_height()); + tab_bar->set_anchor_and_offset(SIDE_TOP, 0.0, 0.0); } updating_visibility = true; @@ -299,7 +303,6 @@ void TabContainer::_repaint() { } updating_visibility = false; - _update_margins(); update_minimum_size(); } @@ -909,7 +912,7 @@ Size2 TabContainer::get_minimum_size() const { for (int i = 0; i < controls.size(); i++) { Control *c = controls[i]; - if (!c->is_visible_in_tree() && !use_hidden_tabs_for_min_size) { + if (!c->is_visible() && !use_hidden_tabs_for_min_size) { continue; } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index d7799588ea..0e8d76d294 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1265,7 +1265,7 @@ void TextEdit::_notification(int p_what) { } if (!clipped && lookup_symbol_word.length() != 0) { // Highlight word - if (is_ascii_alphabet_char(lookup_symbol_word[0]) || lookup_symbol_word[0] == '_' || lookup_symbol_word[0] == '.') { + if (is_unicode_identifier_start(lookup_symbol_word[0]) || lookup_symbol_word[0] == '.') { Color highlight_underline_color = !editable ? theme_cache.font_readonly_color : theme_cache.font_color; int lookup_symbol_word_col = _get_column_pos_of_word(lookup_symbol_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0); int lookup_symbol_word_len = lookup_symbol_word.length(); @@ -2958,7 +2958,7 @@ void TextEdit::_close_ime_window() { void TextEdit::_update_ime_window_position() { DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID; - if (wid == DisplayServer::INVALID_WINDOW_ID || !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) { + if (wid == DisplayServer::INVALID_WINDOW_ID || !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME) || !DisplayServer::get_singleton()->window_is_focused(wid)) { return; } DisplayServer::get_singleton()->window_set_ime_active(true, wid); @@ -3034,6 +3034,7 @@ Variant TextEdit::get_drag_data(const Point2 &p_point) { if (has_selection() && selection_drag_attempt) { String t = get_selected_text(); Label *l = memnew(Label); + l->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // Don't translate user input. l->set_text(t); set_drag_preview(l); return t; @@ -3366,6 +3367,14 @@ bool TextEdit::is_middle_mouse_paste_enabled() const { return middle_mouse_paste_enabled; } +void TextEdit::set_empty_selection_clipboard_enabled(bool p_enabled) { + empty_selection_clipboard_enabled = p_enabled; +} + +bool TextEdit::is_empty_selection_clipboard_enabled() const { + return empty_selection_clipboard_enabled; +} + // Text manipulation void TextEdit::clear() { setting_text = true; @@ -6568,6 +6577,9 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_middle_mouse_paste_enabled", "enabled"), &TextEdit::set_middle_mouse_paste_enabled); ClassDB::bind_method(D_METHOD("is_middle_mouse_paste_enabled"), &TextEdit::is_middle_mouse_paste_enabled); + ClassDB::bind_method(D_METHOD("set_empty_selection_clipboard_enabled", "enabled"), &TextEdit::set_empty_selection_clipboard_enabled); + ClassDB::bind_method(D_METHOD("is_empty_selection_clipboard_enabled"), &TextEdit::is_empty_selection_clipboard_enabled); + // Text manipulation ClassDB::bind_method(D_METHOD("clear"), &TextEdit::clear); @@ -6961,6 +6973,7 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_and_drop_selection_enabled"), "set_drag_and_drop_selection_enabled", "is_drag_and_drop_selection_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "empty_selection_clipboard_enabled"), "set_empty_selection_clipboard_enabled", "is_empty_selection_clipboard_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_mode", PROPERTY_HINT_ENUM, "None,Boundary"), "set_line_wrapping_mode", "get_line_wrapping_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Arbitrary:1,Word:2,Word (Smart):3"), "set_autowrap_mode", "get_autowrap_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "indent_wrapped_lines"), "set_indent_wrapped_lines", "is_indent_wrapped_lines"); @@ -7215,6 +7228,10 @@ void TextEdit::_cut_internal(int p_caret) { return; } + if (!empty_selection_clipboard_enabled) { + return; + } + // Remove full lines. begin_complex_operation(); begin_multicaret_edit(); @@ -7245,6 +7262,10 @@ void TextEdit::_copy_internal(int p_caret) { return; } + if (!empty_selection_clipboard_enabled) { + return; + } + // Copy full lines. StringBuilder clipboard; Vector<Point2i> line_ranges; diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index c5f838020b..94b105d486 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -319,6 +319,7 @@ private: bool shortcut_keys_enabled = true; bool virtual_keyboard_enabled = true; bool middle_mouse_paste_enabled = true; + bool empty_selection_clipboard_enabled = true; // Overridable actions. String cut_copy_line = ""; @@ -770,6 +771,9 @@ public: void set_middle_mouse_paste_enabled(bool p_enabled); bool is_middle_mouse_paste_enabled() const; + void set_empty_selection_clipboard_enabled(bool p_enabled); + bool is_empty_selection_clipboard_enabled() const; + // Text manipulation void clear(); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 858fc2246b..d921cc5b67 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -111,6 +111,7 @@ void Node::_notification(int p_notification) { data.auto_translate_mode = AUTO_TRANSLATE_MODE_ALWAYS; } data.is_auto_translate_dirty = true; + data.is_translation_domain_dirty = true; #ifdef TOOLS_ENABLED // Don't translate UI elements when they're being edited. @@ -1320,6 +1321,51 @@ bool Node::can_auto_translate() const { return data.is_auto_translating; } +StringName Node::get_translation_domain() const { + ERR_READ_THREAD_GUARD_V(StringName()); + + if (data.is_translation_domain_inherited && data.is_translation_domain_dirty) { + const_cast<Node *>(this)->_translation_domain = data.parent ? data.parent->get_translation_domain() : StringName(); + data.is_translation_domain_dirty = false; + } + return _translation_domain; +} + +void Node::set_translation_domain(const StringName &p_domain) { + ERR_THREAD_GUARD + + if (!data.is_translation_domain_inherited && _translation_domain == p_domain) { + return; + } + + _translation_domain = p_domain; + data.is_translation_domain_inherited = false; + data.is_translation_domain_dirty = false; + _propagate_translation_domain_dirty(); +} + +void Node::set_translation_domain_inherited() { + ERR_THREAD_GUARD + + if (data.is_translation_domain_inherited) { + return; + } + data.is_translation_domain_inherited = true; + data.is_translation_domain_dirty = true; + _propagate_translation_domain_dirty(); +} + +void Node::_propagate_translation_domain_dirty() { + for (KeyValue<StringName, Node *> &K : data.children) { + Node *child = K.value; + if (child->data.is_translation_domain_inherited) { + child->data.is_translation_domain_dirty = true; + child->_propagate_translation_domain_dirty(); + } + } + notification(NOTIFICATION_TRANSLATION_CHANGED); +} + StringName Node::get_name() const { return data.name; } @@ -3610,6 +3656,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("set_auto_translate_mode", "mode"), &Node::set_auto_translate_mode); ClassDB::bind_method(D_METHOD("get_auto_translate_mode"), &Node::get_auto_translate_mode); + ClassDB::bind_method(D_METHOD("set_translation_domain_inherited"), &Node::set_translation_domain_inherited); ClassDB::bind_method(D_METHOD("get_window"), &Node::get_window); ClassDB::bind_method(D_METHOD("get_last_exclusive_window"), &Node::get_last_exclusive_window); @@ -3972,4 +4019,9 @@ bool Node::is_connected(const StringName &p_signal, const Callable &p_callable) return Object::is_connected(p_signal, p_callable); } +bool Node::has_connections(const StringName &p_signal) const { + ERR_THREAD_GUARD_V(false); + return Object::has_connections(p_signal); +} + #endif diff --git a/scene/main/node.h b/scene/main/node.h index dc65513fca..298cbc7e59 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -255,6 +255,9 @@ private: mutable bool is_auto_translating = true; mutable bool is_auto_translate_dirty = true; + mutable bool is_translation_domain_inherited = true; + mutable bool is_translation_domain_dirty = true; + mutable NodePath *path_cache = nullptr; } data; @@ -281,6 +284,7 @@ private: void _propagate_physics_interpolation_reset_requested(bool p_requested); void _propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification); void _propagate_groups_dirty(); + void _propagate_translation_domain_dirty(); Array _get_node_and_resource(const NodePath &p_path); void _duplicate_properties(const Node *p_root, const Node *p_original, Node *p_copy, int p_flags) const; @@ -735,6 +739,10 @@ public: AutoTranslateMode get_auto_translate_mode() const; bool can_auto_translate() const; + virtual StringName get_translation_domain() const override; + virtual void set_translation_domain(const StringName &p_domain) override; + void set_translation_domain_inherited(); + _FORCE_INLINE_ String atr(const String p_message, const StringName p_context = "") const { return can_auto_translate() ? tr(p_message, p_context) : p_message; } _FORCE_INLINE_ String atr_n(const String p_message, const StringName &p_message_plural, int p_n, const StringName p_context = "") const { return can_auto_translate() ? tr_n(p_message, p_message_plural, p_n, p_context) : p_message; } @@ -789,6 +797,7 @@ public: virtual Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0) override; virtual void disconnect(const StringName &p_signal, const Callable &p_callable) override; virtual bool is_connected(const StringName &p_signal, const Callable &p_callable) const override; + virtual bool has_connections(const StringName &p_signal) const override; #endif Node(); ~Node(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index a4e27a3d16..ba69f8cc45 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -111,6 +111,9 @@ void ViewportTexture::set_viewport_path_in_scene(const NodePath &p_path) { if (get_local_scene() && !path.is_empty()) { setup_local_to_scene(); } else { + if (path.is_empty()) { + vp_changed = false; + } emit_changed(); } } @@ -121,9 +124,7 @@ NodePath ViewportTexture::get_viewport_path_in_scene() const { int ViewportTexture::get_width() const { if (!vp) { - if (!vp_pending) { - ERR_PRINT("Viewport Texture must be set to use it."); - } + _err_print_viewport_not_set(); return 0; } return vp->size.width; @@ -131,9 +132,7 @@ int ViewportTexture::get_width() const { int ViewportTexture::get_height() const { if (!vp) { - if (!vp_pending) { - ERR_PRINT("Viewport Texture must be set to use it."); - } + _err_print_viewport_not_set(); return 0; } return vp->size.height; @@ -141,9 +140,7 @@ int ViewportTexture::get_height() const { Size2 ViewportTexture::get_size() const { if (!vp) { - if (!vp_pending) { - ERR_PRINT("Viewport Texture must be set to use it."); - } + _err_print_viewport_not_set(); return Size2(); } return vp->size; @@ -163,14 +160,18 @@ bool ViewportTexture::has_alpha() const { Ref<Image> ViewportTexture::get_image() const { if (!vp) { - if (!vp_pending) { - ERR_PRINT("Viewport Texture must be set to use it."); - } + _err_print_viewport_not_set(); return Ref<Image>(); } return RS::get_singleton()->texture_2d_get(vp->texture_rid); } +void ViewportTexture::_err_print_viewport_not_set() const { + if (!vp_pending && !vp_changed) { + ERR_PRINT("Viewport Texture must be set to use it."); + } +} + void ViewportTexture::_setup_local_to_scene(const Node *p_loc_scene) { // Always reset this, even if this call fails with an error. vp_pending = false; @@ -4670,6 +4671,7 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d); ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d); + ClassDB::bind_method(D_METHOD("get_audio_listener_2d"), &Viewport::get_audio_listener_2d); ClassDB::bind_method(D_METHOD("get_camera_2d"), &Viewport::get_camera_2d); #ifndef _3D_DISABLED @@ -4680,6 +4682,7 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_own_world_3d", "enable"), &Viewport::set_use_own_world_3d); ClassDB::bind_method(D_METHOD("is_using_own_world_3d"), &Viewport::is_using_own_world_3d); + ClassDB::bind_method(D_METHOD("get_audio_listener_3d"), &Viewport::get_audio_listener_3d); ClassDB::bind_method(D_METHOD("get_camera_3d"), &Viewport::get_camera_3d); ClassDB::bind_method(D_METHOD("set_as_audio_listener_3d", "enable"), &Viewport::set_as_audio_listener_3d); ClassDB::bind_method(D_METHOD("is_audio_listener_3d"), &Viewport::is_audio_listener_3d); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index edacee2d88..a18dc1f6f0 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -63,6 +63,7 @@ class ViewportTexture : public Texture2D { bool vp_changed = false; void _setup_local_to_scene(const Node *p_loc_scene); + void _err_print_viewport_not_set() const; mutable RID proxy_ph; mutable RID proxy; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 76678e609a..09227e260f 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -117,6 +117,7 @@ #include "scene/resources/compressed_texture.h" #include "scene/resources/curve_texture.h" #include "scene/resources/environment.h" +#include "scene/resources/external_texture.h" #include "scene/resources/font.h" #include "scene/resources/gradient.h" #include "scene/resources/gradient_texture.h" @@ -926,6 +927,7 @@ void register_scene_types() { GDREGISTER_CLASS(GradientTexture2D); GDREGISTER_CLASS(AnimatedTexture); GDREGISTER_CLASS(CameraTexture); + GDREGISTER_CLASS(ExternalTexture); GDREGISTER_VIRTUAL_CLASS(TextureLayered); GDREGISTER_ABSTRACT_CLASS(ImageTextureLayered); GDREGISTER_VIRTUAL_CLASS(Texture3D); diff --git a/scene/resources/2d/tile_set.h b/scene/resources/2d/tile_set.h index 931495d020..15e1a16359 100644 --- a/scene/resources/2d/tile_set.h +++ b/scene/resources/2d/tile_set.h @@ -571,25 +571,25 @@ public: // Not exposed. virtual void set_tile_set(const TileSet *p_tile_set); TileSet *get_tile_set() const; - virtual void notify_tile_data_properties_should_change(){}; - virtual void add_occlusion_layer(int p_index){}; - virtual void move_occlusion_layer(int p_from_index, int p_to_pos){}; - virtual void remove_occlusion_layer(int p_index){}; - virtual void add_physics_layer(int p_index){}; - virtual void move_physics_layer(int p_from_index, int p_to_pos){}; - virtual void remove_physics_layer(int p_index){}; - virtual void add_terrain_set(int p_index){}; - virtual void move_terrain_set(int p_from_index, int p_to_pos){}; - virtual void remove_terrain_set(int p_index){}; - virtual void add_terrain(int p_terrain_set, int p_index){}; - virtual void move_terrain(int p_terrain_set, int p_from_index, int p_to_pos){}; - virtual void remove_terrain(int p_terrain_set, int p_index){}; - virtual void add_navigation_layer(int p_index){}; - virtual void move_navigation_layer(int p_from_index, int p_to_pos){}; - virtual void remove_navigation_layer(int p_index){}; - virtual void add_custom_data_layer(int p_index){}; - virtual void move_custom_data_layer(int p_from_index, int p_to_pos){}; - virtual void remove_custom_data_layer(int p_index){}; + virtual void notify_tile_data_properties_should_change() {} + virtual void add_occlusion_layer(int p_index) {} + virtual void move_occlusion_layer(int p_from_index, int p_to_pos) {} + virtual void remove_occlusion_layer(int p_index) {} + virtual void add_physics_layer(int p_index) {} + virtual void move_physics_layer(int p_from_index, int p_to_pos) {} + virtual void remove_physics_layer(int p_index) {} + virtual void add_terrain_set(int p_index) {} + virtual void move_terrain_set(int p_from_index, int p_to_pos) {} + virtual void remove_terrain_set(int p_index) {} + virtual void add_terrain(int p_terrain_set, int p_index) {} + virtual void move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) {} + virtual void remove_terrain(int p_terrain_set, int p_index) {} + virtual void add_navigation_layer(int p_index) {} + virtual void move_navigation_layer(int p_from_index, int p_to_pos) {} + virtual void remove_navigation_layer(int p_index) {} + virtual void add_custom_data_layer(int p_index) {} + virtual void move_custom_data_layer(int p_from_index, int p_to_pos) {} + virtual void remove_custom_data_layer(int p_index) {} virtual void reset_state() override; // Tiles. diff --git a/scene/resources/3d/primitive_meshes.h b/scene/resources/3d/primitive_meshes.h index fc2489923a..85f46a482a 100644 --- a/scene/resources/3d/primitive_meshes.h +++ b/scene/resources/3d/primitive_meshes.h @@ -77,7 +77,7 @@ protected: Vector2 get_uv2_scale(Vector2 p_margin_scale = Vector2(1.0, 1.0)) const; float get_lightmap_texel_size() const; - virtual void _update_lightmap_size(){}; + virtual void _update_lightmap_size() {} void _on_settings_changed(); @@ -541,7 +541,7 @@ private: Vector2 point; bool sharp = false; - ContourPoint(){}; + ContourPoint() {} ContourPoint(const Vector2 &p_pt, bool p_sharp) { point = p_pt; sharp = p_sharp; @@ -551,7 +551,7 @@ private: struct ContourInfo { real_t length = 0.0; bool ccw = true; - ContourInfo(){}; + ContourInfo() {} ContourInfo(real_t p_len, bool p_ccw) { length = p_len; ccw = p_ccw; diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index a2ed6af23c..9abc6a02d2 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -321,8 +321,12 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { Vector<real_t> times = d["times"]; Vector<real_t> values = d["points"]; #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V(!d.has("handle_modes"), false); - Vector<int> handle_modes = d["handle_modes"]; + Vector<int> handle_modes; + if (d.has("handle_modes")) { + handle_modes = d["handle_modes"]; + } else { + handle_modes.resize_zeroed(times.size()); + } #endif // TOOLS_ENABLED ERR_FAIL_COND_V(times.size() * 5 != values.size(), false); @@ -4804,9 +4808,9 @@ void Animation::compress(uint32_t p_page_size, uint32_t p_fps, float p_split_tol continue; // This track is exhausted (all keys were added already), don't consider. } } - - uint32_t key_frame = double(track_get_key_time(uncomp_track, time_tracks[i].key_index)) / frame_len; - + double key_time = track_get_key_time(uncomp_track, time_tracks[i].key_index); + double result = key_time / frame_len; + uint32_t key_frame = Math::fast_ftoi(result); if (time_tracks[i].needs_start_frame && key_frame > base_page_frame) { start_frame = true; best_frame = base_page_frame; diff --git a/scene/resources/camera_attributes.h b/scene/resources/camera_attributes.h index 0f819134e2..de57b0ce8f 100644 --- a/scene/resources/camera_attributes.h +++ b/scene/resources/camera_attributes.h @@ -53,7 +53,7 @@ protected: float auto_exposure_max = 64.0; float auto_exposure_speed = 0.5; float auto_exposure_scale = 0.4; - virtual void _update_auto_exposure(){}; + virtual void _update_auto_exposure() {} public: virtual RID get_rid() const override; diff --git a/scene/resources/camera_texture.cpp b/scene/resources/camera_texture.cpp index b575a099ed..b219f89e59 100644 --- a/scene/resources/camera_texture.cpp +++ b/scene/resources/camera_texture.cpp @@ -47,6 +47,11 @@ void CameraTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "camera_is_active"), "set_camera_active", "get_camera_active"); } +void CameraTexture::_on_format_changed() { + // FIXME: `emit_changed` is more appropriate, but causes errors for some reason. + callable_mp((Resource *)this, &Resource::emit_changed).call_deferred(); +} + int CameraTexture::get_width() const { Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id); if (feed.is_valid()) { @@ -82,13 +87,26 @@ RID CameraTexture::get_rid() const { } Ref<Image> CameraTexture::get_image() const { - // not (yet) supported - return Ref<Image>(); + return RenderingServer::get_singleton()->texture_2d_get(get_rid()); } void CameraTexture::set_camera_feed_id(int p_new_id) { + Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id); + if (feed.is_valid()) { + if (feed->is_connected("format_changed", callable_mp(this, &CameraTexture::_on_format_changed))) { + feed->disconnect("format_changed", callable_mp(this, &CameraTexture::_on_format_changed)); + } + } + camera_feed_id = p_new_id; + + feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id); + if (feed.is_valid()) { + feed->connect("format_changed", callable_mp(this, &CameraTexture::_on_format_changed)); + } + notify_property_list_changed(); + callable_mp((Resource *)this, &Resource::emit_changed).call_deferred(); } int CameraTexture::get_camera_feed_id() const { @@ -98,6 +116,7 @@ int CameraTexture::get_camera_feed_id() const { void CameraTexture::set_which_feed(CameraServer::FeedImage p_which) { which_feed = p_which; notify_property_list_changed(); + callable_mp((Resource *)this, &Resource::emit_changed).call_deferred(); } CameraServer::FeedImage CameraTexture::get_which_feed() const { @@ -109,6 +128,7 @@ void CameraTexture::set_camera_active(bool p_active) { if (feed.is_valid()) { feed->set_active(p_active); notify_property_list_changed(); + callable_mp((Resource *)this, &Resource::emit_changed).call_deferred(); } } diff --git a/scene/resources/camera_texture.h b/scene/resources/camera_texture.h index 521121f9ea..dd216a72d6 100644 --- a/scene/resources/camera_texture.h +++ b/scene/resources/camera_texture.h @@ -43,6 +43,7 @@ private: protected: static void _bind_methods(); + void _on_format_changed(); public: virtual int get_width() const override; diff --git a/scene/resources/external_texture.cpp b/scene/resources/external_texture.cpp new file mode 100644 index 0000000000..0552bbd081 --- /dev/null +++ b/scene/resources/external_texture.cpp @@ -0,0 +1,89 @@ +/**************************************************************************/ +/* external_texture.cpp */ +/**************************************************************************/ +/* 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. */ +/**************************************************************************/ + +#include "external_texture.h" + +void ExternalTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &ExternalTexture::set_size); + ClassDB::bind_method(D_METHOD("get_external_texture_id"), &ExternalTexture::get_external_texture_id); + ClassDB::bind_method(D_METHOD("set_external_buffer_id", "external_buffer_id"), &ExternalTexture::set_external_buffer_id); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); +} + +uint64_t ExternalTexture::get_external_texture_id() const { + return RenderingServer::get_singleton()->texture_get_native_handle(texture); +} + +void ExternalTexture::set_size(const Size2 &p_size) { + if (p_size.width > 0 && p_size.height > 0 && p_size != size) { + size = p_size; + RenderingServer::get_singleton()->texture_external_update(texture, size.width, size.height, external_buffer); + emit_changed(); + } +} + +Size2 ExternalTexture::get_size() const { + return size; +} + +void ExternalTexture::set_external_buffer_id(uint64_t p_external_buffer) { + if (p_external_buffer != external_buffer) { + external_buffer = p_external_buffer; + RenderingServer::get_singleton()->texture_external_update(texture, size.width, size.height, external_buffer); + } +} + +int ExternalTexture::get_width() const { + return size.width; +} + +int ExternalTexture::get_height() const { + return size.height; +} + +bool ExternalTexture::has_alpha() const { + return false; +} + +RID ExternalTexture::get_rid() const { + return texture; +} + +ExternalTexture::ExternalTexture() { + texture = RenderingServer::get_singleton()->texture_external_create(size.width, size.height); +} + +ExternalTexture::~ExternalTexture() { + if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); + RenderingServer::get_singleton()->free(texture); + } +} diff --git a/scene/resources/external_texture.h b/scene/resources/external_texture.h new file mode 100644 index 0000000000..96bcd8d0fe --- /dev/null +++ b/scene/resources/external_texture.h @@ -0,0 +1,66 @@ +/**************************************************************************/ +/* external_texture.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 EXTERNAL_TEXTURE_H +#define EXTERNAL_TEXTURE_H + +#include "scene/resources/texture.h" + +// External textures as defined by OES_EGL_image_external (GLES) or VK_ANDROID_external_memory_android_hardware_buffer (Vulkan). +class ExternalTexture : public Texture2D { + GDCLASS(ExternalTexture, Texture2D); + +private: + RID texture; + Size2 size = Size2(256, 256); + uint64_t external_buffer = 0; + +protected: + static void _bind_methods(); + +public: + uint64_t get_external_texture_id() const; + + virtual Size2 get_size() const override; + void set_size(const Size2 &p_size); + + void set_external_buffer_id(uint64_t p_external_buffer); + + virtual int get_width() const override; + virtual int get_height() const override; + + virtual RID get_rid() const override; + virtual bool has_alpha() const override; + + ExternalTexture(); + ~ExternalTexture(); +}; + +#endif // EXTERNAL_TEXTURE_H diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 26666538af..3db1ab9338 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -8081,17 +8081,28 @@ int VisualShaderNodeRemap::get_input_port_count() const { } VisualShaderNodeRemap::PortType VisualShaderNodeRemap::get_input_port_type(int p_port) const { - switch (p_port) { - case 0: - return PORT_TYPE_SCALAR; - case 1: - return PORT_TYPE_SCALAR; - case 2: - return PORT_TYPE_SCALAR; - case 3: - return PORT_TYPE_SCALAR; - case 4: - return PORT_TYPE_SCALAR; + switch (op_type) { + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_2D_SCALAR: + if (p_port == 0) { + return PORT_TYPE_VECTOR_2D; + } + break; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + case OP_TYPE_VECTOR_3D_SCALAR: + if (p_port == 0) { + return PORT_TYPE_VECTOR_3D; + } + break; + case OP_TYPE_VECTOR_4D: + return PORT_TYPE_VECTOR_4D; + case OP_TYPE_VECTOR_4D_SCALAR: + if (p_port == 0) { + return PORT_TYPE_VECTOR_4D; + } + break; default: break; } @@ -8123,23 +8134,159 @@ int VisualShaderNodeRemap::get_output_port_count() const { } VisualShaderNodeRemap::PortType VisualShaderNodeRemap::get_output_port_type(int p_port) const { - return PORT_TYPE_SCALAR; + switch (op_type) { + case OP_TYPE_VECTOR_2D: + case OP_TYPE_VECTOR_2D_SCALAR: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + case OP_TYPE_VECTOR_3D_SCALAR: + return PORT_TYPE_VECTOR_3D; + case OP_TYPE_VECTOR_4D: + case OP_TYPE_VECTOR_4D_SCALAR: + return PORT_TYPE_VECTOR_4D; + default: + return PORT_TYPE_SCALAR; + } } String VisualShaderNodeRemap::get_output_port_name(int p_port) const { return "value"; } +void VisualShaderNodeRemap::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX)); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_SCALAR: { + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); + set_input_port_default_value(2, 1.0, get_input_port_default_value(2)); + set_input_port_default_value(3, 0.0, get_input_port_default_value(3)); + set_input_port_default_value(4, 1.0, get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector2(1.0, 1.0), get_input_port_default_value(2)); + set_input_port_default_value(3, Vector2(), get_input_port_default_value(3)); + set_input_port_default_value(4, Vector2(1.0, 1.0), get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_2D_SCALAR: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); + set_input_port_default_value(2, 1.0, get_input_port_default_value(2)); + set_input_port_default_value(3, 0.0, get_input_port_default_value(3)); + set_input_port_default_value(4, 1.0, get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector3(1.0, 1.0, 1.0), get_input_port_default_value(2)); + set_input_port_default_value(3, Vector3(), get_input_port_default_value(3)); + set_input_port_default_value(4, Vector3(1.0, 1.0, 1.0), get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_3D_SCALAR: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); + set_input_port_default_value(2, 1.0, get_input_port_default_value(2)); + set_input_port_default_value(3, 0.0, get_input_port_default_value(3)); + set_input_port_default_value(4, 1.0, get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_4D: { + set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0)); + set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1)); + set_input_port_default_value(2, Quaternion(1.0, 1.0, 1.0, 1.0), get_input_port_default_value(2)); + set_input_port_default_value(3, Quaternion(), get_input_port_default_value(3)); + set_input_port_default_value(4, Quaternion(1.0, 1.0, 1.0, 1.0), get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_4D_SCALAR: { + set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); + set_input_port_default_value(2, 1.0, get_input_port_default_value(2)); + set_input_port_default_value(3, 0.0, get_input_port_default_value(3)); + set_input_port_default_value(4, 1.0, get_input_port_default_value(4)); + } break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + +VisualShaderNodeRemap::OpType VisualShaderNodeRemap::get_op_type() const { + return op_type; +} + String VisualShaderNodeRemap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; code += " {\n"; - code += vformat(" float __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); - code += vformat(" float __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); - code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + switch (op_type) { + case OP_TYPE_SCALAR: { + code += vformat(" float __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" float __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_2D: { + code += vformat(" vec2 __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec2 __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_2D_SCALAR: { + code += vformat(" vec2 __input_range = vec2(%s - %s);\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec2 __output_range = vec2(%s - %s);\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = vec2(%s) + __output_range * ((%s - vec2(%s)) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_3D: { + code += vformat(" vec3 __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec3 __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_3D_SCALAR: { + code += vformat(" vec3 __input_range = vec3(%s - %s);\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec3 __output_range = vec3(%s - %s);\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = vec3(%s) + __output_range * ((%s - vec3(%s)) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_4D: { + code += vformat(" vec4 __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec4 __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_4D_SCALAR: { + code += vformat(" vec4 __input_range = vec4(%s - %s);\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec4 __output_range = vec4(%s - %s);\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = vec4(%s) + __output_range * ((%s - vec4(%s)) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + default: + break; + } code += " }\n"; return code; } +Vector<StringName> VisualShaderNodeRemap::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; +} + +void VisualShaderNodeRemap::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "op_type"), &VisualShaderNodeRemap::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeRemap::get_op_type); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector2Scalar,Vector3,Vector3Scalar,Vector4,Vector4Scalar"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); +} + VisualShaderNodeRemap::VisualShaderNodeRemap() { set_input_port_default_value(1, 0.0); set_input_port_default_value(2, 1.0); diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index ff02e55fb2..67dc8f7353 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -3068,10 +3068,30 @@ public: VisualShaderNodeRandomRange(); }; +/////////////////////////////////////// +/// Remap +/////////////////////////////////////// + class VisualShaderNodeRemap : public VisualShaderNode { GDCLASS(VisualShaderNodeRemap, VisualShaderNode); public: + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR_2D, + OP_TYPE_VECTOR_2D_SCALAR, + OP_TYPE_VECTOR_3D, + OP_TYPE_VECTOR_3D_SCALAR, + OP_TYPE_VECTOR_4D, + OP_TYPE_VECTOR_4D_SCALAR, + OP_TYPE_MAX, + }; + +protected: + OpType op_type = OP_TYPE_SCALAR; + static void _bind_methods(); + +public: virtual String get_caption() const override; virtual int get_input_port_count() const override; @@ -3082,13 +3102,26 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + void set_op_type(OpType p_op_type); + OpType get_op_type() const; + + virtual Vector<StringName> get_editable_properties() const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; - virtual Category get_category() const override { return CATEGORY_UTILITY; } + virtual Category get_category() const override { + if (op_type == OP_TYPE_SCALAR) { + return CATEGORY_SCALAR; + } else { + return CATEGORY_VECTOR; + } + } VisualShaderNodeRemap(); }; +VARIANT_ENUM_CAST(VisualShaderNodeRemap::OpType) + class VisualShaderNodeRotationByAxis : public VisualShaderNode { GDCLASS(VisualShaderNodeRotationByAxis, VisualShaderNode); |