diff options
Diffstat (limited to 'scene')
36 files changed, 344 insertions, 291 deletions
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index d57e6bd21c..2c5df48b75 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -490,9 +490,7 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() { params.thickness = th; _compute_sdf(¶ms); - Ref<Image> ret; - ret.instantiate(); - ret->create(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, cells_data); + Ref<Image> ret = Image::create_from_data(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, cells_data); ret->convert(Image::FORMAT_RH); //convert to half, save space ret->set_meta("depth", sdf_size.z); //hack, make sure to add to the docs of this function diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 3ea1de57cd..1b5427c80d 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -145,10 +145,7 @@ Array LightmapGIData::_get_light_textures_data() const { for (int i = 0; i < texture_count; i++) { int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture; - Ref<Image> texture_image; - texture_image.instantiate(); - - texture_image->create(slice_width, slice_height * texture_slice_count, false, images[0]->get_format()); + Ref<Image> texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format()); for (int j = 0; j < texture_slice_count; j++) { texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j)); @@ -818,7 +815,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } md.albedo_on_uv2.instantiate(); - md.albedo_on_uv2->create(lightmap_size.width, lightmap_size.height, false, Image::FORMAT_RGBA8, albedom); + md.albedo_on_uv2->set_data(lightmap_size.width, lightmap_size.height, false, Image::FORMAT_RGBA8, albedom); } md.emission_on_uv2 = images[RS::BAKE_CHANNEL_EMISSION]; @@ -1054,7 +1051,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } break; case ENVIRONMENT_MODE_CUSTOM_COLOR: { environment_image.instantiate(); - environment_image->create(128, 64, false, Image::FORMAT_RGBAF); + environment_image->initialize_data(128, 64, false, Image::FORMAT_RGBAF); Color c = environment_custom_color; c.r *= environment_custom_energy; c.g *= environment_custom_energy; diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index 90c7bc89ef..04f73a4cbd 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -96,6 +96,7 @@ private: mutable SelfList<Node> xform_change; + // This Data struct is to avoid namespace pollution in derived classes. struct Data { mutable Transform3D global_transform; mutable Transform3D local_transform; diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index 3dba0221bb..7caf2f4874 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -77,9 +77,7 @@ Dictionary VoxelGIData::_get_data() const { d["octree_cells"] = get_octree_cells(); d["octree_data"] = get_data_cells(); if (otsize != Vector3i()) { - Ref<Image> img; - img.instantiate(); - img->create(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field()); + Ref<Image> img = Image::create_from_data(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field()); Vector<uint8_t> df_png = img->save_png_to_buffer(); ERR_FAIL_COND_V(df_png.size() == 0, Dictionary()); d["octree_df_png"] = df_png; diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index 4401d22f30..fe4ccbc7dc 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -36,49 +36,37 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// -void XRCamera3D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - // need to find our XROrigin3D parent and let it know we're its camera! - XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); - if (origin != nullptr) { - origin->set_tracked_camera(this); - } - } break; +void XRCamera3D::_bind_tracker() { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL(xr_server); - case NOTIFICATION_EXIT_TREE: { - // need to find our XROrigin3D parent and let it know we're no longer its camera! - XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); - if (origin != nullptr && origin->get_tracked_camera() == this) { - origin->set_tracked_camera(nullptr); - } - } break; + tracker = xr_server->get_tracker(tracker_name); + if (tracker.is_valid()) { + tracker->connect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed)); + + Ref<XRPose> pose = tracker->get_pose(pose_name); + if (pose.is_valid()) { + set_transform(pose->get_adjusted_transform()); + } } } +void XRCamera3D::_unbind_tracker() { + if (tracker.is_valid()) { + tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed)); + } + tracker.unref(); +} + void XRCamera3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) { if (p_tracker_name == tracker_name) { - XRServer *xr_server = XRServer::get_singleton(); - ERR_FAIL_NULL(xr_server); - - tracker = xr_server->get_tracker(p_tracker_name); - if (tracker.is_valid()) { - tracker->connect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed)); - - Ref<XRPose> pose = tracker->get_pose(pose_name); - if (pose.is_valid()) { - set_transform(pose->get_adjusted_transform()); - } - } + _bind_tracker(); } } void XRCamera3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) { if (p_tracker_name == tracker_name) { - if (tracker.is_valid()) { - tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed)); - } - tracker.unref(); + _unbind_tracker(); } } @@ -213,6 +201,9 @@ XRCamera3D::XRCamera3D() { xr_server->connect("tracker_added", callable_mp(this, &XRCamera3D::_changed_tracker)); xr_server->connect("tracker_updated", callable_mp(this, &XRCamera3D::_changed_tracker)); xr_server->connect("tracker_removed", callable_mp(this, &XRCamera3D::_removed_tracker)); + + // check if our tracker already exists and if so, bind it... + _bind_tracker(); } XRCamera3D::~XRCamera3D() { @@ -582,11 +573,22 @@ Plane XRAnchor3D::get_plane() const { //////////////////////////////////////////////////////////////////////////////////////////////////// +Vector<XROrigin3D *> XROrigin3D::origin_nodes; + PackedStringArray XROrigin3D::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible() && is_inside_tree()) { - if (tracked_camera == nullptr) { + bool has_camera = false; + for (int i = 0; !has_camera && i < get_child_count(); i++) { + XRCamera3D *camera = Object::cast_to<XRCamera3D>(get_child(i)); + if (camera) { + // found it! + has_camera = true; + } + } + + if (!has_camera) { warnings.push_back(RTR("XROrigin3D requires an XRCamera3D child node.")); } } @@ -603,14 +605,10 @@ void XROrigin3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_world_scale", "world_scale"), &XROrigin3D::set_world_scale); ClassDB::bind_method(D_METHOD("get_world_scale"), &XROrigin3D::get_world_scale); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale"); -} -void XROrigin3D::set_tracked_camera(XRCamera3D *p_tracked_camera) { - tracked_camera = p_tracked_camera; -} - -XRCamera3D *XROrigin3D::get_tracked_camera() const { - return tracked_camera; + ClassDB::bind_method(D_METHOD("set_current", "enabled"), &XROrigin3D::set_current); + ClassDB::bind_method(D_METHOD("is_current"), &XROrigin3D::is_current); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); } real_t XROrigin3D::get_world_scale() const { @@ -629,6 +627,44 @@ void XROrigin3D::set_world_scale(real_t p_world_scale) { xr_server->set_world_scale(p_world_scale); } +void XROrigin3D::set_current(bool p_enabled) { + current = p_enabled; + + if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) { + return; + } + + // Notify us of any transform changes + set_notify_local_transform(current); + set_notify_transform(current); + + if (current) { + for (int i = 0; i < origin_nodes.size(); i++) { + if (origin_nodes[i] != this) { + origin_nodes[i]->set_current(false); + } + } + } else { + bool found = false; + // We no longer have a current origin so find the first one we can make current + for (int i = 0; !found && i < origin_nodes.size(); i++) { + if (origin_nodes[i] != this) { + origin_nodes[i]->set_current(true); + found = true; + } + } + } +} + +bool XROrigin3D::is_current() const { + if (Engine::get_singleton()->is_editor_hint()) { + // return as is + return current; + } else { + return current && is_inside_tree(); + } +} + void XROrigin3D::_notification(int p_what) { // get our XRServer XRServer *xr_server = XRServer::get_singleton(); @@ -636,34 +672,47 @@ void XROrigin3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - set_process_internal(true); + if (!Engine::get_singleton()->is_editor_hint()) { + if (origin_nodes.is_empty()) { + // first entry always becomes current + current = true; + } + + origin_nodes.push_back(this); + + if (current) { + // set this again so we do whatever setup is needed. + set_current(true); + } + } } break; case NOTIFICATION_EXIT_TREE: { - set_process_internal(false); - } break; - - case NOTIFICATION_INTERNAL_PROCESS: { - // set our world origin to our node transform - xr_server->set_world_origin(get_global_transform()); + if (!Engine::get_singleton()->is_editor_hint()) { + origin_nodes.erase(this); - // check if we have a primary interface - Ref<XRInterface> xr_interface = xr_server->get_primary_interface(); - if (xr_interface.is_valid() && tracked_camera != nullptr) { - // get our positioning transform for our headset - Transform3D t = xr_interface->get_camera_transform(); + if (current) { + // We are no longer current + set_current(false); + } + } + } break; - // now apply this to our camera - tracked_camera->set_transform(t); + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: + case NOTIFICATION_TRANSFORM_CHANGED: { + if (current && !Engine::get_singleton()->is_editor_hint()) { + xr_server->set_world_origin(get_global_transform()); } } break; } - // send our notification to all active XE interfaces, they may need to react to it also - for (int i = 0; i < xr_server->get_interface_count(); i++) { - Ref<XRInterface> interface = xr_server->get_interface(i); - if (interface.is_valid() && interface->is_initialized()) { - interface->notification(p_what); + if (current) { + // send our notification to all active XE interfaces, they may need to react to it also + for (int i = 0; i < xr_server->get_interface_count(); i++) { + Ref<XRInterface> interface = xr_server->get_interface(i); + if (interface.is_valid() && interface->is_initialized()) { + interface->notification(p_what); + } } } } diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index ef846cc3a3..990fb61983 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -48,8 +48,8 @@ protected: StringName pose_name = "default"; Ref<XRPositionalTracker> tracker; - void _notification(int p_what); - + void _bind_tracker(); + void _unbind_tracker(); void _changed_tracker(const StringName p_tracker_name, int p_tracker_type); void _removed_tracker(const StringName p_tracker_name, int p_tracker_type); void _pose_changed(const Ref<XRPose> &p_pose); @@ -180,7 +180,8 @@ class XROrigin3D : public Node3D { GDCLASS(XROrigin3D, Node3D); private: - XRCamera3D *tracked_camera = nullptr; + bool current = false; + static Vector<XROrigin3D *> origin_nodes; // all origin nodes in tree protected: void _notification(int p_what); @@ -189,12 +190,12 @@ protected: public: PackedStringArray get_configuration_warnings() const override; - void set_tracked_camera(XRCamera3D *p_tracked_camera); - XRCamera3D *get_tracked_camera() const; - real_t get_world_scale() const; void set_world_scale(real_t p_world_scale); + void set_current(bool p_enabled); + bool is_current() const; + XROrigin3D() {} ~XROrigin3D() {} }; diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index af6a99ca62..552345e4fe 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -60,7 +60,7 @@ void BaseButton::gui_input(const Ref<InputEvent> &p_event) { } Ref<InputEventMouseButton> mouse_button = p_event; - bool ui_accept = p_event->is_action("ui_accept") && !p_event->is_echo(); + bool ui_accept = p_event->is_action("ui_accept", true) && !p_event->is_echo(); bool button_masked = mouse_button.is_valid() && (mouse_button_to_mask(mouse_button->get_button_index()) & button_mask) != MouseButton::NONE; if (button_masked || ui_accept) { @@ -349,10 +349,6 @@ Ref<Shortcut> BaseButton::get_shortcut() const { void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (!_is_focus_owner_in_shortcut_context()) { - return; - } - if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->matches_event(p_event)) { on_action_event(p_event); accept_event(); @@ -389,34 +385,6 @@ Ref<ButtonGroup> BaseButton::get_button_group() const { return button_group; } -void BaseButton::set_shortcut_context(Node *p_node) { - if (p_node != nullptr) { - shortcut_context = p_node->get_instance_id(); - } else { - shortcut_context = ObjectID(); - } -} - -Node *BaseButton::get_shortcut_context() const { - Object *ctx_obj = ObjectDB::get_instance(shortcut_context); - Node *ctx_node = Object::cast_to<Node>(ctx_obj); - - return ctx_node; -} - -bool BaseButton::_is_focus_owner_in_shortcut_context() const { - if (shortcut_context == ObjectID()) { - // No context, therefore global - always "in" context. - return true; - } - - Node *ctx_node = get_shortcut_context(); - Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr; - - // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it. - return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus)); -} - bool BaseButton::_was_pressed_by_mouse() const { return was_mouse_pressed; } @@ -446,9 +414,6 @@ void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_button_group", "button_group"), &BaseButton::set_button_group); ClassDB::bind_method(D_METHOD("get_button_group"), &BaseButton::get_button_group); - ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &BaseButton::set_shortcut_context); - ClassDB::bind_method(D_METHOD("get_shortcut_context"), &BaseButton::get_shortcut_context); - GDVIRTUAL_BIND(_pressed); GDVIRTUAL_BIND(_toggled, "button_pressed"); @@ -466,7 +431,6 @@ void BaseButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "Shortcut"), "set_shortcut", "get_shortcut"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "button_group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context"); BIND_ENUM_CONSTANT(DRAW_NORMAL); BIND_ENUM_CONSTANT(DRAW_PRESSED); diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index c83b08aadf..7839239800 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -81,7 +81,6 @@ protected: virtual void shortcut_input(const Ref<InputEvent> &p_event) override; void _notification(int p_what); - bool _is_focus_owner_in_shortcut_context() const; bool _was_pressed_by_mouse() const; GDVIRTUAL0(_pressed) @@ -132,9 +131,6 @@ public: void set_button_group(const Ref<ButtonGroup> &p_group); Ref<ButtonGroup> get_button_group() const; - void set_shortcut_context(Node *p_node); - Node *get_shortcut_context() const; - BaseButton(); ~BaseButton(); }; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 2dcae2553c..565e450d60 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1759,6 +1759,34 @@ void Control::warp_mouse(const Point2 &p_position) { get_viewport()->warp_mouse(get_global_transform_with_canvas().xform(p_position)); } +void Control::set_shortcut_context(const Node *p_node) { + if (p_node != nullptr) { + data.shortcut_context = p_node->get_instance_id(); + } else { + data.shortcut_context = ObjectID(); + } +} + +Node *Control::get_shortcut_context() const { + Object *ctx_obj = ObjectDB::get_instance(data.shortcut_context); + Node *ctx_node = Object::cast_to<Node>(ctx_obj); + + return ctx_node; +} + +bool Control::is_focus_owner_in_shortcut_context() const { + if (data.shortcut_context == ObjectID()) { + // No context, therefore global - always "in" context. + return true; + } + + const Node *ctx_node = get_shortcut_context(); + const Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr; + + // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it. + return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus)); +} + // Drag and drop handling. void Control::set_drag_forwarding(Object *p_target) { @@ -2885,8 +2913,8 @@ void Control::_notification(int p_notification) { if (data.parent_canvas_item) { data.parent_canvas_item->disconnect("item_rect_changed", callable_mp(this, &Control::_size_changed)); data.parent_canvas_item = nullptr; - } else if (!is_set_as_top_level()) { - //disconnect viewport + } else { + // Disconnect viewport. Viewport *viewport = get_viewport(); ERR_FAIL_COND(!viewport); viewport->disconnect("size_changed", callable_mp(this, &Control::_size_changed)); @@ -3133,6 +3161,9 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Control::warp_mouse); + ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &Control::set_shortcut_context); + ClassDB::bind_method(D_METHOD("get_shortcut_context"), &Control::get_shortcut_context); + ClassDB::bind_method(D_METHOD("update_minimum_size"), &Control::update_minimum_size); ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Control::set_layout_direction); @@ -3206,6 +3237,9 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mouse_force_pass_scroll_events"), "set_force_pass_scroll_events", "is_force_pass_scroll_events"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_default_cursor_shape", PROPERTY_HINT_ENUM, "Arrow,I-Beam,Pointing Hand,Cross,Wait,Busy,Drag,Can Drop,Forbidden,Vertical Resize,Horizontal Resize,Secondary Diagonal Resize,Main Diagonal Resize,Move,Vertical Split,Horizontal Split,Help"), "set_default_cursor_shape", "get_default_cursor_shape"); + ADD_GROUP("Input", ""); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context"); + ADD_GROUP("Theme", "theme_"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation"); diff --git a/scene/gui/control.h b/scene/gui/control.h index ee6443c81c..e526690cbe 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -159,6 +159,7 @@ private: } }; + // This Data struct is to avoid namespace pollution in derived classes. struct Data { // Global relations. @@ -218,6 +219,8 @@ private: NodePath focus_next; NodePath focus_prev; + ObjectID shortcut_context; + // Theming. ThemeOwner *theme_owner = nullptr; @@ -487,6 +490,10 @@ public: void warp_mouse(const Point2 &p_position); + bool is_focus_owner_in_shortcut_context() const; + void set_shortcut_context(const Node *p_node); + Node *get_shortcut_context() const; + // Drag and drop handling. virtual void set_drag_forwarding(Object *p_target); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 90552c32c2..caf8db4515 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -1385,16 +1385,16 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { } if (p_ev->is_pressed()) { - if (p_ev->is_action("ui_graph_duplicate")) { + if (p_ev->is_action("ui_graph_duplicate", true)) { emit_signal(SNAME("duplicate_nodes_request")); accept_event(); - } else if (p_ev->is_action("ui_copy")) { + } else if (p_ev->is_action("ui_copy", true)) { emit_signal(SNAME("copy_nodes_request")); accept_event(); - } else if (p_ev->is_action("ui_paste")) { + } else if (p_ev->is_action("ui_paste", true)) { emit_signal(SNAME("paste_nodes_request")); accept_event(); - } else if (p_ev->is_action("ui_graph_delete")) { + } else if (p_ev->is_action("ui_graph_delete", true)) { TypedArray<StringName> nodes; for (int i = 0; i < get_child_count(); i++) { diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 0dc791f71d..223428906a 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -728,7 +728,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { } if (p_event->is_pressed() && items.size() > 0) { - if (p_event->is_action("ui_up")) { + if (p_event->is_action("ui_up", true)) { if (!search_string.is_empty()) { uint64_t now = OS::get_singleton()->get_ticks_msec(); uint64_t diff = now - search_time_msec; @@ -766,7 +766,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { } accept_event(); } - } else if (p_event->is_action("ui_down")) { + } else if (p_event->is_action("ui_down", true)) { if (!search_string.is_empty()) { uint64_t now = OS::get_singleton()->get_ticks_msec(); uint64_t diff = now - search_time_msec; @@ -803,7 +803,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { } accept_event(); } - } else if (p_event->is_action("ui_page_up")) { + } else if (p_event->is_action("ui_page_up", true)) { search_string = ""; //any mousepress cancels for (int i = 4; i > 0; i--) { @@ -817,7 +817,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { break; } } - } else if (p_event->is_action("ui_page_down")) { + } else if (p_event->is_action("ui_page_down", true)) { search_string = ""; //any mousepress cancels for (int i = 4; i > 0; i--) { @@ -832,7 +832,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { break; } } - } else if (p_event->is_action("ui_left")) { + } else if (p_event->is_action("ui_left", true)) { search_string = ""; //any mousepress cancels if (current % current_columns != 0) { @@ -852,7 +852,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { } accept_event(); } - } else if (p_event->is_action("ui_right")) { + } else if (p_event->is_action("ui_right", true)) { search_string = ""; //any mousepress cancels if (current % current_columns != (current_columns - 1) && current + 1 < items.size()) { @@ -872,9 +872,9 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { } accept_event(); } - } else if (p_event->is_action("ui_cancel")) { + } else if (p_event->is_action("ui_cancel", true)) { search_string = ""; - } else if (p_event->is_action("ui_select") && select_mode == SELECT_MULTI) { + } else if (p_event->is_action("ui_select", true) && select_mode == SELECT_MULTI) { if (current >= 0 && current < items.size()) { if (items[current].selectable && !items[current].disabled && !items[current].selected) { select(current, false); @@ -884,7 +884,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { emit_signal(SNAME("multi_selected"), current, false); } } - } else if (p_event->is_action("ui_accept")) { + } else if (p_event->is_action("ui_accept", true)) { search_string = ""; //any mousepress cancels if (current >= 0 && current < items.size()) { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 36e85b5d02..65670b7786 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -2175,6 +2175,12 @@ void LineEdit::_emit_text_change() { } void LineEdit::_shape() { + const Ref<Font> &font = theme_cache.font; + int font_size = theme_cache.font_size; + if (font.is_null()) { + return; + } + Size2 old_size = TS->shaped_text_get_size(text_rid); TS->shaped_text_clear(text_rid); @@ -2197,9 +2203,6 @@ void LineEdit::_shape() { } TS->shaped_text_set_preserve_control(text_rid, draw_control_chars); - const Ref<Font> &font = theme_cache.font; - int font_size = theme_cache.font_size; - ERR_FAIL_COND(font.is_null()); TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, font->get_opentype_features(), language); for (int i = 0; i < TextServer::SPACING_MAX; i++) { TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i))); diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index 742042f65f..82ef53e317 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -41,7 +41,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) { } MutexLock lock(mutex); - if (p_event->is_action("ui_left") && p_event->is_pressed()) { + if (p_event->is_action("ui_left", true) && p_event->is_pressed()) { int new_sel = selected_menu; int old_sel = (selected_menu < 0) ? 0 : selected_menu; do { @@ -63,7 +63,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) { _open_popup(selected_menu, true); } return; - } else if (p_event->is_action("ui_right") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_right", true) && p_event->is_pressed()) { int new_sel = selected_menu; int old_sel = (selected_menu < 0) ? menu_cache.size() - 1 : selected_menu; do { @@ -149,10 +149,6 @@ void MenuBar::_open_popup(int p_index, bool p_focus_item) { void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (!_is_focus_owner_in_shortcut_context()) { - return; - } - if (disable_shortcuts) { return; } @@ -175,34 +171,6 @@ void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) { } } -void MenuBar::set_shortcut_context(Node *p_node) { - if (p_node != nullptr) { - shortcut_context = p_node->get_instance_id(); - } else { - shortcut_context = ObjectID(); - } -} - -Node *MenuBar::get_shortcut_context() const { - Object *ctx_obj = ObjectDB::get_instance(shortcut_context); - Node *ctx_node = Object::cast_to<Node>(ctx_obj); - - return ctx_node; -} - -bool MenuBar::_is_focus_owner_in_shortcut_context() const { - if (shortcut_context == ObjectID()) { - // No context, therefore global - always "in" context. - return true; - } - - Node *ctx_node = get_shortcut_context(); - Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr; - - // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it. - return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus)); -} - void MenuBar::_popup_visibility_changed(bool p_visible) { if (!p_visible) { active_menu = -1; @@ -694,16 +662,12 @@ void MenuBar::_bind_methods() { ClassDB::bind_method(D_METHOD("set_menu_hidden", "menu", "hidden"), &MenuBar::set_menu_hidden); ClassDB::bind_method(D_METHOD("is_menu_hidden", "menu"), &MenuBar::is_menu_hidden); - ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &MenuBar::set_shortcut_context); - ClassDB::bind_method(D_METHOD("get_shortcut_context"), &MenuBar::get_shortcut_context); - ClassDB::bind_method(D_METHOD("get_menu_popup", "menu"), &MenuBar::get_menu_popup); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "start_index"), "set_start_index", "get_start_index"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefer_global_menu"), "set_prefer_global_menu", "is_prefer_global_menu"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context"); ADD_GROUP("BiDi", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h index f7ef19e98b..c057a7c96f 100644 --- a/scene/gui/menu_bar.h +++ b/scene/gui/menu_bar.h @@ -118,8 +118,6 @@ class MenuBar : public Control { void _clear_menu(); void _update_menu(); - bool _is_focus_owner_in_shortcut_context() const; - protected: virtual void shortcut_input(const Ref<InputEvent> &p_event) override; @@ -170,9 +168,6 @@ public: void set_menu_hidden(int p_menu, bool p_hidden); bool is_menu_hidden(int p_menu) const; - void set_shortcut_context(Node *p_node); - Node *get_shortcut_context() const; - PopupMenu *get_menu_popup(int p_menu) const; virtual void get_translatable_strings(List<String> *p_strings) const override; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 78aeab9457..786f23873e 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -36,10 +36,6 @@ void MenuButton::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (!_is_focus_owner_in_shortcut_context()) { - return; - } - if (disable_shortcuts) { return; } diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 4cdde5902e..9a411ef7ed 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -273,7 +273,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (!items.is_empty()) { - if (p_event->is_action("ui_down") && p_event->is_pressed()) { + if (p_event->is_action("ui_down", true) && p_event->is_pressed()) { int search_from = mouse_over + 1; if (search_from >= items.size()) { search_from = 0; @@ -305,7 +305,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { } } } - } else if (p_event->is_action("ui_up") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_up", true) && p_event->is_pressed()) { int search_from = mouse_over - 1; if (search_from < 0) { search_from = items.size() - 1; @@ -337,7 +337,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { } } } - } else if (p_event->is_action("ui_left") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_left", true) && p_event->is_pressed()) { Node *n = get_parent(); if (n) { if (Object::cast_to<PopupMenu>(n)) { @@ -349,7 +349,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { return; } } - } else if (p_event->is_action("ui_right") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_right", true) && p_event->is_pressed()) { if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && !items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) { _activate_submenu(mouse_over, true); set_input_as_handled(); @@ -361,7 +361,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { return; } } - } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_accept", true) && p_event->is_pressed()) { if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) { if (!items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) { _activate_submenu(mouse_over, true); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 9217f31310..c96d3c763d 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -2019,36 +2019,36 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { if (k->is_pressed()) { bool handled = false; - if (k->is_action("ui_page_up") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_page_up", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(vscroll->get_value() - vscroll->get_page()); handled = true; } - if (k->is_action("ui_page_down") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_page_down", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(vscroll->get_value() + vscroll->get_page()); handled = true; } - if (k->is_action("ui_up") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_up", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(vscroll->get_value() - theme_cache.normal_font->get_height(theme_cache.normal_font_size)); handled = true; } - if (k->is_action("ui_down") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_down", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(vscroll->get_value() + theme_cache.normal_font->get_height(theme_cache.normal_font_size)); handled = true; } - if (k->is_action("ui_home") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_home", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(0); handled = true; } - if (k->is_action("ui_end") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_end", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(vscroll->get_max()); handled = true; } if (is_shortcut_keys_enabled()) { - if (k->is_action("ui_text_select_all")) { + if (k->is_action("ui_text_select_all", true)) { select_all(); handled = true; } - if (k->is_action("ui_copy")) { + if (k->is_action("ui_copy", true)) { selection_copy(); handled = true; } diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 6c05b171e3..193c6f1ce7 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -183,35 +183,35 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { } if (p_event->is_pressed()) { - if (p_event->is_action("ui_left")) { + if (p_event->is_action("ui_left", true)) { if (orientation != HORIZONTAL) { return; } set_value(get_value() - (custom_step >= 0 ? custom_step : get_step())); - } else if (p_event->is_action("ui_right")) { + } else if (p_event->is_action("ui_right", true)) { if (orientation != HORIZONTAL) { return; } set_value(get_value() + (custom_step >= 0 ? custom_step : get_step())); - } else if (p_event->is_action("ui_up")) { + } else if (p_event->is_action("ui_up", true)) { if (orientation != VERTICAL) { return; } set_value(get_value() - (custom_step >= 0 ? custom_step : get_step())); - } else if (p_event->is_action("ui_down")) { + } else if (p_event->is_action("ui_down", true)) { if (orientation != VERTICAL) { return; } set_value(get_value() + (custom_step >= 0 ? custom_step : get_step())); - } else if (p_event->is_action("ui_home")) { + } else if (p_event->is_action("ui_home", true)) { set_value(get_min()); - } else if (p_event->is_action("ui_end")) { + } else if (p_event->is_action("ui_end", true)) { set_value(get_max()); } } diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index a7d44c0f3c..6cbacf0dd3 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -138,10 +138,10 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) { } set_value(get_value() - (custom_step >= 0 ? custom_step : get_step())); accept_event(); - } else if (p_event->is_action("ui_home") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_home", true) && p_event->is_pressed()) { set_value(get_min()); accept_event(); - } else if (p_event->is_action("ui_end") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_end", true) && p_event->is_pressed()) { set_value(get_max()); accept_event(); } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 2e8fa1e606..6f9a9a5141 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -3191,7 +3191,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; bool is_command = k.is_valid() && k->is_command_or_control_pressed(); - if (p_event->is_action("ui_right") && p_event->is_pressed()) { + if (p_event->is_action("ui_right", true) && p_event->is_pressed()) { if (!cursor_can_exit_tree) { accept_event(); } @@ -3209,7 +3209,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } else { _go_right(); } - } else if (p_event->is_action("ui_left") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_left", true) && p_event->is_pressed()) { if (!cursor_can_exit_tree) { accept_event(); } @@ -3229,21 +3229,21 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { _go_left(); } - } else if (p_event->is_action("ui_up") && p_event->is_pressed() && !is_command) { + } else if (p_event->is_action("ui_up", true) && p_event->is_pressed() && !is_command) { if (!cursor_can_exit_tree) { accept_event(); } _go_up(); - } else if (p_event->is_action("ui_down") && p_event->is_pressed() && !is_command) { + } else if (p_event->is_action("ui_down", true) && p_event->is_pressed() && !is_command) { if (!cursor_can_exit_tree) { accept_event(); } _go_down(); - } else if (p_event->is_action("ui_page_down") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_page_down", true) && p_event->is_pressed()) { if (!cursor_can_exit_tree) { accept_event(); } @@ -3281,7 +3281,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } ensure_cursor_is_visible(); - } else if (p_event->is_action("ui_page_up") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_page_up", true) && p_event->is_pressed()) { if (!cursor_can_exit_tree) { accept_event(); } @@ -3318,7 +3318,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { prev->select(selected_col); } ensure_cursor_is_visible(); - } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_accept", true) && p_event->is_pressed()) { if (selected_item) { //bring up editor if possible if (!edit_selected()) { @@ -3327,7 +3327,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } } accept_event(); - } else if (p_event->is_action("ui_select") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_select", true) && p_event->is_pressed()) { if (select_mode == SELECT_MULTI) { if (!selected_item) { return; diff --git a/scene/gui/view_panner.cpp b/scene/gui/view_panner.cpp index 3b7f499a07..e8e3e3e556 100644 --- a/scene/gui/view_panner.cpp +++ b/scene/gui/view_panner.cpp @@ -38,7 +38,9 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect) Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { Vector2 scroll_vec = Vector2((mb->get_button_index() == MouseButton::WHEEL_RIGHT) - (mb->get_button_index() == MouseButton::WHEEL_LEFT), (mb->get_button_index() == MouseButton::WHEEL_DOWN) - (mb->get_button_index() == MouseButton::WHEEL_UP)); - if (scroll_vec != Vector2()) { + // Moving the scroll wheel sends two events: one with pressed as true, + // and one with pressed as false. Make sure we only process one of them. + if (scroll_vec != Vector2() && mb->is_pressed()) { if (control_scheme == SCROLL_PANS) { if (mb->is_ctrl_pressed()) { scroll_vec.y *= mb->get_factor(); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 6ab27853f1..2ea45df309 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -322,62 +322,62 @@ void Node::_propagate_exit_tree() { data.depth = -1; } -void Node::move_child(Node *p_child, int p_pos) { +void Node::move_child(Node *p_child, int p_index) { ERR_FAIL_NULL(p_child); ERR_FAIL_COND_MSG(p_child->data.parent != this, "Child is not a child of this node."); // We need to check whether node is internal and move it only in the relevant node range. if (p_child->_is_internal_front()) { - if (p_pos < 0) { - p_pos += data.internal_children_front; + if (p_index < 0) { + p_index += data.internal_children_front; } - ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_front, vformat("Invalid new child position: %d. Child is internal.", p_pos)); - _move_child(p_child, p_pos); + ERR_FAIL_INDEX_MSG(p_index, data.internal_children_front, vformat("Invalid new child index: %d. Child is internal.", p_index)); + _move_child(p_child, p_index); } else if (p_child->_is_internal_back()) { - if (p_pos < 0) { - p_pos += data.internal_children_back; + if (p_index < 0) { + p_index += data.internal_children_back; } - ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_back, vformat("Invalid new child position: %d. Child is internal.", p_pos)); - _move_child(p_child, data.children.size() - data.internal_children_back + p_pos); + ERR_FAIL_INDEX_MSG(p_index, data.internal_children_back, vformat("Invalid new child index: %d. Child is internal.", p_index)); + _move_child(p_child, data.children.size() - data.internal_children_back + p_index); } else { - if (p_pos < 0) { - p_pos += get_child_count(false); + if (p_index < 0) { + p_index += get_child_count(false); } - ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child position: %d.", p_pos)); - _move_child(p_child, p_pos + data.internal_children_front); + ERR_FAIL_INDEX_MSG(p_index, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child index: %d.", p_index)); + _move_child(p_child, p_index + data.internal_children_front); } } -void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) { +void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) { ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup)."); // Specifying one place beyond the end - // means the same as moving to the last position + // means the same as moving to the last index if (!p_ignore_end) { // p_ignore_end is a little hack to make back internal children work properly. if (p_child->_is_internal_front()) { - if (p_pos == data.internal_children_front) { - p_pos--; + if (p_index == data.internal_children_front) { + p_index--; } } else if (p_child->_is_internal_back()) { - if (p_pos == data.children.size()) { - p_pos--; + if (p_index == data.children.size()) { + p_index--; } } else { - if (p_pos == data.children.size() - data.internal_children_back) { - p_pos--; + if (p_index == data.children.size() - data.internal_children_back) { + p_index--; } } } - if (p_child->data.pos == p_pos) { + if (p_child->data.index == p_index) { return; //do nothing } - int motion_from = MIN(p_pos, p_child->data.pos); - int motion_to = MAX(p_pos, p_child->data.pos); + int motion_from = MIN(p_index, p_child->data.index); + int motion_to = MAX(p_index, p_child->data.index); - data.children.remove_at(p_child->data.pos); - data.children.insert(p_pos, p_child); + data.children.remove_at(p_child->data.index); + data.children.insert(p_index, p_child); if (data.tree) { data.tree->tree_changed(); @@ -386,7 +386,7 @@ void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) { data.blocked++; //new pos first for (int i = motion_from; i <= motion_to; i++) { - data.children[i]->data.pos = i; + data.children[i]->data.index = i; } // notification second move_child_notify(p_child); @@ -1104,7 +1104,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) { //add a child node quickly, without name validation p_child->data.name = p_name; - p_child->data.pos = data.children.size(); + p_child->data.index = data.children.size(); data.children.push_back(p_child); p_child->data.parent = this; @@ -1171,9 +1171,9 @@ void Node::remove_child(Node *p_child) { Node **children = data.children.ptrw(); int idx = -1; - if (p_child->data.pos >= 0 && p_child->data.pos < child_count) { - if (children[p_child->data.pos] == p_child) { - idx = p_child->data.pos; + if (p_child->data.index >= 0 && p_child->data.index < child_count) { + if (children[p_child->data.index] == p_child) { + idx = p_child->data.index; } } @@ -1209,12 +1209,12 @@ void Node::remove_child(Node *p_child) { children = data.children.ptrw(); for (int i = idx; i < child_count; i++) { - children[i]->data.pos = i; + children[i]->data.index = i; children[i]->notification(NOTIFICATION_MOVED_IN_PARENT); } p_child->data.parent = nullptr; - p_child->data.pos = -1; + p_child->data.index = -1; if (data.inside_tree) { p_child->_propagate_after_exit_tree(); @@ -1473,7 +1473,7 @@ bool Node::is_greater_than(const Node *p_node) const { int idx = data.depth - 1; while (n) { ERR_FAIL_INDEX_V(idx, data.depth, false); - this_stack[idx--] = n->data.pos; + this_stack[idx--] = n->data.index; n = n->data.parent; } ERR_FAIL_COND_V(idx != -1, false); @@ -1481,7 +1481,7 @@ bool Node::is_greater_than(const Node *p_node) const { idx = p_node->data.depth - 1; while (n) { ERR_FAIL_INDEX_V(idx, p_node->data.depth, false); - that_stack[idx--] = n->data.pos; + that_stack[idx--] = n->data.index; n = n->data.parent; } @@ -1892,9 +1892,9 @@ int Node::get_index(bool p_include_internal) const { ERR_FAIL_COND_V_MSG(!p_include_internal && (_is_internal_front() || _is_internal_back()), -1, "Node is internal. Can't get index with 'include_internal' being false."); if (data.parent && !p_include_internal) { - return data.pos - data.parent->data.internal_children_front; + return data.index - data.parent->data.internal_children_front; } - return data.pos; + return data.index; } Ref<Tween> Node::create_tween() { @@ -2389,12 +2389,12 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) { } Node *parent = data.parent; - int pos_in_parent = data.pos; + int index_in_parent = data.index; if (data.parent) { parent->remove_child(this); parent->add_child(p_node); - parent->move_child(p_node, pos_in_parent); + parent->move_child(p_node, index_in_parent); } while (get_child_count()) { @@ -2757,7 +2757,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("add_to_group", "group", "persistent"), &Node::add_to_group, DEFVAL(false)); ClassDB::bind_method(D_METHOD("remove_from_group", "group"), &Node::remove_from_group); ClassDB::bind_method(D_METHOD("is_in_group", "group"), &Node::is_in_group); - ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_position"), &Node::move_child); + ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_index"), &Node::move_child); ClassDB::bind_method(D_METHOD("get_groups"), &Node::_get_groups); ClassDB::bind_method(D_METHOD("set_owner", "owner"), &Node::set_owner); ClassDB::bind_method(D_METHOD("get_owner"), &Node::get_owner); diff --git a/scene/main/node.h b/scene/main/node.h index 4e6530cccd..c8c8c395ce 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -91,6 +91,7 @@ private: SceneTree::Group *group = nullptr; }; + // This Data struct is to avoid namespace pollution in derived classes. struct Data { String scene_file_path; Ref<SceneState> instance_state; @@ -104,7 +105,7 @@ private: int internal_children_front = 0; int internal_children_back = 0; - int pos = -1; + int index = -1; int depth = -1; int blocked = 0; // Safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed. StringName name; @@ -186,8 +187,8 @@ private: Error _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Error _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.pos < data.parent->data.internal_children_front; } - _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.pos >= data.parent->data.children.size() - data.parent->data.internal_children_back; } + _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.index < data.parent->data.internal_children_front; } + _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.index >= data.parent->data.children.size() - data.parent->data.internal_children_back; } friend class SceneTree; @@ -346,8 +347,8 @@ public: void get_groups(List<GroupInfo> *p_groups) const; int get_persistent_group_count() const; - void move_child(Node *p_child, int p_pos); - void _move_child(Node *p_child, int p_pos, bool p_ignore_end = false); + void move_child(Node *p_child, int p_index); + void _move_child(Node *p_child, int p_index, bool p_ignore_end = false); void set_owner(Node *p_owner); Node *get_owner() const; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 64eb3b879b..270e5b7025 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -44,6 +44,7 @@ #include "node.h" #include "scene/animation/tween.h" #include "scene/debugger/scene_debugger.h" +#include "scene/gui/control.h" #include "scene/main/multiplayer_api.h" #include "scene/main/viewport.h" #include "scene/resources/environment.h" @@ -895,6 +896,8 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal call_lock++; + Vector<Node *> no_context_nodes; + for (int i = gr_node_count - 1; i >= 0; i--) { if (p_viewport->is_input_handled()) { break; @@ -913,9 +916,22 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal case CALL_INPUT_TYPE_INPUT: n->_call_input(p_input); break; - case CALL_INPUT_TYPE_SHORTCUT_INPUT: + case CALL_INPUT_TYPE_SHORTCUT_INPUT: { + const Control *c = Object::cast_to<Control>(n); + if (c) { + // If calling shortcut input on a control, ensure it respects the shortcut context. + // Shortcut context (based on focus) only makes sense for controls (UI), so don't need to worry about it for nodes + if (c->get_shortcut_context() == nullptr) { + no_context_nodes.append(n); + continue; + } + if (!c->is_focus_owner_in_shortcut_context()) { + continue; + } + } n->_call_shortcut_input(p_input); break; + } case CALL_INPUT_TYPE_UNHANDLED_INPUT: n->_call_unhandled_input(p_input); break; @@ -925,6 +941,10 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal } } + for (Node *n : no_context_nodes) { + n->_call_shortcut_input(p_input); + } + call_lock--; if (call_lock == 0) { call_skip.clear(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index f7a515dc1d..f66337a2f9 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1490,7 +1490,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.key_event_accepted = false; Point2 mpos = mb->get_position(); - gui.last_mouse_pos = mpos; if (mb->is_pressed()) { Size2 pos = mpos; if (gui.mouse_focus_mask != MouseButton::NONE) { @@ -1644,8 +1643,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.key_event_accepted = false; Point2 mpos = mm->get_position(); - gui.last_mouse_pos = mpos; - // Drag & drop. if (!gui.drag_attempted && gui.mouse_focus && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) { gui.drag_accum += mm->get_relative(); @@ -2759,6 +2756,11 @@ void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) { ev = p_event; } + Ref<InputEventMouse> me = ev; + if (me.is_valid()) { + gui.last_mouse_pos = me->get_position(); + } + if (is_embedding_subwindows() && _sub_windows_forward_input(ev)) { set_input_as_handled(); return; diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index 0505f6b559..1b06e09bb8 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -639,9 +639,7 @@ void BitMap::resize(const Size2i &p_new_size) { } Ref<Image> BitMap::convert_to_image() const { - Ref<Image> image; - image.instantiate(); - image->create(width, height, false, Image::FORMAT_L8); + Ref<Image> image = Image::create_empty(width, height, false, Image::FORMAT_L8); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp index 4eaae111a1..5bcefcd0e4 100644 --- a/scene/resources/convex_polygon_shape_3d.cpp +++ b/scene/resources/convex_polygon_shape_3d.cpp @@ -42,9 +42,9 @@ Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const { if (err == OK) { Vector<Vector3> lines; lines.resize(md.edges.size() * 2); - for (int i = 0; i < md.edges.size(); i++) { - lines.write[i * 2 + 0] = md.vertices[md.edges[i].a]; - lines.write[i * 2 + 1] = md.vertices[md.edges[i].b]; + for (uint32_t i = 0; i < md.edges.size(); i++) { + lines.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a]; + lines.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b]; } return lines; } diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 1f71d583b1..1c99fa5554 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -1546,7 +1546,7 @@ Array SceneState::get_connection_binds(int p_idx) const { return binds; } -bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method) { +bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method, bool p_no_inheritance) { // this method cannot be const because of this Ref<SceneState> ss = this; @@ -1578,6 +1578,10 @@ bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p } } + if (p_no_inheritance) { + break; + } + ss = ss->get_base_scene_state(); } while (ss.is_valid()); diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 8e1a1d29b6..c6f82ddd5e 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -176,7 +176,7 @@ public: int get_connection_unbinds(int p_idx) const; Array get_connection_binds(int p_idx) const; - bool has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method); + bool has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method, bool p_no_inheritance = false); Vector<NodePath> get_editable_instances() const; diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp index 692a40badc..b77430c154 100644 --- a/scene/resources/particle_process_material.cpp +++ b/scene/resources/particle_process_material.cpp @@ -115,6 +115,7 @@ void ParticleProcessMaterial::init_shaders() { shader_names->sub_emitter_frequency = "sub_emitter_frequency"; shader_names->sub_emitter_amount_at_end = "sub_emitter_amount_at_end"; + shader_names->sub_emitter_amount_at_collision = "sub_emitter_amount_at_collision"; shader_names->sub_emitter_keep_velocity = "sub_emitter_keep_velocity"; shader_names->collision_friction = "collision_friction"; @@ -235,6 +236,9 @@ void ParticleProcessMaterial::_update_shader() { if (sub_emitter_mode == SUB_EMITTER_AT_END) { code += "uniform int sub_emitter_amount_at_end;\n"; } + if (sub_emitter_mode == SUB_EMITTER_AT_COLLISION) { + code += "uniform int sub_emitter_amount_at_collision;\n"; + } code += "uniform bool sub_emitter_keep_velocity;\n"; } @@ -866,7 +870,7 @@ void ParticleProcessMaterial::_update_shader() { code += " if (DELTA >= interval_rem) emit_count = 1;\n"; } break; case SUB_EMITTER_AT_COLLISION: { - code += " if (COLLIDED) emit_count = 1;\n"; + code += " if (COLLIDED) emit_count = sub_emitter_amount_at_collision;\n"; } break; case SUB_EMITTER_AT_END: { code += " float unit_delta = DELTA/LIFETIME;\n"; @@ -1425,6 +1429,10 @@ void ParticleProcessMaterial::_validate_property(PropertyInfo &p_property) const p_property.usage = PROPERTY_USAGE_NONE; } + if (p_property.name == "sub_emitter_amount_at_collision" && sub_emitter_mode != SUB_EMITTER_AT_COLLISION) { + p_property.usage = PROPERTY_USAGE_NONE; + } + if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { p_property.usage = PROPERTY_USAGE_NONE; } @@ -1480,6 +1488,15 @@ int ParticleProcessMaterial::get_sub_emitter_amount_at_end() const { return sub_emitter_amount_at_end; } +void ParticleProcessMaterial::set_sub_emitter_amount_at_collision(int p_amount) { + sub_emitter_amount_at_collision = p_amount; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_collision, p_amount); +} + +int ParticleProcessMaterial::get_sub_emitter_amount_at_collision() const { + return sub_emitter_amount_at_collision; +} + void ParticleProcessMaterial::set_sub_emitter_keep_velocity(bool p_enable) { sub_emitter_keep_velocity = p_enable; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable); @@ -1632,6 +1649,9 @@ void ParticleProcessMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticleProcessMaterial::get_sub_emitter_amount_at_end); ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_end); + ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_collision"), &ParticleProcessMaterial::get_sub_emitter_amount_at_collision); + ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_collision", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_collision); + ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticleProcessMaterial::get_sub_emitter_keep_velocity); ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticleProcessMaterial::set_sub_emitter_keep_velocity); @@ -1744,6 +1764,7 @@ void ParticleProcessMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,At End,At Collision"), "set_sub_emitter_mode", "get_sub_emitter_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:Hz"), "set_sub_emitter_frequency", "get_sub_emitter_frequency"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_collision", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_collision", "get_sub_emitter_amount_at_collision"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity"); ADD_GROUP("Attractor Interaction", "attractor_interaction_"); @@ -1851,6 +1872,7 @@ ParticleProcessMaterial::ParticleProcessMaterial() : set_sub_emitter_mode(SUB_EMITTER_DISABLED); set_sub_emitter_frequency(4); set_sub_emitter_amount_at_end(1); + set_sub_emitter_amount_at_collision(1); set_sub_emitter_keep_velocity(false); set_attractor_interaction_enabled(true); diff --git a/scene/resources/particle_process_material.h b/scene/resources/particle_process_material.h index 8fe9223a47..64d828b3e7 100644 --- a/scene/resources/particle_process_material.h +++ b/scene/resources/particle_process_material.h @@ -246,6 +246,7 @@ private: StringName sub_emitter_frequency; StringName sub_emitter_amount_at_end; + StringName sub_emitter_amount_at_collision; StringName sub_emitter_keep_velocity; StringName collision_friction; @@ -304,6 +305,7 @@ private: SubEmitterMode sub_emitter_mode; double sub_emitter_frequency = 0.0; int sub_emitter_amount_at_end = 0; + int sub_emitter_amount_at_collision = 0; bool sub_emitter_keep_velocity = false; //do not save emission points here @@ -418,6 +420,9 @@ public: void set_sub_emitter_amount_at_end(int p_amount); int get_sub_emitter_amount_at_end() const; + void set_sub_emitter_amount_at_collision(int p_amount); + int get_sub_emitter_amount_at_collision() const; + void set_sub_emitter_keep_velocity(bool p_enable); bool get_sub_emitter_keep_velocity() const; diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 7d0336cff3..eb83a37c7b 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -771,6 +771,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto thisrow = 0; prevrow = 0; + const real_t side_normal_y = (bottom_radius - top_radius) / height; for (j = 0; j <= (rings + 1); j++) { v = j; v /= (rings + 1); @@ -789,7 +790,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto Vector3 p = Vector3(x * radius, y, z * radius); points.push_back(p); - normals.push_back(Vector3(x, 0.0, z)); + normals.push_back(Vector3(x, side_normal_y, z).normalized()); ADD_TANGENT(z, 0.0, -x, 1.0) uvs.push_back(Vector2(u, v * 0.5)); point++; diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 4085aa8ec2..3a2b0ed9cb 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -740,7 +740,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si } } - image->create(w, h, true, mipmap_images[0]->get_format(), img_data); + image->set_data(w, h, true, mipmap_images[0]->get_format(), img_data); return image; } @@ -766,10 +766,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si f->get_buffer(wr, data.size()); } - Ref<Image> image; - image.instantiate(); - - image->create(tw, th, mipmaps - i ? true : false, format, data); + Ref<Image> image = Image::create_from_data(tw, th, mipmaps - i ? true : false, format, data); return image; } @@ -2336,11 +2333,11 @@ void GradientTexture2D::_update() { image.instantiate(); if (gradient->get_points_count() <= 1) { // No need to interpolate. - image->create(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8); + image->initialize_data(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8); image->fill((gradient->get_points_count() == 1) ? gradient->get_color(0) : Color(0, 0, 0, 1)); } else { if (use_hdr) { - image->create(width, height, false, Image::FORMAT_RGBAF); + image->initialize_data(width, height, false, Image::FORMAT_RGBAF); Gradient &g = **gradient; // `create()` isn't available for non-uint8_t data, so fill in the data manually. for (int y = 0; y < height; y++) { @@ -2367,7 +2364,7 @@ void GradientTexture2D::_update() { } } } - image->create(width, height, false, Image::FORMAT_RGBA8, data); + image->set_data(width, height, false, Image::FORMAT_RGBA8, data); } } diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index d7d7b5fe31..3caf6484d9 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -1801,11 +1801,11 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) { // Get the best tile. Ref<Texture2D> texture = counts[terrain_set][terrain].texture; Rect2i region = counts[terrain_set][terrain].region; - image->create(region.size.x, region.size.y, false, Image::FORMAT_RGBA8); + image->initialize_data(region.size.x, region.size.y, false, Image::FORMAT_RGBA8); image->blit_rect(texture->get_image(), region, Point2i()); image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST); } else { - image->create(1, 1, false, Image::FORMAT_RGBA8); + image->initialize_data(1, 1, false, Image::FORMAT_RGBA8); image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain)); } Ref<ImageTexture> icon = ImageTexture::create_from_image(image); @@ -4602,9 +4602,7 @@ void TileSetAtlasSource::_update_padded_texture() { return; } - Ref<Image> image; - image.instantiate(); - image->create(size.x, size.y, false, src->get_format()); + Ref<Image> image = Image::create_empty(size.x, size.y, false, src->get_format()); for (KeyValue<Vector2i, TileAlternativesData> kv : tiles) { for (int frame = 0; frame < (int)kv.value.animation_frames_durations.size(); frame++) { diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp index ab7354f6e7..f125b05a26 100644 --- a/scene/resources/visual_shader_particle_nodes.cpp +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -460,9 +460,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector2> image.instantiate(); if (p_array.size() == 0) { - image->create(1, 1, false, Image::Format::FORMAT_RGBF); + image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBF); } else { - image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); + image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); } for (int i = 0; i < p_array.size(); i++) { @@ -481,9 +481,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector3> image.instantiate(); if (p_array.size() == 0) { - image->create(1, 1, false, Image::Format::FORMAT_RGBF); + image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBF); } else { - image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); + image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); } for (int i = 0; i < p_array.size(); i++) { @@ -502,9 +502,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Color> &p image.instantiate(); if (p_array.size() == 0) { - image->create(1, 1, false, Image::Format::FORMAT_RGBA8); + image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBA8); } else { - image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8); + image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8); } for (int i = 0; i < p_array.size(); i++) { |