summaryrefslogtreecommitdiffstats
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/parallax_2d.cpp6
-rw-r--r--scene/2d/physics/shape_cast_2d.cpp2
-rw-r--r--scene/2d/tile_map_layer.h2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp11
-rw-r--r--scene/3d/audio_stream_player_3d.h1
-rw-r--r--scene/3d/physics/character_body_3d.cpp9
-rw-r--r--scene/animation/animation_blend_tree.cpp6
-rw-r--r--scene/gui/code_edit.cpp3
-rw-r--r--scene/gui/color_mode.h14
-rw-r--r--scene/gui/file_dialog.cpp1
-rw-r--r--scene/gui/line_edit.cpp5
-rw-r--r--scene/gui/rich_text_label.cpp1
-rw-r--r--scene/gui/scroll_container.cpp32
-rw-r--r--scene/gui/scroll_container.h4
-rw-r--r--scene/gui/tab_bar.cpp1
-rw-r--r--scene/gui/tab_container.cpp11
-rw-r--r--scene/gui/text_edit.cpp25
-rw-r--r--scene/gui/text_edit.h4
-rw-r--r--scene/main/node.cpp52
-rw-r--r--scene/main/node.h9
-rw-r--r--scene/main/viewport.cpp27
-rw-r--r--scene/main/viewport.h1
-rw-r--r--scene/register_scene_types.cpp2
-rw-r--r--scene/resources/2d/tile_set.h38
-rw-r--r--scene/resources/3d/primitive_meshes.h6
-rw-r--r--scene/resources/animation.cpp14
-rw-r--r--scene/resources/camera_attributes.h2
-rw-r--r--scene/resources/camera_texture.cpp24
-rw-r--r--scene/resources/camera_texture.h1
-rw-r--r--scene/resources/external_texture.cpp89
-rw-r--r--scene/resources/external_texture.h66
-rw-r--r--scene/resources/visual_shader_nodes.cpp177
-rw-r--r--scene/resources/visual_shader_nodes.h35
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);